diff --git a/CMakeLists.txt b/CMakeLists.txt index 5da43a0b6..cb24499fa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -183,6 +183,8 @@ gui/mainwindow.h gui/mainwindow.cpp gui/settingsdialog.h gui/settingsdialog.cpp +gui/CopyInstanceDialog.h +gui/CopyInstanceDialog.cpp gui/newinstancedialog.h gui/newinstancedialog.cpp gui/logindialog.h @@ -322,6 +324,8 @@ logic/tasks/Task.cpp # Utilities logic/JavaUtils.h logic/JavaUtils.cpp +logic/NagUtils.h +logic/NagUtils.cpp ) @@ -330,6 +334,7 @@ logic/JavaUtils.cpp SET(MULTIMC_UIS gui/mainwindow.ui gui/settingsdialog.ui +gui/CopyInstanceDialog.ui gui/newinstancedialog.ui gui/logindialog.ui gui/aboutdialog.ui diff --git a/MultiMC.cpp b/MultiMC.cpp index bb65050fc..e04904b4a 100644 --- a/MultiMC.cpp +++ b/MultiMC.cpp @@ -291,10 +291,6 @@ void MultiMC::initGlobalSettings() m_settings->registerSetting(new Setting("ShowConsole", true)); m_settings->registerSetting(new Setting("AutoCloseConsole", true)); - // Toolbar settings - m_settings->registerSetting(new Setting("InstanceToolbarVisible", true)); - m_settings->registerSetting(new Setting("InstanceToolbarPosition", QPoint())); - // Console Colors // m_settings->registerSetting(new Setting("SysMessageColor", QColor(Qt::blue))); // m_settings->registerSetting(new Setting("StdOutColor", QColor(Qt::black))); @@ -328,6 +324,8 @@ void MultiMC::initGlobalSettings() // Shall the main window hide on instance launch m_settings->registerSetting(new Setting("NoHide", false)); + m_settings->registerSetting(new Setting("InstSortMode", "Name")); + // Persistent value for the client ID m_settings->registerSetting(new Setting("YggdrasilClientToken", "")); QString currentYggID = m_settings->get("YggdrasilClientToken").toString(); diff --git a/MultiMC.h b/MultiMC.h index 62375cba6..cd4a5f7de 100644 --- a/MultiMC.h +++ b/MultiMC.h @@ -23,6 +23,15 @@ class JavaVersionList; #endif #define MMC (static_cast(QCoreApplication::instance())) +// FIXME: possibly move elsewhere +enum InstSortMode +{ + // Sort alphabetically by name. + Sort_Name, + // Sort by which instance was launched most recently. + Sort_LastLaunch, +}; + class MultiMC : public QApplication { Q_OBJECT diff --git a/depends/util/src/pathutils.cpp b/depends/util/src/pathutils.cpp index 590ac89d3..ad8d75669 100644 --- a/depends/util/src/pathutils.cpp +++ b/depends/util/src/pathutils.cpp @@ -149,3 +149,5 @@ void openFileInDefaultProgram ( QString filename ) { QDesktopServices::openUrl ( "file:///" + QFileInfo ( filename ).absolutePath() ); } + + diff --git a/gui/CopyInstanceDialog.cpp b/gui/CopyInstanceDialog.cpp new file mode 100644 index 000000000..1e0b9e6c9 --- /dev/null +++ b/gui/CopyInstanceDialog.cpp @@ -0,0 +1,84 @@ +/* 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 "CopyInstanceDialog.h" +#include "ui_CopyInstanceDialog.h" + +#include "logic/InstanceFactory.h" +#include "logic/BaseVersion.h" +#include "logic/lists/IconList.h" +#include "logic/lists/MinecraftVersionList.h" +#include "logic/tasks/Task.h" +#include + +#include "gui/platform.h" +#include "versionselectdialog.h" +#include "ProgressDialog.h" +#include "IconPickerDialog.h" + +#include +#include + +CopyInstanceDialog::CopyInstanceDialog(BaseInstance *original, QWidget *parent) + : m_original(original), QDialog(parent), ui(new Ui::CopyInstanceDialog) +{ + MultiMCPlatform::fixWM_CLASS(this); + ui->setupUi(this); + resize(minimumSizeHint()); + layout()->setSizeConstraint(QLayout::SetFixedSize); + + InstIconKey = original->iconKey(); + ui->iconButton->setIcon(MMC->icons()->getIcon(InstIconKey)); + ui->instNameTextBox->setText(original->name()); + ui->instNameTextBox->setFocus(); +} + +CopyInstanceDialog::~CopyInstanceDialog() +{ + delete ui; +} + +void CopyInstanceDialog::updateDialogState() +{ + ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(!instName().isEmpty()); +} + +QString CopyInstanceDialog::instName() const +{ + return ui->instNameTextBox->text(); +} + +QString CopyInstanceDialog::iconKey() const +{ + return InstIconKey; +} + +void CopyInstanceDialog::on_iconButton_clicked() +{ + IconPickerDialog dlg(this); + dlg.exec(InstIconKey); + + if (dlg.result() == QDialog::Accepted) + { + InstIconKey = dlg.selectedIconKey; + ui->iconButton->setIcon(MMC->icons()->getIcon(InstIconKey)); + } +} + +void CopyInstanceDialog::on_instNameTextBox_textChanged(const QString &arg1) +{ + updateDialogState(); +} diff --git a/gui/CopyInstanceDialog.h b/gui/CopyInstanceDialog.h new file mode 100644 index 000000000..7ab366e2a --- /dev/null +++ b/gui/CopyInstanceDialog.h @@ -0,0 +1,50 @@ +/* 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 "logic/BaseVersion.h" + +class BaseInstance; + +namespace Ui +{ +class CopyInstanceDialog; +} + +class CopyInstanceDialog : public QDialog +{ + Q_OBJECT + +public: + explicit CopyInstanceDialog(BaseInstance *original, QWidget *parent = 0); + ~CopyInstanceDialog(); + + void updateDialogState(); + + QString instName() const; + QString iconKey() const; + +private +slots: + void on_iconButton_clicked(); + void on_instNameTextBox_textChanged(const QString &arg1); + +private: + Ui::CopyInstanceDialog *ui; + QString InstIconKey; + BaseInstance *m_original; +}; diff --git a/gui/CopyInstanceDialog.ui b/gui/CopyInstanceDialog.ui new file mode 100644 index 000000000..1327ce0bb --- /dev/null +++ b/gui/CopyInstanceDialog.ui @@ -0,0 +1,134 @@ + + + CopyInstanceDialog + + + Qt::ApplicationModal + + + + 0 + 0 + 345 + 205 + + + + Copy Instance + + + + :/icons/toolbar/copy:/icons/toolbar/copy + + + true + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + :/icons/instances/infinity:/icons/instances/infinity + + + + 80 + 80 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + Name + + + + + + + Qt::Horizontal + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + + + buttonBox + accepted() + CopyInstanceDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + buttonBox + rejected() + CopyInstanceDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + + diff --git a/gui/mainwindow.cpp b/gui/mainwindow.cpp index 00cfacf70..20a2b84be 100644 --- a/gui/mainwindow.cpp +++ b/gui/mainwindow.cpp @@ -66,6 +66,7 @@ #include "logic/OneSixAssets.h" #include "logic/OneSixUpdate.h" #include "logic/JavaUtils.h" +#include "logic/NagUtils.h" #include "logic/LegacyInstance.h" @@ -73,6 +74,7 @@ #include "IconPickerDialog.h" #include "LabeledToolButton.h" #include "EditNotesDialog.h" +#include "CopyInstanceDialog.h" MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { @@ -90,7 +92,9 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWi // The instance action toolbar customizations { + // disabled until we have an instance selected ui->instanceToolBar->setEnabled(false); + // the rename label is inside the rename tool button renameButton = new LabeledToolButton(); renameButton->setText("Instance Name"); @@ -125,8 +129,8 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWi view->installEventFilter(this); proxymodel = new InstanceProxyModel(this); - proxymodel->setSortRole(KCategorizedSortFilterProxyModel::CategorySortRole); - proxymodel->setFilterRole(KCategorizedSortFilterProxyModel::CategorySortRole); +// proxymodel->setSortRole(KCategorizedSortFilterProxyModel::CategorySortRole); + //proxymodel->setFilterRole(KCategorizedSortFilterProxyModel::CategorySortRole); // proxymodel->setDynamicSortFilter ( true ); // FIXME: instList should be global-ish, or at least not tied to the main window... @@ -266,8 +270,9 @@ void MainWindow::on_actionAddInstance_triggered() BaseInstance *newInstance = NULL; - QString instDirName = DirNameFromString(newInstDlg.instName()); - QString instDir = PathCombine(MMC->settings()->get("InstanceDir").toString(), instDirName); + QString instancesDir = MMC->settings()->get("InstanceDir").toString(); + QString instDirName = DirNameFromString(newInstDlg.instName(), instancesDir); + QString instDir = PathCombine(instancesDir, instDirName); auto &loader = InstanceFactory::get(); @@ -304,6 +309,56 @@ void MainWindow::on_actionAddInstance_triggered() } } +void MainWindow::on_actionCopyInstance_triggered() +{ + if (!m_selectedInstance) + return; + + CopyInstanceDialog copyInstDlg(m_selectedInstance, this); + if (!copyInstDlg.exec()) + return; + + QString instancesDir = MMC->settings()->get("InstanceDir").toString(); + QString instDirName = DirNameFromString(copyInstDlg.instName(), instancesDir); + QString instDir = PathCombine(instancesDir, instDirName); + + auto &loader = InstanceFactory::get(); + + BaseInstance *newInstance = NULL; + auto error = loader.copyInstance(newInstance, m_selectedInstance, instDir); + + QString errorMsg = QString("Failed to create instance %1: ").arg(instDirName); + switch (error) + { + case InstanceFactory::NoCreateError: + newInstance->setName(copyInstDlg.instName()); + newInstance->setIconKey(copyInstDlg.iconKey()); + MMC->instances()->add(InstancePtr(newInstance)); + return; + + case InstanceFactory::InstExists: + { + errorMsg += "An instance with the given directory name already exists."; + CustomMessageBox::selectable(this, tr("Error"), errorMsg, QMessageBox::Warning)->show(); + break; + } + + case InstanceFactory::CantCreateDir: + { + errorMsg += "Failed to create the instance directory."; + CustomMessageBox::selectable(this, tr("Error"), errorMsg, QMessageBox::Warning)->show(); + break; + } + + default: + { + errorMsg += QString("Unknown instance loader error %1").arg(error); + CustomMessageBox::selectable(this, tr("Error"), errorMsg, QMessageBox::Warning)->show(); + break; + } + } +} + void MainWindow::on_actionChangeInstIcon_triggered() { if (!m_selectedInstance) @@ -365,6 +420,9 @@ void MainWindow::on_actionSettings_triggered() { SettingsDialog dialog(this); dialog.exec(); + //FIXME: quick HACK to make this work. improve, optimize. + proxymodel->invalidate(); + proxymodel->sort(0); } void MainWindow::on_actionReportBug_triggered() @@ -394,10 +452,10 @@ void MainWindow::on_actionDeleteInstance_triggered() { if (m_selectedInstance) { - auto response = CustomMessageBox::selectable(this, tr("CAREFUL"), - tr("This is permanent! Are you sure?\nAbout to delete: ") - + m_selectedInstance->name(), - QMessageBox::Question, QMessageBox::Yes | QMessageBox::No)->exec(); + auto response = CustomMessageBox::selectable( + this, tr("CAREFUL"), tr("This is permanent! Are you sure?\nAbout to delete: ") + + m_selectedInstance->name(), + QMessageBox::Question, QMessageBox::Yes | QMessageBox::No)->exec(); if (response == QMessageBox::Yes) { m_selectedInstance->nuke(); @@ -471,9 +529,12 @@ void MainWindow::instanceActivated(QModelIndex index) { if (!index.isValid()) return; + BaseInstance *inst = (BaseInstance *)index.data(InstanceList::InstancePointerRole).value(); + NagUtils::checkJVMArgs(MMC->settings()->get("JvmArgs").toString(), this); + bool autoLogin = MMC->settings()->get("AutoLogin").toBool(); if (autoLogin) doAutoLogin(); @@ -485,6 +546,7 @@ void MainWindow::on_actionLaunchInstance_triggered() { if (m_selectedInstance) { + NagUtils::checkJVMArgs(MMC->settings()->get("JvmArgs").toString(), this); doLogin(); } } @@ -635,7 +697,8 @@ void MainWindow::onGameUpdateComplete() void MainWindow::onGameUpdateError(QString error) { - CustomMessageBox::selectable(this, tr("Error updating instance"), error, QMessageBox::Warning)->show(); + CustomMessageBox::selectable(this, tr("Error updating instance"), error, + QMessageBox::Warning)->show(); } void MainWindow::launchInstance(BaseInstance *instance, LoginResponse response) @@ -704,9 +767,10 @@ void MainWindow::on_actionMakeDesktopShortcut_triggered() QStringList() << "-dl" << QDir::currentPath() << "test", name, "application-x-octet-stream"); - CustomMessageBox::selectable(this, tr("Not useful"), - tr("A Dummy Shortcut was created. it will not do anything productive"), - QMessageBox::Warning)->show(); + CustomMessageBox::selectable( + this, tr("Not useful"), + tr("A Dummy Shortcut was created. it will not do anything productive"), + QMessageBox::Warning)->show(); } // BrowserDialog @@ -727,10 +791,11 @@ void MainWindow::on_actionChangeInstMCVersion_triggered() { if (m_selectedInstance->versionIsCustom()) { - auto result = CustomMessageBox::selectable(this, tr("Are you sure?"), - tr("This will remove any library/version customization you did previously. " - "This includes things like Forge install and similar."), - QMessageBox::Warning, QMessageBox::Ok, QMessageBox::Abort)->exec(); + auto result = CustomMessageBox::selectable( + this, tr("Are you sure?"), + tr("This will remove any library/version customization you did previously. " + "This includes things like Forge install and similar."), + QMessageBox::Warning, QMessageBox::Ok, QMessageBox::Abort)->exec(); if (result != QMessageBox::Ok) return; @@ -862,11 +927,12 @@ void MainWindow::checkSetDefaultJava() java = std::dynamic_pointer_cast(vselect.selectedVersion()); else { - CustomMessageBox::selectable(this, tr("Invalid version selected"), - tr("You didn't select a valid Java version, so MultiMC will " - "select the default. " - "You can change this in the settings dialog."), - QMessageBox::Warning)->show(); + CustomMessageBox::selectable( + this, tr("Invalid version selected"), + tr("You didn't select a valid Java version, so MultiMC will " + "select the default. " + "You can change this in the settings dialog."), + QMessageBox::Warning)->show(); JavaUtils ju; java = ju.GetDefaultJava(); diff --git a/gui/mainwindow.h b/gui/mainwindow.h index 6715acbb3..36562563e 100644 --- a/gui/mainwindow.h +++ b/gui/mainwindow.h @@ -22,6 +22,7 @@ #include "logic/net/LoginTask.h" #include "logic/BaseInstance.h" +class QToolButton; class LabeledToolButton; class QLabel; class InstanceProxyModel; @@ -51,13 +52,16 @@ public: void checkSetDefaultJava(); -private slots: +private +slots: void onCatToggled(bool); void on_actionAbout_triggered(); void on_actionAddInstance_triggered(); + void on_actionCopyInstance_triggered(); + void on_actionChangeInstGroup_triggered(); void on_actionChangeInstIcon_triggered(); @@ -122,7 +126,8 @@ private slots: void assetsFailed(); void assetsFinished(); -public slots: +public +slots: void instanceActivated(QModelIndex); void instanceChanged(const QModelIndex ¤t, const QModelIndex &previous); @@ -146,6 +151,7 @@ private: ConsoleWindow *console; OneSixAssets *assets_downloader; LabeledToolButton *renameButton; + QToolButton *changeIconButton; BaseInstance *m_selectedInstance; diff --git a/gui/mainwindow.ui b/gui/mainwindow.ui index 0f883d13f..6f70fc981 100644 --- a/gui/mainwindow.ui +++ b/gui/mainwindow.ui @@ -62,6 +62,8 @@ false + + @@ -310,6 +312,9 @@ Change the selected instance's icon. + + true + @@ -445,6 +450,21 @@ <html><head/><body><p align="center"><span style=" font-weight:600; color:#ff0004;">Catnarok!</span></p><p align="center">Or just a cat with a ball of yarn?</p><p align="center"><span style=" font-style:italic;">WHO KNOWS?!</span></p><p align="center"><img src=":/icons/instances/tnt"/></p></body></html> + + + + :/icons/toolbar/copy:/icons/toolbar/copy + + + Copy Instance + + + Copy the selected instance. + + + Add a new instance. + + diff --git a/gui/newinstancedialog.h b/gui/newinstancedialog.h index 408cf7577..4357c28d3 100644 --- a/gui/newinstancedialog.h +++ b/gui/newinstancedialog.h @@ -3,7 +3,7 @@ * 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 @@ -13,44 +13,43 @@ * limitations under the License. */ -#ifndef NEWINSTANCEDIALOG_H -#define NEWINSTANCEDIALOG_H +#pragma once #include #include "logic/BaseVersion.h" -namespace Ui { +namespace Ui +{ class NewInstanceDialog; } class NewInstanceDialog : public QDialog { Q_OBJECT - + public: explicit NewInstanceDialog(QWidget *parent = 0); ~NewInstanceDialog(); - + void updateDialogState(); - + void setSelectedVersion(BaseVersionPtr version); - + void loadVersionList(); - + QString instName() const; QString iconKey() const; BaseVersionPtr selectedVersion() const; - -private slots: + +private +slots: void on_btnChangeVersion_clicked(); void on_iconButton_clicked(); void on_instNameTextBox_textChanged(const QString &arg1); - + private: Ui::NewInstanceDialog *ui; - + BaseVersionPtr m_selectedVersion; QString InstIconKey; }; - -#endif // NEWINSTANCEDIALOG_H diff --git a/gui/settingsdialog.cpp b/gui/settingsdialog.cpp index 346f74143..bf331fc07 100644 --- a/gui/settingsdialog.cpp +++ b/gui/settingsdialog.cpp @@ -17,6 +17,7 @@ #include "settingsdialog.h" #include "ui_settingsdialog.h" #include "logic/JavaUtils.h" +#include "logic/NagUtils.h" #include "gui/versionselectdialog.h" #include "gui/platform.h" #include "gui/CustomMessageBox.h" @@ -32,6 +33,8 @@ SettingsDialog::SettingsDialog(QWidget *parent) : QDialog(parent), ui(new Ui::Se { MultiMCPlatform::fixWM_CLASS(this); ui->setupUi(this); + ui->sortingModeGroup->setId(ui->sortByNameBtn, Sort_Name); + ui->sortingModeGroup->setId(ui->sortLastLaunchedBtn, Sort_LastLaunch); loadSettings(MMC->settings().get()); updateCheckboxStuff(); @@ -159,10 +162,25 @@ void SettingsDialog::applySettings(SettingsObject *s) // Java Settings s->set("JavaPath", ui->javaPathTextBox->text()); s->set("JvmArgs", ui->jvmArgsTextBox->text()); + NagUtils::checkJVMArgs(s->get("JvmArgs").toString(), this->parentWidget()); // Custom Commands s->set("PreLaunchCommand", ui->preLaunchCmdTextBox->text()); s->set("PostExitCommand", ui->postExitCmdTextBox->text()); + + auto sortMode = (InstSortMode) ui->sortingModeGroup->checkedId(); + switch(sortMode) + { + case Sort_LastLaunch: + s->set("InstSortMode", "LastLaunch"); + break; + case Sort_Name: + default: + s->set("InstSortMode", "Name"); + break; + } + + s->set("PostExitCommand", ui->postExitCmdTextBox->text()); } void SettingsDialog::loadSettings(SettingsObject *s) @@ -193,6 +211,17 @@ void SettingsDialog::loadSettings(SettingsObject *s) ui->maxMemSpinBox->setValue(s->get("MaxMemAlloc").toInt()); ui->permGenSpinBox->setValue(s->get("PermGen").toInt()); + QString sortMode = s->get("InstSortMode").toString(); + + if(sortMode == "LastLaunch") + { + ui->sortLastLaunchedBtn->setChecked(true); + } + else + { + ui->sortByNameBtn->setChecked(true); + } + // Java Settings ui->javaPathTextBox->setText(s->get("JavaPath").toString()); ui->jvmArgsTextBox->setText(s->get("JvmArgs").toString()); diff --git a/logic/InstanceFactory.cpp b/logic/InstanceFactory.cpp index 0da62803f..e64d22cad 100644 --- a/logic/InstanceFactory.cpp +++ b/logic/InstanceFactory.cpp @@ -3,7 +3,7 @@ * 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 @@ -34,30 +34,29 @@ InstanceFactory InstanceFactory::loader; -InstanceFactory::InstanceFactory() : - QObject(NULL) +InstanceFactory::InstanceFactory() : QObject(NULL) { - } -InstanceFactory::InstLoadError InstanceFactory::loadInstance(BaseInstance *&inst, const QString &instDir) +InstanceFactory::InstLoadError InstanceFactory::loadInstance(BaseInstance *&inst, + const QString &instDir) { auto m_settings = new INISettingsObject(PathCombine(instDir, "instance.cfg")); - + m_settings->registerSetting(new Setting("InstanceType", "Legacy")); - + QString inst_type = m_settings->get("InstanceType").toString(); - - //FIXME: replace with a map lookup, where instance classes register their types - if(inst_type == "Legacy") + + // FIXME: replace with a map lookup, where instance classes register their types + if (inst_type == "Legacy") { inst = new LegacyInstance(instDir, m_settings, this); } - else if(inst_type == "OneSix") + else if (inst_type == "OneSix") { inst = new OneSixInstance(instDir, m_settings, this); } - else if(inst_type == "Nostalgia") + else if (inst_type == "Nostalgia") { inst = new NostalgiaInstance(instDir, m_settings, this); } @@ -68,50 +67,81 @@ InstanceFactory::InstLoadError InstanceFactory::loadInstance(BaseInstance *&inst return NoLoadError; } - -InstanceFactory::InstCreateError InstanceFactory::createInstance( BaseInstance*& inst, BaseVersionPtr version, const QString& instDir ) +InstanceFactory::InstCreateError InstanceFactory::createInstance(BaseInstance *&inst, + BaseVersionPtr version, + const QString &instDir) { QDir rootDir(instDir); - + QLOG_DEBUG() << instDir.toUtf8(); if (!rootDir.exists() && !rootDir.mkpath(".")) { return InstanceFactory::CantCreateDir; } auto mcVer = std::dynamic_pointer_cast(version); - if(!mcVer) + if (!mcVer) return InstanceFactory::NoSuchVersion; - + auto m_settings = new INISettingsObject(PathCombine(instDir, "instance.cfg")); m_settings->registerSetting(new Setting("InstanceType", "Legacy")); - - switch(mcVer->type) + + 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; - } + 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; } - - //FIXME: really, how do you even know? + } + + // FIXME: really, how do you even know? return InstanceFactory::NoCreateError; } + +InstanceFactory::InstCreateError InstanceFactory::copyInstance(BaseInstance *&newInstance, + BaseInstance *&oldInstance, + const QString &instDir) +{ + QDir rootDir(instDir); + + QLOG_DEBUG() << instDir.toUtf8(); + if (!copyPath(oldInstance->instanceRoot(), instDir)) + { + rootDir.removeRecursively(); + return InstanceFactory::CantCreateDir; + } + auto error = loadInstance(newInstance, instDir); + switch(error) + { + case NoLoadError: + return NoCreateError; + case UnknownLoadError: + { + rootDir.removeRecursively(); + return UnknownCreateError; + } + case NotAnInstance: + { + rootDir.removeRecursively(); + return CantCreateDir; + } + }; +} diff --git a/logic/InstanceFactory.h b/logic/InstanceFactory.h index 1c5277493..01e5af7ea 100644 --- a/logic/InstanceFactory.h +++ b/logic/InstanceFactory.h @@ -3,7 +3,7 @@ * 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 @@ -34,15 +34,18 @@ public: /*! * \brief Gets a reference to the instance loader. */ - static InstanceFactory &get() { return loader; } - + static InstanceFactory &get() + { + return loader; + } + enum InstLoadError { NoLoadError = 0, UnknownLoadError, NotAnInstance }; - + enum InstCreateError { NoCreateError = 0, @@ -51,18 +54,33 @@ public: InstExists, CantCreateDir }; - + /*! * \brief Creates a stub instance * * \param inst Pointer to store the created instance in. - * \param instDir The instance's directory. + * \param inst Game version to use for the instance + * \param instDir The new instance's directory. * \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); - + InstCreateError createInstance(BaseInstance *&inst, BaseVersionPtr version, + const QString &instDir); + + /*! + * \brief Creates a copy of an existing instance with a new name + * + * \param newInstance Pointer to store the created instance in. + * \param oldInstance The instance to copy + * \param instDir The new instance's directory. + * \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 copyInstance(BaseInstance *&newInstance, BaseInstance *&oldInstance, + const QString &instDir); + /*! * \brief Loads an instance from the given directory. * Checks the instance's INI file to figure out what the instance's type is first. @@ -72,9 +90,9 @@ public: * - NotAnInstance if the given instance directory isn't a valid instance. */ InstLoadError loadInstance(BaseInstance *&inst, const QString &instDir); - + private: InstanceFactory(); - + static InstanceFactory loader; }; diff --git a/logic/NagUtils.cpp b/logic/NagUtils.cpp new file mode 100644 index 000000000..ccabf71f8 --- /dev/null +++ b/logic/NagUtils.cpp @@ -0,0 +1,37 @@ +/* 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 "NagUtils.h" +#include "gui/CustomMessageBox.h" + +namespace NagUtils +{ +void checkJVMArgs(QString jvmargs, QWidget *parent) +{ + if(jvmargs.contains("-XX:PermSize=") || jvmargs.contains(QRegExp("-Xm[sx]"))) + { + CustomMessageBox::selectable(parent, parent->tr("JVM arguments warning"), + parent->tr("You tried to manually set a JVM memory option (using " + " \"-XX:PermSize\", \"-Xmx\" or \"-Xms\") - there" + " are dedicated boxes for these in the settings (Java" + " tab, in the Memory group at the top).\n" + "Your manual settings will be overridden by the" + " dedicated options.\n" + "This message will be displayed until you remove them" + " from the JVM arguments."), + QMessageBox::Warning)->exec(); + } +} +} diff --git a/logic/NagUtils.h b/logic/NagUtils.h new file mode 100644 index 000000000..9564a2b12 --- /dev/null +++ b/logic/NagUtils.h @@ -0,0 +1,23 @@ +/* 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 + +namespace NagUtils +{ +void checkJVMArgs(QString args, QWidget *parent); +} diff --git a/logic/OneSixAssets.cpp b/logic/OneSixAssets.cpp index 375c87f1d..500385adb 100644 --- a/logic/OneSixAssets.cpp +++ b/logic/OneSixAssets.cpp @@ -102,6 +102,7 @@ void OneSixAssets::start() job->addNetAction( S3ListBucket::make(QUrl("http://s3.amazonaws.com/Minecraft.Resources/"))); connect(job, SIGNAL(succeeded()), SLOT(S3BucketFinished())); + connect(job, SIGNAL(failed()), SIGNAL(failed())); emit indexStarted(); index_job.reset(job); job->start(); diff --git a/logic/lists/InstanceList.cpp b/logic/lists/InstanceList.cpp index 08985a192..b42d7b7a3 100644 --- a/logic/lists/InstanceList.cpp +++ b/logic/lists/InstanceList.cpp @@ -422,7 +422,13 @@ bool InstanceProxyModel::subSortLessThan(const QModelIndex &left, { BaseInstance *pdataLeft = static_cast(left.internalPointer()); BaseInstance *pdataRight = static_cast(right.internalPointer()); - // kDebug() << *pdataLeft << *pdataRight; - return QString::localeAwareCompare(pdataLeft->name(), pdataRight->name()) < 0; - // return pdataLeft->name() < pdataRight->name(); + 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/multimc.qrc b/multimc.qrc index 06a649522..86f50b805 100644 --- a/multimc.qrc +++ b/multimc.qrc @@ -6,6 +6,7 @@ resources/icons/toolbar/checkupdate.png resources/icons/toolbar/help.png resources/icons/toolbar/new.png + resources/icons/toolbar/InstCopy.png resources/icons/toolbar/NewsIcon.png resources/icons/toolbar/refresh.png resources/icons/toolbar/settings.png diff --git a/resources/icons/toolbar/InstCopy.png b/resources/icons/toolbar/InstCopy.png new file mode 100644 index 000000000..c8f9db413 Binary files /dev/null and b/resources/icons/toolbar/InstCopy.png differ