summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorisanae <14251494+isanae@users.noreply.github.com>2020-07-23 10:27:58 -0400
committerisanae <14251494+isanae@users.noreply.github.com>2020-11-03 11:39:04 -0500
commitb10bcf4cb72bf3db06735a6b893c93319cead965 (patch)
tree9e75147f39337ec8efd04f0a390c68ac76384faf
parente0ed1c2153be0a9f922a619c527b3646b40377eb (diff)
instance name page
-rw-r--r--src/createinstancedialog.cpp215
-rw-r--r--src/createinstancedialog.h16
-rw-r--r--src/createinstancedialog.ui23
-rw-r--r--src/instancemanager.cpp21
-rw-r--r--src/instancemanager.h5
5 files changed, 252 insertions, 28 deletions
diff --git a/src/createinstancedialog.cpp b/src/createinstancedialog.cpp
index 79eaa79a..908c20d6 100644
--- a/src/createinstancedialog.cpp
+++ b/src/createinstancedialog.cpp
@@ -21,11 +21,40 @@ public:
return true;
}
+ virtual bool skip() const
+ {
+ // no-op
+ return false;
+ }
+
+ virtual void activated()
+ {
+ // no-op
+ }
+
+ void updateNavigation()
+ {
+ m_dlg.updateNavigation();
+ }
+
void next()
{
m_dlg.next();
}
+
+ virtual CreateInstanceDialog::Types selectedType() const
+ {
+ // no-op
+ return CreateInstanceDialog::NoType;
+ }
+
+ virtual MOBase::IPluginGame* selectedGame() const
+ {
+ // no-op
+ return nullptr;
+ }
+
protected:
Ui::CreateInstanceDialog* ui;
CreateInstanceDialog& m_dlg;
@@ -40,7 +69,7 @@ class TypePage : public Page
{
public:
TypePage(CreateInstanceDialog& dlg, std::size_t i)
- : Page(dlg, i)
+ : Page(dlg, i), m_type(CreateInstanceDialog::NoType)
{
ui->createGlobal->setDescription(
ui->createGlobal->description()
@@ -59,12 +88,17 @@ public:
bool ready() const override
{
- return m_global.has_value();
+ return (m_type != CreateInstanceDialog::NoType);
+ }
+
+ CreateInstanceDialog::Types selectedType() const
+ {
+ return m_type;
}
void global()
{
- m_global = true;
+ m_type = CreateInstanceDialog::Global;
ui->createGlobal->setChecked(true);
ui->createPortable->setChecked(false);
@@ -74,7 +108,7 @@ public:
void portable()
{
- m_global = false;
+ m_type = CreateInstanceDialog::Portable;
ui->createGlobal->setChecked(false);
ui->createPortable->setChecked(true);
@@ -83,7 +117,7 @@ public:
}
private:
- std::optional<bool> m_global;
+ CreateInstanceDialog::Types m_type;
};
@@ -99,26 +133,40 @@ public:
QObject::connect(ui->showAllGames, &QCheckBox::clicked, [&]{ fillList(); });
}
+ bool ready() const override
+ {
+ return (m_selection != nullptr);
+ }
+
+ MOBase::IPluginGame* selectedGame() const override
+ {
+ if (!m_selection) {
+ return nullptr;
+ }
+
+ return m_selection->game;
+ }
+
void select(MOBase::IPluginGame* game)
{
Game* checked = findGame(game);
- if (!checked) {
- return;
- }
- if (!checked->installed) {
- const auto path = QFileDialog::getExistingDirectory(
- &m_dlg, QObject::tr("Find game installation"));
+ if (checked) {
+ if (!checked->installed) {
+ const auto path = QFileDialog::getExistingDirectory(
+ &m_dlg, QObject::tr("Find game installation"));
- if (path.isEmpty()) {
- checked = nullptr;
- } else {
- checked = checkInstallation(path, checked);
+ if (path.isEmpty()) {
+ checked = nullptr;
+ } else {
+ checked = checkInstallation(path, checked);
+ }
}
}
m_selection = checked;
selectButton(checked);
+ updateNavigation();
}
void selectCustom()
@@ -430,8 +478,90 @@ class NamePage : public Page
{
public:
NamePage(CreateInstanceDialog& dlg, std::size_t i)
- : Page(dlg, i)
+ : Page(dlg, i), m_modified(false), m_okay(false)
+ {
+ m_originalLabel = ui->instanceNameLabel->text();
+
+ QObject::connect(
+ ui->instanceName, &QLineEdit::textEdited, [&]{ onChanged(); });
+ }
+
+ bool ready() const override
+ {
+ return m_okay;
+ }
+
+ bool skip() const override
{
+ return (m_dlg.selectedType() == CreateInstanceDialog::Portable);
+ }
+
+ void activated() override
+ {
+ auto* g = m_dlg.selectedGame();
+ if (!g) {
+ // shouldn't happen, next should be disabled
+ return;
+ }
+
+ ui->instanceNameLabel->setText(m_originalLabel.arg(g->gameName()));
+
+ if (!m_modified || ui->instanceName->text().isEmpty()) {
+ const auto n = InstanceManager::instance().makeUniqueName(g->gameName());
+ ui->instanceName->setText(n);
+ m_modified = false;
+ }
+
+ updateWarnings();
+ }
+
+private:
+ QString m_originalLabel;
+ bool m_modified;
+ bool m_okay;
+
+ void onChanged()
+ {
+ m_modified = true;
+ updateWarnings();
+ }
+
+ void updateWarnings()
+ {
+ bool exists = false;
+ bool invalid = false;
+ bool empty = false;
+
+ auto& m = InstanceManager::instance();
+
+ const auto name = ui->instanceName->text().trimmed();
+
+ if (name.isEmpty()) {
+ empty = true;
+ } else {
+ const auto sanitized = m.sanitizeInstanceName(name);
+ if (name != sanitized) {
+ invalid = true;
+ } else {
+ exists = m.instanceExists(name);
+ }
+ }
+
+ if (exists) {
+ m_okay = false;
+ ui->instanceNameExists->setVisible(true);
+ ui->instanceNameInvalid->setVisible(false);
+ } else if (invalid) {
+ m_okay = false;
+ ui->instanceNameExists->setVisible(false);
+ ui->instanceNameInvalid->setVisible(true);
+ } else {
+ m_okay = !empty;
+ ui->instanceNameExists->setVisible(false);
+ ui->instanceNameInvalid->setVisible(false);
+ }
+
+ updateNavigation();
}
};
@@ -463,7 +593,7 @@ CreateInstanceDialog::CreateInstanceDialog(
ui->pages->setCurrentIndex(0);
- updateNavigationButtons();
+ updateNavigation();
connect(ui->next, &QPushButton::clicked, [&]{ next(); });
connect(ui->back, &QPushButton::clicked, [&]{ back(); });
@@ -483,17 +613,35 @@ const PluginContainer& CreateInstanceDialog::pluginContainer()
void CreateInstanceDialog::next()
{
- ui->pages->setCurrentIndex(ui->pages->currentIndex() + 1);
- updateNavigationButtons();
+ selectPage(ui->pages->currentIndex() + 1);
}
void CreateInstanceDialog::back()
{
- ui->pages->setCurrentIndex(ui->pages->currentIndex() - 1);
- updateNavigationButtons();
+ selectPage(ui->pages->currentIndex() - 1);
}
-void CreateInstanceDialog::updateNavigationButtons()
+void CreateInstanceDialog::selectPage(std::size_t i)
+{
+ while (i < m_pages.size()) {
+ if (!m_pages[i]->skip()) {
+ break;
+ }
+
+ ++i;
+ }
+
+ if (i >= m_pages.size()) {
+ return;
+ }
+
+ ui->pages->setCurrentIndex(static_cast<int>(i));
+ m_pages[i]->activated();
+
+ updateNavigation();
+}
+
+void CreateInstanceDialog::updateNavigation()
{
const auto i = ui->pages->currentIndex();
const auto last = (i == (ui->pages->count() - 1));
@@ -501,3 +649,26 @@ void CreateInstanceDialog::updateNavigationButtons()
ui->next->setEnabled(m_pages[i]->ready() && !last);
ui->back->setEnabled(i > 0);
}
+
+CreateInstanceDialog::Types CreateInstanceDialog::selectedType() const
+{
+ for (auto&& p : m_pages) {
+ const auto t = p->selectedType();
+ if (t != NoType) {
+ return t;
+ }
+ }
+
+ return NoType;
+}
+
+MOBase::IPluginGame* CreateInstanceDialog::selectedGame() const
+{
+ for (auto&& p : m_pages) {
+ if (auto* g=p->selectedGame()) {
+ return g;
+ }
+ }
+
+ return nullptr;
+}
diff --git a/src/createinstancedialog.h b/src/createinstancedialog.h
index df056f85..3fd19d55 100644
--- a/src/createinstancedialog.h
+++ b/src/createinstancedialog.h
@@ -3,6 +3,7 @@
#include <QDialog>
+namespace MOBase { class IPluginGame; }
namespace Ui { class CreateInstanceDialog; };
namespace cid { class Page; }
@@ -13,6 +14,13 @@ class CreateInstanceDialog : public QDialog
Q_OBJECT
public:
+ enum Types
+ {
+ NoType = 0,
+ Global,
+ Portable
+ };
+
explicit CreateInstanceDialog(
const PluginContainer& pc, QWidget *parent = nullptr);
@@ -23,13 +31,17 @@ public:
void next();
void back();
+ void selectPage(std::size_t i);
+
+ void updateNavigation();
+
+ Types selectedType() const;
+ MOBase::IPluginGame* selectedGame() const;
private:
std::unique_ptr<Ui::CreateInstanceDialog> ui;
const PluginContainer& m_pc;
std::vector<std::unique_ptr<cid::Page>> m_pages;
-
- void updateNavigationButtons();
};
#endif // MODORGANIZER_CREATEINSTANCEDIALOG_INCLUDED
diff --git a/src/createinstancedialog.ui b/src/createinstancedialog.ui
index 8cad959d..6f215539 100644
--- a/src/createinstancedialog.ui
+++ b/src/createinstancedialog.ui
@@ -305,9 +305,12 @@
<number>0</number>
</property>
<item>
- <widget class="QLabel" name="label_4">
+ <widget class="QLabel" name="instanceNameLabel">
<property name="text">
- <string>&lt;h3&gt;Pick a name for this instance.&lt;/h3&gt;</string>
+ <string>&lt;h3&gt;Customize the name for this &lt;span style=&quot;white-space: nowrap;&quot;&gt;%1&lt;/span&gt; instance.&lt;/h3&gt;</string>
+ </property>
+ <property name="wordWrap">
+ <bool>true</bool>
</property>
</widget>
</item>
@@ -318,7 +321,7 @@
<widget class="QWidget" name="widget_9" native="true">
<layout class="QVBoxLayout" name="verticalLayout_8">
<property name="spacing">
- <number>0</number>
+ <number>9</number>
</property>
<item>
<widget class="QLineEdit" name="instanceName">
@@ -328,6 +331,20 @@
</widget>
</item>
<item>
+ <widget class="QLabel" name="instanceNameExists">
+ <property name="text">
+ <string>There is already an instance with this name.</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="instanceNameInvalid">
+ <property name="text">
+ <string>The name contains invalid characters. It must be a valid folder name.</string>
+ </property>
+ </widget>
+ </item>
+ <item>
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
diff --git a/src/instancemanager.cpp b/src/instancemanager.cpp
index 98edba47..b135cac1 100644
--- a/src/instancemanager.cpp
+++ b/src/instancemanager.cpp
@@ -650,6 +650,27 @@ MOBase::IPluginGame* InstanceManager::determineCurrentGame(
return nullptr;
}
+QString InstanceManager::makeUniqueName(const QString& instanceName) const
+{
+ const QString sanitized = sanitizeInstanceName(instanceName);
+
+ QString name = sanitized;
+ for (int i=2; i<100; ++i) {
+ if (!instanceExists(name)) {
+ return name;
+ }
+
+ name = QString("%1 (%2)").arg(sanitized).arg(i);
+ }
+
+ return {};
+}
+
+bool InstanceManager::instanceExists(const QString& instanceName) const
+{
+ const QDir root = instancesPath();
+ return root.exists(instanceName);
+}
QString InstanceManager::sanitizeInstanceName(const QString &name) const
{
diff --git a/src/instancemanager.h b/src/instancemanager.h
index d53f4391..0cd5ef4c 100644
--- a/src/instancemanager.h
+++ b/src/instancemanager.h
@@ -53,6 +53,10 @@ public:
QStringList instanceNames() const;
std::vector<QDir> instancePaths() const;
+ QString sanitizeInstanceName(const QString &name) const;
+ QString makeUniqueName(const QString& instanceName) const;
+ bool instanceExists(const QString& instanceName) const;
+
private:
InstanceManager();
@@ -63,7 +67,6 @@ private:
QString manageInstances(const QStringList &instanceList) const;
- QString sanitizeInstanceName(const QString &name) const;
void setCurrentInstance(const QString &name);
QString queryInstanceName(const QStringList &instanceList) const;