Initial FTB support. Allows "tracking" of FTB instances.
This commit is contained in:
		
				
					committed by
					
						 Petr Mrázek
						Petr Mrázek
					
				
			
			
				
	
			
			
			
						parent
						
							34a3fedf7b
						
					
				
				
					commit
					82c87aa06f
				
			| @@ -20,7 +20,9 @@ | ||||
|  | ||||
| #include "BaseInstance.h" | ||||
| #include "LegacyInstance.h" | ||||
| #include "LegacyFTBInstance.h" | ||||
| #include "OneSixInstance.h" | ||||
| #include "OneSixFTBInstance.h" | ||||
| #include "NostalgiaInstance.h" | ||||
| #include "BaseVersion.h" | ||||
| #include "MinecraftVersion.h" | ||||
| @@ -60,6 +62,14 @@ InstanceFactory::InstLoadError InstanceFactory::loadInstance(BaseInstance *&inst | ||||
| 	{ | ||||
| 		inst = new NostalgiaInstance(instDir, m_settings, this); | ||||
| 	} | ||||
| 	else if (inst_type == "LegacyFTB") | ||||
| 	{ | ||||
| 		inst = new LegacyFTBInstance(instDir, m_settings, this); | ||||
| 	} | ||||
| 	else if (inst_type == "OneSixFTB") | ||||
| 	{ | ||||
| 		inst = new OneSixFTBInstance(instDir, m_settings, this); | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		return InstanceFactory::UnknownLoadError; | ||||
| @@ -69,7 +79,8 @@ InstanceFactory::InstLoadError InstanceFactory::loadInstance(BaseInstance *&inst | ||||
|  | ||||
| InstanceFactory::InstCreateError InstanceFactory::createInstance(BaseInstance *&inst, | ||||
| 																 BaseVersionPtr version, | ||||
| 																 const QString &instDir) | ||||
| 																 const QString &instDir, | ||||
| 																 const InstType type) | ||||
| { | ||||
| 	QDir rootDir(instDir); | ||||
|  | ||||
| @@ -85,32 +96,63 @@ InstanceFactory::InstCreateError InstanceFactory::createInstance(BaseInstance *& | ||||
| 	auto m_settings = new INISettingsObject(PathCombine(instDir, "instance.cfg")); | ||||
| 	m_settings->registerSetting(new Setting("InstanceType", "Legacy")); | ||||
|  | ||||
| 	switch (mcVer->type) | ||||
| 	if (type == NormalInst) | ||||
| 	{ | ||||
| 	case MinecraftVersion::Legacy: | ||||
| 		m_settings->set("InstanceType", "Legacy"); | ||||
| 		inst = new LegacyInstance(instDir, m_settings, this); | ||||
| 		inst->setIntendedVersionId(version->descriptor()); | ||||
| 		inst->setShouldUseCustomBaseJar(false); | ||||
| 		break; | ||||
| 	case MinecraftVersion::OneSix: | ||||
| 		m_settings->set("InstanceType", "OneSix"); | ||||
| 		inst = new OneSixInstance(instDir, m_settings, this); | ||||
| 		inst->setIntendedVersionId(version->descriptor()); | ||||
| 		inst->setShouldUseCustomBaseJar(false); | ||||
| 		break; | ||||
| 	case MinecraftVersion::Nostalgia: | ||||
| 		m_settings->set("InstanceType", "Nostalgia"); | ||||
| 		inst = new NostalgiaInstance(instDir, m_settings, this); | ||||
| 		inst->setIntendedVersionId(version->descriptor()); | ||||
| 		inst->setShouldUseCustomBaseJar(false); | ||||
| 		break; | ||||
| 	default: | ||||
| 		switch (mcVer->type) | ||||
| 		{ | ||||
| 		case MinecraftVersion::Legacy: | ||||
| 			m_settings->set("InstanceType", "Legacy"); | ||||
| 			inst = new LegacyInstance(instDir, m_settings, this); | ||||
| 			inst->setIntendedVersionId(version->descriptor()); | ||||
| 			inst->setShouldUseCustomBaseJar(false); | ||||
| 			break; | ||||
| 		case MinecraftVersion::OneSix: | ||||
| 			m_settings->set("InstanceType", "OneSix"); | ||||
| 			inst = new OneSixInstance(instDir, m_settings, this); | ||||
| 			inst->setIntendedVersionId(version->descriptor()); | ||||
| 			inst->setShouldUseCustomBaseJar(false); | ||||
| 			break; | ||||
| 		case MinecraftVersion::Nostalgia: | ||||
| 			m_settings->set("InstanceType", "Nostalgia"); | ||||
| 			inst = new NostalgiaInstance(instDir, m_settings, this); | ||||
| 			inst->setIntendedVersionId(version->descriptor()); | ||||
| 			inst->setShouldUseCustomBaseJar(false); | ||||
| 			break; | ||||
| 		default: | ||||
| 		{ | ||||
| 			delete m_settings; | ||||
| 			return InstanceFactory::NoSuchVersion; | ||||
| 		} | ||||
| 		} | ||||
| 	} | ||||
| 	else if (type == FTBInstance) | ||||
| 	{ | ||||
| 		switch (mcVer->type) | ||||
| 		{ | ||||
| 		case MinecraftVersion::Legacy: | ||||
| 			m_settings->set("InstanceType", "LegacyFTB"); | ||||
| 			inst = new LegacyFTBInstance(instDir, m_settings, this); | ||||
| 			inst->setIntendedVersionId(version->descriptor()); | ||||
| 			inst->setShouldUseCustomBaseJar(false); | ||||
| 			break; | ||||
| 		case MinecraftVersion::OneSix: | ||||
| 			m_settings->set("InstanceType", "OneSixFTB"); | ||||
| 			inst = new OneSixFTBInstance(instDir, m_settings, this); | ||||
| 			inst->setIntendedVersionId(version->descriptor()); | ||||
| 			inst->setShouldUseCustomBaseJar(false); | ||||
| 			break; | ||||
| 		default: | ||||
| 		{ | ||||
| 			delete m_settings; | ||||
| 			return InstanceFactory::NoSuchVersion; | ||||
| 		} | ||||
| 		} | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		delete m_settings; | ||||
| 		return InstanceFactory::NoSuchVersion; | ||||
| 	} | ||||
| 	} | ||||
|  | ||||
| 	// FIXME: really, how do you even know? | ||||
| 	return InstanceFactory::NoCreateError; | ||||
|   | ||||
| @@ -55,18 +55,25 @@ public: | ||||
| 		CantCreateDir | ||||
| 	}; | ||||
|  | ||||
| 	enum InstType | ||||
| 	{ | ||||
| 		NormalInst, | ||||
| 		FTBInstance | ||||
| 	}; | ||||
|  | ||||
| 	/*! | ||||
| 	 * \brief Creates a stub instance | ||||
| 	 * | ||||
| 	 * \param inst Pointer to store the created instance in. | ||||
| 	 * \param inst Game version to use for the instance | ||||
| 	 * \param version Game version to use for the instance | ||||
| 	 * \param instDir The new instance's directory. | ||||
| 	 * \param type The type of instance to create | ||||
| 	 * \return An InstCreateError error code. | ||||
| 	 * - InstExists if the given instance directory is already an instance. | ||||
| 	 * - CantCreateDir if the given instance directory cannot be created. | ||||
| 	 */ | ||||
| 	InstCreateError createInstance(BaseInstance *&inst, BaseVersionPtr version, | ||||
| 								   const QString &instDir); | ||||
| 								   const QString &instDir, const InstType type = NormalInst); | ||||
|  | ||||
| 	/*! | ||||
| 	 * \brief Creates a copy of an existing instance with a new name | ||||
|   | ||||
							
								
								
									
										16
									
								
								logic/LegacyFTBInstance.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								logic/LegacyFTBInstance.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | ||||
| #include "LegacyFTBInstance.h" | ||||
|  | ||||
| LegacyFTBInstance::LegacyFTBInstance(const QString &rootDir, SettingsObject *settings, QObject *parent) : | ||||
| 	LegacyInstance(rootDir, settings, parent) | ||||
| { | ||||
| } | ||||
|  | ||||
| QString LegacyFTBInstance::getStatusbarDescription() | ||||
| { | ||||
| 	return "Legacy FTB: " + intendedVersionId(); | ||||
| } | ||||
|  | ||||
| bool LegacyFTBInstance::menuActionEnabled(QString action_name) const | ||||
| { | ||||
| 	return false; | ||||
| } | ||||
							
								
								
									
										13
									
								
								logic/LegacyFTBInstance.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								logic/LegacyFTBInstance.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,13 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "LegacyInstance.h" | ||||
|  | ||||
| class LegacyFTBInstance : public LegacyInstance | ||||
| { | ||||
| 	Q_OBJECT | ||||
| public: | ||||
| 	explicit LegacyFTBInstance(const QString &rootDir, SettingsObject *settings, | ||||
| 							   QObject *parent = 0); | ||||
| 	virtual QString getStatusbarDescription(); | ||||
| 	virtual bool menuActionEnabled(QString action_name) const; | ||||
| }; | ||||
							
								
								
									
										111
									
								
								logic/OneSixFTBInstance.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										111
									
								
								logic/OneSixFTBInstance.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,111 @@ | ||||
| #include "OneSixFTBInstance.h" | ||||
|  | ||||
| #include "OneSixVersion.h" | ||||
| #include "OneSixLibrary.h" | ||||
| #include "tasks/SequentialTask.h" | ||||
| #include "ForgeInstaller.h" | ||||
| #include "lists/ForgeVersionList.h" | ||||
| #include "MultiMC.h" | ||||
|  | ||||
| class OneSixFTBInstanceForge : public Task | ||||
| { | ||||
| 	Q_OBJECT | ||||
| public: | ||||
| 	explicit OneSixFTBInstanceForge(const QString &version, OneSixFTBInstance *inst, QObject *parent = 0) : | ||||
| 		Task(parent), instance(inst), version("Forge " + version) | ||||
| 	{ | ||||
| 	} | ||||
|  | ||||
| 	void executeTask() | ||||
| 	{ | ||||
| 		for (int i = 0; i < MMC->forgelist()->count(); ++i) | ||||
| 		{ | ||||
| 			if (MMC->forgelist()->at(i)->name() == version) | ||||
| 			{ | ||||
| 				forgeVersion = std::dynamic_pointer_cast<ForgeVersion>(MMC->forgelist()->at(i)); | ||||
| 				break; | ||||
| 			} | ||||
| 		} | ||||
| 		if (!forgeVersion) | ||||
| 			return; | ||||
| 		entry = MMC->metacache()->resolveEntry("minecraftforge", forgeVersion->filename); | ||||
| 		if (entry->stale) | ||||
| 		{ | ||||
| 			setStatus(tr("Downloading Forge...")); | ||||
| 			fjob = new NetJob("Forge download"); | ||||
| 			fjob->addNetAction(CacheDownload::make(forgeVersion->installer_url, entry)); | ||||
| 			connect(fjob, &NetJob::failed, [this](){emitFailed(m_failReason);}); | ||||
| 			connect(fjob, &NetJob::succeeded, this, &OneSixFTBInstanceForge::installForge); | ||||
| 			connect(fjob, &NetJob::progress, [this](qint64 c, qint64 total){ setProgress(100 * c / total); }); | ||||
| 			fjob->start(); | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			installForge(); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| private | ||||
| slots: | ||||
| 	void installForge() | ||||
| 	{ | ||||
| 		setStatus(tr("Installing Forge...")); | ||||
| 		QString forgePath = entry->getFullPath(); | ||||
| 		ForgeInstaller forge(forgePath, forgeVersion->universal_url); | ||||
| 		if (!instance->reloadFullVersion()) | ||||
| 		{ | ||||
| 			emitFailed(tr("Couldn't load the version config")); | ||||
| 			return; | ||||
| 		} | ||||
| 		if (!forge.apply(instance->getFullVersion())) | ||||
| 		{ | ||||
| 			emitFailed(tr("Couldn't install Forge")); | ||||
| 			return; | ||||
| 		} | ||||
| 		emitSucceeded(); | ||||
| 	} | ||||
|  | ||||
| private: | ||||
| 	OneSixFTBInstance *instance; | ||||
| 	QString version; | ||||
| 	ForgeVersionPtr forgeVersion; | ||||
| 	MetaEntryPtr entry; | ||||
| 	NetJob *fjob; | ||||
| }; | ||||
|  | ||||
| OneSixFTBInstance::OneSixFTBInstance(const QString &rootDir, SettingsObject *settings, QObject *parent) : | ||||
| 	OneSixInstance(rootDir, settings, parent) | ||||
| { | ||||
| 	QFile f(QDir(minecraftRoot()).absoluteFilePath("pack.json")); | ||||
| 	if (f.open(QFile::ReadOnly)) | ||||
| 	{ | ||||
| 		QString data = QString::fromUtf8(f.readAll()); | ||||
| 		QRegularExpressionMatch match = QRegularExpression("net.minecraftforge:minecraftforge:[\\.\\d]*").match(data); | ||||
| 		m_forge.reset(new OneSixLibrary(match.captured())); | ||||
| 		m_forge->finalize(); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| QString OneSixFTBInstance::getStatusbarDescription() | ||||
| { | ||||
| 	return "OneSix FTB: " + intendedVersionId(); | ||||
| } | ||||
| bool OneSixFTBInstance::menuActionEnabled(QString action_name) const | ||||
| { | ||||
| 	return false; | ||||
| } | ||||
|  | ||||
| std::shared_ptr<Task> OneSixFTBInstance::doUpdate(bool only_prepare) | ||||
| { | ||||
| 	std::shared_ptr<SequentialTask> task; | ||||
| 	task.reset(new SequentialTask(this)); | ||||
| 	if (!MMC->forgelist()->isLoaded()) | ||||
| 	{ | ||||
| 		task->addTask(std::shared_ptr<Task>(MMC->forgelist()->getLoadTask())); | ||||
| 	} | ||||
| 	task->addTask(OneSixInstance::doUpdate(only_prepare)); | ||||
| 	task->addTask(std::shared_ptr<Task>(new OneSixFTBInstanceForge(m_forge->version(), this, this))); | ||||
| 	return task; | ||||
| } | ||||
|  | ||||
| #include "OneSixFTBInstance.moc" | ||||
							
								
								
									
										20
									
								
								logic/OneSixFTBInstance.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								logic/OneSixFTBInstance.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,20 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "OneSixInstance.h" | ||||
|  | ||||
| class OneSixLibrary; | ||||
|  | ||||
| class OneSixFTBInstance : public OneSixInstance | ||||
| { | ||||
| 	Q_OBJECT | ||||
| public: | ||||
| 	explicit OneSixFTBInstance(const QString &rootDir, SettingsObject *settings, | ||||
| 							QObject *parent = 0); | ||||
| 	virtual QString getStatusbarDescription(); | ||||
| 	virtual bool menuActionEnabled(QString action_name) const; | ||||
|  | ||||
| 	virtual std::shared_ptr<Task> doUpdate(bool only_prepare) override; | ||||
|  | ||||
| private: | ||||
| 	std::shared_ptr<OneSixLibrary> m_forge; | ||||
| }; | ||||
| @@ -159,6 +159,7 @@ ForgeListLoadTask::ForgeListLoadTask(ForgeVersionList *vlist) : Task() | ||||
|  | ||||
| void ForgeListLoadTask::executeTask() | ||||
| { | ||||
| 	setStatus(tr("Fetching Forge version list")); | ||||
| 	auto job = new NetJob("Version index"); | ||||
| 	// we do not care if the version is stale or not. | ||||
| 	auto forgeListEntry = MMC->metacache()->resolveEntry("minecraftforge", "list.json"); | ||||
|   | ||||
| @@ -22,11 +22,14 @@ | ||||
| #include <QJsonDocument> | ||||
| #include <QJsonObject> | ||||
| #include <QJsonArray> | ||||
| #include <QXmlStreamReader> | ||||
| #include <QRegularExpression> | ||||
| #include <pathutils.h> | ||||
|  | ||||
| #include "MultiMC.h" | ||||
| #include "logic/lists/InstanceList.h" | ||||
| #include "logic/lists/IconList.h" | ||||
| #include "logic/lists/MinecraftVersionList.h" | ||||
| #include "logic/BaseInstance.h" | ||||
| #include "logic/InstanceFactory.h" | ||||
| #include "logger/QsLog.h" | ||||
| @@ -42,6 +45,8 @@ InstanceList::InstanceList(const QString &instDir, QObject *parent) | ||||
| 	{ | ||||
| 		QDir::current().mkpath(m_instDir); | ||||
| 	} | ||||
|  | ||||
| 	connect(MMC->minecraftlist().get(), &MinecraftVersionList::modelReset, this, &InstanceList::loadList); | ||||
| } | ||||
|  | ||||
| InstanceList::~InstanceList() | ||||
| @@ -285,57 +290,87 @@ InstanceList::InstListError InstanceList::loadList() | ||||
| 	beginResetModel(); | ||||
|  | ||||
| 	m_instances.clear(); | ||||
| 	QDir dir(m_instDir); | ||||
| 	QDirIterator iter(m_instDir, QDir::Dirs | QDir::NoDot | QDir::NoDotDot | QDir::Readable, | ||||
| 					  QDirIterator::FollowSymlinks); | ||||
| 	while (iter.hasNext()) | ||||
|  | ||||
| 	{ | ||||
| 		QString subDir = iter.next(); | ||||
| 		if (!QFileInfo(PathCombine(subDir, "instance.cfg")).exists()) | ||||
| 			continue; | ||||
|  | ||||
| 		BaseInstance *instPtr = NULL; | ||||
| 		auto &loader = InstanceFactory::get(); | ||||
| 		auto error = loader.loadInstance(instPtr, subDir); | ||||
|  | ||||
| 		if (error != InstanceFactory::NoLoadError && error != InstanceFactory::NotAnInstance) | ||||
| 		QDirIterator iter(m_instDir, QDir::Dirs | QDir::NoDot | QDir::NoDotDot | QDir::Readable, | ||||
| 						  QDirIterator::FollowSymlinks); | ||||
| 		while (iter.hasNext()) | ||||
| 		{ | ||||
| 			QString errorMsg = QString("Failed to load instance %1: ") | ||||
| 								   .arg(QFileInfo(subDir).baseName()) | ||||
| 								   .toUtf8(); | ||||
| 			QString subDir = iter.next(); | ||||
| 			if (!QFileInfo(PathCombine(subDir, "instance.cfg")).exists()) | ||||
| 				continue; | ||||
|  | ||||
| 			switch (error) | ||||
| 			{ | ||||
| 			default: | ||||
| 				errorMsg += QString("Unknown instance loader error %1").arg(error); | ||||
| 				break; | ||||
| 			} | ||||
| 			QLOG_ERROR() << errorMsg.toUtf8(); | ||||
| 			BaseInstance *instPtr = NULL; | ||||
| 			auto error = InstanceFactory::get().loadInstance(instPtr, subDir); | ||||
| 			continueProcessInstance(instPtr, error, subDir, groupMap); | ||||
| 		} | ||||
| 		else if (!instPtr) | ||||
| 	} | ||||
|  | ||||
| 	if (MMC->settings()->get("TrackFTBInstances").toBool() && MMC->minecraftlist()->isLoaded()) | ||||
| 	{ | ||||
| 		QDir dir = QDir(MMC->settings()->get("FTBLauncherRoot").toString()); | ||||
| 		QDir dataDir = QDir(MMC->settings()->get("FTBRoot").toString()); | ||||
| 		if (!dir.exists()) | ||||
| 		{ | ||||
| 			QLOG_ERROR() << QString("Error loading instance %1. Instance loader returned null.") | ||||
| 								.arg(QFileInfo(subDir).baseName()) | ||||
| 								.toUtf8(); | ||||
| 			QLOG_INFO() << "The FTB launcher directory specified does not exist. Please check your settings."; | ||||
| 		} | ||||
| 		else if (!dataDir.exists()) | ||||
| 		{ | ||||
| 			QLOG_INFO() << "The FTB directory specified does not exist. Please check your settings"; | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			std::shared_ptr<BaseInstance> inst(instPtr); | ||||
| 			auto iter = groupMap.find(inst->id()); | ||||
| 			if (iter != groupMap.end()) | ||||
| 			dir.cd("ModPacks"); | ||||
| 			QFile f(dir.absoluteFilePath("modpacks.xml")); | ||||
| 			if (f.open(QFile::ReadOnly)) | ||||
| 			{ | ||||
| 				inst->setGroupInitial((*iter)); | ||||
| 				QXmlStreamReader reader(&f); | ||||
| 				while (!reader.atEnd()) | ||||
| 				{ | ||||
| 					switch (reader.readNext()) | ||||
| 					{ | ||||
| 					case QXmlStreamReader::StartElement: | ||||
| 					{ | ||||
| 						if (reader.name() == "modpack") | ||||
| 						{ | ||||
| 							QXmlStreamAttributes attrs = reader.attributes(); | ||||
| 							const QDir instanceDir = QDir(dataDir.absoluteFilePath(attrs.value("dir").toString())); | ||||
| 							if (instanceDir.exists()) | ||||
| 							{ | ||||
| 								const QString name = attrs.value("name").toString(); | ||||
| 								const QString iconKey = attrs.value("logo").toString().remove(QRegularExpression("\\..*")); | ||||
| 								const QString mcVersion = attrs.value("mcVersion").toString(); | ||||
| 								const QString notes = attrs.value("description").toString(); | ||||
| 								QLOG_DEBUG() << dir.absoluteFilePath(attrs.value("logo").toString()); | ||||
| 								MMC->icons()->addIcon(iconKey, iconKey, dir.absoluteFilePath(attrs.value("dir").toString() + QDir::separator() + attrs.value("logo").toString()), true); | ||||
|  | ||||
| 								BaseInstance *instPtr = NULL; | ||||
| 								auto error = InstanceFactory::get().createInstance(instPtr, MMC->minecraftlist()->findVersion(mcVersion), instanceDir.absolutePath(), InstanceFactory::FTBInstance); | ||||
| 								if (instPtr && error == InstanceFactory::NoCreateError) | ||||
| 								{ | ||||
| 									instPtr->setGroupInitial("FTB"); | ||||
| 									instPtr->setName(name); | ||||
| 									instPtr->setIconKey(iconKey); | ||||
| 									instPtr->setIntendedVersionId(mcVersion); | ||||
| 									instPtr->setNotes(notes); | ||||
| 								} | ||||
| 								continueProcessInstance(instPtr, error, instanceDir, groupMap); | ||||
| 							} | ||||
| 						} | ||||
| 						break; | ||||
| 					} | ||||
| 					case QXmlStreamReader::EndElement: | ||||
| 						break; | ||||
| 					case QXmlStreamReader::Characters: | ||||
| 						break; | ||||
| 					default: | ||||
| 						break; | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 			QLOG_INFO() << "Loaded instance " << inst->name(); | ||||
| 			inst->setParent(this); | ||||
| 			m_instances.append(inst); | ||||
| 			connect(instPtr, SIGNAL(propertiesChanged(BaseInstance *)), this, | ||||
| 					SLOT(propertiesChanged(BaseInstance *))); | ||||
| 			connect(instPtr, SIGNAL(groupChanged()), this, SLOT(groupChanged())); | ||||
| 			connect(instPtr, SIGNAL(nuked(BaseInstance *)), this, | ||||
| 					SLOT(instanceNuked(BaseInstance *))); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	endResetModel(); | ||||
| 	emit dataIsInvalid(); | ||||
| 	return NoError; | ||||
| @@ -409,6 +444,46 @@ int InstanceList::getInstIndex(BaseInstance *inst) const | ||||
| 	return -1; | ||||
| } | ||||
|  | ||||
| void InstanceList::continueProcessInstance(BaseInstance *instPtr, const int error, const QDir &dir, QMap<QString, QString> &groupMap) | ||||
| { | ||||
| 	if (error != InstanceFactory::NoLoadError && error != InstanceFactory::NotAnInstance) | ||||
| 	{ | ||||
| 		QString errorMsg = QString("Failed to load instance %1: ") | ||||
| 				.arg(QFileInfo(dir.absolutePath()).baseName()) | ||||
| 				.toUtf8(); | ||||
|  | ||||
| 		switch (error) | ||||
| 		{ | ||||
| 		default: | ||||
| 			errorMsg += QString("Unknown instance loader error %1").arg(error); | ||||
| 			break; | ||||
| 		} | ||||
| 		QLOG_ERROR() << errorMsg.toUtf8(); | ||||
| 	} | ||||
| 	else if (!instPtr) | ||||
| 	{ | ||||
| 		QLOG_ERROR() << QString("Error loading instance %1. Instance loader returned null.") | ||||
| 						.arg(QFileInfo(dir.absolutePath()).baseName()) | ||||
| 						.toUtf8(); | ||||
| 	} | ||||
| 	else | ||||
| 	{ | ||||
| 		auto iter = groupMap.find(instPtr->id()); | ||||
| 		if (iter != groupMap.end()) | ||||
| 		{ | ||||
| 			instPtr->setGroupInitial((*iter)); | ||||
| 		} | ||||
| 		QLOG_INFO() << "Loaded instance " << instPtr->name(); | ||||
| 		instPtr->setParent(this); | ||||
| 		m_instances.append(std::shared_ptr<BaseInstance>(instPtr)); | ||||
| 		connect(instPtr, SIGNAL(propertiesChanged(BaseInstance *)), this, | ||||
| 				SLOT(propertiesChanged(BaseInstance *))); | ||||
| 		connect(instPtr, SIGNAL(groupChanged()), this, SLOT(groupChanged())); | ||||
| 		connect(instPtr, SIGNAL(nuked(BaseInstance *)), this, | ||||
| 				SLOT(instanceNuked(BaseInstance *))); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void InstanceList::instanceNuked(BaseInstance *inst) | ||||
| { | ||||
| 	int i = getInstIndex(inst); | ||||
|   | ||||
| @@ -25,6 +25,8 @@ | ||||
|  | ||||
| class BaseInstance; | ||||
|  | ||||
| class QDir; | ||||
|  | ||||
| class InstanceList : public QAbstractListModel | ||||
| { | ||||
| 	Q_OBJECT | ||||
| @@ -65,11 +67,6 @@ public: | ||||
| 		return m_instDir; | ||||
| 	} | ||||
|  | ||||
| 	/*! | ||||
| 	 * \brief Loads the instance list. Triggers notifications. | ||||
| 	 */ | ||||
| 	InstListError loadList(); | ||||
|  | ||||
| 	/*! | ||||
| 	 * \brief Get the instance at index | ||||
| 	 */ | ||||
| @@ -108,6 +105,11 @@ public | ||||
| slots: | ||||
| 	void on_InstFolderChanged(const Setting &setting, QVariant value); | ||||
|  | ||||
| 	/*! | ||||
| 	 * \brief Loads the instance list. Triggers notifications. | ||||
| 	 */ | ||||
| 	InstListError loadList(); | ||||
|  | ||||
| private | ||||
| slots: | ||||
| 	void propertiesChanged(BaseInstance *inst); | ||||
| @@ -117,6 +119,8 @@ slots: | ||||
| private: | ||||
| 	int getInstIndex(BaseInstance *inst) const; | ||||
|  | ||||
| 	void continueProcessInstance(BaseInstance *instPtr, const int error, const QDir &dir, QMap<QString, QString> &groupMap); | ||||
|  | ||||
| protected: | ||||
| 	QString m_instDir; | ||||
| 	QList<InstancePtr> m_instances; | ||||
|   | ||||
							
								
								
									
										77
									
								
								logic/tasks/SequentialTask.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										77
									
								
								logic/tasks/SequentialTask.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,77 @@ | ||||
| #include "SequentialTask.h" | ||||
|  | ||||
| SequentialTask::SequentialTask(QObject *parent) : | ||||
| 	Task(parent), m_currentIndex(-1) | ||||
| { | ||||
|  | ||||
| } | ||||
|  | ||||
| QString SequentialTask::getStatus() const | ||||
| { | ||||
| 	if (m_queue.isEmpty() || m_currentIndex >= m_queue.size()) | ||||
| 	{ | ||||
| 		return QString(); | ||||
| 	} | ||||
| 	return m_queue.at(m_currentIndex)->getStatus(); | ||||
| } | ||||
|  | ||||
| void SequentialTask::getProgress(qint64 ¤t, qint64 &total) | ||||
| { | ||||
| 	current = 0; | ||||
| 	total = 0; | ||||
| 	for (int i = 0; i < m_queue.size(); ++i) | ||||
| 	{ | ||||
| 		qint64 subCurrent, subTotal; | ||||
| 		m_queue.at(i)->getProgress(subCurrent, subTotal); | ||||
| 		current += subCurrent; | ||||
| 		total += subTotal; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void SequentialTask::addTask(std::shared_ptr<Task> task) | ||||
| { | ||||
| 	m_queue.append(task); | ||||
| } | ||||
|  | ||||
| void SequentialTask::executeTask() | ||||
| { | ||||
| 	m_currentIndex = -1; | ||||
| 	startNext(); | ||||
| } | ||||
|  | ||||
| void SequentialTask::startNext() | ||||
| { | ||||
| 	if (m_currentIndex != -1) | ||||
| 	{ | ||||
| 		std::shared_ptr<Task> previous = m_queue[m_currentIndex]; | ||||
| 		disconnect(previous.get(), 0, this, 0); | ||||
| 	} | ||||
| 	m_currentIndex++; | ||||
| 	if (m_queue.isEmpty() || m_currentIndex >= m_queue.size()) | ||||
| 	{ | ||||
| 		emitSucceeded(); | ||||
| 		return; | ||||
| 	} | ||||
| 	std::shared_ptr<Task> next = m_queue[m_currentIndex]; | ||||
| 	connect(next.get(), SIGNAL(failed(QString)), this, SLOT(subTaskFailed(QString))); | ||||
| 	connect(next.get(), SIGNAL(status(QString)), this, SLOT(subTaskStatus(QString))); | ||||
| 	connect(next.get(), SIGNAL(progress(qint64,qint64)), this, SLOT(subTaskProgress())); | ||||
| 	connect(next.get(), SIGNAL(succeeded()), this, SLOT(startNext())); | ||||
| 	next->start(); | ||||
| 	emit status(getStatus()); | ||||
| } | ||||
|  | ||||
| void SequentialTask::subTaskFailed(const QString &msg) | ||||
| { | ||||
| 	emitFailed(msg); | ||||
| } | ||||
| void SequentialTask::subTaskStatus(const QString &msg) | ||||
| { | ||||
| 	setStatus(msg); | ||||
| } | ||||
| void SequentialTask::subTaskProgress() | ||||
| { | ||||
| 	qint64 current, total; | ||||
| 	getProgress(current, total); | ||||
| 	setProgress(100 * current / total); | ||||
| } | ||||
							
								
								
									
										32
									
								
								logic/tasks/SequentialTask.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								logic/tasks/SequentialTask.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,32 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "Task.h" | ||||
|  | ||||
| #include <QQueue> | ||||
| #include <memory> | ||||
|  | ||||
| class SequentialTask : public Task | ||||
| { | ||||
| 	Q_OBJECT | ||||
| public: | ||||
| 	explicit SequentialTask(QObject *parent = 0); | ||||
|  | ||||
| 	virtual QString getStatus() const; | ||||
| 	virtual void getProgress(qint64 ¤t, qint64 &total); | ||||
|  | ||||
| 	void addTask(std::shared_ptr<Task> task); | ||||
|  | ||||
| protected: | ||||
| 	void executeTask(); | ||||
|  | ||||
| private | ||||
| slots: | ||||
| 	void startNext(); | ||||
| 	void subTaskFailed(const QString &msg); | ||||
| 	void subTaskStatus(const QString &msg); | ||||
| 	void subTaskProgress(); | ||||
|  | ||||
| private: | ||||
| 	QQueue<std::shared_ptr<Task> > m_queue; | ||||
| 	int m_currentIndex; | ||||
| }; | ||||
		Reference in New Issue
	
	Block a user