Started to update addon loader to support new xml structure. It's not expected
to work yet. git-svn-id: svn+ssh://svn.code.sf.net/p/supertuxkart/code/main/trunk@8217 178a84e3-b1eb-0310-8ba1-8eac791a3b58
This commit is contained in:
parent
699967dd05
commit
ea32a4d52e
@ -12,7 +12,7 @@
|
|||||||
<spacer proportion="1" />
|
<spacer proportion="1" />
|
||||||
<div width="50%" height="100%" layout="vertical-row" >
|
<div width="50%" height="100%" layout="vertical-row" >
|
||||||
<label word_wrap="true" id="description" width="100%" text="Description:" proportion="1" />
|
<label word_wrap="true" id="description" width="100%" text="Description:" proportion="1" />
|
||||||
<label id="version" width="100%" text="Version:" proportion="1" />
|
<label id="revision" width="100%" text="Version:" proportion="1" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -32,13 +32,13 @@ Addon::Addon(const XMLNode &xml)
|
|||||||
m_name = "";
|
m_name = "";
|
||||||
m_id = "";
|
m_id = "";
|
||||||
m_installed = false;
|
m_installed = false;
|
||||||
m_installed_version = 0;
|
m_installed_revision = 0;
|
||||||
m_version = 0 ;
|
m_revision = 0 ;
|
||||||
m_zip_file = "";
|
m_zip_file = "";
|
||||||
m_description = "";
|
m_description = "";
|
||||||
m_icon_url = "";
|
m_icon_url = "";
|
||||||
m_icon_basename = "";
|
m_icon_basename = "";
|
||||||
m_icon_version = 0;
|
m_icon_revision = 0;
|
||||||
m_icon_ready = false;
|
m_icon_ready = false;
|
||||||
m_type = xml.getName();
|
m_type = xml.getName();
|
||||||
|
|
||||||
@ -46,27 +46,27 @@ Addon::Addon(const XMLNode &xml)
|
|||||||
m_id = StringUtils::toLowerCase(m_name);
|
m_id = StringUtils::toLowerCase(m_name);
|
||||||
xml.get("id", &m_id);
|
xml.get("id", &m_id);
|
||||||
xml.get("installed", &m_installed );
|
xml.get("installed", &m_installed );
|
||||||
xml.get("installed-version", &m_installed_version);
|
xml.get("installed-revision", &m_installed_revision);
|
||||||
xml.get("version", &m_version );
|
xml.get("revision", &m_revision );
|
||||||
xml.get("file", &m_zip_file );
|
xml.get("file", &m_zip_file );
|
||||||
xml.get("description", &m_description );
|
xml.get("description", &m_description );
|
||||||
xml.get("icon", &m_icon_url );
|
xml.get("image", &m_icon_url );
|
||||||
xml.get("icon-version", &m_icon_version );
|
xml.get("icon-revision", &m_icon_revision );
|
||||||
m_icon_basename = StringUtils::getBasename(m_icon_url);
|
m_icon_basename = StringUtils::getBasename(m_icon_url);
|
||||||
}; // Addon(const XML&)
|
}; // Addon(const XML&)
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
/** Copies the installation data (like description, version, icon) from the
|
/** Copies the installation data (like description, revision, icon) from the
|
||||||
* downloaded online list to this entry.
|
* downloaded online list to this entry.
|
||||||
*/
|
*/
|
||||||
void Addon::copyInstallData(const Addon &addon)
|
void Addon::copyInstallData(const Addon &addon)
|
||||||
{
|
{
|
||||||
m_description = addon.m_description;
|
m_description = addon.m_description;
|
||||||
m_version = addon.m_version;
|
m_revision = addon.m_revision;
|
||||||
m_zip_file = addon.m_zip_file;
|
m_zip_file = addon.m_zip_file;
|
||||||
m_icon_url = addon.m_icon_url;
|
m_icon_url = addon.m_icon_url;
|
||||||
m_icon_basename = addon.m_icon_basename;
|
m_icon_basename = addon.m_icon_basename;
|
||||||
m_icon_version = addon.m_version;
|
m_icon_revision = addon.m_revision;
|
||||||
} // copyInstallData
|
} // copyInstallData
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
@ -81,8 +81,8 @@ void Addon::writeXML(std::ofstream *out_stream)
|
|||||||
<< "\" id=\"" << m_id
|
<< "\" id=\"" << m_id
|
||||||
<< "\" installed=\""
|
<< "\" installed=\""
|
||||||
<< (m_installed ? "true" : "false" )
|
<< (m_installed ? "true" : "false" )
|
||||||
<< "\" installed-version=\"" << m_installed_version
|
<< "\" installed-revision=\"" << m_installed_revision
|
||||||
<<"\" icon-version=\"" << m_icon_version
|
<<"\" icon-revision=\"" << m_icon_revision
|
||||||
<< "\"/>\n";
|
<< "\"/>\n";
|
||||||
} // writeXML
|
} // writeXML
|
||||||
|
|
||||||
|
@ -32,12 +32,12 @@ public:
|
|||||||
/** Internal id for this addon, which is the name in lower case.
|
/** Internal id for this addon, which is the name in lower case.
|
||||||
* This is used to create a subdirectory for this addon. */
|
* This is used to create a subdirectory for this addon. */
|
||||||
std::string m_id;
|
std::string m_id;
|
||||||
/** The (highest) version available online. */
|
/** The (highest) revision number available online. */
|
||||||
int m_version;
|
int m_revision;
|
||||||
/** The currently installed version. */
|
/** The currently installed revision. */
|
||||||
int m_installed_version;
|
int m_installed_revision;
|
||||||
/** The version of the icon that was downloaded. */
|
/** The version of the icon that was downloaded. */
|
||||||
int m_icon_version;
|
int m_icon_revision;
|
||||||
/** A description of this addon. */
|
/** A description of this addon. */
|
||||||
std::string m_description;
|
std::string m_description;
|
||||||
/** The URL of the icon (relative to the server) */
|
/** The URL of the icon (relative to the server) */
|
||||||
@ -82,13 +82,13 @@ public:
|
|||||||
/** Returns if the addon is installed. */
|
/** Returns if the addon is installed. */
|
||||||
bool isInstalled() const { return m_installed; }
|
bool isInstalled() const { return m_installed; }
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
/** Returns the installed version of an addon. */
|
/** Returns the installed revision number of an addon. */
|
||||||
int getInstalledVersion() const { return m_installed_version; }
|
int getInstalledRevision() const { return m_installed_revision; }
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
/** Returns the latest version of this addon.
|
/** Returns the latest revision number of this addon.
|
||||||
* m_version>m_installed_version if a newer version is available
|
* m_revision>m_installed_revision if a newer revision is available
|
||||||
* online. */
|
* online. */
|
||||||
int getVersion() const { return m_version; }
|
int getRevision() const { return m_revision; }
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
/** Returns the ID of this addon. */
|
/** Returns the ID of this addon. */
|
||||||
const std::string& getId() const { return m_id; }
|
const std::string& getId() const { return m_id; }
|
||||||
@ -96,26 +96,26 @@ public:
|
|||||||
/** True if this addon needs to be updated. */
|
/** True if this addon needs to be updated. */
|
||||||
bool needsUpdate() const
|
bool needsUpdate() const
|
||||||
{
|
{
|
||||||
return m_installed && getInstalledVersion() < getVersion();
|
return m_installed && getInstalledRevision() < getRevision();
|
||||||
} // needsUpdate
|
} // needsUpdate
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
/** Returns true if the (cached) icon needs to be updated. This is the
|
/** Returns true if the (cached) icon needs to be updated. This is the
|
||||||
* case if the addon version number is higher than the version number
|
* case if the addon revision number is higher than the revision number
|
||||||
* of the icon (this leaves some chance of false positives - i.e. icons
|
* of the icon (this leaves some chance of false positives - i.e. icons
|
||||||
* that were not changed will still be downloaded). */
|
* that were not changed will still be downloaded). */
|
||||||
bool iconNeedsUpdate() const
|
bool iconNeedsUpdate() const
|
||||||
{
|
{
|
||||||
return m_version > m_icon_version;
|
return m_revision > m_icon_revision;
|
||||||
} // iconNeedsUpdate
|
} // iconNeedsUpdate
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
/** Marks this addon to be installed. If the addon is marked as being
|
/** Marks this addon to be installed. If the addon is marked as being
|
||||||
* installed, it also updates the installed version number to be the
|
* installed, it also updates the installed revision number to be the
|
||||||
* same as currently available version number. */
|
* same as currently available revision number. */
|
||||||
void setInstalled(bool state)
|
void setInstalled(bool state)
|
||||||
{
|
{
|
||||||
m_installed = state;
|
m_installed = state;
|
||||||
if(state)
|
if(state)
|
||||||
m_installed_version = m_version;
|
m_installed_revision = m_revision;
|
||||||
} // setInstalled
|
} // setInstalled
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
/** Returns true if the icon of this addon was downloaded and is ready
|
/** Returns true if the icon of this addon was downloaded and is ready
|
||||||
@ -125,7 +125,7 @@ public:
|
|||||||
/** Marks that the icon for this addon can be displayed. */
|
/** Marks that the icon for this addon can be displayed. */
|
||||||
void setIconReady()
|
void setIconReady()
|
||||||
{
|
{
|
||||||
m_icon_version = m_version;
|
m_icon_revision = m_revision;
|
||||||
m_icon_ready=true;
|
m_icon_ready=true;
|
||||||
} // setIconReady
|
} // setIconReady
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
|
@ -53,12 +53,12 @@ AddonsManager::AddonsManager() : m_addons_list(std::vector<Addon>() ),
|
|||||||
} // AddonsManager
|
} // AddonsManager
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
/** This initialises the online portion of the addons manager. It downloads
|
/** This initialises the online portion of the addons manager. It uses the
|
||||||
* the list of available addons. This is called by network_http before it
|
* downloaded list of available addons. This is called by network_http before
|
||||||
* goes into command-receiving mode, so we can't use any asynchronous calls
|
* it goes into command-receiving mode, so we can't use any asynchronous calls
|
||||||
* here (though this is being called from a separate thread anyway, so the
|
* here (though this is being called from a separate thread anyway, so the
|
||||||
* main GUI is not blocked). This function will update the state variable
|
* main GUI is not blocked anyway). This function will update the state
|
||||||
*
|
* variable
|
||||||
*/
|
*/
|
||||||
void AddonsManager::initOnline(const XMLNode *xml)
|
void AddonsManager::initOnline(const XMLNode *xml)
|
||||||
{
|
{
|
||||||
@ -77,12 +77,11 @@ void AddonsManager::initOnline(const XMLNode *xml)
|
|||||||
Addon addon(*node);
|
Addon addon(*node);
|
||||||
int index = getAddonIndex(addon.getId());
|
int index = getAddonIndex(addon.getId());
|
||||||
|
|
||||||
float stk_version=0;
|
int stk_version=0;
|
||||||
node->get("stkversion", &stk_version);
|
node->get("format", &stk_version);
|
||||||
int testing=-1;
|
int testing=-1;
|
||||||
node->get("testing", &testing);
|
node->get("testing", &testing);
|
||||||
|
|
||||||
#ifdef WHILE_WEBPAGE_IS_NOT_UPDATED_YET
|
|
||||||
bool wrong_version=false;
|
bool wrong_version=false;
|
||||||
|
|
||||||
if(addon.getType()=="kart")
|
if(addon.getType()=="kart")
|
||||||
@ -91,10 +90,9 @@ void AddonsManager::initOnline(const XMLNode *xml)
|
|||||||
else
|
else
|
||||||
wrong_version = stk_version <stk_config->m_min_track_version ||
|
wrong_version = stk_version <stk_config->m_min_track_version ||
|
||||||
stk_version >stk_config->m_max_track_version ;
|
stk_version >stk_config->m_max_track_version ;
|
||||||
#endif
|
|
||||||
// Check which version to use: only for this stk version,
|
// Check which version to use: only for this stk version,
|
||||||
// and not addons that are marked as hidden (testing=0)
|
// and not addons that are marked as hidden (testing=0)
|
||||||
if(stk_version!=0.7f || testing==0)
|
if(wrong_version|| testing==0)
|
||||||
{
|
{
|
||||||
// If the version is too old (e.g. after an update of stk)
|
// If the version is too old (e.g. after an update of stk)
|
||||||
// remove a cached icon.
|
// remove a cached icon.
|
||||||
|
@ -125,9 +125,8 @@ void *NetworkHttp::mainLoop(void *obj)
|
|||||||
const XMLNode *xml = new XMLNode(xml_file);
|
const XMLNode *xml = new XMLNode(xml_file);
|
||||||
me->checkRedirect(xml);
|
me->checkRedirect(xml);
|
||||||
me->updateNews(xml, xml_file);
|
me->updateNews(xml, xml_file);
|
||||||
me->loadAddonsList(xml, xml_file);
|
|
||||||
#ifdef ADDONS_MANAGER
|
#ifdef ADDONS_MANAGER
|
||||||
addons_manager->initOnline(xml);
|
me->loadAddonsList(xml, xml_file);
|
||||||
if(UserConfigParams::m_verbosity>=3)
|
if(UserConfigParams::m_verbosity>=3)
|
||||||
printf("[addons] Addons manager list downloaded\n");
|
printf("[addons] Addons manager list downloaded\n");
|
||||||
#endif
|
#endif
|
||||||
@ -171,7 +170,7 @@ void *NetworkHttp::mainLoop(void *obj)
|
|||||||
assert(false);
|
assert(false);
|
||||||
break;
|
break;
|
||||||
case HC_DOWNLOAD_FILE:
|
case HC_DOWNLOAD_FILE:
|
||||||
me->downloadFileInternal(me->m_file, me->m_save_filename,
|
me->downloadFileInternal(me->m_url, me->m_save_filename,
|
||||||
/*is_asynchron*/true );
|
/*is_asynchron*/true );
|
||||||
} // switch(m_command)
|
} // switch(m_command)
|
||||||
me->m_command = HC_SLEEP;
|
me->m_command = HC_SLEEP;
|
||||||
@ -344,7 +343,23 @@ void NetworkHttp::loadAddonsList(const XMLNode *xml,
|
|||||||
bool download = mtime > UserConfigParams::m_addons_last_updated;
|
bool download = mtime > UserConfigParams::m_addons_last_updated;
|
||||||
if(!download)
|
if(!download)
|
||||||
{
|
{
|
||||||
std::string filename=file_manager->getAddonsFile("addon_list.xml");
|
std::string filename=file_manager->getAddonsFile("addons.xml");
|
||||||
|
if(!file_manager->fileExists(filename))
|
||||||
|
download = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!download || downloadFileSynchron(addon_list_url, "addons.xml"))
|
||||||
|
{
|
||||||
|
std::string xml_file = file_manager->getAddonsFile("addons.xml");
|
||||||
|
if(download)
|
||||||
|
UserConfigParams::m_addons_last_updated=Time::getTimeSinceEpoch();
|
||||||
|
const XMLNode *xml = new XMLNode(xml_file);
|
||||||
|
#ifdef ADDONS_MANAGER
|
||||||
|
addons_manager->initOnline(xml);
|
||||||
|
if(UserConfigParams::m_verbosity>=3)
|
||||||
|
printf("[addons] Addons manager list downloaded\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
} // loadAddonsList
|
} // loadAddonsList
|
||||||
|
|
||||||
@ -603,15 +618,18 @@ std::string NetworkHttp::downloadToStrInternal(std::string url)
|
|||||||
* will be added to file.
|
* will be added to file.
|
||||||
* \param progress_data is used to have the state of the download (in %)
|
* \param progress_data is used to have the state of the download (in %)
|
||||||
*/
|
*/
|
||||||
bool NetworkHttp::downloadFileInternal(const std::string &file,
|
bool NetworkHttp::downloadFileInternal(const std::string &url,
|
||||||
const std::string &save_filename,
|
const std::string &save_filename,
|
||||||
bool is_asynchron)
|
bool is_asynchron)
|
||||||
{
|
{
|
||||||
if(UserConfigParams::m_verbosity>=3)
|
if(UserConfigParams::m_verbosity>=3)
|
||||||
printf("[addons] Downloading %s\n", file.c_str());
|
printf("[addons] Downloading %s\n", url.c_str());
|
||||||
CURL *session = curl_easy_init();
|
CURL *session = curl_easy_init();
|
||||||
std::string full_url = (std::string)UserConfigParams::m_server_addons
|
std::string full_url = url;
|
||||||
+ "/" + file;
|
if(url.substr(0, 5)!="http:" && url.substr(0, 4)!="ftp:")
|
||||||
|
full_url = (std::string)UserConfigParams::m_server_addons
|
||||||
|
+ "/" + url;
|
||||||
|
|
||||||
curl_easy_setopt(session, CURLOPT_URL, full_url.c_str());
|
curl_easy_setopt(session, CURLOPT_URL, full_url.c_str());
|
||||||
std::string uagent = (std::string)"SuperTuxKart/" + STK_VERSION;
|
std::string uagent = (std::string)"SuperTuxKart/" + STK_VERSION;
|
||||||
curl_easy_setopt(session, CURLOPT_USERAGENT, uagent.c_str());
|
curl_easy_setopt(session, CURLOPT_USERAGENT, uagent.c_str());
|
||||||
@ -664,19 +682,19 @@ void NetworkHttp::cancelDownload()
|
|||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
/** External interface to download a file synchronously, i.e. it will only
|
/** External interface to download a file synchronously, i.e. it will only
|
||||||
* return once the download is complete.
|
* return once the download is complete.
|
||||||
* \param file The file from the server to download.
|
* \param url The file from the server to download.
|
||||||
* \param save The name to save the downloaded file under. Defaults to
|
* \param save The name to save the downloaded file under. Defaults to
|
||||||
* the name given in file.
|
* the name given in file.
|
||||||
*/
|
*/
|
||||||
bool NetworkHttp::downloadFileSynchron(const std::string &file,
|
bool NetworkHttp::downloadFileSynchron(const std::string &url,
|
||||||
const std::string &save)
|
const std::string &save)
|
||||||
{
|
{
|
||||||
const std::string &save_filename = (save!="") ? save : file;
|
const std::string &save_filename = (save!="") ? save : url;
|
||||||
if(UserConfigParams::m_verbosity>=3)
|
if(UserConfigParams::m_verbosity>=3)
|
||||||
printf("[addons] Download synchron '%s' as '%s'.\n",
|
printf("[addons] Download synchron '%s' as '%s'.\n",
|
||||||
file.c_str(), save_filename.c_str());
|
url.c_str(), save_filename.c_str());
|
||||||
|
|
||||||
return downloadFileInternal(file, save_filename,
|
return downloadFileInternal(url, save_filename,
|
||||||
/*is_asynchron*/false);
|
/*is_asynchron*/false);
|
||||||
} // downloadFileSynchron
|
} // downloadFileSynchron
|
||||||
|
|
||||||
@ -684,20 +702,20 @@ bool NetworkHttp::downloadFileSynchron(const std::string &file,
|
|||||||
/** External interface to download a file asynchronously. This will wake up
|
/** External interface to download a file asynchronously. This will wake up
|
||||||
* the thread and schedule it to download the file. The calling program has
|
* the thread and schedule it to download the file. The calling program has
|
||||||
* to poll using getProgress() to find out if the download has finished.
|
* to poll using getProgress() to find out if the download has finished.
|
||||||
* \param file The file from the server to download.
|
* \param url The file from the server to download.
|
||||||
* \param save The name to save the downloaded file under. Defaults to
|
* \param save The name to save the downloaded file under. Defaults to
|
||||||
* the name given in file.
|
* the name given in file.
|
||||||
*/
|
*/
|
||||||
void NetworkHttp::downloadFileAsynchron(const std::string &file,
|
void NetworkHttp::downloadFileAsynchron(const std::string &url,
|
||||||
const std::string &save)
|
const std::string &save)
|
||||||
{
|
{
|
||||||
m_progress.set(0.0f);
|
m_progress.set(0.0f);
|
||||||
m_file = file;
|
m_url = url;
|
||||||
m_save_filename = (save!="") ? save : file;
|
m_save_filename = (save!="") ? save : url;
|
||||||
|
|
||||||
if(UserConfigParams::m_verbosity>=3)
|
if(UserConfigParams::m_verbosity>=3)
|
||||||
printf("[addons] Download asynchron '%s' as '%s'.\n",
|
printf("[addons] Download asynchron '%s' as '%s'.\n",
|
||||||
file.c_str(), m_save_filename.c_str());
|
url.c_str(), m_save_filename.c_str());
|
||||||
// Wake up the network http thread
|
// Wake up the network http thread
|
||||||
pthread_mutex_lock(&m_mutex_command);
|
pthread_mutex_lock(&m_mutex_command);
|
||||||
{
|
{
|
||||||
|
@ -106,7 +106,7 @@ private:
|
|||||||
pthread_cond_t m_cond_command;
|
pthread_cond_t m_cond_command;
|
||||||
|
|
||||||
/** The file to download when a file download is triggered. */
|
/** The file to download when a file download is triggered. */
|
||||||
std::string m_file;
|
std::string m_url;
|
||||||
|
|
||||||
/** The name and path under which to save the downloaded file. */
|
/** The name and path under which to save the downloaded file. */
|
||||||
std::string m_save_filename;
|
std::string m_save_filename;
|
||||||
@ -131,7 +131,7 @@ private:
|
|||||||
const std::string &filename);
|
const std::string &filename);
|
||||||
std::string downloadToStrInternal(std::string url);
|
std::string downloadToStrInternal(std::string url);
|
||||||
void updateMessageDisplayCount();
|
void updateMessageDisplayCount();
|
||||||
bool downloadFileInternal(const std::string &file,
|
bool downloadFileInternal(const std::string &url,
|
||||||
const std::string &save_filename,
|
const std::string &save_filename,
|
||||||
bool is_asynchron);
|
bool is_asynchron);
|
||||||
static int progressDownload(void *clientp, double dltotal, double dlnow,
|
static int progressDownload(void *clientp, double dltotal, double dlnow,
|
||||||
@ -143,9 +143,9 @@ public:
|
|||||||
~NetworkHttp();
|
~NetworkHttp();
|
||||||
static size_t writeStr(char str [], size_t size, size_t nb_char,
|
static size_t writeStr(char str [], size_t size, size_t nb_char,
|
||||||
std::string * stream);
|
std::string * stream);
|
||||||
void downloadFileAsynchron(const std::string &file,
|
void downloadFileAsynchron(const std::string &url,
|
||||||
const std::string &save = "");
|
const std::string &save = "");
|
||||||
bool downloadFileSynchron(const std::string &file,
|
bool downloadFileSynchron(const std::string &url,
|
||||||
const std::string &save = "");
|
const std::string &save = "");
|
||||||
|
|
||||||
const core::stringw
|
const core::stringw
|
||||||
|
@ -68,8 +68,8 @@ AddonsLoading::AddonsLoading(const float w, const float h,
|
|||||||
core::stringw desc = _("Description: %i", m_addon.getDescription().c_str());
|
core::stringw desc = _("Description: %i", m_addon.getDescription().c_str());
|
||||||
getWidget<LabelWidget>("description")->setText(desc, false);
|
getWidget<LabelWidget>("description")->setText(desc, false);
|
||||||
|
|
||||||
core::stringw version = _("Version: %d", m_addon.getVersion());
|
core::stringw revision = _("Version: %d", m_addon.getRevision());
|
||||||
getWidget<LabelWidget>("version")->setText(version, false);
|
getWidget<LabelWidget>("revision")->setText(revision, false);
|
||||||
|
|
||||||
} // AddonsLoading
|
} // AddonsLoading
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user