summaryrefslogtreecommitdiffstats
path: root/backend/lists/InstanceList.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'backend/lists/InstanceList.cpp')
-rw-r--r--backend/lists/InstanceList.cpp232
1 files changed, 232 insertions, 0 deletions
diff --git a/backend/lists/InstanceList.cpp b/backend/lists/InstanceList.cpp
new file mode 100644
index 00000000..101d52c5
--- /dev/null
+++ b/backend/lists/InstanceList.cpp
@@ -0,0 +1,232 @@
+/* Copyright 2013 MultiMC Contributors
+ *
+ * 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 <QDir>
+#include <QFile>
+#include <QDirIterator>
+#include <QThread>
+#include <QTextStream>
+#include <QJsonDocument>
+#include <QJsonObject>
+#include <QJsonArray>
+
+#include "lists/InstanceList.h"
+#include "BaseInstance.h"
+#include "InstanceFactory.h"
+
+#include "pathutils.h"
+
+const static int GROUP_FILE_FORMAT_VERSION = 1;
+
+InstanceList::InstanceList(const QString &instDir, QObject *parent) :
+ QObject(parent), m_instDir("instances")
+{
+
+}
+
+void InstanceList::loadGroupList(QMap<QString, QString> & groupMap)
+{
+ QString groupFileName = m_instDir + "/instgroups.json";
+
+ // if there's no group file, fail
+ if(!QFileInfo(groupFileName).exists())
+ return;
+
+ QFile groupFile(groupFileName);
+
+ // if you can't open the file, fail
+ if (!groupFile.open(QIODevice::ReadOnly))
+ {
+ // An error occurred. Ignore it.
+ qDebug("Failed to read instance group file.");
+ return;
+ }
+
+ QTextStream in(&groupFile);
+ QString jsonStr = in.readAll();
+ groupFile.close();
+
+ QJsonParseError error;
+ QJsonDocument jsonDoc = QJsonDocument::fromJson(jsonStr.toUtf8(), &error);
+
+ // if the json was bad, fail
+ if (error.error != QJsonParseError::NoError)
+ {
+ qWarning(QString("Failed to parse instance group file: %1 at offset %2").
+ arg(error.errorString(), QString::number(error.offset)).toUtf8());
+ return;
+ }
+
+ // if the root of the json wasn't an object, fail
+ if (!jsonDoc.isObject())
+ {
+ qWarning("Invalid group file. Root entry should be an object.");
+ return;
+ }
+
+ QJsonObject rootObj = jsonDoc.object();
+
+ // Make sure the format version matches, otherwise fail.
+ if (rootObj.value("formatVersion").toVariant().toInt() != GROUP_FILE_FORMAT_VERSION)
+ return;
+
+ // Get the groups. if it's not an object, fail
+ if (!rootObj.value("groups").isObject())
+ {
+ qWarning("Invalid group list JSON: 'groups' should be an object.");
+ return;
+ }
+
+ // Iterate through all the groups.
+ QJsonObject groupMapping = rootObj.value("groups").toObject();
+ for (QJsonObject::iterator iter = groupMapping.begin(); iter != groupMapping.end(); iter++)
+ {
+ QString groupName = iter.key();
+
+ // If not an object, complain and skip to the next one.
+ if (!iter.value().isObject())
+ {
+ qWarning(QString("Group '%1' in the group list should "
+ "be an object.").arg(groupName).toUtf8());
+ continue;
+ }
+
+ QJsonObject groupObj = iter.value().toObject();
+ if (!groupObj.value("instances").isArray())
+ {
+ qWarning(QString("Group '%1' in the group list is invalid. "
+ "It should contain an array "
+ "called 'instances'.").arg(groupName).toUtf8());
+ continue;
+ }
+
+ // Iterate through the list of instances in the group.
+ QJsonArray instancesArray = groupObj.value("instances").toArray();
+
+ for (QJsonArray::iterator iter2 = instancesArray.begin();
+ iter2 != instancesArray.end(); iter2++)
+ {
+ groupMap[(*iter2).toString()] = groupName;
+ }
+ }
+}
+
+InstanceList::InstListError InstanceList::loadList()
+{
+ // load the instance groups
+ QMap<QString, QString> groupMap;
+ loadGroupList(groupMap);
+
+ m_instances.clear();
+ QDir dir(m_instDir);
+ QDirIterator iter(dir);
+ 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);
+
+ switch(error)
+ {
+ case InstanceFactory::NoLoadError:
+ break;
+ case InstanceFactory::NotAnInstance:
+ break;
+ }
+
+ if (error != InstanceFactory::NoLoadError &&
+ error != InstanceFactory::NotAnInstance)
+ {
+ QString errorMsg = QString("Failed to load instance %1: ").
+ arg(QFileInfo(subDir).baseName()).toUtf8();
+
+ switch (error)
+ {
+ default:
+ errorMsg += QString("Unknown instance loader error %1").
+ arg(error);
+ break;
+ }
+ qDebug(errorMsg.toUtf8());
+ }
+ else if (!instPtr)
+ {
+ qDebug(QString("Error loading instance %1. Instance loader returned null.").
+ arg(QFileInfo(subDir).baseName()).toUtf8());
+ }
+ else
+ {
+ QSharedPointer<BaseInstance> inst(instPtr);
+ auto iter = groupMap.find(inst->id());
+ if(iter != groupMap.end())
+ {
+ inst->setGroup((*iter));
+ }
+ qDebug(QString("Loaded instance %1").arg(inst->name()).toUtf8());
+ inst->setParent(this);
+ m_instances.append(inst);
+ connect(instPtr, SIGNAL(propertiesChanged(BaseInstance*)),this, SLOT(propertiesChanged(BaseInstance*)));
+ }
+ }
+ emit invalidated();
+ return NoError;
+}
+
+/// Clear all instances. Triggers notifications.
+void InstanceList::clear()
+{
+ m_instances.clear();
+ emit invalidated();
+};
+
+/// Add an instance. Triggers notifications, returns the new index
+int InstanceList::add(InstancePtr t)
+{
+ m_instances.append(t);
+ emit instanceAdded(count() - 1);
+ return count() - 1;
+}
+
+InstancePtr InstanceList::getInstanceById(QString instId)
+{
+ QListIterator<InstancePtr> iter(m_instances);
+ InstancePtr inst;
+ while(iter.hasNext())
+ {
+ inst = iter.next();
+ if (inst->id() == instId)
+ break;
+ }
+ if (inst->id() != instId)
+ return InstancePtr();
+ else
+ return iter.peekPrevious();
+}
+
+void InstanceList::propertiesChanged(BaseInstance * inst)
+{
+ for(int i = 0; i < m_instances.count(); i++)
+ {
+ if(inst == m_instances[i].data())
+ {
+ emit instanceChanged(i);
+ break;
+ }
+ }
+}