From 055198303c7bf15f456687838c37650871596946 Mon Sep 17 00:00:00 2001 From: Andrew Date: Fri, 3 May 2013 14:41:37 -0500 Subject: Removed old plugin system and implemented some version list stuff. --- libmultimc/src/instance.cpp | 34 +++ libmultimc/src/instancelist.cpp | 10 +- libmultimc/src/instanceloader.cpp | 78 +---- libmultimc/src/instversion.cpp | 37 ++- libmultimc/src/minecraftversion.cpp | 142 ++++++++++ libmultimc/src/minecraftversionlist.cpp | 489 ++++++++++++++++++++++++++++++++ 6 files changed, 717 insertions(+), 73 deletions(-) create mode 100644 libmultimc/src/minecraftversion.cpp create mode 100644 libmultimc/src/minecraftversionlist.cpp (limited to 'libmultimc/src') diff --git a/libmultimc/src/instance.cpp b/libmultimc/src/instance.cpp index f9e105c7..f4a6a3c9 100644 --- a/libmultimc/src/instance.cpp +++ b/libmultimc/src/instance.cpp @@ -22,6 +22,7 @@ #include "overridesetting.h" #include "pathutils.h" +#include Instance::Instance(const QString &rootDir, QObject *parent) : QObject(parent) @@ -151,6 +152,39 @@ QString Instance::modListFile() const return PathCombine(rootDir(), "modlist"); } +InstVersionList *Instance::versionList() const +{ + return &MinecraftVersionList::getMainList(); +} + +bool Instance::shouldUpdateCurrentVersion() +{ + QFileInfo jar(mcJar()); + return jar.lastModified().toUTC().toMSecsSinceEpoch() != lastCurrentVersionUpdate(); +} + +void Instance::updateCurrentVersion(bool keepCurrent) +{ + QFileInfo jar(mcJar()); + + if(!jar.exists()) + { + setLastCurrentVersionUpdate(0); + setCurrentVersion("Unknown"); + return; + } + + qint64 time = jar.lastModified().toUTC().toMSecsSinceEpoch(); + + setLastCurrentVersionUpdate(time); + if (!keepCurrent) + { + // TODO: Implement GetMinecraftJarVersion function. + QString newVersion = "Unknown";//javautils::GetMinecraftJarVersion(jar.absoluteFilePath()); + setCurrentVersion(newVersion); + } +} + SettingsObject &Instance::settings() const { return *m_settings; diff --git a/libmultimc/src/instancelist.cpp b/libmultimc/src/instancelist.cpp index f9c525d0..6f5a9f99 100644 --- a/libmultimc/src/instancelist.cpp +++ b/libmultimc/src/instancelist.cpp @@ -147,21 +147,17 @@ InstanceList::InstListError InstanceList::loadList() { Instance *instPtr = NULL; - InstanceLoader::InstTypeError error = InstanceLoader::get(). + InstanceLoader::InstLoaderError error = InstanceLoader::get(). loadInstance(instPtr, subDir); if (error != InstanceLoader::NoError && - error != InstanceLoader::NotAnInstance) + error != InstanceLoader::NotAnInstance) { QString errorMsg = QString("Failed to load instance %1: "). arg(QFileInfo(subDir).baseName()).toUtf8(); switch (error) { - case InstanceLoader::TypeNotRegistered: - errorMsg += "Instance type not found."; - break; - default: errorMsg += QString("Unknown instance loader error %1"). arg(error); @@ -234,4 +230,4 @@ void InstanceList::propertiesChanged(Instance * inst) break; } } -} \ No newline at end of file +} diff --git a/libmultimc/src/instanceloader.cpp b/libmultimc/src/instanceloader.cpp index 9d98230f..e9924af4 100644 --- a/libmultimc/src/instanceloader.cpp +++ b/libmultimc/src/instanceloader.cpp @@ -15,9 +15,10 @@ #include "include/instanceloader.h" +#include #include -#include "include/instancetypeinterface.h" +#include "include/instance.h" #include "inifile.h" @@ -31,79 +32,30 @@ InstanceLoader::InstanceLoader() : } - -InstanceLoader::InstTypeError InstanceLoader::registerInstanceType(InstanceTypeInterface *type) +InstanceLoader::InstLoaderError InstanceLoader::loadInstance( + Instance *&inst, const QString &instDir) { - // Check to see if the type ID exists. - if (m_typeMap.contains(type->typeID())) - return TypeIDExists; + Instance *loadedInst = new Instance(instDir, this); - // Set the parent to this. - // ((QObject *)type)->setParent(this); + // TODO: Sanity checks to verify that the instance is valid. - // Add it to the map. - m_typeMap.insert(type->typeID(), type); + inst = loadedInst; - qDebug(QString("Registered instance type %1."). - arg(type->typeID()).toUtf8()); return NoError; } -InstanceLoader::InstTypeError InstanceLoader::createInstance(Instance *&inst, - const InstanceTypeInterface *type, - const QString &instDir) -{ - // Check if the type is registered. - if (!type || findType(type->typeID()) != type) - return TypeNotRegistered; - - // Create the instance. - return type->createInstance(inst, instDir); -} - -InstanceLoader::InstTypeError InstanceLoader::loadInstance(Instance *&inst, - const InstanceTypeInterface *type, - const QString &instDir) -{ - // Check if the type is registered. - if (!type || findType(type->typeID()) != type) - return TypeNotRegistered; - - return type->loadInstance(inst, instDir); -} - -InstanceLoader::InstTypeError InstanceLoader::loadInstance(Instance *&inst, - const QString &instDir) -{ - QFileInfo instConfig(PathCombine(instDir, "instance.cfg")); - - if (!instConfig.exists()) - return NotAnInstance; - - INIFile ini; - ini.loadFile(instConfig.path()); - QString typeName = ini.get("type", "net.forkk.MultiMC.StdInstance").toString(); - const InstanceTypeInterface *type = findType(typeName); - - return loadInstance(inst, type, instDir); -} -const InstanceTypeInterface *InstanceLoader::findType(const QString &id) +InstanceLoader::InstLoaderError InstanceLoader::createInstance(Instance *&inst, const QString &instDir) { - if (!m_typeMap.contains(id)) - return NULL; - else - return m_typeMap[id]; -} - -InstTypeList InstanceLoader::typeList() -{ - InstTypeList typeList; + QDir rootDir(instDir); - for (QMap::iterator iter = m_typeMap.begin(); iter != m_typeMap.end(); iter++) + qDebug(instDir.toUtf8()); + if (!rootDir.exists() && !rootDir.mkpath(".")) { - typeList.append(*iter); + return InstanceLoader::CantCreateDir; } - return typeList; + inst = new Instance(instDir, this); + + return InstanceLoader::NoError; } diff --git a/libmultimc/src/instversion.cpp b/libmultimc/src/instversion.cpp index cedb61df..d3d078a9 100644 --- a/libmultimc/src/instversion.cpp +++ b/libmultimc/src/instversion.cpp @@ -16,17 +16,48 @@ #include "include/instversion.h" #include "include/instversionlist.h" -InstVersion::InstVersion(InstVersionList *parent) : - QObject(parent) +InstVersion::InstVersion(const QString &descriptor, + const QString &name, + qint64 timestamp, + InstVersionList *parent) : + QObject(parent), m_descriptor(descriptor), m_name(name), m_timestamp(timestamp) +{ + +} + +InstVersion::InstVersion(const InstVersion &other, QObject *parent) : + QObject(parent ? parent : other.parent()), + m_descriptor(other.descriptor()), m_name(other.name()), m_timestamp(other.timestamp()) { } InstVersionList *InstVersion::versionList() const { - // Parent should *always* be an InstVersionList + // Parent should *always* be either an InstVersionList or NULL. if (!parent() || !parent()->inherits("InstVersionList")) return NULL; else return (InstVersionList *)parent(); } + +bool InstVersion::isMeta() const +{ + return false; +} + + +QString InstVersion::descriptor() const +{ + return m_descriptor; +} + +QString InstVersion::name() const +{ + return m_name; +} + +qint64 InstVersion::timestamp() const +{ + return m_timestamp; +} diff --git a/libmultimc/src/minecraftversion.cpp b/libmultimc/src/minecraftversion.cpp new file mode 100644 index 00000000..896c2e18 --- /dev/null +++ b/libmultimc/src/minecraftversion.cpp @@ -0,0 +1,142 @@ +/* Copyright 2013 Andrew Okin + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "minecraftversion.h" + +MinecraftVersion::MinecraftVersion(QString descriptor, + QString name, + qint64 timestamp, + QString dlUrl, + QString etag, + InstVersionList *parent) : + InstVersion(descriptor, name, timestamp, parent), m_dlUrl(dlUrl), m_etag(etag) +{ + m_linkedVersion = NULL; +} + +MinecraftVersion::MinecraftVersion(const MinecraftVersion *linkedVersion) : + InstVersion(linkedVersion->descriptor(), linkedVersion->name(), linkedVersion->timestamp(), + linkedVersion->versionList()) +{ + m_linkedVersion = (MinecraftVersion *)linkedVersion; +} + +MinecraftVersion::MinecraftVersion(const MinecraftVersion &other, QObject *parent) : + InstVersion(other, parent) +{ + if (other.m_linkedVersion) + m_linkedVersion = other.m_linkedVersion; + else + { + m_dlUrl = other.downloadURL(); + m_etag = other.etag(); + } +} + +QString MinecraftVersion::descriptor() const +{ + return m_descriptor; +} + +QString MinecraftVersion::name() const +{ + return m_name; +} + +QString MinecraftVersion::typeName() const +{ + if (m_linkedVersion) + return m_linkedVersion->typeName(); + + switch (versionType()) + { + case OldSnapshot: + return "Old Snapshot"; + + case Stable: + return "Stable"; + + case CurrentStable: + return "Current Stable"; + + case Snapshot: + return "Snapshot"; + + case MCNostalgia: + return "MCNostalgia"; + + case MetaCustom: + // Not really sure what this does, but it was in the code for v4, + // so it must be important... Right? + return "Custom Meta Version"; + + case MetaLatestSnapshot: + return "Latest Snapshot"; + + case MetaLatestStable: + return "Latest Stable"; + + default: + return QString("Unknown Type %1").arg(versionType()); + } +} + +qint64 MinecraftVersion::timestamp() const +{ + return m_timestamp; +} + +MinecraftVersion::VersionType MinecraftVersion::versionType() const +{ + return m_type; +} + +void MinecraftVersion::setVersionType(MinecraftVersion::VersionType typeName) +{ + m_type = typeName; +} + +QString MinecraftVersion::downloadURL() const +{ + return m_dlUrl; +} + +QString MinecraftVersion::etag() const +{ + return m_etag; +} + +bool MinecraftVersion::isMeta() const +{ + return versionType() == MetaCustom || + versionType() == MetaLatestSnapshot || + versionType() == MetaLatestStable; +} + +InstVersion *MinecraftVersion::copyVersion(InstVersionList *newParent) const +{ + if (isMeta()) + { + MinecraftVersion *version = new MinecraftVersion((MinecraftVersion *)m_linkedVersion); + return version; + } + else + { + MinecraftVersion *version = new MinecraftVersion( + descriptor(), name(), timestamp(), downloadURL(), etag(), newParent); + version->setVersionType(versionType()); + return version; + } +} diff --git a/libmultimc/src/minecraftversionlist.cpp b/libmultimc/src/minecraftversionlist.cpp new file mode 100644 index 00000000..ce02a769 --- /dev/null +++ b/libmultimc/src/minecraftversionlist.cpp @@ -0,0 +1,489 @@ +/* Copyright 2013 Andrew Okin + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "include/minecraftversionlist.h" + +#include + +#include + +#include +#include +#include +#include +#include + +#include + +#define MCVLIST_URLBASE "http://s3.amazonaws.com/Minecraft.Download/versions/" +#define ASSETS_URLBASE "http://assets.minecraft.net/" +#define MCN_URLBASE "http://sonicrules.org/mcnweb.py" + +MinecraftVersionList mcVList; + +MinecraftVersionList::MinecraftVersionList(QObject *parent) : + InstVersionList(parent) +{ + +} + +Task *MinecraftVersionList::getLoadTask() +{ + return new MCVListLoadTask(this); +} + +bool MinecraftVersionList::isLoaded() +{ + return m_loaded; +} + +const InstVersion *MinecraftVersionList::at(int i) const +{ + return m_vlist.at(i); +} + +int MinecraftVersionList::count() const +{ + return m_vlist.count(); +} + +void MinecraftVersionList::printToStdOut() const +{ + qDebug() << "---------------- Version List ----------------"; + + for (int i = 0; i < m_vlist.count(); i++) + { + MinecraftVersion *version = qobject_cast(m_vlist.at(i)); + + if (!version) + continue; + + qDebug() << "Version " << version->name(); + qDebug() << "\tDownload: " << version->downloadURL(); + qDebug() << "\tTimestamp: " << version->timestamp(); + qDebug() << "\tType: " << version->typeName(); + qDebug() << "----------------------------------------------"; + } +} + +MinecraftVersionList &MinecraftVersionList::getMainList() +{ + return mcVList; +} + +void MinecraftVersionList::updateListData(QList versions) +{ + // First, we populate a temporary list with the copies of the versions. + QList tempList; + for (int i = 0; i < versions.length(); i++) + { + InstVersion *version = versions[i]->copyVersion(this); + Q_ASSERT(version != NULL); + tempList.append(version); + } + + // Now we swap the temporary list into the actual version list. + // This applies our changes to the version list immediately and still gives us + // access to the old version list so that we can delete the objects in it and + // free their memory. By doing this, we cause the version list to update as + // quickly as possible. + beginResetModel(); + m_vlist.swap(tempList); + m_loaded = true; + endResetModel(); + + // We called swap, so all the data that was in the version list previously is now in + // tempList (and vice-versa). Now we just free the memory. + while (!tempList.isEmpty()) + delete tempList.takeFirst(); +} + +inline QDomElement getDomElementByTagName(QDomElement parent, QString tagname) +{ + QDomNodeList elementList = parent.elementsByTagName(tagname); + if (elementList.count()) + return elementList.at(0).toElement(); + else + return QDomElement(); +} + +inline QDateTime timeFromS3Time(QString str) +{ + const QString fmt("yyyy-MM-dd'T'HH:mm:ss'.000Z'"); + return QDateTime::fromString(str, fmt); +} + +inline void waitForNetRequest(QNetworkReply *netReply) +{ + QEventLoop loop; + loop.connect(netReply, SIGNAL(finished()), SLOT(quit())); + loop.exec(); +} + + +MCVListLoadTask::MCVListLoadTask(MinecraftVersionList *vlist) +{ + m_list = vlist; + m_currentStable = NULL; +} + +MCVListLoadTask::~MCVListLoadTask() +{ +// delete netMgr; +} + +void MCVListLoadTask::executeTask() +{ + setSubStatus(); + + QNetworkAccessManager networkMgr; + netMgr = &networkMgr; + + if (!loadFromVList()) + { + qDebug() << "Failed to load from Mojang version list."; + } + if (!loadFromAssets()) + { + qDebug() << "Failed to load assets version list."; + } + if (!loadMCNostalgia()) + { + qDebug() << "Failed to load MCNostalgia version list."; + } + finalize(); +} + +void MCVListLoadTask::setSubStatus(const QString msg) +{ + if (msg.isEmpty()) + setStatus("Loading instance version list..."); + else + setStatus("Loading instance version list: " + msg); +} + +bool MCVListLoadTask::loadFromVList() +{ + QNetworkReply *vlistReply = netMgr->get(QNetworkRequest(QUrl(QString(MCVLIST_URLBASE) + + "versions.json"))); + waitForNetRequest(vlistReply); + + switch (vlistReply->error()) + { + case QNetworkReply::NoError: + { + QJsonParseError jsonError; + QJsonDocument jsonDoc = QJsonDocument::fromJson(vlistReply->readAll(), &jsonError); + + if (jsonError.error == QJsonParseError::NoError) + { + Q_ASSERT_X(jsonDoc.isObject(), "loadFromVList", "jsonDoc is not an object"); + + QJsonObject root = jsonDoc.object(); + + // Get the ID of the latest release and the latest snapshot. + Q_ASSERT_X(root.value("latest").isObject(), "loadFromVList", + "version list is missing 'latest' object"); + QJsonObject latest = root.value("latest").toObject(); + + QString latestReleaseID = latest.value("release").toString(""); + QString latestSnapshotID = latest.value("snapshot").toString(""); + Q_ASSERT_X(!latestReleaseID.isEmpty(), "loadFromVList", "latest release field is missing"); + Q_ASSERT_X(!latestSnapshotID.isEmpty(), "loadFromVList", "latest snapshot field is missing"); + + // Now, get the array of versions. + Q_ASSERT_X(root.value("versions").isArray(), "loadFromVList", + "version list object is missing 'versions' array"); + QJsonArray versions = root.value("versions").toArray(); + + for (int i = 0; i < versions.count(); i++) + { + // Load the version info. + Q_ASSERT_X(versions[i].isObject(), "loadFromVList", + QString("in versions array, index %1 is not an object"). + arg(i).toUtf8()); + QJsonObject version = versions[i].toObject(); + + QString versionID = version.value("id").toString(""); + QString versionTimeStr = version.value("time").toString(""); + QString versionTypeStr = version.value("type").toString(""); + + Q_ASSERT_X(!versionID.isEmpty(), "loadFromVList", + QString("in versions array, index %1's \"id\" field is not a valid string"). + arg(i).toUtf8()); + Q_ASSERT_X(!versionTimeStr.isEmpty(), "loadFromVList", + QString("in versions array, index %1's \"time\" field is not a valid string"). + arg(i).toUtf8()); + Q_ASSERT_X(!versionTypeStr.isEmpty(), "loadFromVList", + QString("in versions array, index %1's \"type\" field is not a valid string"). + arg(i).toUtf8()); + + + // Now, process that info and add the version to the list. + + // Parse the timestamp. + QDateTime versionTime = timeFromS3Time(versionTimeStr); + + // Parse the type. + MinecraftVersion::VersionType versionType; + if (versionTypeStr == "release") + { + // Check if this version is the current stable version. + if (versionID == latestReleaseID) + versionType = MinecraftVersion::CurrentStable; + else + versionType = MinecraftVersion::Stable; + } + else + { + versionType = MinecraftVersion::Snapshot; + } + + // Get the download URL. + QString dlUrl = QString(MCVLIST_URLBASE) + versionID + "/"; + + + // Now, we construct the version object and add it to the list. + MinecraftVersion *mcVersion = new MinecraftVersion( + versionID, versionID, versionTime.toMSecsSinceEpoch(), + dlUrl, ""); + mcVersion->setVersionType(versionType); + tempList.append(mcVersion); + } + } + else + { + qDebug() << "Error parsing version list JSON:" << jsonError.errorString(); + } + + break; + } + + default: + // TODO: Network error handling. + qDebug() << "Failed to load Minecraft main version list" << vlistReply->errorString(); + break; + } + + return true; +} + +bool MCVListLoadTask::loadFromAssets() +{ + setSubStatus("Loading versions from assets.minecraft.net..."); + + bool succeeded = false; + + QNetworkReply *assetsReply = netMgr->get(QNetworkRequest(QUrl(ASSETS_URLBASE))); + waitForNetRequest(assetsReply); + + switch (assetsReply->error()) + { + case QNetworkReply::NoError: + { + // Get the XML string. + QString xmlString = assetsReply->readAll(); + + QString xmlErrorMsg; + + QDomDocument doc; + if (!doc.setContent(xmlString, false, &xmlErrorMsg)) + { + // TODO: Display error message to the user. + qDebug() << "Failed to process assets.minecraft.net. XML error:" << + xmlErrorMsg << xmlString; + } + + QDomNodeList contents = doc.elementsByTagName("Contents"); + + QRegExp mcRegex("/minecraft.jar$"); + QRegExp snapshotRegex("[0-9][0-9]w[0-9][0-9][a-z]|pre|rc"); + + for (int i = 0; i < contents.length(); i++) + { + QDomElement element = contents.at(i).toElement(); + + if (element.isNull()) + continue; + + QDomElement keyElement = getDomElementByTagName(element, "Key"); + QDomElement lastmodElement = getDomElementByTagName(element, "LastModified"); + QDomElement etagElement = getDomElementByTagName(element, "ETag"); + + if (keyElement.isNull() || lastmodElement.isNull() || etagElement.isNull()) + continue; + + QString key = keyElement.text(); + QString lastModStr = lastmodElement.text(); + QString etagStr = etagElement.text(); + + if (!key.contains(mcRegex)) + continue; + + QString versionDirName = key.left(key.length() - 14); + QString dlUrl = QString("http://assets.minecraft.net/%1/").arg(versionDirName); + + QString versionName = versionDirName.replace("_", "."); + + QDateTime versionTimestamp = timeFromS3Time(lastModStr); + if (!versionTimestamp.isValid()) + { + qDebug(QString("Failed to parse timestamp for version %1 %2"). + arg(versionName, lastModStr).toUtf8()); + versionTimestamp = QDateTime::currentDateTime(); + } + + if (m_currentStable) + { + { + bool older = versionTimestamp.toMSecsSinceEpoch() < m_currentStable->timestamp(); + bool newer = versionTimestamp.toMSecsSinceEpoch() > m_currentStable->timestamp(); + bool isSnapshot = versionName.contains(snapshotRegex); + + MinecraftVersion *version = new MinecraftVersion( + versionName, versionName, + versionTimestamp.toMSecsSinceEpoch(), + dlUrl, etagStr); + + if (newer) + { + version->setVersionType(MinecraftVersion::Snapshot); + } + else if (older && isSnapshot) + { + version->setVersionType(MinecraftVersion::OldSnapshot); + } + else if (older) + { + version->setVersionType(MinecraftVersion::Stable); + } + else + { + // Shouldn't happen, but just in case... + version->setVersionType(MinecraftVersion::CurrentStable); + } + + assetsList.push_back(version); + } + } + else // If there isn't a current stable version. + { + bool isSnapshot = versionName.contains(snapshotRegex); + + MinecraftVersion *version = new MinecraftVersion( + versionName, versionName, + versionTimestamp.toMSecsSinceEpoch(), + dlUrl, etagStr); + version->setVersionType(isSnapshot? MinecraftVersion::Snapshot : + MinecraftVersion::Stable); + assetsList.push_back(version); + } + } + + setSubStatus("Loaded assets.minecraft.net"); + succeeded = true; + break; + } + + default: + // TODO: Network error handling. + qDebug() << "Failed to load assets.minecraft.net" << assetsReply->errorString(); + break; + } + + processedAssetsReply = true; + updateStuff(); + return succeeded; +} + +bool MCVListLoadTask::loadMCNostalgia() +{ + QNetworkReply *mcnReply = netMgr->get(QNetworkRequest(QUrl(QString(MCN_URLBASE) + "?pversion=1&list=True"))); + waitForNetRequest(mcnReply); + return true; +} + +bool MCVListLoadTask::finalize() +{ + // First, we need to do some cleanup. We loaded assets versions into assetsList, + // MCNostalgia versions into mcnList and all the others into tempList. MCNostalgia + // provides some versions that are on assets.minecraft.net and we want to ignore + // those, so we remove and delete them from mcnList. assets.minecraft.net also provides + // versions that are on Mojang's version list and we want to ignore those as well. + + // To start, we get a list of the descriptors in tmpList. + QStringList tlistDescriptors; + for (int i = 0; i < tempList.count(); i++) + tlistDescriptors.append(tempList.at(i)->descriptor()); + + // Now, we go through our assets version list and remove anything with + // a descriptor that matches one we already have in tempList. + for (int i = 0; i < assetsList.count(); i++) + if (tlistDescriptors.contains(assetsList.at(i)->descriptor())) + delete assetsList.takeAt(i--); // We need to decrement here because we're removing an item. + + // We also need to rebuild the list of descriptors. + tlistDescriptors.clear(); + for (int i = 0; i < tempList.count(); i++) + tlistDescriptors.append(tempList.at(i)->descriptor()); + + // Next, we go through our MCNostalgia version list and do the same thing. + for (int i = 0; i < mcnList.count(); i++) + if (tlistDescriptors.contains(mcnList.at(i)->descriptor())) + delete mcnList.takeAt(i--); // We need to decrement here because we're removing an item. + + // Now that the duplicates are gone, we need to merge the lists. This is + // simple enough. + tempList.append(assetsList); + tempList.append(mcnList); + + // We're done with these lists now, but the items have been moved over to + // tempList, so we don't need to delete them yet. + + // Now, we invoke the updateListData slot on the GUI thread. This will copy all + // the versions we loaded and set their parents to the version list. + // Then, it will swap the new list with the old one and free the old list's memory. + QMetaObject::invokeMethod(m_list, "updateListData", Qt::BlockingQueuedConnection, + Q_ARG(QList, tempList)); + + // Once that's finished, we can delete the versions in our temp list. + while (!tempList.isEmpty()) + delete tempList.takeFirst(); + +#ifdef PRINT_VERSIONS + m_list->printToStdOut(); +#endif + return true; +} + +void MCVListLoadTask::updateStuff() +{ + const int totalReqs = 3; + int reqsComplete = 0; + + if (processedMCVListReply) + reqsComplete++; + if (processedAssetsReply) + reqsComplete++; + if (processedMCNReply) + reqsComplete++; + + calcProgress(reqsComplete, totalReqs); + + if (reqsComplete >= totalReqs) + { + quit(); + } +} -- cgit v1.2.3