From 5513b273c679b9edda951f418ef013a762ca587a Mon Sep 17 00:00:00 2001
From: isanae <14251494+isanae@users.noreply.github.com>
Date: Thu, 23 Jul 2020 04:53:20 -0400
Subject: added empty instance manager dialog
---
src/instancemanagerdialog.ui | 378 +++++++++++++++++++++++++++++++++++++++++++
1 file changed, 378 insertions(+)
create mode 100644 src/instancemanagerdialog.ui
(limited to 'src/instancemanagerdialog.ui')
diff --git a/src/instancemanagerdialog.ui b/src/instancemanagerdialog.ui
new file mode 100644
index 00000000..b35d2e58
--- /dev/null
+++ b/src/instancemanagerdialog.ui
@@ -0,0 +1,378 @@
+
+
+ InstanceManagerDialog
+
+
+
+ 0
+ 0
+ 531
+ 413
+
+
+
+ Instance manager
+
+
+ -
+
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 5
+
+
-
+
+
+ Create new instance
+
+
+
+ :/MO/gui/add:/MO/gui/add
+
+
+
+ -
+
+
+ Create portable instance
+
+
+
+ :/MO/gui/package:/MO/gui/package
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+ -
+
+
+ <html><head/><body><p><a href="https://github.com/ModOrganizer2/modorganizer/wiki/Instance"><span style=" text-decoration: underline; color:#0000ff;">What is an instance?</span></a></p></body></html>
+
+
+ true
+
+
+
+
+
+
+ -
+
+
-
+
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
-
+
+
+ Qt::Horizontal
+
+
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
-
+
+
+
+
+
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+ -
+
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
-
+
+
+ instance name
+
+
+ Qt::TextBrowserInteraction
+
+
+
+ -
+
+
+ Game:
+
+
+
+ -
+
+
+ Name:
+
+
+
+ -
+
+
+ Location:
+
+
+
+ -
+
+
+ Rename
+
+
+
+ -
+
+
+ location path
+
+
+ Qt::TextBrowserInteraction
+
+
+
+ -
+
+
+ Base folder:
+
+
+
+ -
+
+
+ base folder path
+
+
+ Qt::TextBrowserInteraction
+
+
+
+ -
+
+
+ Explore
+
+
+
+ -
+
+
+ Explore
+
+
+
+ -
+
+
+ game name
+
+
+ Qt::TextBrowserInteraction
+
+
+
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 10
+
+
+
+
+ -
+
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
-
+
+
+ Convert to portable
+
+
+
+ -
+
+
+ Convert to global
+
+
+
+ -
+
+
+ Delete instance
+
+
+
+ :/MO/gui/remove:/MO/gui/remove
+
+
+
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
+
+
+
+
+
+
+
+
+
+ -
+
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
-
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+ -
+
+
+ Switch to this instance
+
+
+
+ :/MO/gui/next:/MO/gui/next
+
+
+
+ -
+
+
+ Cancel
+
+
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
--
cgit v1.3.1
From 60b59ddf097fffa846a4d28e0d9256630da5149c Mon Sep 17 00:00:00 2001
From: isanae <14251494+isanae@users.noreply.github.com>
Date: Thu, 23 Jul 2020 07:32:06 -0400
Subject: started create instance dialog allow for multiple instances of
Settings fill in information in instance manager
---
src/CMakeLists.txt | 1 +
src/createinstancedialog.cpp | 176 ++++++++++++
src/createinstancedialog.h | 30 ++
src/createinstancedialog.ui | 655 ++++++++++++++++++++++++++++++++++++++++++
src/instancemanager.h | 2 +-
src/instancemanagerdialog.cpp | 102 ++++++-
src/instancemanagerdialog.h | 16 +-
src/instancemanagerdialog.ui | 116 ++++----
src/main.cpp | 9 +
src/settings.cpp | 19 +-
src/settings.h | 1 +
11 files changed, 1064 insertions(+), 63 deletions(-)
create mode 100644 src/createinstancedialog.cpp
create mode 100644 src/createinstancedialog.h
create mode 100644 src/createinstancedialog.ui
(limited to 'src/instancemanagerdialog.ui')
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 1f048be8..af350584 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -84,6 +84,7 @@ add_filter(NAME src/executables GROUPS
)
add_filter(NAME src/instances GROUPS
+ createinstancedialog
instancemanager
instancemanagerdialog
)
diff --git a/src/createinstancedialog.cpp b/src/createinstancedialog.cpp
new file mode 100644
index 00000000..d43fba1c
--- /dev/null
+++ b/src/createinstancedialog.cpp
@@ -0,0 +1,176 @@
+#include "createinstancedialog.h"
+#include "ui_createinstancedialog.h"
+#include "instancemanager.h"
+
+namespace cid
+{
+
+class Page
+{
+public:
+ Page(CreateInstanceDialog& dlg, std::size_t i)
+ : ui(dlg.getUI()), m_dlg(dlg), m_index(i)
+ {
+ }
+
+ virtual bool ready() const
+ {
+ return true;
+ }
+
+ void next()
+ {
+ m_dlg.next();
+ }
+
+protected:
+ Ui::CreateInstanceDialog* ui;
+
+private:
+ CreateInstanceDialog& m_dlg;
+ std::size_t m_index;
+};
+
+class TypePage : public Page
+{
+public:
+ TypePage(CreateInstanceDialog& dlg, std::size_t i)
+ : Page(dlg, i)
+ {
+ ui->createGlobal->setDescription(
+ ui->createGlobal->description()
+ .arg(InstanceManager::instance().instancesPath()));
+
+ ui->createPortable->setDescription(
+ ui->createPortable->description()
+ .arg(qApp->applicationDirPath()));
+
+ QObject::connect(
+ ui->createGlobal, &QAbstractButton::clicked, [&]{ global(); });
+
+ QObject::connect(
+ ui->createPortable, &QAbstractButton::clicked, [&]{ portable(); });
+ }
+
+ bool ready() const override
+ {
+ return m_global.has_value();
+ }
+
+ void global()
+ {
+ m_global = true;
+
+ ui->createGlobal->setChecked(true);
+ ui->createPortable->setChecked(false);
+
+ next();
+ }
+
+ void portable()
+ {
+ m_global = false;
+
+ ui->createGlobal->setChecked(false);
+ ui->createPortable->setChecked(true);
+
+ next();
+ }
+
+private:
+ std::optional m_global;
+};
+
+
+class GamePage : public Page
+{
+public:
+ GamePage(CreateInstanceDialog& dlg, std::size_t i)
+ : Page(dlg, i)
+ {
+ }
+};
+
+
+class NamePage : public Page
+{
+public:
+ NamePage(CreateInstanceDialog& dlg, std::size_t i)
+ : Page(dlg, i)
+ {
+ }
+};
+
+
+class PathsPage : public Page
+{
+public:
+ PathsPage(CreateInstanceDialog& dlg, std::size_t i)
+ : Page(dlg, i)
+ {
+ }
+};
+
+} // namespace
+
+
+CreateInstanceDialog::CreateInstanceDialog(QWidget *parent)
+ : QDialog(parent), ui(new Ui::CreateInstanceDialog)
+{
+ using namespace cid;
+
+ ui->setupUi(this);
+
+ m_pages.push_back(std::make_unique(*this, 0));
+ m_pages.push_back(std::make_unique(*this, 1));
+ m_pages.push_back(std::make_unique(*this, 2));
+ m_pages.push_back(std::make_unique(*this, 3));
+
+ ui->pages->setCurrentIndex(0);
+
+ updateNavigationButtons();
+
+ connect(ui->next, &QPushButton::clicked, [&]{ next(); });
+ connect(ui->back, &QPushButton::clicked, [&]{ back(); });
+
+ //
+ //SelectionDialog games(tr("Select a game to manage."));
+ //
+ //for (auto* game : m_pc.plugins()) {
+ // if (game->isInstalled()) {
+ // games.addChoice(game->gameName(), game->gameDirectory().path(), {});
+ // } else {
+ // games.addChoice(game->gameName(), "", {});
+ // }
+ //}
+ //
+ //games.exec();
+}
+
+CreateInstanceDialog::~CreateInstanceDialog() = default;
+
+Ui::CreateInstanceDialog* CreateInstanceDialog::getUI()
+{
+ return ui.get();
+}
+
+void CreateInstanceDialog::next()
+{
+ ui->pages->setCurrentIndex(ui->pages->currentIndex() + 1);
+ updateNavigationButtons();
+}
+
+void CreateInstanceDialog::back()
+{
+ ui->pages->setCurrentIndex(ui->pages->currentIndex() - 1);
+ updateNavigationButtons();
+}
+
+void CreateInstanceDialog::updateNavigationButtons()
+{
+ const auto i = ui->pages->currentIndex();
+ const auto last = (i == (ui->pages->count() - 1));
+
+ ui->next->setEnabled(m_pages[i]->ready() && !last);
+ ui->back->setEnabled(i > 0);
+}
diff --git a/src/createinstancedialog.h b/src/createinstancedialog.h
new file mode 100644
index 00000000..03e9de01
--- /dev/null
+++ b/src/createinstancedialog.h
@@ -0,0 +1,30 @@
+#ifndef MODORGANIZER_CREATEINSTANCEDIALOG_INCLUDED
+#define MODORGANIZER_CREATEINSTANCEDIALOG_INCLUDED
+
+#include
+
+namespace Ui { class CreateInstanceDialog; };
+namespace cid { class Page; }
+
+class CreateInstanceDialog : public QDialog
+{
+ Q_OBJECT
+
+public:
+ explicit CreateInstanceDialog(QWidget *parent = nullptr);
+
+ ~CreateInstanceDialog();
+
+ Ui::CreateInstanceDialog* getUI();
+
+ void next();
+ void back();
+
+private:
+ std::unique_ptr ui;
+ std::vector> m_pages;
+
+ void updateNavigationButtons();
+};
+
+#endif // MODORGANIZER_CREATEINSTANCEDIALOG_INCLUDED
diff --git a/src/createinstancedialog.ui b/src/createinstancedialog.ui
new file mode 100644
index 00000000..bcfddb20
--- /dev/null
+++ b/src/createinstancedialog.ui
@@ -0,0 +1,655 @@
+
+
+ CreateInstanceDialog
+
+
+
+ 0
+ 0
+ 493
+ 423
+
+
+
+ Creating an instance
+
+
+ -
+
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
-
+
+
+ <h2>Creating a new instance</h2>
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+ QSizePolicy::Fixed
+
+
+
+ 20
+ 10
+
+
+
+
+
+
+
+ -
+
+
+ 0
+
+
+
+
-
+
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
-
+
+
+ <h3>Select the type of instance to create.</h3>
+
+
+
+
+
+
+ -
+
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
-
+
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
-
+
+
+ Create a global instance
+
+
+ true
+
+
+ Global instances are stored in %1, but some paths can be changed to be on a different drive if necessary. A single installation of Mod Organizer can manage multiple global instances.
+
+
+
+ -
+
+
+ Create a portable instance
+
+
+ true
+
+
+ A portable instance stores everything in Mod Organizer's installation folder, currently %1. There can only be one portable instance per installation of Mod Organizer.
+
+
+
+
+
+
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
+
+
+
+
+ -
+
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
-
+
+
+ <h3>Select the game to manage.</h3>
+
+
+
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+ -
+
+
+ Show all supported games
+
+
+
+
+
+
+ -
+
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
-
+
+
+
+
+
+
+
+
+
+ -
+
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
-
+
+
+ <h3>Pick a name for this instance.</h3>
+
+
+
+
+
+
+ -
+
+
+
+ 0
+
+
-
+
+
+ Instance name
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
+
+
+
+
+
+
+
+ -
+
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
-
+
+
+ <h3>Select a folder where the data should be stored.</h3>
+
+
+
+ -
+
+
+ This includes downloads, mods, profiles and overwrite. If there is enough space on this drive, you should use the default folder.
+
+
+ true
+
+
+
+
+
+
+ -
+
+
+
-
+
+
+ 1
+
+
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
-
+
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
-
+
+
+ ...
+
+
+
+ -
+
+
+ Location
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
+ -
+
+
+
+
+
+
+
+
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+ -
+
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
-
+
+
+ Overwrite
+
+
+
+ -
+
+
+ Mods
+
+
+
+ -
+
+
+ Base directory
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 40
+
+
+
+
+ -
+
+
+ Profiles
+
+
+
+ -
+
+
+ -
+
+
+ Downloads
+
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ -
+
+
+ Use <code>%BASE_DIR%</code> to refer to the Base Directory.
+
+
+
+ -
+
+
+ ...
+
+
+
+ -
+
+
+ ...
+
+
+
+ -
+
+
+ ...
+
+
+
+ -
+
+
+ ...
+
+
+
+ -
+
+
+ ...
+
+
+
+
+
+
+
+
+
+
+ -
+
+
+
+ 0
+ 0
+
+
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
-
+
+
+ Qt::Horizontal
+
+
+
+ 292
+ 20
+
+
+
+
+ -
+
+
+ Show advanced options
+
+
+
+
+
+
+
+
+
+
+
+
+
+ -
+
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
-
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
+ -
+
+
+ < Back
+
+
+
+ -
+
+
+ Next >
+
+
+ true
+
+
+
+ -
+
+
+ Cancel
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/instancemanager.h b/src/instancemanager.h
index 8bbbbee9..d53f4391 100644
--- a/src/instancemanager.h
+++ b/src/instancemanager.h
@@ -49,6 +49,7 @@ public:
bool allowedToChangeInstance() const;
static bool isPortablePath(const QString& dataPath);
+ QString instancesPath() const;
QStringList instanceNames() const;
std::vector instancePaths() const;
@@ -56,7 +57,6 @@ private:
InstanceManager();
- QString instancesPath() const;
QString instancePath(const QString& instanceName) const;
bool deleteLocalInstance(const QString &instanceId) const;
diff --git a/src/instancemanagerdialog.cpp b/src/instancemanagerdialog.cpp
index 1b482099..c7042aa8 100644
--- a/src/instancemanagerdialog.cpp
+++ b/src/instancemanagerdialog.cpp
@@ -1,12 +1,19 @@
#include "instancemanagerdialog.h"
#include "ui_instancemanagerdialog.h"
#include "instancemanager.h"
+#include "createinstancedialog.h"
+#include "settings.h"
+#include "selectiondialog.h"
+#include "plugincontainer.h"
+#include "shared/appconfig.h"
+#include
class InstanceInfo
{
public:
- InstanceInfo(QDir dir)
- : m_dir(std::move(dir))
+ InstanceInfo(QDir dir) :
+ m_dir(std::move(dir)),
+ m_settings(dir.filePath(QString::fromStdWString(AppConfig::iniFileName())))
{
}
@@ -15,22 +22,105 @@ public:
return m_dir.dirName();
}
+ QString gameName() const
+ {
+ if (auto n=m_settings.game().name()) {
+ if (auto e=m_settings.game().edition()) {
+ if (!e->isEmpty()) {
+ return *n + " (" + *e + ")";
+ }
+ }
+
+ return *n;
+ } else {
+ return {};
+ }
+ }
+
+ QString gamePath() const
+ {
+ if (auto n=m_settings.game().directory()) {
+ return *n;
+ } else {
+ return {};
+ }
+ }
+
+ QString location() const
+ {
+ return m_dir.path();
+ }
+
+ QString baseDirectory() const
+ {
+ return m_settings.paths().base();
+ }
+
private:
QDir m_dir;
+ Settings m_settings;
};
-InstanceManagerDialog::InstanceManagerDialog(QWidget *parent)
- : QDialog(parent), ui(new Ui::InstanceManagerDialog)
+InstanceManagerDialog::InstanceManagerDialog(
+ const PluginContainer& pc, QWidget *parent)
+ : QDialog(parent), ui(new Ui::InstanceManagerDialog), m_pc(pc)
{
ui->setupUi(this);
+ ui->splitter->setSizes({200, 1});
+ ui->splitter->setStretchFactor(0, 0);
+ ui->splitter->setStretchFactor(1, 1);
auto& m = InstanceManager::instance();
for (auto&& d : m.instancePaths()) {
- InstanceInfo i(d);
- ui->list->addItem(i.name());
+ auto ii = std::make_unique(d);
+
+ ui->list->addItem(ii->name());
+ m_instances.push_back(std::move(ii));
+ }
+
+ if (!m_instances.empty()) {
+ select(0);
}
+
+ connect(ui->createNew, &QPushButton::clicked, [&]{ createNew(); });
+ connect(ui->list, &QListWidget::itemSelectionChanged, [&]{ onSelection(); });
}
InstanceManagerDialog::~InstanceManagerDialog() = default;
+
+void InstanceManagerDialog::select(std::size_t i)
+{
+ if (i >= m_instances.size()) {
+ return;
+ }
+
+ const auto& ii = m_instances[i];
+ fill(*ii);
+}
+
+void InstanceManagerDialog::onSelection()
+{
+ const auto sel = ui->list->selectionModel()->selectedIndexes();
+ if (sel.size() != 1) {
+ return;
+ }
+
+ select(static_cast(sel[0].row()));
+}
+
+void InstanceManagerDialog::createNew()
+{
+ CreateInstanceDialog dlg(this);
+ dlg.exec();
+}
+
+void InstanceManagerDialog::fill(const InstanceInfo& ii)
+{
+ ui->name->setText(ii.name());
+ ui->location->setText(ii.location());
+ ui->baseDirectory->setText(ii.baseDirectory());
+ ui->gameName->setText(ii.gameName());
+ ui->gameDir->setText(ii.gamePath());
+}
diff --git a/src/instancemanagerdialog.h b/src/instancemanagerdialog.h
index ea1cfc48..c3e947dd 100644
--- a/src/instancemanagerdialog.h
+++ b/src/instancemanagerdialog.h
@@ -5,16 +5,30 @@
namespace Ui { class InstanceManagerDialog; };
+class InstanceInfo;
+class PluginContainer;
+
class InstanceManagerDialog : public QDialog
{
Q_OBJECT
public:
- explicit InstanceManagerDialog(QWidget *parent = nullptr);
+ explicit InstanceManagerDialog(
+ const PluginContainer& pc, QWidget *parent = nullptr);
+
~InstanceManagerDialog();
+ void select(std::size_t i);
+
private:
std::unique_ptr ui;
+ const PluginContainer& m_pc;
+ std::vector> m_instances;
+
+ void onSelection();
+ void createNew();
+
+ void fill(const InstanceInfo& ii);
};
#endif // MODORGANIZER_INSTANCEMANAGERDIALOG_INCLUDED
diff --git a/src/instancemanagerdialog.ui b/src/instancemanagerdialog.ui
index b35d2e58..146b5fb5 100644
--- a/src/instancemanagerdialog.ui
+++ b/src/instancemanagerdialog.ui
@@ -6,7 +6,7 @@
0
0
- 531
+ 689
413
@@ -40,17 +40,6 @@
- -
-
-
- Create portable instance
-
-
-
- :/MO/gui/package:/MO/gui/package
-
-
-
-
@@ -65,9 +54,9 @@
-
-
+
- <html><head/><body><p><a href="https://github.com/ModOrganizer2/modorganizer/wiki/Instance"><span style=" text-decoration: underline; color:#0000ff;">What is an instance?</span></a></p></body></html>
+ <html><head/><body><p><a href="https://github.com/ModOrganizer2/modorganizer/wiki/Instance">What is an instance?</a></p></body></html>
true
@@ -134,7 +123,7 @@
-
-
+
0
@@ -148,33 +137,51 @@
0
-
-
+
+
+ true
+
+
+
+ -
+
- instance name
+ Name
-
- Qt::TextBrowserInteraction
+
+
+ -
+
+
+ Explore
- -
+
-
- Game:
+ Game
- -
-
-
- Name:
+
-
+
+
+ true
+
+
+
+ -
+
+
+ true
-
- Location:
+ Location
@@ -185,30 +192,24 @@
- -
-
+
-
+
- location path
-
-
- Qt::TextBrowserInteraction
+ Game location
-
- Base folder:
+ Base folder
-
-
-
- base folder path
-
-
- Qt::TextBrowserInteraction
+
+
+ true
@@ -219,20 +220,17 @@
- -
-
-
- Explore
+
-
+
+
+ true
- -
-
+
-
+
- game name
-
-
- Qt::TextBrowserInteraction
+ Explore
@@ -292,6 +290,19 @@
+ -
+
+
+ Qt::Horizontal
+
+
+
+ 40
+ 20
+
+
+
+
@@ -371,6 +382,13 @@
+
+
+ LinkLabel
+ QLabel
+
+
+
diff --git a/src/main.cpp b/src/main.cpp
index 08d70dd9..71fb0bbd 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -25,6 +25,7 @@ along with Mod Organizer. If not, see .
#include "tutorialmanager.h"
#include "nxmaccessmanager.h"
#include "instancemanager.h"
+#include "instancemanagerdialog.h"
#include "organizercore.h"
#include "env.h"
#include "envmodule.h"
@@ -298,6 +299,8 @@ int runApplication(
try
{
Settings settings(dataPath + "/" + QString::fromStdWString(AppConfig::iniFileName()));
+ settings.setGlobalInstance();
+
log::getDefault().setLevel(settings.diagnostics().logLevel());
log::debug("using ini at '{}'", settings.filename());
@@ -429,6 +432,12 @@ int runApplication(
tt.stop();
+ QTimer::singleShot(std::chrono::milliseconds(1), [&]
+ {
+ InstanceManagerDialog dlg(*pluginContainer, &mainWindow);
+ dlg.exec();
+ });
+
res = application.exec();
mainWindow.close();
diff --git a/src/settings.cpp b/src/settings.cpp
index d37f0d99..43e7a4fa 100644
--- a/src/settings.cpp
+++ b/src/settings.cpp
@@ -68,17 +68,24 @@ Settings::Settings(const QString& path) :
m_Network(m_Settings), m_Nexus(*this, m_Settings), m_Steam(*this, m_Settings),
m_Interface(m_Settings), m_Diagnostics(m_Settings)
{
- if (s_Instance != nullptr) {
- throw std::runtime_error("second instance of \"Settings\" created");
- } else {
- s_Instance = this;
- }
}
Settings::~Settings()
{
MOBase::QuestionBoxMemory::setCallbacks({}, {}, {});
- s_Instance = nullptr;
+
+ if (s_Instance == this) {
+ s_Instance = nullptr;
+ }
+}
+
+void Settings::setGlobalInstance()
+{
+ if (s_Instance != nullptr) {
+ throw std::runtime_error("second instance of \"Settings\" created");
+ } else {
+ s_Instance = this;
+ }
}
Settings &Settings::instance()
diff --git a/src/settings.h b/src/settings.h
index a1b30462..84102c72 100644
--- a/src/settings.h
+++ b/src/settings.h
@@ -681,6 +681,7 @@ public:
~Settings();
static Settings &instance();
+ void setGlobalInstance();
// name of the ini file
//
--
cgit v1.3.1
From ea4485857c09fd3ab6879966e7377d3c56951a85 Mon Sep 17 00:00:00 2001
From: isanae <14251494+isanae@users.noreply.github.com>
Date: Thu, 30 Jul 2020 04:36:12 -0400
Subject: filter, explore buttons, instance rename
---
src/createinstancedialog.ui | 21 +++++-
src/createinstancedialogpages.cpp | 62 ++-------------
src/instancemanager.cpp | 9 +++
src/instancemanager.h | 1 +
src/instancemanagerdialog.cpp | 154 ++++++++++++++++++++++++++++++++++++--
src/instancemanagerdialog.h | 12 ++-
src/instancemanagerdialog.ui | 27 ++++++-
7 files changed, 221 insertions(+), 65 deletions(-)
(limited to 'src/instancemanagerdialog.ui')
diff --git a/src/createinstancedialog.ui b/src/createinstancedialog.ui
index a3c3db92..b7f4f502 100644
--- a/src/createinstancedialog.ui
+++ b/src/createinstancedialog.ui
@@ -77,9 +77,12 @@
-
-
+
- Never show this again
+ <html><head/><body><p><a href="https://github.com/ModOrganizer2/modorganizer/wiki/Instance">More information</a></p></body></html>
+
+
+ true
@@ -96,6 +99,13 @@
+ -
+
+
+ Never show this page again
+
+
+
@@ -1202,6 +1212,13 @@
+
+
+ LinkLabel
+ QLabel
+
+
+
diff --git a/src/createinstancedialogpages.cpp b/src/createinstancedialogpages.cpp
index 127243c6..8d304635 100644
--- a/src/createinstancedialogpages.cpp
+++ b/src/createinstancedialogpages.cpp
@@ -21,50 +21,6 @@ QString makeDefaultPath(const std::wstring& dir)
QString::fromStdWString(dir)));
}
-QString sanitizeFileName(const QString& name)
-{
- QString new_name = name;
-
- // Restrict the allowed characters
- new_name = new_name.remove(QRegExp("[^A-Za-z0-9 _=+;!@#$%^'\\-\\.\\[\\]\\{\\}\\(\\)]"));
-
- // Don't end in spaces and periods
- new_name = new_name.remove(QRegExp("\\.*$"));
- new_name = new_name.remove(QRegExp(" *$"));
-
- // Recurse until stuff stops changing
- if (new_name != name) {
- return sanitizeFileName(new_name);
- }
-
- return new_name;
-}
-
-// same thing as above, but allows path separators and colons
-//
-QString sanitizePath(const QString& path)
-{
- QString new_name = path;
-
- // Restrict the allowed characters
- new_name = new_name.remove(QRegExp("[^\\\\\\/A-Za-z0-9 _=+;!@#$%^:'\\-\\.\\[\\]\\{\\}\\(\\)]"));
-
- // Don't end in spaces and periods
- new_name = new_name.remove(QRegExp("\\.*$"));
- new_name = new_name.remove(QRegExp(" *$"));
-
- // Recurse until stuff stops changing
- if (new_name != path) {
- return sanitizeFileName(new_name);
- }
-
- return new_name;
-}
-
-void setPossiblePlaceholder(
- QLabel* label, const QString& s, const QString& arg)
-{
-}
PlaceholderLabel::PlaceholderLabel(QLabel* label)
@@ -762,7 +718,7 @@ QString NamePage::selectedInstanceName() const
}
const auto text = ui->instanceName->text().trimmed();
- return sanitizeFileName(text);
+ return InstanceManager::instance().sanitizeInstanceName(text);
}
void NamePage::onChanged()
@@ -790,12 +746,10 @@ bool NamePage::checkName(QString parentDir, QString name)
if (name.isEmpty()) {
empty = true;
} else {
- const QString sanitized = sanitizeFileName(name);
-
- if (name != sanitized) {
- invalid = true;
- } else {
+ if (InstanceManager::instance().validInstanceName(name)) {
exists = QDir(parentDir).exists(name);
+ } else {
+ invalid = true;
}
}
@@ -963,11 +917,9 @@ bool PathsPage::checkPath(
if (path.isEmpty()) {
empty = true;
} else {
- const QString sanitized = sanitizePath(path);
+ const QDir d(path);
- if (path != sanitized) {
- invalid = true;
- } else {
+ if (InstanceManager::instance().validInstanceName(d.dirName())) {
if (m_dlg.instanceType() == CreateInstanceDialog::Portable) {
// the default data path for a portable instance is the application
// directory, so it's not an error if it exists
@@ -977,6 +929,8 @@ bool PathsPage::checkPath(
} else {
exists = QDir(path).exists();
}
+ } else {
+ invalid = true;
}
}
diff --git a/src/instancemanager.cpp b/src/instancemanager.cpp
index b6798fa9..111f948b 100644
--- a/src/instancemanager.cpp
+++ b/src/instancemanager.cpp
@@ -676,3 +676,12 @@ QString InstanceManager::sanitizeInstanceName(const QString &name) const
}
return new_name;
}
+
+bool InstanceManager::validInstanceName(const QString& instanceName) const
+{
+ if (instanceName.isEmpty()) {
+ return false;
+ }
+
+ return (instanceName == sanitizeInstanceName(instanceName));
+}
diff --git a/src/instancemanager.h b/src/instancemanager.h
index 9250ffe9..33e115a7 100644
--- a/src/instancemanager.h
+++ b/src/instancemanager.h
@@ -63,6 +63,7 @@ public:
QString sanitizeInstanceName(const QString &name) const;
QString makeUniqueName(const QString& instanceName) const;
bool instanceExists(const QString& instanceName) const;
+ bool validInstanceName(const QString& instanceName) const;
QString instancePath(const QString& instanceName) const;
private:
diff --git a/src/instancemanagerdialog.cpp b/src/instancemanagerdialog.cpp
index a038d3c2..aa6bdb04 100644
--- a/src/instancemanagerdialog.cpp
+++ b/src/instancemanagerdialog.cpp
@@ -8,8 +8,12 @@
#include "shared/appconfig.h"
#include
+namespace shell = MOBase::shell;
+
void openInstanceManager(PluginContainer& pc, QWidget* parent)
{
+ //CreateInstanceDialog dlg(pc, parent);
+ //dlg.exec();
InstanceManagerDialog dlg(pc, parent);
dlg.exec();
}
@@ -77,12 +81,20 @@ InstanceManagerDialog::InstanceManagerDialog(
ui->splitter->setStretchFactor(0, 0);
ui->splitter->setStretchFactor(1, 1);
+ auto* model = new QStandardItemModel;
+ ui->list->setModel(model);
+
+ m_filter.setEdit(ui->filter);
+ m_filter.setList(ui->list);
+ m_filter.setUpdateDelay(false);
+ m_filter.setFilteredBorder(false);
+
auto& m = InstanceManager::instance();
for (auto&& d : m.instancePaths()) {
auto ii = std::make_unique(d);
- ui->list->addItem(ii->name());
+ model->appendRow(new QStandardItem(ii->name()));
m_instances.push_back(std::move(ii));
}
@@ -91,8 +103,12 @@ InstanceManagerDialog::InstanceManagerDialog(
}
connect(ui->createNew, &QPushButton::clicked, [&]{ createNew(); });
- connect(ui->list, &QListWidget::itemSelectionChanged, [&]{ onSelection(); });
+ connect(ui->list->selectionModel(), &QItemSelectionModel::selectionChanged, [&]{ onSelection(); });
//connect(ui->list, &QListWidget::itemActivated, [&]{ openSelectedInstance(); });
+ connect(ui->rename, &QPushButton::clicked, [&]{ rename(); });
+ connect(ui->exploreLocation, &QPushButton::clicked, [&]{ exploreLocation(); });
+ connect(ui->exploreBaseDirectory, &QPushButton::clicked, [&]{ exploreBaseDirectory(); });
+ connect(ui->exploreGame, &QPushButton::clicked, [&]{ exploreGame(); });
}
InstanceManagerDialog::~InstanceManagerDialog() = default;
@@ -105,11 +121,15 @@ void InstanceManagerDialog::select(std::size_t i)
const auto& ii = m_instances[i];
fill(*ii);
+
+ ui->list->selectionModel()->select(
+ m_filter.mapFromSource(m_filter.sourceModel()->index(i, 0)),
+ QItemSelectionModel::ClearAndSelect);
}
void InstanceManagerDialog::openSelectedInstance()
{
- const auto i = singleSelection();
+ const auto i = singleSelectionIndex();
if (i == NoSelection) {
return;
}
@@ -117,9 +137,107 @@ void InstanceManagerDialog::openSelectedInstance()
InstanceManager::instance().switchToInstance(m_instances[i]->name());
}
+void InstanceManagerDialog::rename()
+{
+ auto* i = singleSelection();
+ if (!i) {
+ return;
+ }
+
+ auto& m = InstanceManager::instance();
+ if (m.currentInstance() == i->name()) {
+ QMessageBox::information(this,
+ tr("Rename instance"), tr("The active instance cannot be renamed"));
+ return;
+ }
+
+ QDialog dlg(this);
+ dlg.setWindowTitle(tr("Rename instance"));
+
+ auto* ly = new QVBoxLayout(&dlg);
+
+ auto* bb = new QDialogButtonBox(
+ QDialogButtonBox::Cancel | QDialogButtonBox::Ok);
+
+ auto* text = new QLineEdit(i->name());
+ text->selectAll();
+
+ auto* error = new QLabel;
+
+ ly->addWidget(new QLabel(tr("Instance name")));
+ ly->addWidget(text);
+ ly->addWidget(error);
+ ly->addStretch();
+ ly->addWidget(bb);
+
+ connect(text, &QLineEdit::textChanged, [&] {
+ bool okay = false;
+
+ if (!m.validInstanceName(text->text())) {
+ error->setText(tr("The instance name must be a valid folder name."));
+ } else {
+ const auto name = m.sanitizeInstanceName(text->text());
+
+ if ((name != i->name()) && m.instanceExists(text->text())) {
+ error->setText(tr("An instance with this name already exists."));
+ } else {
+ okay = true;
+ }
+ }
+
+ error->setVisible(!okay);
+ bb->button(QDialogButtonBox::Ok)->setEnabled(okay);
+ });
+
+ connect(bb, &QDialogButtonBox::accepted, [&]{ dlg.accept(); });
+ connect(bb, &QDialogButtonBox::rejected, [&]{ dlg.reject(); });
+
+ dlg.resize({400, 120});
+ if (dlg.exec() != QDialog::Accepted) {
+ return;
+ }
+
+
+ const QString newName = m.sanitizeInstanceName(text->text());
+ const QString src = QDir::toNativeSeparators(i->location());
+ const QString dest = QDir::toNativeSeparators(
+ QFileInfo(i->location()).dir().path() + "/" + newName);
+
+ const auto r = shell::Rename(src, dest, false);
+ if (!r) {
+ QMessageBox::critical(
+ this, tr("Error"),
+ tr("Failed to rename \"%1\" to \"%2\": %3")
+ .arg(src).arg(dest).arg(r.toString()));
+
+ return;
+ }
+}
+
+void InstanceManagerDialog::exploreLocation()
+{
+ if (const auto* i=singleSelection()) {
+ shell::Explore(i->location());
+ }
+}
+
+void InstanceManagerDialog::exploreBaseDirectory()
+{
+ if (const auto* i=singleSelection()) {
+ shell::Explore(i->baseDirectory());
+ }
+}
+
+void InstanceManagerDialog::exploreGame()
+{
+ if (const auto* i=singleSelection()) {
+ shell::Explore(i->gamePath());
+ }
+}
+
void InstanceManagerDialog::onSelection()
{
- const auto i = singleSelection();
+ const auto i = singleSelectionIndex();
if (i == NoSelection) {
return;
}
@@ -133,14 +251,36 @@ void InstanceManagerDialog::createNew()
dlg.exec();
}
-std::size_t InstanceManagerDialog::singleSelection() const
+std::size_t InstanceManagerDialog::singleSelectionIndex() const
{
- const auto sel = ui->list->selectionModel()->selectedIndexes();
+ const auto sel = m_filter.mapSelectionToSource(
+ ui->list->selectionModel()->selection());
+
if (sel.size() != 1) {
return NoSelection;
}
- return static_cast(sel[0].row());
+ return static_cast(sel.indexes()[0].row());
+}
+
+InstanceInfo* InstanceManagerDialog::singleSelection()
+{
+ const auto i = singleSelectionIndex();
+ if (i == NoSelection) {
+ return nullptr;
+ }
+
+ return m_instances[i].get();
+}
+
+const InstanceInfo* InstanceManagerDialog::singleSelection() const
+{
+ const auto i = singleSelectionIndex();
+ if (i == NoSelection) {
+ return nullptr;
+ }
+
+ return m_instances[i].get();
}
void InstanceManagerDialog::fill(const InstanceInfo& ii)
diff --git a/src/instancemanagerdialog.h b/src/instancemanagerdialog.h
index 6dbf015f..529a99b8 100644
--- a/src/instancemanagerdialog.h
+++ b/src/instancemanagerdialog.h
@@ -1,6 +1,7 @@
#ifndef MODORGANIZER_INSTANCEMANAGERDIALOG_INCLUDED
#define MODORGANIZER_INSTANCEMANAGERDIALOG_INCLUDED
+#include
#include
namespace Ui { class InstanceManagerDialog; };
@@ -21,17 +22,26 @@ public:
void select(std::size_t i);
void openSelectedInstance();
+ void rename();
+ void exploreLocation();
+ void exploreBaseDirectory();
+ void exploreGame();
+
private:
static const std::size_t NoSelection = -1;
std::unique_ptr ui;
const PluginContainer& m_pc;
std::vector> m_instances;
+ MOBase::FilterWidget m_filter;
void onSelection();
void createNew();
- std::size_t singleSelection() const;
+ std::size_t singleSelectionIndex() const;
+ InstanceInfo* singleSelection();
+ const InstanceInfo* singleSelection() const;
+
void fill(const InstanceInfo& ii);
};
diff --git a/src/instancemanagerdialog.ui b/src/instancemanagerdialog.ui
index 146b5fb5..08894ec1 100644
--- a/src/instancemanagerdialog.ui
+++ b/src/instancemanagerdialog.ui
@@ -103,7 +103,32 @@
0
-
-
+
+
+ -
+
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
-
+
+
+ Filter
+
+
+
+
+
--
cgit v1.3.1
From 5fc6b0cd142b18ea574381580752ef6647102c9f Mon Sep 17 00:00:00 2001
From: isanae <14251494+isanae@users.noreply.github.com>
Date: Fri, 31 Jul 2020 09:07:40 -0400
Subject: renamed cancel to close add portable instance to the list, handle
some of the buttons
---
src/instancemanagerdialog.cpp | 102 +++++++++++++++++++++++++++++++++---------
src/instancemanagerdialog.h | 6 ++-
src/instancemanagerdialog.ui | 6 +--
3 files changed, 88 insertions(+), 26 deletions(-)
(limited to 'src/instancemanagerdialog.ui')
diff --git a/src/instancemanagerdialog.cpp b/src/instancemanagerdialog.cpp
index aa6bdb04..99ade7ad 100644
--- a/src/instancemanagerdialog.cpp
+++ b/src/instancemanagerdialog.cpp
@@ -21,15 +21,19 @@ void openInstanceManager(PluginContainer& pc, QWidget* parent)
class InstanceInfo
{
public:
- InstanceInfo(QDir dir) :
- m_dir(std::move(dir)),
+ InstanceInfo(QDir dir, bool isPortable) :
+ m_dir(std::move(dir)), m_portable(isPortable),
m_settings(dir.filePath(QString::fromStdWString(AppConfig::iniFileName())))
{
}
QString name() const
{
- return m_dir.dirName();
+ if (m_portable) {
+ return QObject::tr("Portable");
+ } else {
+ return m_dir.dirName();
+ }
}
QString gameName() const
@@ -66,52 +70,83 @@ public:
return m_settings.paths().base();
}
+ bool isPortable() const
+ {
+ return m_portable;
+ }
+
private:
QDir m_dir;
+ bool m_portable;
Settings m_settings;
};
+InstanceManagerDialog::~InstanceManagerDialog() = default;
+
InstanceManagerDialog::InstanceManagerDialog(
- const PluginContainer& pc, QWidget *parent)
- : QDialog(parent), ui(new Ui::InstanceManagerDialog), m_pc(pc)
+ const PluginContainer& pc, QWidget *parent) :
+ QDialog(parent), ui(new Ui::InstanceManagerDialog), m_pc(pc),
+ m_model(nullptr)
{
ui->setupUi(this);
ui->splitter->setSizes({200, 1});
ui->splitter->setStretchFactor(0, 0);
ui->splitter->setStretchFactor(1, 1);
- auto* model = new QStandardItemModel;
- ui->list->setModel(model);
+ m_model = new QStandardItemModel;
+ ui->list->setModel(m_model);
m_filter.setEdit(ui->filter);
m_filter.setList(ui->list);
m_filter.setUpdateDelay(false);
m_filter.setFilteredBorder(false);
- auto& m = InstanceManager::instance();
-
- for (auto&& d : m.instancePaths()) {
- auto ii = std::make_unique(d);
-
- model->appendRow(new QStandardItem(ii->name()));
- m_instances.push_back(std::move(ii));
- }
-
- if (!m_instances.empty()) {
- select(0);
- }
+ updateInstances();
+ updateList();
connect(ui->createNew, &QPushButton::clicked, [&]{ createNew(); });
+
connect(ui->list->selectionModel(), &QItemSelectionModel::selectionChanged, [&]{ onSelection(); });
//connect(ui->list, &QListWidget::itemActivated, [&]{ openSelectedInstance(); });
+
connect(ui->rename, &QPushButton::clicked, [&]{ rename(); });
connect(ui->exploreLocation, &QPushButton::clicked, [&]{ exploreLocation(); });
connect(ui->exploreBaseDirectory, &QPushButton::clicked, [&]{ exploreBaseDirectory(); });
connect(ui->exploreGame, &QPushButton::clicked, [&]{ exploreGame(); });
+
+ connect(ui->switchToInstance, &QPushButton::clicked, [&]{ openSelectedInstance(); });
+ connect(ui->close, &QPushButton::clicked, [&]{ close(); });
}
-InstanceManagerDialog::~InstanceManagerDialog() = default;
+void InstanceManagerDialog::updateInstances()
+{
+ auto& m = InstanceManager::instance();
+
+ m_instances.clear();
+
+ if (m.portableInstanceExists()) {
+ m_instances.push_back(std::make_unique(
+ m.portablePath(), true));
+ }
+
+ for (auto&& d : m.instancePaths()) {
+ m_instances.push_back(std::make_unique(d, false));
+ }
+}
+
+void InstanceManagerDialog::updateList()
+{
+ m_model->clear();
+
+ for (auto&& ii : m_instances) {
+ m_model->appendRow(new QStandardItem(ii->name()));
+ }
+
+ if (!m_instances.empty()) {
+ select(0);
+ }
+}
void InstanceManagerDialog::select(std::size_t i)
{
@@ -120,7 +155,7 @@ void InstanceManagerDialog::select(std::size_t i)
}
const auto& ii = m_instances[i];
- fill(*ii);
+ fillData(*ii);
ui->list->selectionModel()->select(
m_filter.mapFromSource(m_filter.sourceModel()->index(i, 0)),
@@ -212,6 +247,8 @@ void InstanceManagerDialog::rename()
return;
}
+
+
}
void InstanceManagerDialog::exploreLocation()
@@ -283,11 +320,32 @@ const InstanceInfo* InstanceManagerDialog::singleSelection() const
return m_instances[i].get();
}
-void InstanceManagerDialog::fill(const InstanceInfo& ii)
+void InstanceManagerDialog::fillData(const InstanceInfo& ii)
{
ui->name->setText(ii.name());
ui->location->setText(ii.location());
ui->baseDirectory->setText(ii.baseDirectory());
ui->gameName->setText(ii.gameName());
ui->gameDir->setText(ii.gamePath());
+
+ const auto& m = InstanceManager::instance();
+
+ ui->rename->setEnabled(!ii.isPortable());
+
+ if (ii.isPortable()) {
+ ui->convertToPortable->setVisible(false);
+ ui->convertToGlobal->setVisible(true);
+ ui->convertToGlobal->setEnabled(true);
+ } else {
+ ui->convertToPortable->setVisible(true);
+ ui->convertToGlobal->setVisible(false);
+
+ if (m.portableInstanceExists()) {
+ ui->convertToPortable->setEnabled(false);
+ ui->convertToPortable->setToolTip(tr("A portable instance already exists."));
+ } else {
+ ui->convertToPortable->setEnabled(false);
+ ui->convertToPortable->setToolTip("");
+ }
+ }
}
diff --git a/src/instancemanagerdialog.h b/src/instancemanagerdialog.h
index 529a99b8..d102facb 100644
--- a/src/instancemanagerdialog.h
+++ b/src/instancemanagerdialog.h
@@ -34,6 +34,9 @@ private:
const PluginContainer& m_pc;
std::vector> m_instances;
MOBase::FilterWidget m_filter;
+ QStandardItemModel* m_model;
+
+ void updateInstances();
void onSelection();
void createNew();
@@ -42,7 +45,8 @@ private:
InstanceInfo* singleSelection();
const InstanceInfo* singleSelection() const;
- void fill(const InstanceInfo& ii);
+ void updateList();
+ void fillData(const InstanceInfo& ii);
};
#endif // MODORGANIZER_INSTANCEMANAGERDIALOG_INCLUDED
diff --git a/src/instancemanagerdialog.ui b/src/instancemanagerdialog.ui
index 08894ec1..8bf28ed6 100644
--- a/src/instancemanagerdialog.ui
+++ b/src/instancemanagerdialog.ui
@@ -382,7 +382,7 @@
-
-
+
Switch to this instance
@@ -393,9 +393,9 @@
-
-
+
- Cancel
+ Close
true
--
cgit v1.3.1
From f7e9724eb1a817bdef372f87ebf96e9692db2bc9 Mon Sep 17 00:00:00 2001
From: isanae <14251494+isanae@users.noreply.github.com>
Date: Fri, 14 Aug 2020 19:44:31 -0400
Subject: delete instance
---
src/instancemanagerdialog.cpp | 268 ++++++++++++++++++++++++++++++++++++++----
src/instancemanagerdialog.h | 7 ++
src/instancemanagerdialog.ui | 24 ++--
3 files changed, 265 insertions(+), 34 deletions(-)
(limited to 'src/instancemanagerdialog.ui')
diff --git a/src/instancemanagerdialog.cpp b/src/instancemanagerdialog.cpp
index 99ade7ad..5f42f409 100644
--- a/src/instancemanagerdialog.cpp
+++ b/src/instancemanagerdialog.cpp
@@ -6,9 +6,11 @@
#include "selectiondialog.h"
#include "plugincontainer.h"
#include "shared/appconfig.h"
+#include
+#include
#include
-namespace shell = MOBase::shell;
+using namespace MOBase;
void openInstanceManager(PluginContainer& pc, QWidget* parent)
{
@@ -54,7 +56,7 @@ public:
QString gamePath() const
{
if (auto n=m_settings.game().directory()) {
- return *n;
+ return QDir::toNativeSeparators(*n);
} else {
return {};
}
@@ -62,12 +64,12 @@ public:
QString location() const
{
- return m_dir.path();
+ return QDir::toNativeSeparators(m_dir.path());
}
QString baseDirectory() const
{
- return m_settings.paths().base();
+ return QDir::toNativeSeparators(m_settings.paths().base());
}
bool isPortable() const
@@ -75,6 +77,19 @@ public:
return m_portable;
}
+ bool isActive() const
+ {
+ auto& m = InstanceManager::instance();
+
+ if (m_portable && m.currentInstance() == "") {
+ return true;
+ } else if (m.currentInstance() == name()) {
+ return true;
+ }
+
+ return false;
+ }
+
private:
QDir m_dir;
bool m_portable;
@@ -90,6 +105,7 @@ InstanceManagerDialog::InstanceManagerDialog(
m_model(nullptr)
{
ui->setupUi(this);
+
ui->splitter->setSizes({200, 1});
ui->splitter->setStretchFactor(0, 0);
ui->splitter->setStretchFactor(1, 1);
@@ -114,6 +130,7 @@ InstanceManagerDialog::InstanceManagerDialog(
connect(ui->exploreLocation, &QPushButton::clicked, [&]{ exploreLocation(); });
connect(ui->exploreBaseDirectory, &QPushButton::clicked, [&]{ exploreBaseDirectory(); });
connect(ui->exploreGame, &QPushButton::clicked, [&]{ exploreGame(); });
+ connect(ui->deleteInstance, &QPushButton::clicked, [&]{ deleteInstance(); });
connect(ui->switchToInstance, &QPushButton::clicked, [&]{ openSelectedInstance(); });
connect(ui->close, &QPushButton::clicked, [&]{ close(); });
@@ -137,29 +154,51 @@ void InstanceManagerDialog::updateInstances()
void InstanceManagerDialog::updateList()
{
+ const auto prevSelIndex = singleSelectionIndex();
+ const auto* prevSel = singleSelection();
+
m_model->clear();
- for (auto&& ii : m_instances) {
- m_model->appendRow(new QStandardItem(ii->name()));
+ const std::size_t NoSel = -1;
+ std::size_t sel = NoSel;
+
+ for (std::size_t i=0; iappendRow(new QStandardItem(ii.name()));
+
+ if (&ii == prevSel) {
+ sel = i;
+ }
}
- if (!m_instances.empty()) {
- select(0);
+
+ if (m_instances.empty()) {
+ select(-1);
+ } else {
+ if (sel == NoSel) {
+ if (prevSelIndex >= m_instances.size()) {
+ sel = m_instances.size() - 1;
+ } else {
+ sel = prevSelIndex;
+ }
+ }
+
+ select(sel);
}
}
void InstanceManagerDialog::select(std::size_t i)
{
- if (i >= m_instances.size()) {
- return;
- }
-
- const auto& ii = m_instances[i];
- fillData(*ii);
+ if (i < m_instances.size()) {
+ const auto& ii = m_instances[i];
+ fillData(*ii);
- ui->list->selectionModel()->select(
- m_filter.mapFromSource(m_filter.sourceModel()->index(i, 0)),
- QItemSelectionModel::ClearAndSelect);
+ ui->list->selectionModel()->select(
+ m_filter.mapFromSource(m_filter.sourceModel()->index(i, 0)),
+ QItemSelectionModel::ClearAndSelect);
+ } else {
+ clearData();
+ }
}
void InstanceManagerDialog::openSelectedInstance()
@@ -180,9 +219,9 @@ void InstanceManagerDialog::rename()
}
auto& m = InstanceManager::instance();
- if (m.currentInstance() == i->name()) {
+ if (i->isActive()) {
QMessageBox::information(this,
- tr("Rename instance"), tr("The active instance cannot be renamed"));
+ tr("Rename instance"), tr("The active instance cannot be renamed."));
return;
}
@@ -234,7 +273,7 @@ void InstanceManagerDialog::rename()
const QString newName = m.sanitizeInstanceName(text->text());
- const QString src = QDir::toNativeSeparators(i->location());
+ const QString src = i->location();
const QString dest = QDir::toNativeSeparators(
QFileInfo(i->location()).dir().path() + "/" + newName);
@@ -247,8 +286,6 @@ void InstanceManagerDialog::rename()
return;
}
-
-
}
void InstanceManagerDialog::exploreLocation()
@@ -272,6 +309,160 @@ void InstanceManagerDialog::exploreGame()
}
}
+void InstanceManagerDialog::deleteInstance()
+{
+ const auto* i = singleSelection();
+ if (!i) {
+ return;
+ }
+
+ auto& m = InstanceManager::instance();
+ if (i->isActive()) {
+ QMessageBox::information(this,
+ tr("Deleting instance"), tr("The active instance cannot be deleted."));
+ return;
+ }
+
+ if (i->isPortable()) {
+ deletePortable(*i);
+ } else {
+ deleteGlobal(*i);
+ }
+
+ updateInstances();
+ updateList();
+}
+
+bool InstanceManagerDialog::deletePortable(const InstanceInfo& i)
+{
+ const auto Recycle = QMessageBox::Save;
+ const auto Delete = QMessageBox::Yes;
+ const auto Cancel = QMessageBox::Cancel;
+
+ const std::vector fileNames = {
+ AppConfig::iniFileName(),
+ };
+
+ const std::vector dirNames = {
+ AppConfig::dumpsDir(),
+ AppConfig::downloadPath(),
+ AppConfig::logPath(),
+ AppConfig::modsPath(),
+ AppConfig::overwritePath(),
+ AppConfig::profilesPath(),
+ AppConfig::cachePath()
+ };
+
+ QStringList files;
+ for (const auto& n : fileNames) {
+ files.push_back(QDir::toNativeSeparators(
+ i.location() + "/" + QString::fromStdWString(n)));
+ }
+
+ QStringList dirs;
+ for (const auto& n : dirNames) {
+ dirs.push_back(QDir::toNativeSeparators(
+ i.location() + "/" + QString::fromStdWString(n)));
+ }
+
+ QString details = QObject::tr("These files will be deleted:");
+ for (const auto& f : files) {
+ details += "\n - " + f;
+ }
+
+ details += "\n\n" + QObject::tr("These folders will be deleted:");
+ for (const auto& d : dirs) {
+ details += "\n - " + d;
+ }
+
+
+ QStringList all;
+ all.append(files);
+ all.append(dirs);
+
+
+ const auto r = MOBase::TaskDialog(this)
+ .title(("Deleting portable instance"))
+ .main(tr("This will delete the data of the portable instance."))
+ .content(tr(
+ "The data is in %1. Only the relevant files and folders will be "
+ "deleted. The Mod Organizer installation itself will be untouched.")
+ .arg(i.location()))
+ .details(details)
+ .icon(QMessageBox::Warning)
+ .button({tr("Move the data to the recycle bin"), Recycle})
+ .button({tr("Delete the data permanently"), Delete})
+ .button({tr("Cancel"), Cancel})
+ .exec();
+
+ switch (r)
+ {
+ case Recycle:
+ return doDelete(all, true);
+
+ case Delete:
+ return doDelete(all, false);
+
+ case Cancel: // fall-through
+ default:
+ {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool InstanceManagerDialog::deleteGlobal(const InstanceInfo& i)
+{
+ const auto Recycle = QMessageBox::Save;
+ const auto Delete = QMessageBox::Yes;
+ const auto Cancel = QMessageBox::Cancel;
+
+ const auto r = MOBase::TaskDialog(this)
+ .title(tr("Deleting instance"))
+ .main(tr("The instance folder will be deleted."))
+ .content(i.location())
+ .icon(QMessageBox::Warning)
+ .button({tr("Move the folder to the recycle bin"), Recycle})
+ .button({tr("Delete the folder permanently"), Delete})
+ .button({tr("Cancel"), Cancel})
+ .exec();
+
+ switch (r)
+ {
+ case Recycle:
+ return doDelete(QStringList(i.location()), true);
+
+ case Delete:
+ return doDelete(QStringList(i.location()), false);
+
+ case Cancel: // fall-through
+ default:
+ {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool InstanceManagerDialog::doDelete(const QStringList& files, bool recycle)
+{
+ if (MOBase::shellDelete(files, recycle, this)) {
+ return true;
+ }
+
+ const auto e = GetLastError();
+ if (e == ERROR_CANCELLED) {
+ log::debug("deletion cancelled by user");
+ } else {
+ log::error("failed to delete, {}", formatSystemMessage(e));
+ }
+
+ return false;
+}
+
void InstanceManagerDialog::onSelection()
{
const auto i = singleSelectionIndex();
@@ -327,6 +518,7 @@ void InstanceManagerDialog::fillData(const InstanceInfo& ii)
ui->baseDirectory->setText(ii.baseDirectory());
ui->gameName->setText(ii.gameName());
ui->gameDir->setText(ii.gamePath());
+ setButtonsEnabled(true);
const auto& m = InstanceManager::instance();
@@ -348,4 +540,36 @@ void InstanceManagerDialog::fillData(const InstanceInfo& ii)
ui->convertToPortable->setToolTip("");
}
}
+
+
+ // these are not currently implemented; the ui sets them correctly above,
+ // but force them hidden for now
+ ui->convertToPortable->setVisible(false);
+ ui->convertToGlobal->setVisible(false);
+}
+
+void InstanceManagerDialog::clearData()
+{
+ ui->name->clear();
+ ui->location->clear();
+ ui->baseDirectory->clear();
+ ui->gameName->clear();
+ ui->gameDir->clear();
+
+ setButtonsEnabled(false);
+
+ ui->convertToPortable->setVisible(false);
+ ui->convertToGlobal->setVisible(false);
+}
+
+void InstanceManagerDialog::setButtonsEnabled(bool b)
+{
+ ui->rename->setEnabled(b);
+ ui->exploreLocation->setEnabled(b);
+ ui->exploreBaseDirectory->setEnabled(b);
+ ui->exploreGame->setEnabled(b);
+ ui->convertToPortable->setEnabled(b);
+ ui->convertToGlobal->setEnabled(b);
+ ui->deleteInstance->setEnabled(b);
+ ui->switchToInstance->setEnabled(b);
}
diff --git a/src/instancemanagerdialog.h b/src/instancemanagerdialog.h
index d102facb..3daa0800 100644
--- a/src/instancemanagerdialog.h
+++ b/src/instancemanagerdialog.h
@@ -26,6 +26,7 @@ public:
void exploreLocation();
void exploreBaseDirectory();
void exploreGame();
+ void deleteInstance();
private:
static const std::size_t NoSelection = -1;
@@ -47,6 +48,12 @@ private:
void updateList();
void fillData(const InstanceInfo& ii);
+ void clearData();
+ void setButtonsEnabled(bool b);
+
+ bool deletePortable(const InstanceInfo& ii);
+ bool deleteGlobal(const InstanceInfo& ii);
+ bool doDelete(const QStringList& files, bool recycle);
};
#endif // MODORGANIZER_INSTANCEMANAGERDIALOG_INCLUDED
diff --git a/src/instancemanagerdialog.ui b/src/instancemanagerdialog.ui
index 8bf28ed6..a8e5e2b7 100644
--- a/src/instancemanagerdialog.ui
+++ b/src/instancemanagerdialog.ui
@@ -305,18 +305,7 @@
-
-
-
- Delete instance
-
-
-
- :/MO/gui/remove:/MO/gui/remove
-
-
-
- -
-
+
Qt::Horizontal
@@ -328,6 +317,17 @@
+ -
+
+
+ Delete instance
+
+
+
+ :/MO/gui/remove:/MO/gui/remove
+
+
+
--
cgit v1.3.1
From 003ef66d2ff8e83e864d362f152a6f87ae05cbc4 Mon Sep 17 00:00:00 2001
From: isanae <14251494+isanae@users.noreply.github.com>
Date: Sat, 15 Aug 2020 20:53:42 -0400
Subject: - changed PathSettings::base() to use the ini's parent directory
instead of the global "dataPath" property; this is always the same thing,
unless another Settings object is created for a different instance than the
active one, which happens in the instance manager dialog - instance manager
dialog: - select the active instance when opening - instance deletion
now handles custom paths from the ini - started on instance conversions,
not functional
---
src/instancemanagerdialog.cpp | 455 +++++++++++++++++++++++++++++-------------
src/instancemanagerdialog.h | 3 +
src/instancemanagerdialog.ui | 6 +-
src/settings.cpp | 4 +-
4 files changed, 328 insertions(+), 140 deletions(-)
(limited to 'src/instancemanagerdialog.ui')
diff --git a/src/instancemanagerdialog.cpp b/src/instancemanagerdialog.cpp
index 5f42f409..a91e3d92 100644
--- a/src/instancemanagerdialog.cpp
+++ b/src/instancemanagerdialog.cpp
@@ -20,12 +20,17 @@ void openInstanceManager(PluginContainer& pc, QWidget* parent)
dlg.exec();
}
+QString iniFile(const QDir& dir)
+{
+ return dir.filePath(QString::fromStdWString(AppConfig::iniFileName()));
+}
+
+
class InstanceInfo
{
public:
InstanceInfo(QDir dir, bool isPortable) :
- m_dir(std::move(dir)), m_portable(isPortable),
- m_settings(dir.filePath(QString::fromStdWString(AppConfig::iniFileName())))
+ m_dir(std::move(dir)), m_portable(isPortable), m_settings(iniFile(dir))
{
}
@@ -90,6 +95,154 @@ public:
return false;
}
+ // returns a list of files and folders that must be deleted when deleting
+ // this instance
+ //
+ QStringList filesForDeletion() const
+ {
+ // native separators and ending slash
+ auto prettyDir = [](auto s) {
+ if (!s.endsWith("/") || !s.endsWith("\\")) {
+ s += "/";
+ }
+
+ return QDir::toNativeSeparators(s);
+ };
+
+ // native separators
+ auto prettyFile = [](auto s) {
+ return QDir::toNativeSeparators(s);
+ };
+
+
+ // lowercase, native separators and ending slash
+ auto canonicalDir = [](auto s) {
+ s = s.toLower();
+ if (!s.endsWith("/") || !s.endsWith("\\")) {
+ s += "/";
+ }
+
+ return QDir::toNativeSeparators(s);
+ };
+
+ // lower and native separators
+ auto canonicalFile = [](auto s) {
+ return QDir::toNativeSeparators(s.toLower());
+ };
+
+
+
+ // whether the given directory is contained in the root
+ auto dirInRoot = [&](auto root, auto dir) {
+ return canonicalDir(dir).startsWith(canonicalDir(root));
+ };
+
+ // whether the given file is contained in the root
+ auto fileInRoot = [&](auto root, auto file) {
+ return canonicalFile(file).startsWith(canonicalDir(root));
+ };
+
+
+
+
+ const auto loc = location();
+ const auto base = m_settings.paths().base();
+
+
+ // directories that might contain the individual files and directories
+ // set in the path settings
+ QStringList roots;
+
+ // a portable instance has its location in the installation directory,
+ // don't delete that
+ if (!isPortable()) {
+ roots.append(loc);
+ }
+
+ // the base directory is the location directory by default, don't add it
+ // if it's the same
+ if (canonicalDir(base) != canonicalDir(loc)) {
+ roots.append(base);
+ }
+
+
+ // all the directories that are part of an instance
+ const QStringList dirs = {
+ m_settings.paths().downloads(),
+ m_settings.paths().mods(),
+ m_settings.paths().overwrite(),
+ m_settings.paths().profiles(),
+ m_settings.paths().cache(),
+ m_dir.filePath(QString::fromStdWString(AppConfig::dumpsDir())),
+ m_dir.filePath(QString::fromStdWString(AppConfig::logPath())),
+ };
+
+ // all the files that are part of an instance
+ const QStringList files = {
+ iniFile(m_dir),
+ };
+
+
+ // this will contain the root directories, plus all the individual
+ // directories that are not inside these roots
+ QStringList cleanDirs;
+
+ for (const auto& f : dirs) {
+ bool inRoots = false;
+
+ for (const auto& root : roots) {
+ if (dirInRoot(root, f)) {
+ inRoots = true;
+ break;
+ }
+ }
+
+ if (!inRoots) {
+ // not in roots, this is a path that was changed by the user
+ cleanDirs.append(prettyDir(f));
+ }
+ }
+
+ // adding the roots
+ for (const auto& root : roots) {
+ cleanDirs.append(prettyDir(root));
+ }
+
+ cleanDirs.sort(Qt::CaseInsensitive);
+
+
+ // this will contain the individual files that are not inside the roots;
+ // not that this only contains the INI file for now, so most of this is
+ // useless
+ QStringList cleanFiles;
+
+ for (const auto& f : files) {
+ bool inRoots = false;
+
+ for (const auto& root : roots) {
+ if (fileInRoot(root, f)) {
+ inRoots = true;
+ break;
+ }
+ }
+
+ if (!inRoots) {
+ // not in roots, this is a path that was changed by the user
+ cleanFiles.append(prettyFile(f));
+ }
+ }
+
+ cleanFiles.sort(Qt::CaseInsensitive);
+
+
+ // contains all the directories and files to be deleted
+ QStringList all;
+ all.append(cleanDirs);
+ all.append(cleanFiles);
+
+ return all;
+ }
+
private:
QDir m_dir;
bool m_portable;
@@ -120,11 +273,12 @@ InstanceManagerDialog::InstanceManagerDialog(
updateInstances();
updateList();
+ selectActiveInstance();
connect(ui->createNew, &QPushButton::clicked, [&]{ createNew(); });
connect(ui->list->selectionModel(), &QItemSelectionModel::selectionChanged, [&]{ onSelection(); });
- //connect(ui->list, &QListWidget::itemActivated, [&]{ openSelectedInstance(); });
+ connect(ui->list, &QListView::activated, [&]{ openSelectedInstance(); });
connect(ui->rename, &QPushButton::clicked, [&]{ rename(); });
connect(ui->exploreLocation, &QPushButton::clicked, [&]{ exploreLocation(); });
@@ -132,6 +286,9 @@ InstanceManagerDialog::InstanceManagerDialog(
connect(ui->exploreGame, &QPushButton::clicked, [&]{ exploreGame(); });
connect(ui->deleteInstance, &QPushButton::clicked, [&]{ deleteInstance(); });
+ connect(ui->convertToGlobal, &QPushButton::clicked, [&]{ convertToGlobal(); });
+ connect(ui->convertToPortable, &QPushButton::clicked, [&]{ convertToPortable(); });
+
connect(ui->switchToInstance, &QPushButton::clicked, [&]{ openSelectedInstance(); });
connect(ui->close, &QPushButton::clicked, [&]{ close(); });
}
@@ -171,19 +328,22 @@ void InstanceManagerDialog::updateList()
}
}
-
- if (m_instances.empty()) {
- select(-1);
- } else {
- if (sel == NoSel) {
- if (prevSelIndex >= m_instances.size()) {
- sel = m_instances.size() - 1;
- } else {
- sel = prevSelIndex;
+ // keep current selection or select the next one if there was a selection;
+ // there's no selection when opening the dialog, that's handled in the ctor
+ if (prevSel) {
+ if (m_instances.empty()) {
+ select(-1);
+ } else {
+ if (sel == NoSel) {
+ if (prevSelIndex >= m_instances.size()) {
+ sel = m_instances.size() - 1;
+ } else {
+ sel = prevSelIndex;
+ }
}
- }
- select(sel);
+ select(sel);
+ }
}
}
@@ -201,6 +361,24 @@ void InstanceManagerDialog::select(std::size_t i)
}
}
+void InstanceManagerDialog::selectActiveInstance()
+{
+ const auto active = InstanceManager::instance().currentInstance();
+
+ for (std::size_t i=0; iname() == active) {
+ select(i);
+
+ ui->list->scrollTo(
+ m_filter.mapFromSource(m_filter.sourceModel()->index(i, 0)));
+
+ return;
+ }
+ }
+
+ select(0);
+}
+
void InstanceManagerDialog::openSelectedInstance()
{
const auto i = singleSelectionIndex();
@@ -211,49 +389,53 @@ void InstanceManagerDialog::openSelectedInstance()
InstanceManager::instance().switchToInstance(m_instances[i]->name());
}
-void InstanceManagerDialog::rename()
+QString getInstanceName(
+ QWidget* parent, const QString& title, const QString& moreText,
+ const QString& label, const QString& oldName={})
{
- auto* i = singleSelection();
- if (!i) {
- return;
- }
-
auto& m = InstanceManager::instance();
- if (i->isActive()) {
- QMessageBox::information(this,
- tr("Rename instance"), tr("The active instance cannot be renamed."));
- return;
- }
- QDialog dlg(this);
- dlg.setWindowTitle(tr("Rename instance"));
+ QDialog dlg(parent);
+ dlg.setWindowTitle(title);
auto* ly = new QVBoxLayout(&dlg);
auto* bb = new QDialogButtonBox(
QDialogButtonBox::Cancel | QDialogButtonBox::Ok);
- auto* text = new QLineEdit(i->name());
+ auto* text = new QLineEdit(oldName);
text->selectAll();
auto* error = new QLabel;
- ly->addWidget(new QLabel(tr("Instance name")));
+ if (!moreText.isEmpty()) {
+ auto* lb = new QLabel(moreText);
+ lb->setWordWrap(true);
+ ly->addWidget(lb);
+ ly->addSpacing(10);
+ }
+
+ auto* lb = new QLabel(label);
+ lb->setWordWrap(true);
+ ly->addWidget(lb);
+
ly->addWidget(text);
ly->addWidget(error);
ly->addStretch();
ly->addWidget(bb);
- connect(text, &QLineEdit::textChanged, [&] {
+ auto check = [&] {
bool okay = false;
- if (!m.validInstanceName(text->text())) {
- error->setText(tr("The instance name must be a valid folder name."));
+ if (text->text().isEmpty()) {
+ error->setText("");
+ } else if (!m.validInstanceName(text->text())) {
+ error->setText(QObject::tr("The instance name must be a valid folder name."));
} else {
const auto name = m.sanitizeInstanceName(text->text());
- if ((name != i->name()) && m.instanceExists(text->text())) {
- error->setText(tr("An instance with this name already exists."));
+ if ((name != oldName) && m.instanceExists(text->text())) {
+ error->setText(QObject::tr("An instance with this name already exists."));
} else {
okay = true;
}
@@ -261,18 +443,43 @@ void InstanceManagerDialog::rename()
error->setVisible(!okay);
bb->button(QDialogButtonBox::Ok)->setEnabled(okay);
- });
+ };
+
+ QObject::connect(text, &QLineEdit::textChanged, [&] { check(); });
+ QObject::connect(bb, &QDialogButtonBox::accepted, [&]{ dlg.accept(); });
+ QObject::connect(bb, &QDialogButtonBox::rejected, [&]{ dlg.reject(); });
- connect(bb, &QDialogButtonBox::accepted, [&]{ dlg.accept(); });
- connect(bb, &QDialogButtonBox::rejected, [&]{ dlg.reject(); });
+ check();
dlg.resize({400, 120});
if (dlg.exec() != QDialog::Accepted) {
+ return {};
+ }
+
+ return m.sanitizeInstanceName(text->text());
+}
+
+void InstanceManagerDialog::rename()
+{
+ auto* i = singleSelection();
+ if (!i) {
return;
}
+ auto& m = InstanceManager::instance();
+ if (i->isActive()) {
+ QMessageBox::information(this,
+ tr("Rename instance"), tr("The active instance cannot be renamed."));
+ return;
+ }
+
+ const auto newName = getInstanceName(
+ this, tr("Rename instance"), "", tr("Instance name"), i->name());
+
+ if (newName.isEmpty()) {
+ return;
+ }
- const QString newName = m.sanitizeInstanceName(text->text());
const QString src = i->location();
const QString dest = QDir::toNativeSeparators(
QFileInfo(i->location()).dir().path() + "/" + newName);
@@ -323,130 +530,71 @@ void InstanceManagerDialog::deleteInstance()
return;
}
- if (i->isPortable()) {
- deletePortable(*i);
- } else {
- deleteGlobal(*i);
- }
-
- updateInstances();
- updateList();
-}
-
-bool InstanceManagerDialog::deletePortable(const InstanceInfo& i)
-{
const auto Recycle = QMessageBox::Save;
const auto Delete = QMessageBox::Yes;
const auto Cancel = QMessageBox::Cancel;
- const std::vector fileNames = {
- AppConfig::iniFileName(),
- };
+ const auto files = i->filesForDeletion();
- const std::vector dirNames = {
- AppConfig::dumpsDir(),
- AppConfig::downloadPath(),
- AppConfig::logPath(),
- AppConfig::modsPath(),
- AppConfig::overwritePath(),
- AppConfig::profilesPath(),
- AppConfig::cachePath()
- };
+ MOBase::TaskDialog dlg(this);
- QStringList files;
- for (const auto& n : fileNames) {
- files.push_back(QDir::toNativeSeparators(
- i.location() + "/" + QString::fromStdWString(n)));
- }
+ dlg
+ .title(("Deleting instance"))
+ .main(QObject::tr("These files and folders will be deleted"))
+ .icon(QMessageBox::Warning)
+ .button({tr("Move to the recycle bin"), Recycle})
+ .button({tr("Delete permanently"), Delete})
+ .button({tr("Cancel"), Cancel});
- QStringList dirs;
- for (const auto& n : dirNames) {
- dirs.push_back(QDir::toNativeSeparators(
- i.location() + "/" + QString::fromStdWString(n)));
- }
+ auto* list = new QPlainTextEdit();
+ list->setReadOnly(true);
+ list->setWordWrapMode(QTextOption::NoWrap);
+ list->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
+ list->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
+ list->setMaximumHeight(150);
- QString details = QObject::tr("These files will be deleted:");
for (const auto& f : files) {
- details += "\n - " + f;
- }
-
- details += "\n\n" + QObject::tr("These folders will be deleted:");
- for (const auto& d : dirs) {
- details += "\n - " + d;
+ list->appendPlainText(f);
}
+ list->moveCursor(QTextCursor::MoveOperation::Start);
- QStringList all;
- all.append(files);
- all.append(dirs);
+ dlg.addContent(list);
-
- const auto r = MOBase::TaskDialog(this)
- .title(("Deleting portable instance"))
- .main(tr("This will delete the data of the portable instance."))
- .content(tr(
- "The data is in %1. Only the relevant files and folders will be "
- "deleted. The Mod Organizer installation itself will be untouched.")
- .arg(i.location()))
- .details(details)
- .icon(QMessageBox::Warning)
- .button({tr("Move the data to the recycle bin"), Recycle})
- .button({tr("Delete the data permanently"), Delete})
- .button({tr("Cancel"), Cancel})
- .exec();
+ const auto r = dlg.exec();
switch (r)
{
case Recycle:
- return doDelete(all, true);
-
- case Delete:
- return doDelete(all, false);
-
- case Cancel: // fall-through
- default:
{
- return false;
- }
- }
-
- return true;
-}
-
-bool InstanceManagerDialog::deleteGlobal(const InstanceInfo& i)
-{
- const auto Recycle = QMessageBox::Save;
- const auto Delete = QMessageBox::Yes;
- const auto Cancel = QMessageBox::Cancel;
-
- const auto r = MOBase::TaskDialog(this)
- .title(tr("Deleting instance"))
- .main(tr("The instance folder will be deleted."))
- .content(i.location())
- .icon(QMessageBox::Warning)
- .button({tr("Move the folder to the recycle bin"), Recycle})
- .button({tr("Delete the folder permanently"), Delete})
- .button({tr("Cancel"), Cancel})
- .exec();
+ if (!doDelete(files, true)) {
+ return;
+ }
- switch (r)
- {
- case Recycle:
- return doDelete(QStringList(i.location()), true);
+ break;
+ }
case Delete:
- return doDelete(QStringList(i.location()), false);
+ {
+ if (!doDelete(files, false)) {
+ return;
+ }
+
+ break;
+ }
case Cancel: // fall-through
default:
{
- return false;
+ return;
}
}
- return true;
+ updateInstances();
+ updateList();
}
+
bool InstanceManagerDialog::doDelete(const QStringList& files, bool recycle)
{
if (MOBase::shellDelete(files, recycle, this)) {
@@ -463,6 +611,43 @@ bool InstanceManagerDialog::doDelete(const QStringList& files, bool recycle)
return false;
}
+void InstanceManagerDialog::convertToGlobal()
+{
+ const auto* i = singleSelection();
+ if (!i) {
+ return;
+ }
+
+ if (!i->isPortable()) {
+ log::error("can't convert to global, this is not a portable instance");
+ return;
+ }
+
+ const auto& m = InstanceManager::instance();
+
+ const auto name = getInstanceName(
+ this,
+ tr("Convert to global instance"),
+ tr(
+ "This will move all the instance data currently in Mod Organizer's "
+ "installation folder into a global instance. If the operation fails or "
+ "is cancelled, no data should be lost, but the move will need to be "
+ "completed or cleaned up manually.
"
+ "Source: %1
"
+ "Destination: %2")
+ .arg(i->location())
+ .arg(QDir::toNativeSeparators(m.instancesPath())),
+ tr("Name of the new instance"));
+
+ if (name.isEmpty()) {
+ return;
+ }
+}
+
+void InstanceManagerDialog::convertToPortable()
+{
+}
+
void InstanceManagerDialog::onSelection()
{
const auto i = singleSelectionIndex();
@@ -540,12 +725,6 @@ void InstanceManagerDialog::fillData(const InstanceInfo& ii)
ui->convertToPortable->setToolTip("");
}
}
-
-
- // these are not currently implemented; the ui sets them correctly above,
- // but force them hidden for now
- ui->convertToPortable->setVisible(false);
- ui->convertToGlobal->setVisible(false);
}
void InstanceManagerDialog::clearData()
diff --git a/src/instancemanagerdialog.h b/src/instancemanagerdialog.h
index 3daa0800..659710fe 100644
--- a/src/instancemanagerdialog.h
+++ b/src/instancemanagerdialog.h
@@ -20,6 +20,7 @@ public:
~InstanceManagerDialog();
void select(std::size_t i);
+ void selectActiveInstance();
void openSelectedInstance();
void rename();
@@ -27,6 +28,8 @@ public:
void exploreBaseDirectory();
void exploreGame();
void deleteInstance();
+ void convertToGlobal();
+ void convertToPortable();
private:
static const std::size_t NoSelection = -1;
diff --git a/src/instancemanagerdialog.ui b/src/instancemanagerdialog.ui
index a8e5e2b7..b2abfa4b 100644
--- a/src/instancemanagerdialog.ui
+++ b/src/instancemanagerdialog.ui
@@ -103,7 +103,11 @@
0
-
-
+
+
+ QAbstractItemView::NoEditTriggers
+
+
-
diff --git a/src/settings.cpp b/src/settings.cpp
index a0758bd4..b286510d 100644
--- a/src/settings.cpp
+++ b/src/settings.cpp
@@ -1545,8 +1545,10 @@ QString PathSettings::makeDefaultPath(const QString dirName)
QString PathSettings::base() const
{
+ const QString dataPath = QFileInfo(m_Settings.fileName()).dir().path();
+
return QDir::fromNativeSeparators(get(m_Settings,
- "Settings", "base_directory", qApp->property("dataPath").toString()));
+ "Settings", "base_directory", dataPath));
}
QString PathSettings::downloads(bool resolve) const
--
cgit v1.3.1
From 14d15070c8b24e73297a6f37132b8ad5c6e966ef Mon Sep 17 00:00:00 2001
From: isanae <14251494+isanae@users.noreply.github.com>
Date: Sat, 15 Aug 2020 21:57:08 -0400
Subject: added checkboxes for deleting instances disabled instance conversion
buttons again, not implemented
---
src/instancemanagerdialog.cpp | 178 ++++++++++++++++++++++--------------------
src/instancemanagerdialog.ui | 22 +++---
2 files changed, 104 insertions(+), 96 deletions(-)
(limited to 'src/instancemanagerdialog.ui')
diff --git a/src/instancemanagerdialog.cpp b/src/instancemanagerdialog.cpp
index a91e3d92..5810a255 100644
--- a/src/instancemanagerdialog.cpp
+++ b/src/instancemanagerdialog.cpp
@@ -29,6 +29,29 @@ QString iniFile(const QDir& dir)
class InstanceInfo
{
public:
+ struct Object
+ {
+ QString path;
+ bool mandatoryDelete;
+
+ Object(QString p, bool d=false)
+ : path(std::move(p)), mandatoryDelete(d)
+ {
+ }
+
+ bool operator<(const Object& o) const
+ {
+ if (mandatoryDelete && !o.mandatoryDelete) {
+ return true;
+ } else if (!mandatoryDelete && o.mandatoryDelete) {
+ return false;
+ }
+
+ return false;
+ }
+ };
+
+
InstanceInfo(QDir dir, bool isPortable) :
m_dir(std::move(dir)), m_portable(isPortable), m_settings(iniFile(dir))
{
@@ -98,7 +121,7 @@ public:
// returns a list of files and folders that must be deleted when deleting
// this instance
//
- QStringList filesForDeletion() const
+ std::vector
+ -
+
+
+ Delete instance
+
+
+
+ :/MO/gui/remove:/MO/gui/remove
+
+
+
-
@@ -321,17 +332,6 @@
- -
-
-
- Delete instance
-
-
-
- :/MO/gui/remove:/MO/gui/remove
-
-
-
--
cgit v1.3.1
From a9772873d69b875f5617c0121c73a271d432a29c Mon Sep 17 00:00:00 2001
From: isanae <14251494+isanae@users.noreply.github.com>
Date: Sat, 15 Aug 2020 22:35:19 -0400
Subject: open ini button update when renaming instance update and select when
creating instance
---
src/createinstancedialog.cpp | 13 +++++--
src/createinstancedialog.h | 2 +
src/instancemanagerdialog.cpp | 86 ++++++++++++++++++++++++++++++++++---------
src/instancemanagerdialog.h | 5 ++-
src/instancemanagerdialog.ui | 19 ++++++++++
5 files changed, 103 insertions(+), 22 deletions(-)
(limited to 'src/instancemanagerdialog.ui')
diff --git a/src/createinstancedialog.cpp b/src/createinstancedialog.cpp
index 935b9ee9..f4140e01 100644
--- a/src/createinstancedialog.cpp
+++ b/src/createinstancedialog.cpp
@@ -11,8 +11,9 @@
using namespace MOBase;
CreateInstanceDialog::CreateInstanceDialog(
- const PluginContainer& pc, QWidget *parent)
- : QDialog(parent), ui(new Ui::CreateInstanceDialog), m_pc(pc)
+ const PluginContainer& pc, QWidget *parent) :
+ QDialog(parent), ui(new Ui::CreateInstanceDialog), m_pc(pc),
+ m_switching(false)
{
using namespace cid;
@@ -302,8 +303,9 @@ void CreateInstanceDialog::finish()
if (ui->launch->isChecked()) {
InstanceManager::instance().switchToInstance(ci.instanceName);
+ m_switching = true;
} else {
- close();
+ accept();
}
}
catch(Failed&)
@@ -391,6 +393,11 @@ CreateInstanceDialog::Paths CreateInstanceDialog::paths() const
return getSelected(&cid::Page::selectedPaths);
}
+bool CreateInstanceDialog::switching() const
+{
+ return m_switching;
+}
+
void fixVarDir(QString& path, const std::wstring& defaultDir)
{
if (path.isEmpty()) {
diff --git a/src/createinstancedialog.h b/src/createinstancedialog.h
index 2f5774ae..95d4fa68 100644
--- a/src/createinstancedialog.h
+++ b/src/createinstancedialog.h
@@ -70,6 +70,7 @@ public:
QString instanceName() const;
QString dataPath() const;
Paths paths() const;
+ bool switching() const;
CreationInfo creationInfo() const;
@@ -78,6 +79,7 @@ private:
const PluginContainer& m_pc;
std::vector> m_pages;
QString m_originalNext;
+ bool m_switching;
template
T getSelected(T (cid::Page::*mf)() const) const
diff --git a/src/instancemanagerdialog.cpp b/src/instancemanagerdialog.cpp
index 5810a255..37bdea7b 100644
--- a/src/instancemanagerdialog.cpp
+++ b/src/instancemanagerdialog.cpp
@@ -20,7 +20,7 @@ void openInstanceManager(PluginContainer& pc, QWidget* parent)
dlg.exec();
}
-QString iniFile(const QDir& dir)
+QString makeIniFile(const QDir& dir)
{
return dir.filePath(QString::fromStdWString(AppConfig::iniFileName()));
}
@@ -52,9 +52,16 @@ public:
};
- InstanceInfo(QDir dir, bool isPortable) :
- m_dir(std::move(dir)), m_portable(isPortable), m_settings(iniFile(dir))
+ InstanceInfo(QDir dir, bool isPortable)
+ : m_portable(isPortable)
{
+ setDir(dir);
+ }
+
+ void setDir(const QDir& dir)
+ {
+ m_dir = dir;
+ m_settings.reset(new Settings(makeIniFile(dir)));
}
QString name() const
@@ -68,8 +75,8 @@ public:
QString gameName() const
{
- if (auto n=m_settings.game().name()) {
- if (auto e=m_settings.game().edition()) {
+ if (auto n=m_settings->game().name()) {
+ if (auto e=m_settings->game().edition()) {
if (!e->isEmpty()) {
return *n + " (" + *e + ")";
}
@@ -83,7 +90,7 @@ public:
QString gamePath() const
{
- if (auto n=m_settings.game().directory()) {
+ if (auto n=m_settings->game().directory()) {
return QDir::toNativeSeparators(*n);
} else {
return {};
@@ -97,7 +104,12 @@ public:
QString baseDirectory() const
{
- return QDir::toNativeSeparators(m_settings.paths().base());
+ return QDir::toNativeSeparators(m_settings->paths().base());
+ }
+
+ QString iniFile() const
+ {
+ return makeIniFile(m_dir);
}
bool isPortable() const
@@ -169,7 +181,7 @@ public:
const auto loc = location();
- const auto base = m_settings.paths().base();
+ const auto base = m_settings->paths().base();
// directories that might contain the individual files and directories
@@ -192,18 +204,18 @@ public:
// all the directories that are part of an instance; none of them are
// mandatory for deletion
const std::vector dirs = {
- m_settings.paths().downloads(),
- m_settings.paths().mods(),
- m_settings.paths().cache(),
- m_settings.paths().profiles(),
- m_settings.paths().overwrite(),
+ m_settings->paths().downloads(),
+ m_settings->paths().mods(),
+ m_settings->paths().cache(),
+ m_settings->paths().profiles(),
+ m_settings->paths().overwrite(),
m_dir.filePath(QString::fromStdWString(AppConfig::dumpsDir())),
m_dir.filePath(QString::fromStdWString(AppConfig::logPath())),
};
// all the files that are part of an instance
const std::vector files = {
- {iniFile(m_dir), true}, // the ini file must be deleted
+ {iniFile(), true}, // the ini file must be deleted
};
@@ -270,9 +282,9 @@ public:
}
private:
+ const bool m_portable;
QDir m_dir;
- bool m_portable;
- Settings m_settings;
+ std::unique_ptr m_settings;
};
@@ -310,10 +322,11 @@ InstanceManagerDialog::InstanceManagerDialog(
connect(ui->exploreLocation, &QPushButton::clicked, [&]{ exploreLocation(); });
connect(ui->exploreBaseDirectory, &QPushButton::clicked, [&]{ exploreBaseDirectory(); });
connect(ui->exploreGame, &QPushButton::clicked, [&]{ exploreGame(); });
- connect(ui->deleteInstance, &QPushButton::clicked, [&]{ deleteInstance(); });
connect(ui->convertToGlobal, &QPushButton::clicked, [&]{ convertToGlobal(); });
connect(ui->convertToPortable, &QPushButton::clicked, [&]{ convertToPortable(); });
+ connect(ui->openINI, &QPushButton::clicked, [&]{ openINI(); });
+ connect(ui->deleteInstance, &QPushButton::clicked, [&]{ deleteInstance(); });
connect(ui->switchToInstance, &QPushButton::clicked, [&]{ openSelectedInstance(); });
connect(ui->close, &QPushButton::clicked, [&]{ close(); });
@@ -387,6 +400,18 @@ void InstanceManagerDialog::select(std::size_t i)
}
}
+void InstanceManagerDialog::select(const QString& name)
+{
+ for (std::size_t i=0; iname() == name) {
+ select(i);
+ return;
+ }
+ }
+
+ log::error("can't select instance {}, not in list", name);
+}
+
void InstanceManagerDialog::selectActiveInstance()
{
const auto active = InstanceManager::instance().currentInstance();
@@ -492,6 +517,8 @@ void InstanceManagerDialog::rename()
return;
}
+ const auto selIndex = singleSelectionIndex();
+
auto& m = InstanceManager::instance();
if (i->isActive()) {
QMessageBox::information(this,
@@ -519,6 +546,10 @@ void InstanceManagerDialog::rename()
return;
}
+
+ m_model->item(selIndex)->setText(newName);
+ i->setDir(dest);
+ fillData(*i);
}
void InstanceManagerDialog::exploreLocation()
@@ -542,6 +573,13 @@ void InstanceManagerDialog::exploreGame()
}
}
+void InstanceManagerDialog::openINI()
+{
+ if (const auto* i=singleSelection()) {
+ shell::Open(i->iniFile());
+ }
+}
+
void InstanceManagerDialog::deleteInstance()
{
const auto* i = singleSelection();
@@ -665,7 +703,19 @@ void InstanceManagerDialog::onSelection()
void InstanceManagerDialog::createNew()
{
CreateInstanceDialog dlg(m_pc, this);
- dlg.exec();
+ if (dlg.exec() != QDialog::Accepted) {
+ return;
+ }
+
+ if (dlg.switching()) {
+ // restarting MO
+ return;
+ }
+
+ updateInstances();
+ updateList();
+
+ select(dlg.instanceName());
}
std::size_t InstanceManagerDialog::singleSelectionIndex() const
diff --git a/src/instancemanagerdialog.h b/src/instancemanagerdialog.h
index 659710fe..477a7d01 100644
--- a/src/instancemanagerdialog.h
+++ b/src/instancemanagerdialog.h
@@ -20,6 +20,7 @@ public:
~InstanceManagerDialog();
void select(std::size_t i);
+ void select(const QString& name);
void selectActiveInstance();
void openSelectedInstance();
@@ -27,9 +28,11 @@ public:
void exploreLocation();
void exploreBaseDirectory();
void exploreGame();
- void deleteInstance();
+
void convertToGlobal();
void convertToPortable();
+ void openINI();
+ void deleteInstance();
private:
static const std::size_t NoSelection = -1;
diff --git a/src/instancemanagerdialog.ui b/src/instancemanagerdialog.ui
index 414d4982..410b58c1 100644
--- a/src/instancemanagerdialog.ui
+++ b/src/instancemanagerdialog.ui
@@ -107,6 +107,18 @@
QAbstractItemView::NoEditTriggers
+
+ QAbstractItemView::ScrollPerPixel
+
+
+ QAbstractItemView::ScrollPerPixel
+
+
+ QListView::Adjust
+
+
+ true
+
-
@@ -308,6 +320,13 @@
+ -
+
+
+ Open INI
+
+
+
-
--
cgit v1.3.1