From 8a3a0f5a529a95c7511436051b63887dff158c50 Mon Sep 17 00:00:00 2001 From: Petr Mrázek Date: Thu, 8 May 2014 21:20:10 +0200 Subject: Reorganize logic code. --- CMakeLists.txt | 107 +++--- MultiMC.cpp | 8 +- gui/MainWindow.cpp | 10 +- gui/MainWindow.h | 5 +- gui/dialogs/CopyInstanceDialog.cpp | 1 - gui/dialogs/InstanceEditDialog.cpp | 4 +- gui/dialogs/InstanceSettings.cpp | 7 +- gui/dialogs/InstanceSettings.h | 2 +- gui/dialogs/LwjglSelectDialog.cpp | 2 +- gui/dialogs/NewInstanceDialog.cpp | 2 +- gui/dialogs/SettingsDialog.cpp | 7 +- gui/dialogs/SettingsDialog.h | 2 +- gui/dialogs/VersionSelectDialog.cpp | 2 +- gui/groupview/InstanceDelegate.cpp | 2 +- logic/BaseInstaller.cpp | 9 +- logic/BaseInstance.cpp | 2 +- logic/BaseInstance.h | 2 +- logic/BaseVersionList.cpp | 121 ++++++ logic/BaseVersionList.h | 120 ++++++ logic/InstanceFactory.cpp | 27 +- logic/InstanceLauncher.cpp | 2 +- logic/InstanceList.cpp | 618 ++++++++++++++++++++++++++++++ logic/InstanceList.h | 152 ++++++++ logic/JavaChecker.cpp | 124 ------ logic/JavaChecker.h | 42 -- logic/JavaCheckerJob.cpp | 47 --- logic/JavaCheckerJob.h | 100 ----- logic/JavaUtils.cpp | 223 ----------- logic/JavaUtils.h | 43 --- logic/LegacyUpdate.cpp | 20 +- logic/LwjglVersionList.cpp | 199 ++++++++++ logic/LwjglVersionList.h | 148 +++++++ logic/MinecraftVersion.h | 92 ----- logic/OneSixFTBInstance.cpp | 6 +- logic/OneSixInstance.cpp | 21 +- logic/OneSixInstance.h | 4 +- logic/OneSixInstance_p.h | 7 +- logic/OneSixLibrary.cpp | 274 ------------- logic/OneSixLibrary.h | 148 ------- logic/OneSixRule.cpp | 89 ----- logic/OneSixRule.h | 98 ----- logic/OneSixUpdate.cpp | 19 +- logic/OneSixVersionBuilder.cpp | 248 ------------ logic/OneSixVersionBuilder.h | 46 --- logic/OpSys.cpp | 42 -- logic/OpSys.h | 37 -- logic/VersionFile.cpp | 635 ------------------------------- logic/VersionFile.h | 145 ------- logic/VersionFinal.cpp | 431 --------------------- logic/VersionFinal.h | 172 --------- logic/forge/ForgeInstaller.cpp | 4 +- logic/forge/ForgeVersionList.h | 2 +- logic/java/JavaChecker.cpp | 124 ++++++ logic/java/JavaChecker.h | 42 ++ logic/java/JavaCheckerJob.cpp | 47 +++ logic/java/JavaCheckerJob.h | 100 +++++ logic/java/JavaUtils.cpp | 221 +++++++++++ logic/java/JavaUtils.h | 43 +++ logic/java/JavaVersionList.cpp | 241 ++++++++++++ logic/java/JavaVersionList.h | 96 +++++ logic/lists/BaseVersionList.cpp | 121 ------ logic/lists/BaseVersionList.h | 120 ------ logic/lists/InstanceList.cpp | 618 ------------------------------ logic/lists/InstanceList.h | 152 -------- logic/lists/JavaVersionList.cpp | 241 ------------ logic/lists/JavaVersionList.h | 96 ----- logic/lists/LwjglVersionList.cpp | 199 ---------- logic/lists/LwjglVersionList.h | 148 ------- logic/lists/MinecraftVersionList.cpp | 330 ---------------- logic/lists/MinecraftVersionList.h | 76 ---- logic/liteloader/LiteLoaderInstaller.cpp | 4 +- logic/liteloader/LiteLoaderVersionList.h | 4 +- logic/minecraft/MinecraftVersion.h | 92 +++++ logic/minecraft/MinecraftVersionList.cpp | 330 ++++++++++++++++ logic/minecraft/MinecraftVersionList.h | 76 ++++ logic/minecraft/OneSixLibrary.cpp | 274 +++++++++++++ logic/minecraft/OneSixLibrary.h | 148 +++++++ logic/minecraft/OneSixRule.cpp | 89 +++++ logic/minecraft/OneSixRule.h | 98 +++++ logic/minecraft/OneSixVersionBuilder.cpp | 249 ++++++++++++ logic/minecraft/OneSixVersionBuilder.h | 46 +++ logic/minecraft/OpSys.cpp | 42 ++ logic/minecraft/OpSys.h | 37 ++ logic/minecraft/VersionFile.cpp | 635 +++++++++++++++++++++++++++++++ logic/minecraft/VersionFile.h | 145 +++++++ logic/minecraft/VersionFinal.cpp | 429 +++++++++++++++++++++ logic/minecraft/VersionFinal.h | 172 +++++++++ 87 files changed, 5282 insertions(+), 5283 deletions(-) create mode 100644 logic/BaseVersionList.cpp create mode 100644 logic/BaseVersionList.h create mode 100644 logic/InstanceList.cpp create mode 100644 logic/InstanceList.h delete mode 100644 logic/JavaChecker.cpp delete mode 100644 logic/JavaChecker.h delete mode 100644 logic/JavaCheckerJob.cpp delete mode 100644 logic/JavaCheckerJob.h delete mode 100644 logic/JavaUtils.cpp delete mode 100644 logic/JavaUtils.h create mode 100644 logic/LwjglVersionList.cpp create mode 100644 logic/LwjglVersionList.h delete mode 100644 logic/MinecraftVersion.h delete mode 100644 logic/OneSixLibrary.cpp delete mode 100644 logic/OneSixLibrary.h delete mode 100644 logic/OneSixRule.cpp delete mode 100644 logic/OneSixRule.h delete mode 100644 logic/OneSixVersionBuilder.cpp delete mode 100644 logic/OneSixVersionBuilder.h delete mode 100644 logic/OpSys.cpp delete mode 100644 logic/OpSys.h delete mode 100644 logic/VersionFile.cpp delete mode 100644 logic/VersionFile.h delete mode 100644 logic/VersionFinal.cpp delete mode 100644 logic/VersionFinal.h create mode 100644 logic/java/JavaChecker.cpp create mode 100644 logic/java/JavaChecker.h create mode 100644 logic/java/JavaCheckerJob.cpp create mode 100644 logic/java/JavaCheckerJob.h create mode 100644 logic/java/JavaUtils.cpp create mode 100644 logic/java/JavaUtils.h create mode 100644 logic/java/JavaVersionList.cpp create mode 100644 logic/java/JavaVersionList.h delete mode 100644 logic/lists/BaseVersionList.cpp delete mode 100644 logic/lists/BaseVersionList.h delete mode 100644 logic/lists/InstanceList.cpp delete mode 100644 logic/lists/InstanceList.h delete mode 100644 logic/lists/JavaVersionList.cpp delete mode 100644 logic/lists/JavaVersionList.h delete mode 100644 logic/lists/LwjglVersionList.cpp delete mode 100644 logic/lists/LwjglVersionList.h delete mode 100644 logic/lists/MinecraftVersionList.cpp delete mode 100644 logic/lists/MinecraftVersionList.h create mode 100644 logic/minecraft/MinecraftVersion.h create mode 100644 logic/minecraft/MinecraftVersionList.cpp create mode 100644 logic/minecraft/MinecraftVersionList.h create mode 100644 logic/minecraft/OneSixLibrary.cpp create mode 100644 logic/minecraft/OneSixLibrary.h create mode 100644 logic/minecraft/OneSixRule.cpp create mode 100644 logic/minecraft/OneSixRule.h create mode 100644 logic/minecraft/OneSixVersionBuilder.cpp create mode 100644 logic/minecraft/OneSixVersionBuilder.h create mode 100644 logic/minecraft/OpSys.cpp create mode 100644 logic/minecraft/OpSys.h create mode 100644 logic/minecraft/VersionFile.cpp create mode 100644 logic/minecraft/VersionFile.h create mode 100644 logic/minecraft/VersionFinal.cpp create mode 100644 logic/minecraft/VersionFinal.h diff --git a/CMakeLists.txt b/CMakeLists.txt index a8686023..4459b92e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -359,17 +359,13 @@ SET(MULTIMC_SOURCES gui/groupview/InstanceDelegate.cpp gui/groupview/InstanceDelegate.h - # Base classes and infrastructure + # LOGIC - Base classes and infrastructure logic/BaseVersion.h - logic/MinecraftVersion.h logic/InstanceFactory.h logic/InstanceFactory.cpp logic/BaseInstance.h logic/BaseInstance.cpp logic/BaseInstance_p.h - - logic/MinecraftProcess.h - logic/MinecraftProcess.cpp logic/Mod.h logic/Mod.cpp logic/ModList.h @@ -379,9 +375,27 @@ SET(MULTIMC_SOURCES logic/VersionFilterData.h logic/VersionFilterData.cpp - # Basic instance launcher for starting from terminal + # Instance launch logic/InstanceLauncher.h logic/InstanceLauncher.cpp + logic/MinecraftProcess.h + logic/MinecraftProcess.cpp + + # URN parser/resolver + logic/URNResolver.cpp + logic/URNResolver.h + + # Annoying nag screen logic + logic/NagUtils.h + logic/NagUtils.cpp + + # Player skin utilities + logic/SkinUtils.h + logic/SkinUtils.cpp + + # misc model filter + logic/EnabledItemFilter.h + logic/EnabledItemFilter.cpp # JSON parsing helpers logic/MMCJson.h @@ -453,22 +467,34 @@ SET(MULTIMC_SOURCES logic/OneSixInstance_p.h # OneSix version json infrastructure - logic/OneSixVersionBuilder.h - logic/OneSixVersionBuilder.cpp - logic/VersionFile.h - logic/VersionFile.cpp - logic/VersionFinal.h - logic/VersionFinal.cpp - logic/OneSixLibrary.h - logic/OneSixLibrary.cpp - logic/OneSixRule.h - logic/OneSixRule.cpp - logic/OpSys.h - logic/OpSys.cpp - - # Mod installers + logic/minecraft/MinecraftVersion.h + logic/minecraft/OneSixVersionBuilder.h + logic/minecraft/OneSixVersionBuilder.cpp + logic/minecraft/VersionFile.h + logic/minecraft/VersionFile.cpp + logic/minecraft/VersionFinal.h + logic/minecraft/VersionFinal.cpp + logic/minecraft/OneSixLibrary.h + logic/minecraft/OneSixLibrary.cpp + logic/minecraft/OneSixRule.h + logic/minecraft/OneSixRule.cpp + logic/minecraft/MinecraftVersionList.h + logic/minecraft/MinecraftVersionList.cpp + + # Trivial operating system utilities + logic/minecraft/OpSys.h + logic/minecraft/OpSys.cpp + + # Various base classes logic/BaseInstaller.h logic/BaseInstaller.cpp + logic/BaseVersionList.h + logic/BaseVersionList.cpp + + logic/InstanceList.h + logic/InstanceList.cpp + logic/LwjglVersionList.h + logic/LwjglVersionList.cpp # FTB logic/OneSixFTBInstance.h @@ -476,18 +502,6 @@ SET(MULTIMC_SOURCES logic/LegacyFTBInstance.h logic/LegacyFTBInstance.cpp - # Lists - logic/lists/InstanceList.h - logic/lists/InstanceList.cpp - logic/lists/BaseVersionList.h - logic/lists/BaseVersionList.cpp - logic/lists/MinecraftVersionList.h - logic/lists/MinecraftVersionList.cpp - logic/lists/LwjglVersionList.h - logic/lists/LwjglVersionList.cpp - logic/lists/JavaVersionList.h - logic/lists/JavaVersionList.cpp - # the screenshots feature logic/screenshots/Screenshot.h logic/screenshots/Screenshot.cpp @@ -504,11 +518,6 @@ SET(MULTIMC_SOURCES logic/icons/IconList.h logic/icons/IconList.cpp - - # misc model/view - logic/EnabledItemFilter.h - logic/EnabledItemFilter.cpp - # Tasks logic/tasks/ProgressProvider.h logic/tasks/Task.h @@ -518,17 +527,15 @@ SET(MULTIMC_SOURCES logic/tasks/SequentialTask.h logic/tasks/SequentialTask.cpp - # Utilities - logic/JavaChecker.h - logic/JavaChecker.cpp - logic/JavaUtils.h - logic/JavaUtils.cpp - logic/NagUtils.h - logic/NagUtils.cpp - logic/SkinUtils.h - logic/SkinUtils.cpp - logic/JavaCheckerJob.h - logic/JavaCheckerJob.cpp + # Java related code + logic/java/JavaChecker.h + logic/java/JavaChecker.cpp + logic/java/JavaUtils.h + logic/java/JavaUtils.cpp + logic/java/JavaVersionList.h + logic/java/JavaVersionList.cpp + logic/java/JavaCheckerJob.h + logic/java/JavaCheckerJob.cpp # Assets logic/assets/AssetsMigrateTask.h @@ -568,10 +575,6 @@ SET(MULTIMC_SOURCES logic/liteloader/LiteLoaderInstaller.cpp logic/liteloader/LiteLoaderVersionList.h logic/liteloader/LiteLoaderVersionList.cpp - - # MultiMC URN resolver - logic/URNResolver.cpp - logic/URNResolver.h ) diff --git a/MultiMC.cpp b/MultiMC.cpp index 6b5545c1..073646ec 100644 --- a/MultiMC.cpp +++ b/MultiMC.cpp @@ -12,11 +12,11 @@ #include #include "gui/dialogs/VersionSelectDialog.h" -#include "logic/lists/InstanceList.h" +#include "logic/InstanceList.h" #include "logic/auth/MojangAccountList.h" #include "logic/icons/IconList.h" -#include "logic/lists/LwjglVersionList.h" -#include "logic/lists/MinecraftVersionList.h" +#include "logic/LwjglVersionList.h" +#include "logic/minecraft/MinecraftVersionList.h" #include "logic/liteloader/LiteLoaderVersionList.h" #include "logic/forge/ForgeVersionList.h" @@ -29,7 +29,7 @@ #include "logic/net/HttpMetaCache.h" #include "logic/net/URLConstants.h" -#include "logic/JavaUtils.h" +#include "logic/java/JavaUtils.h" #include "logic/updater/UpdateChecker.h" #include "logic/updater/NotificationChecker.h" diff --git a/gui/MainWindow.cpp b/gui/MainWindow.cpp index 95f2ac4c..679938f3 100644 --- a/gui/MainWindow.cpp +++ b/gui/MainWindow.cpp @@ -69,11 +69,11 @@ #include "gui/ConsoleWindow.h" -#include "logic/lists/InstanceList.h" -#include "logic/lists/MinecraftVersionList.h" -#include "logic/lists/LwjglVersionList.h" +#include "logic/InstanceList.h" +#include "logic/minecraft/MinecraftVersionList.h" +#include "logic/LwjglVersionList.h" #include "logic/icons/IconList.h" -#include "logic/lists/JavaVersionList.h" +#include "logic/java/JavaVersionList.h" #include "logic/auth/flows/AuthenticateTask.h" #include "logic/auth/flows/RefreshTask.h" @@ -91,7 +91,7 @@ #include "logic/InstanceFactory.h" #include "logic/MinecraftProcess.h" #include "logic/OneSixUpdate.h" -#include "logic/JavaUtils.h" +#include "logic/java/JavaUtils.h" #include "logic/NagUtils.h" #include "logic/SkinUtils.h" diff --git a/gui/MainWindow.h b/gui/MainWindow.h index 0cd2e84b..cc8b7c99 100644 --- a/gui/MainWindow.h +++ b/gui/MainWindow.h @@ -19,11 +19,10 @@ #include #include -#include "logic/lists/InstanceList.h" +#include "logic/InstanceList.h" #include "logic/BaseInstance.h" - #include "logic/auth/MojangAccount.h" -#include +#include "logic/net/NetJob.h" class QToolButton; class LabeledToolButton; diff --git a/gui/dialogs/CopyInstanceDialog.cpp b/gui/dialogs/CopyInstanceDialog.cpp index 71429367..188cf274 100644 --- a/gui/dialogs/CopyInstanceDialog.cpp +++ b/gui/dialogs/CopyInstanceDialog.cpp @@ -28,7 +28,6 @@ #include "logic/InstanceFactory.h" #include "logic/BaseVersion.h" #include "logic/icons/IconList.h" -#include "logic/lists/MinecraftVersionList.h" #include "logic/tasks/Task.h" #include "logic/BaseInstance.h" diff --git a/gui/dialogs/InstanceEditDialog.cpp b/gui/dialogs/InstanceEditDialog.cpp index a74f3dcb..fc2d6a75 100644 --- a/gui/dialogs/InstanceEditDialog.cpp +++ b/gui/dialogs/InstanceEditDialog.cpp @@ -34,13 +34,13 @@ #include "InstanceSettings.h" #include "logic/ModList.h" -#include "logic/VersionFinal.h" +#include "logic/minecraft/VersionFinal.h" #include "logic/EnabledItemFilter.h" #include "logic/forge/ForgeVersionList.h" #include "logic/forge/ForgeInstaller.h" #include "logic/liteloader/LiteLoaderVersionList.h" #include "logic/liteloader/LiteLoaderInstaller.h" -#include "logic/OneSixVersionBuilder.h" +#include "logic/minecraft/OneSixVersionBuilder.h" #include "logic/auth/MojangAccountList.h" #include diff --git a/gui/dialogs/InstanceSettings.cpp b/gui/dialogs/InstanceSettings.cpp index edb4a921..9f0cae3b 100644 --- a/gui/dialogs/InstanceSettings.cpp +++ b/gui/dialogs/InstanceSettings.cpp @@ -23,10 +23,11 @@ #include "gui/Platform.h" #include "gui/dialogs/VersionSelectDialog.h" -#include "logic/JavaUtils.h" #include "logic/NagUtils.h" -#include "logic/lists/JavaVersionList.h" -#include "logic/JavaChecker.h" + +#include "logic/java/JavaUtils.h" +#include "logic/java/JavaVersionList.h" +#include "logic/java/JavaChecker.h" #include #include diff --git a/gui/dialogs/InstanceSettings.h b/gui/dialogs/InstanceSettings.h index e296db4c..6895589f 100644 --- a/gui/dialogs/InstanceSettings.h +++ b/gui/dialogs/InstanceSettings.h @@ -17,7 +17,7 @@ #include #include "settingsobject.h" -#include "logic/JavaChecker.h" +#include "logic/java/JavaChecker.h" namespace Ui { diff --git a/gui/dialogs/LwjglSelectDialog.cpp b/gui/dialogs/LwjglSelectDialog.cpp index 046a4e2e..e64228b2 100644 --- a/gui/dialogs/LwjglSelectDialog.cpp +++ b/gui/dialogs/LwjglSelectDialog.cpp @@ -18,7 +18,7 @@ #include "ui_LwjglSelectDialog.h" #include "gui/Platform.h" -#include "logic/lists/LwjglVersionList.h" +#include "logic/LwjglVersionList.h" LWJGLSelectDialog::LWJGLSelectDialog(QWidget *parent) : QDialog(parent), ui(new Ui::LWJGLSelectDialog) diff --git a/gui/dialogs/NewInstanceDialog.cpp b/gui/dialogs/NewInstanceDialog.cpp index c7b273af..3192a1cd 100644 --- a/gui/dialogs/NewInstanceDialog.cpp +++ b/gui/dialogs/NewInstanceDialog.cpp @@ -20,7 +20,7 @@ #include "logic/InstanceFactory.h" #include "logic/BaseVersion.h" #include "logic/icons/IconList.h" -#include "logic/lists/MinecraftVersionList.h" +#include "logic/minecraft/MinecraftVersionList.h" #include "logic/tasks/Task.h" #include "gui/Platform.h" diff --git a/gui/dialogs/SettingsDialog.cpp b/gui/dialogs/SettingsDialog.cpp index 2dd19077..4c69c785 100644 --- a/gui/dialogs/SettingsDialog.cpp +++ b/gui/dialogs/SettingsDialog.cpp @@ -22,10 +22,11 @@ #include "gui/dialogs/VersionSelectDialog.h" #include "gui/dialogs/CustomMessageBox.h" -#include "logic/JavaUtils.h" #include "logic/NagUtils.h" -#include "logic/lists/JavaVersionList.h" -#include + +#include "logic/java/JavaUtils.h" +#include "logic/java/JavaVersionList.h" +#include "logic/java/JavaChecker.h" #include "logic/updater/UpdateChecker.h" diff --git a/gui/dialogs/SettingsDialog.h b/gui/dialogs/SettingsDialog.h index d8495fdd..c65e9fb5 100644 --- a/gui/dialogs/SettingsDialog.h +++ b/gui/dialogs/SettingsDialog.h @@ -18,7 +18,7 @@ #include #include -#include "logic/JavaChecker.h" +#include "logic/java/JavaChecker.h" class SettingsObject; diff --git a/gui/dialogs/VersionSelectDialog.cpp b/gui/dialogs/VersionSelectDialog.cpp index cae5a732..fd8b569d 100644 --- a/gui/dialogs/VersionSelectDialog.cpp +++ b/gui/dialogs/VersionSelectDialog.cpp @@ -24,7 +24,7 @@ #include "gui/Platform.h" #include -#include +#include #include VersionSelectDialog::VersionSelectDialog(BaseVersionList *vlist, QString title, QWidget *parent, diff --git a/gui/groupview/InstanceDelegate.cpp b/gui/groupview/InstanceDelegate.cpp index cd26ddaa..64dc31d2 100644 --- a/gui/groupview/InstanceDelegate.cpp +++ b/gui/groupview/InstanceDelegate.cpp @@ -22,7 +22,7 @@ #include "GroupView.h" #include "logic/BaseInstance.h" -#include "logic/lists/InstanceList.h" +#include "logic/InstanceList.h" QCache ListViewDelegate::m_pixmapCache; diff --git a/logic/BaseInstaller.cpp b/logic/BaseInstaller.cpp index 669fd0ac..5660eb07 100644 --- a/logic/BaseInstaller.cpp +++ b/logic/BaseInstaller.cpp @@ -13,15 +13,10 @@ * limitations under the License. */ -#include "BaseInstaller.h" - #include -#include "VersionFinal.h" -#include "OneSixLibrary.h" -#include "OneSixInstance.h" - -#include "cmdutils.h" +#include "logic/BaseInstaller.h" +#include "logic/OneSixInstance.h" BaseInstaller::BaseInstaller() { diff --git a/logic/BaseInstance.cpp b/logic/BaseInstance.cpp index 5fa62593..59aada40 100644 --- a/logic/BaseInstance.cpp +++ b/logic/BaseInstance.cpp @@ -27,7 +27,7 @@ #include "pathutils.h" #include -#include "lists/MinecraftVersionList.h" +#include "logic/minecraft/MinecraftVersionList.h" #include "logic/icons/IconList.h" BaseInstance::BaseInstance(BaseInstancePrivate *d_in, const QString &rootDir, diff --git a/logic/BaseInstance.h b/logic/BaseInstance.h index 41ceda39..d272dc71 100644 --- a/logic/BaseInstance.h +++ b/logic/BaseInstance.h @@ -22,7 +22,7 @@ #include #include "inifile.h" -#include "lists/BaseVersionList.h" +#include "logic/BaseVersionList.h" #include "logic/auth/MojangAccount.h" class QDialog; diff --git a/logic/BaseVersionList.cpp b/logic/BaseVersionList.cpp new file mode 100644 index 00000000..b34750b5 --- /dev/null +++ b/logic/BaseVersionList.cpp @@ -0,0 +1,121 @@ +/* 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 "logic/BaseVersionList.h" +#include "logic/BaseVersion.h" + +BaseVersionList::BaseVersionList(QObject *parent) : QAbstractListModel(parent) +{ +} + +BaseVersionPtr BaseVersionList::findVersion(const QString &descriptor) +{ + for (int i = 0; i < count(); i++) + { + if (at(i)->descriptor() == descriptor) + return at(i); + } + return BaseVersionPtr(); +} + +BaseVersionPtr BaseVersionList::getLatestStable() const +{ + if (count() <= 0) + return BaseVersionPtr(); + else + return at(0); +} + +QVariant BaseVersionList::data(const QModelIndex &index, int role) const +{ + if (!index.isValid()) + return QVariant(); + + if (index.row() > count()) + return QVariant(); + + BaseVersionPtr version = at(index.row()); + + switch (role) + { + case Qt::DisplayRole: + switch (index.column()) + { + case NameColumn: + return version->name(); + + case TypeColumn: + return version->typeString(); + + default: + return QVariant(); + } + + case Qt::ToolTipRole: + return version->descriptor(); + + case VersionPointerRole: + return qVariantFromValue(version); + + default: + return QVariant(); + } +} + +QVariant BaseVersionList::headerData(int section, Qt::Orientation orientation, int role) const +{ + switch (role) + { + case Qt::DisplayRole: + switch (section) + { + case NameColumn: + return "Name"; + + case TypeColumn: + return "Type"; + + default: + return QVariant(); + } + + case Qt::ToolTipRole: + switch (section) + { + case NameColumn: + return "The name of the version."; + + case TypeColumn: + return "The version's type."; + + default: + return QVariant(); + } + + default: + return QVariant(); + } +} + +int BaseVersionList::rowCount(const QModelIndex &parent) const +{ + // Return count + return count(); +} + +int BaseVersionList::columnCount(const QModelIndex &parent) const +{ + return 2; +} diff --git a/logic/BaseVersionList.h b/logic/BaseVersionList.h new file mode 100644 index 00000000..21b44e8d --- /dev/null +++ b/logic/BaseVersionList.h @@ -0,0 +1,120 @@ +/* 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. + */ + +#pragma once + +#include +#include +#include + +#include "logic/BaseVersion.h" + +class Task; + +/*! + * \brief Class that each instance type's version list derives from. + * Version lists are the lists that keep track of the available game versions + * for that instance. This list will not be loaded on startup. It will be loaded + * when the list's load function is called. Before using the version list, you + * should check to see if it has been loaded yet and if not, load the list. + * + * Note that this class also inherits from QAbstractListModel. Methods from that + * class determine how this version list shows up in a list view. Said methods + * all have a default implementation, but they can be overridden by plugins to + * change the behavior of the list. + */ +class BaseVersionList : public QAbstractListModel +{ + Q_OBJECT +public: + enum ModelRoles + { + VersionPointerRole = 0x34B1CB48 + }; + + enum VListColumns + { + // First column - Name + NameColumn = 0, + + // Second column - Type + TypeColumn, + + // Third column - Timestamp + TimeColumn + }; + + explicit BaseVersionList(QObject *parent = 0); + + /*! + * \brief Gets a task that will reload the version list. + * Simply execute the task to load the list. + * The task returned by this function should reset the model when it's done. + * \return A pointer to a task that reloads the version list. + */ + virtual Task *getLoadTask() = 0; + + //! Checks whether or not the list is loaded. If this returns false, the list should be + //loaded. + virtual bool isLoaded() = 0; + + //! Gets the version at the given index. + virtual const BaseVersionPtr at(int i) const = 0; + + //! Returns the number of versions in the list. + virtual int count() const = 0; + + //////// List Model Functions //////// + virtual QVariant data(const QModelIndex &index, int role) const; + virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const; + virtual int rowCount(const QModelIndex &parent) const; + virtual int columnCount(const QModelIndex &parent) const; + + /*! + * \brief Finds a version by its descriptor. + * \param The descriptor of the version to find. + * \return A const pointer to the version with the given descriptor. NULL if + * one doesn't exist. + */ + virtual BaseVersionPtr findVersion(const QString &descriptor); + + /*! + * \brief Gets the latest stable version of this instance type. + * This is the version that will be selected by default. + * By default, this is simply the first version in the list. + */ + virtual BaseVersionPtr getLatestStable() const; + + /*! + * Sorts the version list. + */ + virtual void sort() = 0; + +protected +slots: + /*! + * Updates this list with the given list of versions. + * This is done by copying each version in the given list and inserting it + * into this one. + * We need to do this so that we can set the parents of the versions are set to this + * version list. This can't be done in the load task, because the versions the load + * task creates are on the load task's thread and Qt won't allow their parents + * to be set to something created on another thread. + * To get around that problem, we invoke this method on the GUI thread, which + * then copies the versions and sets their parents correctly. + * \param versions List of versions whose parents should be set. + */ + virtual void updateListData(QList versions) = 0; +}; diff --git a/logic/InstanceFactory.cpp b/logic/InstanceFactory.cpp index 955a3f5b..c0a392e0 100644 --- a/logic/InstanceFactory.cpp +++ b/logic/InstanceFactory.cpp @@ -13,27 +13,26 @@ * limitations under the License. */ -#include "InstanceFactory.h" - #include #include - -#include "BaseInstance.h" -#include "LegacyInstance.h" -#include "LegacyFTBInstance.h" -#include "OneSixInstance.h" -#include "OneSixFTBInstance.h" -#include "OneSixInstance.h" -#include "BaseVersion.h" -#include "MinecraftVersion.h" - -#include "inifile.h" +#include #include #include -#include "pathutils.h" +#include #include "logger/QsLog.h" +#include "logic/InstanceFactory.h" + +#include "logic/BaseInstance.h" +#include "logic/LegacyInstance.h" +#include "logic/LegacyFTBInstance.h" +#include "logic/OneSixInstance.h" +#include "logic/OneSixFTBInstance.h" +#include "logic/OneSixInstance.h" +#include "logic/BaseVersion.h" +#include "logic/minecraft/MinecraftVersion.h" + InstanceFactory InstanceFactory::loader; InstanceFactory::InstanceFactory() : QObject(NULL) diff --git a/logic/InstanceLauncher.cpp b/logic/InstanceLauncher.cpp index c0079d80..9170c87f 100644 --- a/logic/InstanceLauncher.cpp +++ b/logic/InstanceLauncher.cpp @@ -22,7 +22,7 @@ #include "gui/dialogs/ProgressDialog.h" #include "logic/MinecraftProcess.h" -#include "logic/lists/InstanceList.h" +#include "logic/InstanceList.h" InstanceLauncher::InstanceLauncher(QString instId) : QObject(), instId(instId) { diff --git a/logic/InstanceList.cpp b/logic/InstanceList.cpp new file mode 100644 index 00000000..7b9c8b2b --- /dev/null +++ b/logic/InstanceList.cpp @@ -0,0 +1,618 @@ +/* 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "MultiMC.h" +#include "logic/InstanceList.h" +#include "logic/icons/IconList.h" +#include "logic/minecraft/MinecraftVersionList.h" +#include "logic/BaseInstance.h" +#include "logic/InstanceFactory.h" +#include "logger/QsLog.h" +#include "gui/groupview/GroupView.h" + +const static int GROUP_FILE_FORMAT_VERSION = 1; + +InstanceList::InstanceList(const QString &instDir, QObject *parent) + : QAbstractListModel(parent), m_instDir(instDir) +{ + connect(MMC, &MultiMC::aboutToQuit, this, &InstanceList::saveGroupList); + + if (!QDir::current().exists(m_instDir)) + { + QDir::current().mkpath(m_instDir); + } + + /* + * FIXME HACK: instances sometimes need to be created at launch. They need the versions for + * that. + * + * Remove this. it has no business of reloading the whole list. The instances which + * need it should track such events themselves and CHANGE THEIR DATA ONLY! + */ + connect(MMC->minecraftlist().get(), &MinecraftVersionList::modelReset, this, + &InstanceList::loadList); +} + +InstanceList::~InstanceList() +{ +} + +int InstanceList::rowCount(const QModelIndex &parent) const +{ + Q_UNUSED(parent); + return m_instances.count(); +} + +QModelIndex InstanceList::index(int row, int column, const QModelIndex &parent) const +{ + Q_UNUSED(parent); + if (row < 0 || row >= m_instances.size()) + return QModelIndex(); + return createIndex(row, column, (void *)m_instances.at(row).get()); +} + +QVariant InstanceList::data(const QModelIndex &index, int role) const +{ + if (!index.isValid()) + { + return QVariant(); + } + BaseInstance *pdata = static_cast(index.internalPointer()); + switch (role) + { + case InstancePointerRole: + { + QVariant v = qVariantFromValue((void *)pdata); + return v; + } + case InstanceIDRole: + { + return pdata->id(); + } + case Qt::DisplayRole: + { + return pdata->name(); + } + case Qt::ToolTipRole: + { + return pdata->instanceRoot(); + } + case Qt::DecorationRole: + { + QString key = pdata->iconKey(); + return MMC->icons()->getIcon(key); + } + // for now. + case GroupViewRoles::GroupRole: + { + return pdata->group(); + } + default: + break; + } + return QVariant(); +} + +Qt::ItemFlags InstanceList::flags(const QModelIndex &index) const +{ + Qt::ItemFlags f; + if (index.isValid()) + { + f |= (Qt::ItemIsEnabled | Qt::ItemIsSelectable); + } + return f; +} + +void InstanceList::groupChanged() +{ + // save the groups. save all of them. + saveGroupList(); +} + +QStringList InstanceList::getGroups() +{ + return m_groups.toList(); +} + +void InstanceList::saveGroupList() +{ + QString groupFileName = m_instDir + "/instgroups.json"; + QFile groupFile(groupFileName); + + // if you can't open the file, fail + if (!groupFile.open(QIODevice::WriteOnly | QIODevice::Truncate)) + { + // An error occurred. Ignore it. + QLOG_ERROR() << "Failed to save instance group file."; + return; + } + QTextStream out(&groupFile); + QMap> groupMap; + for (auto instance : m_instances) + { + QString id = instance->id(); + QString group = instance->group(); + if (group.isEmpty()) + continue; + + // keep a list/set of groups for choosing + m_groups.insert(group); + + if (!groupMap.count(group)) + { + QSet set; + set.insert(id); + groupMap[group] = set; + } + else + { + QSet &set = groupMap[group]; + set.insert(id); + } + } + QJsonObject toplevel; + toplevel.insert("formatVersion", QJsonValue(QString("1"))); + QJsonObject groupsArr; + for (auto iter = groupMap.begin(); iter != groupMap.end(); iter++) + { + auto list = iter.value(); + auto name = iter.key(); + QJsonObject groupObj; + QJsonArray instanceArr; + groupObj.insert("hidden", QJsonValue(QString("false"))); + for (auto item : list) + { + instanceArr.append(QJsonValue(item)); + } + groupObj.insert("instances", instanceArr); + groupsArr.insert(name, groupObj); + } + toplevel.insert("groups", groupsArr); + QJsonDocument doc(toplevel); + groupFile.write(doc.toJson()); + groupFile.close(); +} + +void InstanceList::loadGroupList(QMap &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. + QLOG_ERROR() << "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) + { + QLOG_ERROR() << 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()) + { + QLOG_WARN() << "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()) + { + QLOG_WARN() << "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()) + { + QLOG_WARN() << 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()) + { + QLOG_WARN() << QString("Group '%1' in the group list is invalid. " + "It should contain an array " + "called 'instances'.") + .arg(groupName) + .toUtf8(); + continue; + } + + // keep a list/set of groups for choosing + m_groups.insert(groupName); + + // 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; + } + } +} + +QList InstanceList::discoverFTBInstances() +{ + QList records; + QDir dir = QDir(MMC->settings()->get("FTBLauncherDataRoot").toString()); + QDir dataDir = QDir(MMC->settings()->get("FTBRoot").toString()); + if (!dataDir.exists()) + { + QLOG_INFO() << "The FTB directory specified does not exist. Please check your settings"; + return records; + } + else if (!dir.exists()) + { + QLOG_INFO() << "The FTB launcher data directory specified does not exist. Please check your settings"; + return records; + } + dir.cd("ModPacks"); + auto allFiles = dir.entryList(QDir::Readable | QDir::Files, QDir::Name); + for (auto filename : allFiles) + { + if (!filename.endsWith(".xml")) + continue; + auto fpath = dir.absoluteFilePath(filename); + QFile f(fpath); + QLOG_INFO() << "Discovering FTB instances -- " << fpath; + if (!f.open(QFile::ReadOnly)) + continue; + + // read the FTB packs XML. + QXmlStreamReader reader(&f); + while (!reader.atEnd()) + { + switch (reader.readNext()) + { + case QXmlStreamReader::StartElement: + { + if (reader.name() == "modpack") + { + QXmlStreamAttributes attrs = reader.attributes(); + FTBRecord record; + record.dirName = attrs.value("dir").toString(); + record.instanceDir = dataDir.absoluteFilePath(record.dirName); + record.templateDir = dir.absoluteFilePath(record.dirName); + QDir test(record.instanceDir); + QLOG_DEBUG() << dataDir.absolutePath() << record.instanceDir << record.dirName; + if (!test.exists()) + continue; + record.name = attrs.value("name").toString(); + record.logo = attrs.value("logo").toString(); + record.mcVersion = attrs.value("mcVersion").toString(); + record.description = attrs.value("description").toString(); + records.append(record); + } + break; + } + case QXmlStreamReader::EndElement: + break; + case QXmlStreamReader::Characters: + break; + default: + break; + } + } + f.close(); + } + return records; +} + +void InstanceList::loadFTBInstances(QMap &groupMap, + QList &tempList) +{ + auto records = discoverFTBInstances(); + if (!records.size()) + { + QLOG_INFO() << "No FTB instances to load."; + return; + } + QLOG_INFO() << "Loading FTB instances! -- got " << records.size(); + // process the records we acquired. + for (auto record : records) + { + QLOG_INFO() << "Loading FTB instance from " << record.instanceDir; + QString iconKey = record.logo; + iconKey.remove(QRegularExpression("\\..*")); + MMC->icons()->addIcon(iconKey, iconKey, PathCombine(record.templateDir, record.logo), + MMCIcon::Transient); + + if (!QFileInfo(PathCombine(record.instanceDir, "instance.cfg")).exists()) + { + QLOG_INFO() << "Converting " << record.name << " as new."; + InstancePtr instPtr; + auto &factory = InstanceFactory::get(); + auto version = MMC->minecraftlist()->findVersion(record.mcVersion); + if (!version) + { + QLOG_ERROR() << "Can't load instance " << record.instanceDir + << " because minecraft version " << record.mcVersion + << " can't be resolved."; + continue; + } + auto error = factory.createInstance(instPtr, version, record.instanceDir, + InstanceFactory::FTBInstance); + + if (!instPtr || error != InstanceFactory::NoCreateError) + continue; + + instPtr->setGroupInitial("FTB"); + instPtr->setName(record.name); + instPtr->setIconKey(iconKey); + instPtr->setIntendedVersionId(record.mcVersion); + instPtr->setNotes(record.description); + if(!continueProcessInstance(instPtr, error, record.instanceDir, groupMap)) + continue; + tempList.append(InstancePtr(instPtr)); + } + else + { + QLOG_INFO() << "Loading existing " << record.name; + InstancePtr instPtr; + auto error = InstanceFactory::get().loadInstance(instPtr, record.instanceDir); + if (!instPtr || error != InstanceFactory::NoLoadError) + continue; + instPtr->setGroupInitial("FTB"); + instPtr->setName(record.name); + instPtr->setIconKey(iconKey); + if (instPtr->intendedVersionId() != record.mcVersion) + instPtr->setIntendedVersionId(record.mcVersion); + instPtr->setNotes(record.description); + if(!continueProcessInstance(instPtr, error, record.instanceDir, groupMap)) + continue; + tempList.append(InstancePtr(instPtr)); + } + } +} + +InstanceList::InstListError InstanceList::loadList() +{ + // load the instance groups + QMap groupMap; + loadGroupList(groupMap); + + QList tempList; + { + 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; + QLOG_INFO() << "Loading MultiMC instance from " << subDir; + InstancePtr instPtr; + auto error = InstanceFactory::get().loadInstance(instPtr, subDir); + if(!continueProcessInstance(instPtr, error, subDir, groupMap)) + continue; + tempList.append(instPtr); + } + } + + if (MMC->settings()->get("TrackFTBInstances").toBool()) + { + loadFTBInstances(groupMap, tempList); + } + beginResetModel(); + m_instances.clear(); + for(auto inst: tempList) + { + inst->setParent(this); + connect(inst.get(), SIGNAL(propertiesChanged(BaseInstance *)), this, + SLOT(propertiesChanged(BaseInstance *))); + connect(inst.get(), SIGNAL(groupChanged()), this, SLOT(groupChanged())); + connect(inst.get(), SIGNAL(nuked(BaseInstance *)), this, + SLOT(instanceNuked(BaseInstance *))); + m_instances.append(inst); + } + endResetModel(); + emit dataIsInvalid(); + return NoError; +} + +/// Clear all instances. Triggers notifications. +void InstanceList::clear() +{ + beginResetModel(); + saveGroupList(); + m_instances.clear(); + endResetModel(); + emit dataIsInvalid(); +} + +void InstanceList::on_InstFolderChanged(const Setting &setting, QVariant value) +{ + m_instDir = value.toString(); + loadList(); +} + +/// Add an instance. Triggers notifications, returns the new index +int InstanceList::add(InstancePtr t) +{ + beginInsertRows(QModelIndex(), m_instances.size(), m_instances.size()); + m_instances.append(t); + t->setParent(this); + connect(t.get(), SIGNAL(propertiesChanged(BaseInstance *)), this, + SLOT(propertiesChanged(BaseInstance *))); + connect(t.get(), SIGNAL(groupChanged()), this, SLOT(groupChanged())); + connect(t.get(), SIGNAL(nuked(BaseInstance *)), this, SLOT(instanceNuked(BaseInstance *))); + endInsertRows(); + return count() - 1; +} + +InstancePtr InstanceList::getInstanceById(QString instId) const +{ + if (m_instances.isEmpty()) + { + return InstancePtr(); + } + + QListIterator 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(); +} + +QModelIndex InstanceList::getInstanceIndexById(const QString &id) const +{ + return index(getInstIndex(getInstanceById(id).get())); +} + +int InstanceList::getInstIndex(BaseInstance *inst) const +{ + for (int i = 0; i < m_instances.count(); i++) + { + if (inst == m_instances[i].get()) + { + return i; + } + } + return -1; +} + +bool InstanceList::continueProcessInstance(InstancePtr instPtr, const int error, + const QDir &dir, QMap &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(); + return false; + } + else if (!instPtr) + { + QLOG_ERROR() << QString("Error loading instance %1. Instance loader returned null.") + .arg(QFileInfo(dir.absolutePath()).baseName()) + .toUtf8(); + return false; + } + else + { + auto iter = groupMap.find(instPtr->id()); + if (iter != groupMap.end()) + { + instPtr->setGroupInitial((*iter)); + } + QLOG_INFO() << "Loaded instance " << instPtr->name() << " from " << dir.absolutePath(); + return true; + } +} + +void InstanceList::instanceNuked(BaseInstance *inst) +{ + int i = getInstIndex(inst); + if (i != -1) + { + beginRemoveRows(QModelIndex(), i, i); + m_instances.removeAt(i); + endRemoveRows(); + } +} + +void InstanceList::propertiesChanged(BaseInstance *inst) +{ + int i = getInstIndex(inst); + if (i != -1) + { + emit dataChanged(index(i), index(i)); + } +} + +InstanceProxyModel::InstanceProxyModel(QObject *parent) : GroupedProxyModel(parent) +{ +} + +bool InstanceProxyModel::subSortLessThan(const QModelIndex &left, + const QModelIndex &right) const +{ + BaseInstance *pdataLeft = static_cast(left.internalPointer()); + BaseInstance *pdataRight = static_cast(right.internalPointer()); + QString sortMode = MMC->settings()->get("InstSortMode").toString(); + if (sortMode == "LastLaunch") + { + return pdataLeft->lastLaunch() > pdataRight->lastLaunch(); + } + else + { + return QString::localeAwareCompare(pdataLeft->name(), pdataRight->name()) < 0; + } +} diff --git a/logic/InstanceList.h b/logic/InstanceList.h new file mode 100644 index 00000000..f0bbb7ec --- /dev/null +++ b/logic/InstanceList.h @@ -0,0 +1,152 @@ +/* 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. + */ + +#pragma once + +#include +#include +#include +#include +#include + +#include "logic/BaseInstance.h" + +class BaseInstance; + +class QDir; + +struct FTBRecord +{ + QString dirName; + QString name; + QString logo; + QString mcVersion; + QString description; + QString instanceDir; + QString templateDir; +}; + +class InstanceList : public QAbstractListModel +{ + Q_OBJECT +private: + void loadGroupList(QMap &groupList); + QList discoverFTBInstances(); + void loadFTBInstances(QMap &groupMap, QList & tempList); + +private +slots: + void saveGroupList(); + +public: + explicit InstanceList(const QString &instDir, QObject *parent = 0); + virtual ~InstanceList(); + +public: + QModelIndex index(int row, int column = 0, const QModelIndex &parent = QModelIndex()) const; + int rowCount(const QModelIndex &parent = QModelIndex()) const; + QVariant data(const QModelIndex &index, int role) const; + Qt::ItemFlags flags(const QModelIndex &index) const; + + enum AdditionalRoles + { + InstancePointerRole = 0x34B1CB48, ///< Return pointer to real instance + InstanceIDRole = 0x34B1CB49 ///< Return id if the instance + }; + /*! + * \brief Error codes returned by functions in the InstanceList class. + * NoError Indicates that no error occurred. + * UnknownError indicates that an unspecified error occurred. + */ + enum InstListError + { + NoError = 0, + UnknownError + }; + + QString instDir() const + { + return m_instDir; + } + + /*! + * \brief Get the instance at index + */ + InstancePtr at(int i) const + { + return m_instances.at(i); + } + ; + + /*! + * \brief Get the count of loaded instances + */ + int count() const + { + return m_instances.count(); + } + ; + + /// Clear all instances. Triggers notifications. + void clear(); + + /// Add an instance. Triggers notifications, returns the new index + int add(InstancePtr t); + + /// Get an instance by ID + InstancePtr getInstanceById(QString id) const; + + QModelIndex getInstanceIndexById(const QString &id) const; + + // FIXME: instead of iterating through all instances and forming a set, keep the set around + QStringList getGroups(); +signals: + void dataIsInvalid(); + +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); + void instanceNuked(BaseInstance *inst); + void groupChanged(); + +private: + int getInstIndex(BaseInstance *inst) const; + + bool continueProcessInstance(InstancePtr instPtr, const int error, const QDir &dir, + QMap &groupMap); + +protected: + QString m_instDir; + QList m_instances; + QSet m_groups; +}; + +class InstanceProxyModel : public GroupedProxyModel +{ +public: + explicit InstanceProxyModel(QObject *parent = 0); + +protected: + virtual bool subSortLessThan(const QModelIndex &left, const QModelIndex &right) const; +}; diff --git a/logic/JavaChecker.cpp b/logic/JavaChecker.cpp deleted file mode 100644 index b87ee3d5..00000000 --- a/logic/JavaChecker.cpp +++ /dev/null @@ -1,124 +0,0 @@ -#include "JavaChecker.h" -#include "MultiMC.h" -#include -#include -#include -#include -#include - -JavaChecker::JavaChecker(QObject *parent) : QObject(parent) -{ -} - -void JavaChecker::performCheck() -{ - QString checkerJar = PathCombine(MMC->bin(), "jars", "JavaCheck.jar"); - - QStringList args = {"-jar", checkerJar}; - - process.reset(new QProcess()); - process->setArguments(args); - process->setProgram(path); - process->setProcessChannelMode(QProcess::SeparateChannels); - QLOG_DEBUG() << "Running java checker!"; - QLOG_DEBUG() << "Java: " + path; - QLOG_DEBUG() << "Args: {" + args.join("|") + "}"; - - connect(process.get(), SIGNAL(finished(int, QProcess::ExitStatus)), this, - SLOT(finished(int, QProcess::ExitStatus))); - connect(process.get(), SIGNAL(error(QProcess::ProcessError)), this, - SLOT(error(QProcess::ProcessError))); - connect(&killTimer, SIGNAL(timeout()), SLOT(timeout())); - killTimer.setSingleShot(true); - killTimer.start(5000); - process->start(); -} - -void JavaChecker::finished(int exitcode, QProcess::ExitStatus status) -{ - killTimer.stop(); - QProcessPtr _process; - _process.swap(process); - - JavaCheckResult result; - { - result.path = path; - result.id = id; - } - QLOG_DEBUG() << "Java checker finished with status " << status << " exit code " << exitcode; - - if (status == QProcess::CrashExit || exitcode == 1) - { - QLOG_DEBUG() << "Java checker failed!"; - emit checkFinished(result); - return; - } - - bool success = true; - QString p_stdout = _process->readAllStandardOutput(); - QLOG_DEBUG() << p_stdout; - - QMap results; - QStringList lines = p_stdout.split("\n", QString::SkipEmptyParts); - for(QString line : lines) - { - line = line.trimmed(); - - auto parts = line.split('=', QString::SkipEmptyParts); - if(parts.size() != 2 || parts[0].isEmpty() || parts[1].isEmpty()) - { - success = false; - } - else - { - results.insert(parts[0], parts[1]); - } - } - - if(!results.contains("os.arch") || !results.contains("java.version") || !success) - { - QLOG_DEBUG() << "Java checker failed - couldn't extract required information."; - emit checkFinished(result); - return; - } - - auto os_arch = results["os.arch"]; - auto java_version = results["java.version"]; - bool is_64 = os_arch == "x86_64" || os_arch == "amd64"; - - - result.valid = true; - result.is_64bit = is_64; - result.mojangPlatform = is_64 ? "64" : "32"; - result.realPlatform = os_arch; - result.javaVersion = java_version; - QLOG_DEBUG() << "Java checker succeeded."; - emit checkFinished(result); -} - -void JavaChecker::error(QProcess::ProcessError err) -{ - if(err == QProcess::FailedToStart) - { - killTimer.stop(); - QLOG_DEBUG() << "Java checker has failed to start."; - JavaCheckResult result; - { - result.path = path; - result.id = id; - } - - emit checkFinished(result); - return; - } -} - -void JavaChecker::timeout() -{ - // NO MERCY. NO ABUSE. - if(process) - { - QLOG_DEBUG() << "Java checker has been killed by timeout."; - process->kill(); - } -} diff --git a/logic/JavaChecker.h b/logic/JavaChecker.h deleted file mode 100644 index e19895f7..00000000 --- a/logic/JavaChecker.h +++ /dev/null @@ -1,42 +0,0 @@ -#pragma once -#include -#include -#include - -class JavaChecker; - - -struct JavaCheckResult -{ - QString path; - QString mojangPlatform; - QString realPlatform; - QString javaVersion; - bool valid = false; - bool is_64bit = false; - int id; -}; - -typedef std::shared_ptr QProcessPtr; -typedef std::shared_ptr JavaCheckerPtr; -class JavaChecker : public QObject -{ - Q_OBJECT -public: - explicit JavaChecker(QObject *parent = 0); - void performCheck(); - - QString path; - int id; - -signals: - void checkFinished(JavaCheckResult result); -private: - QProcessPtr process; - QTimer killTimer; -public -slots: - void timeout(); - void finished(int exitcode, QProcess::ExitStatus); - void error(QProcess::ProcessError); -}; diff --git a/logic/JavaCheckerJob.cpp b/logic/JavaCheckerJob.cpp deleted file mode 100644 index b0aea758..00000000 --- a/logic/JavaCheckerJob.cpp +++ /dev/null @@ -1,47 +0,0 @@ -/* 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 "JavaCheckerJob.h" -#include "pathutils.h" -#include "MultiMC.h" - -#include "logger/QsLog.h" - -void JavaCheckerJob::partFinished(JavaCheckResult result) -{ - num_finished++; - QLOG_INFO() << m_job_name.toLocal8Bit() << "progress:" << num_finished << "/" - << javacheckers.size(); - emit progress(num_finished, javacheckers.size()); - - javaresults.replace(result.id, result); - - if (num_finished == javacheckers.size()) - { - emit finished(javaresults); - } -} - -void JavaCheckerJob::start() -{ - QLOG_INFO() << m_job_name.toLocal8Bit() << " started."; - m_running = true; - for (auto iter : javacheckers) - { - javaresults.append(JavaCheckResult()); - connect(iter.get(), SIGNAL(checkFinished(JavaCheckResult)), SLOT(partFinished(JavaCheckResult))); - iter->performCheck(); - } -} diff --git a/logic/JavaCheckerJob.h b/logic/JavaCheckerJob.h deleted file mode 100644 index 132a92d4..00000000 --- a/logic/JavaCheckerJob.h +++ /dev/null @@ -1,100 +0,0 @@ -/* 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. - */ - -#pragma once - -#include -#include -#include "JavaChecker.h" -#include "logic/tasks/ProgressProvider.h" - -class JavaCheckerJob; -typedef std::shared_ptr JavaCheckerJobPtr; - -class JavaCheckerJob : public ProgressProvider -{ - Q_OBJECT -public: - explicit JavaCheckerJob(QString job_name) : ProgressProvider(), m_job_name(job_name) {}; - - bool addJavaCheckerAction(JavaCheckerPtr base) - { - javacheckers.append(base); - total_progress++; - // if this is already running, the action needs to be started right away! - if (isRunning()) - { - emit progress(current_progress, total_progress); - connect(base.get(), SIGNAL(checkFinished(JavaCheckResult)), SLOT(partFinished(JavaCheckResult))); - - base->performCheck(); - } - return true; - } - - JavaCheckerPtr operator[](int index) - { - return javacheckers[index]; - } - ; - JavaCheckerPtr first() - { - if (javacheckers.size()) - return javacheckers[0]; - return JavaCheckerPtr(); - } - int size() const - { - return javacheckers.size(); - } - virtual void getProgress(qint64 ¤t, qint64 &total) - { - current = current_progress; - total = total_progress; - } - ; - virtual QString getStatus() const - { - return m_job_name; - } - ; - virtual bool isRunning() const - { - return m_running; - } - ; - -signals: - void started(); - void progress(int current, int total); - void finished(QList); -public -slots: - virtual void start(); - // FIXME: implement - virtual void abort() {}; -private -slots: - void partFinished(JavaCheckResult result); - -private: - QString m_job_name; - QList javacheckers; - QList javaresults; - qint64 current_progress = 0; - qint64 total_progress = 0; - int num_finished = 0; - bool m_running = false; -}; diff --git a/logic/JavaUtils.cpp b/logic/JavaUtils.cpp deleted file mode 100644 index 3a3046bd..00000000 --- a/logic/JavaUtils.cpp +++ /dev/null @@ -1,223 +0,0 @@ -/* 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 -#include -#include -#include -#include - -#include -#include - -#include "MultiMC.h" - -#include "JavaUtils.h" -#include "logger/QsLog.h" -#include "gui/dialogs/VersionSelectDialog.h" -#include "JavaCheckerJob.h" -#include "lists/JavaVersionList.h" - -JavaUtils::JavaUtils() -{ -} - -JavaVersionPtr JavaUtils::MakeJavaPtr(QString path, QString id, QString arch) -{ - JavaVersionPtr javaVersion(new JavaVersion()); - - javaVersion->id = id; - javaVersion->arch = arch; - javaVersion->path = path; - - return javaVersion; -} - -JavaVersionPtr JavaUtils::GetDefaultJava() -{ - JavaVersionPtr javaVersion(new JavaVersion()); - - javaVersion->id = "java"; - javaVersion->arch = "unknown"; - javaVersion->path = "java"; - - return javaVersion; -} - -#if WINDOWS -QList JavaUtils::FindJavaFromRegistryKey(DWORD keyType, QString keyName) -{ - QList javas; - - QString archType = "unknown"; - if (keyType == KEY_WOW64_64KEY) - archType = "64"; - else if (keyType == KEY_WOW64_32KEY) - archType = "32"; - - HKEY jreKey; - if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, keyName.toStdString().c_str(), 0, - KEY_READ | keyType | KEY_ENUMERATE_SUB_KEYS, &jreKey) == ERROR_SUCCESS) - { - // Read the current type version from the registry. - // This will be used to find any key that contains the JavaHome value. - char *value = new char[0]; - DWORD valueSz = 0; - if (RegQueryValueExA(jreKey, "CurrentVersion", NULL, NULL, (BYTE *)value, &valueSz) == - ERROR_MORE_DATA) - { - value = new char[valueSz]; - RegQueryValueExA(jreKey, "CurrentVersion", NULL, NULL, (BYTE *)value, &valueSz); - } - - QString recommended = value; - - TCHAR subKeyName[255]; - DWORD subKeyNameSize, numSubKeys, retCode; - - // Get the number of subkeys - RegQueryInfoKey(jreKey, NULL, NULL, NULL, &numSubKeys, NULL, NULL, NULL, NULL, NULL, - NULL, NULL); - - // Iterate until RegEnumKeyEx fails - if (numSubKeys > 0) - { - for (int i = 0; i < numSubKeys; i++) - { - subKeyNameSize = 255; - retCode = RegEnumKeyEx(jreKey, i, subKeyName, &subKeyNameSize, NULL, NULL, NULL, - NULL); - if (retCode == ERROR_SUCCESS) - { - // Now open the registry key for the version that we just got. - QString newKeyName = keyName + "\\" + subKeyName; - - HKEY newKey; - if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, newKeyName.toStdString().c_str(), 0, - KEY_READ | KEY_WOW64_64KEY, &newKey) == ERROR_SUCCESS) - { - // Read the JavaHome value to find where Java is installed. - value = new char[0]; - valueSz = 0; - if (RegQueryValueEx(newKey, "JavaHome", NULL, NULL, (BYTE *)value, - &valueSz) == ERROR_MORE_DATA) - { - value = new char[valueSz]; - RegQueryValueEx(newKey, "JavaHome", NULL, NULL, (BYTE *)value, - &valueSz); - - // Now, we construct the version object and add it to the list. - JavaVersionPtr javaVersion(new JavaVersion()); - - javaVersion->id = subKeyName; - javaVersion->arch = archType; - javaVersion->path = - QDir(PathCombine(value, "bin")).absoluteFilePath("java.exe"); - javas.append(javaVersion); - } - - RegCloseKey(newKey); - } - } - } - } - - RegCloseKey(jreKey); - } - - return javas; -} - -QList JavaUtils::FindJavaPaths() -{ - QList java_candidates; - - QList JRE64s = this->FindJavaFromRegistryKey( - KEY_WOW64_64KEY, "SOFTWARE\\JavaSoft\\Java Runtime Environment"); - QList JDK64s = this->FindJavaFromRegistryKey( - KEY_WOW64_64KEY, "SOFTWARE\\JavaSoft\\Java Development Kit"); - QList JRE32s = this->FindJavaFromRegistryKey( - KEY_WOW64_32KEY, "SOFTWARE\\JavaSoft\\Java Runtime Environment"); - QList JDK32s = this->FindJavaFromRegistryKey( - KEY_WOW64_32KEY, "SOFTWARE\\JavaSoft\\Java Development Kit"); - - java_candidates.append(JRE64s); - java_candidates.append(MakeJavaPtr("C:/Program Files/Java/jre7/bin/java.exe")); - java_candidates.append(MakeJavaPtr("C:/Program Files/Java/jre6/bin/java.exe")); - java_candidates.append(JDK64s); - java_candidates.append(JRE32s); - java_candidates.append(MakeJavaPtr("C:/Program Files (x86)/Java/jre7/bin/java.exe")); - java_candidates.append(MakeJavaPtr("C:/Program Files (x86)/Java/jre6/bin/java.exe")); - java_candidates.append(JDK32s); - java_candidates.append(MakeJavaPtr(this->GetDefaultJava()->path)); - - QList candidates; - for(JavaVersionPtr java_candidate : java_candidates) - { - if(!candidates.contains(java_candidate->path)) - { - candidates.append(java_candidate->path); - } - } - - return candidates; -} - -#elif OSX -QList JavaUtils::FindJavaPaths() -{ - QList javas; - javas.append(this->GetDefaultJava()->path); - javas.append("/Applications/Xcode.app/Contents/Applications/Application Loader.app/Contents/MacOS/itms/java/bin/java"); - javas.append("/Library/Internet Plug-Ins/JavaAppletPlugin.plugin/Contents/Home/bin/java"); - javas.append("/System/Library/Frameworks/JavaVM.framework/Versions/Current/Commands/java"); - QDir libraryJVMDir("/Library/Java/JavaVirtualMachines/"); - QStringList libraryJVMJavas = libraryJVMDir.entryList(QDir::Dirs | QDir::NoDotAndDotDot); - foreach (const QString &java, libraryJVMJavas) { - javas.append(libraryJVMDir.absolutePath() + "/" + java + "/Contents/Home/bin/java"); - javas.append(libraryJVMDir.absolutePath() + "/" + java + "/Contents/Home/jre/bin/java"); - } - QDir systemLibraryJVMDir("/System/Library/Java/JavaVirtualMachines/"); - QStringList systemLibraryJVMJavas = systemLibraryJVMDir.entryList(QDir::Dirs | QDir::NoDotAndDotDot); - foreach (const QString &java, systemLibraryJVMJavas) { - javas.append(systemLibraryJVMDir.absolutePath() + "/" + java + "/Contents/Home/bin/java"); - javas.append(systemLibraryJVMDir.absolutePath() + "/" + java + "/Contents/Commands/java"); - } - return javas; -} - -#elif LINUX -QList JavaUtils::FindJavaPaths() -{ - QLOG_INFO() << "Linux Java detection incomplete - d