diff options
| author | isanae <14251494+isanae@users.noreply.github.com> | 2020-07-23 10:27:58 -0400 |
|---|---|---|
| committer | isanae <14251494+isanae@users.noreply.github.com> | 2020-11-03 11:39:04 -0500 |
| commit | b10bcf4cb72bf3db06735a6b893c93319cead965 (patch) | |
| tree | 9e75147f39337ec8efd04f0a390c68ac76384faf | |
| parent | e0ed1c2153be0a9f922a619c527b3646b40377eb (diff) | |
instance name page
| -rw-r--r-- | src/createinstancedialog.cpp | 215 | ||||
| -rw-r--r-- | src/createinstancedialog.h | 16 | ||||
| -rw-r--r-- | src/createinstancedialog.ui | 23 | ||||
| -rw-r--r-- | src/instancemanager.cpp | 21 | ||||
| -rw-r--r-- | src/instancemanager.h | 5 |
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><h3>Pick a name for this instance.</h3></string> + <string><h3>Customize the name for this <span style="white-space: nowrap;">%1</span> instance.</h3></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; |
