diff options
| author | isanae <14251494+isanae@users.noreply.github.com> | 2019-06-14 04:30:33 -0400 |
|---|---|---|
| committer | isanae <14251494+isanae@users.noreply.github.com> | 2019-06-15 14:40:40 -0400 |
| commit | 7671725436551b7254ea89ff6985c5491fcc743d (patch) | |
| tree | 8b9b36e71e7a5725b912f68dcb9b39db76a4f70d | |
| parent | 82975a6a38d0807e962b0e4b6cbd76337dc8189c (diff) | |
removed concept of custom executables, everything is modifiable
added apply button to dialog
added reset button that re-adds plugin executables and renames existing ones if needed
moved executables files to their filter in visual studio
| -rw-r--r-- | src/CMakeLists.txt | 11 | ||||
| -rw-r--r-- | src/editexecutablesdialog.cpp | 143 | ||||
| -rw-r--r-- | src/editexecutablesdialog.h | 9 | ||||
| -rw-r--r-- | src/editexecutablesdialog.ui | 37 | ||||
| -rw-r--r-- | src/executableslist.cpp | 156 | ||||
| -rw-r--r-- | src/executableslist.h | 24 | ||||
| -rw-r--r-- | src/mainwindow.cpp | 3 | ||||
| -rw-r--r-- | src/pch.h | 1 |
8 files changed, 221 insertions, 163 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 5623a851..645a5a73 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -293,7 +293,6 @@ set(core categories shared/directoryentry directoryrefresher - executableslist installationmanager instancemanager loadmechanism @@ -309,7 +308,6 @@ set(dialogs activatemodsdialog categoriesdialog credentialsdialog - editexecutablesdialog filedialogmemory forcedloaddialog forcedloaddialogwidget @@ -333,6 +331,11 @@ set(downloads downloadmanager ) +set(executables + executableslist + editexecutablesdialog +) + set(locking ilockedwaitingforprocess lockeddialog @@ -412,8 +415,8 @@ set(widgets ) set(src_filters - application core browser dialogs downloads locking modinfo modlist plugins - previews profiles settings utilities widgets + application core browser dialogs downloads executables locking modinfo + modlist plugins previews profiles settings utilities widgets ) foreach(filter in list ${src_filters}) diff --git a/src/editexecutablesdialog.cpp b/src/editexecutablesdialog.cpp index 6c0522e4..882bb8b5 100644 --- a/src/editexecutablesdialog.cpp +++ b/src/editexecutablesdialog.cpp @@ -49,8 +49,9 @@ EditExecutablesDialog::EditExecutablesDialog(OrganizerCore& oc, QWidget* parent) m_customOverwrites.load(m_organizerCore.currentProfile(), m_executablesList); m_forcedLibraries.load(m_organizerCore.currentProfile(), m_executablesList); - fillExecutableList(); + fillList(); ui->mods->addItems(m_organizerCore.modList()->allMods()); + setDirty(false); // some widgets need to do more than just save() and have their own handler connect(ui->binary, &QLineEdit::textChanged, [&]{ save(); }); @@ -59,13 +60,7 @@ EditExecutablesDialog::EditExecutablesDialog(OrganizerCore& oc, QWidget* parent) connect(ui->steamAppID, &QLineEdit::textChanged, [&]{ save(); }); connect(ui->mods, &QComboBox::currentTextChanged, [&]{ save(); }); connect(ui->useApplicationIcon, &QCheckBox::toggled, [&]{ save(); }); - - // select the first one in the list, if any - if (ui->list->count() > 0) { - ui->list->item(0)->setSelected(true); - } else { - updateUI(nullptr, nullptr); - } + connect(ui->list->model(), &QAbstractItemModel::rowsMoved, [&]{ saveOrder(); }); } EditExecutablesDialog::~EditExecutablesDialog() = default; @@ -132,6 +127,15 @@ void EditExecutablesDialog::commitChanges() // set the new executables list m_organizerCore.setExecutablesList(newExecutables); + + setDirty(false); +} + +void EditExecutablesDialog::setDirty(bool b) +{ + if (auto* button=ui->buttons->button(QDialogButtonBox::Apply)) { + button->setEnabled(b); + } } QListWidgetItem* EditExecutablesDialog::selectedItem() @@ -162,26 +166,25 @@ Executable* EditExecutablesDialog::selectedExe() return &*itor; } -void EditExecutablesDialog::fillExecutableList() +void EditExecutablesDialog::fillList() { ui->list->clear(); for(const auto& exe : m_executablesList) { ui->list->addItem(createListItem(exe)); } + + // select the first one in the list, if any + if (ui->list->count() > 0) { + ui->list->item(0)->setSelected(true); + } else { + updateUI(nullptr, nullptr); + } } QListWidgetItem* EditExecutablesDialog::createListItem(const Executable& exe) { - QListWidgetItem *newItem = new QListWidgetItem(exe.title()); - - if (!exe.isCustom()) { - auto f = newItem->font(); - f.setItalic(true); - newItem->setFont(f); - } - - return newItem; + return new QListWidgetItem(exe.title()); } void EditExecutablesDialog::updateUI( @@ -205,14 +208,12 @@ void EditExecutablesDialog::updateUI( void EditExecutablesDialog::setButtons( const QListWidgetItem* item, const Executable* e) { - // add is always enabled + // add and remove are always enabled if (item) { - ui->remove->setEnabled(e->isCustom()); ui->up->setEnabled(canMove(item, -1)); ui->down->setEnabled(canMove(item, +1)); } else { - ui->remove->setEnabled(false); ui->up->setEnabled(false); ui->down->setEnabled(false); } @@ -243,7 +244,6 @@ void EditExecutablesDialog::clearEdits() ui->configureLibraries->setEnabled(false); ui->useApplicationIcon->setEnabled(false); ui->useApplicationIcon->setChecked(false); - ui->pluginProvidedLabel->setVisible(false); } void EditExecutablesDialog::setEdits(const Executable& e) @@ -287,19 +287,15 @@ void EditExecutablesDialog::setEdits(const Executable& e) ui->configureLibraries->setEnabled(hasForcedLibraries); } - ui->pluginProvidedLabel->setVisible(!e.isCustom()); - - // only enabled for custom executables - ui->title->setEnabled(e.isCustom()); - ui->binary->setEnabled(e.isCustom()); - ui->browseBinary->setEnabled(e.isCustom()); - ui->workingDirectory->setEnabled(e.isCustom()); - ui->browseWorkingDirectory->setEnabled(e.isCustom()); - ui->arguments->setEnabled(e.isCustom()); - ui->overwriteSteamAppID->setEnabled(e.isCustom()); - ui->useApplicationIcon->setEnabled(e.isCustom()); - // always enabled + ui->title->setEnabled(true); + ui->binary->setEnabled(true); + ui->browseBinary->setEnabled(true); + ui->workingDirectory->setEnabled(true); + ui->browseWorkingDirectory->setEnabled(true); + ui->arguments->setEnabled(true); + ui->overwriteSteamAppID->setEnabled(true); + ui->useApplicationIcon->setEnabled(true); ui->createFilesInMod->setEnabled(true); ui->forceLoadLibraries->setEnabled(true); } @@ -361,6 +357,14 @@ void EditExecutablesDialog::save() } else { e->flags(e->flags() & (~Executable::UseApplicationIcon)); } + + setDirty(true); +} + +void EditExecutablesDialog::saveOrder() +{ + m_executablesList = getExecutablesList(); + setDirty(true); } bool EditExecutablesDialog::canMove(const QListWidgetItem* item, int direction) @@ -393,6 +397,8 @@ void EditExecutablesDialog::move(QListWidgetItem* item, int direction) ui->list->takeItem(row); ui->list->insertItem(row + (direction > 0 ? 1 : -1), item); item->setSelected(true); + + setDirty(true); } void EditExecutablesDialog::on_list_itemSelectionChanged() @@ -400,22 +406,43 @@ void EditExecutablesDialog::on_list_itemSelectionChanged() updateUI(selectedItem(), selectedExe()); } +void EditExecutablesDialog::on_reset_clicked() +{ + const auto title = tr("Reset plugin executables"); + + const auto text = tr( + "This will restore all the executables provided by the game plugin. If " + "there are existing executables with the same names, they will be " + "automatically renamed and left unchanged."); + + const auto buttons = QMessageBox::Ok | QMessageBox::Cancel; + + if (QMessageBox::question(this, title, text, buttons) != QMessageBox::Ok) { + return; + } + + m_executablesList.resetFromPlugin(m_organizerCore.managedGame()); + fillList(); + + setDirty(true); +} + void EditExecutablesDialog::on_add_clicked() { - auto title = makeNonConflictingTitle(tr("New Executable")); + auto title = m_executablesList.makeNonConflictingTitle(tr("New Executable")); if (!title) { return; } - auto e = Executable() - .title(*title) - .flags(Executable::CustomExecutable); + const Executable e(*title); m_executablesList.setExecutable(e); auto* item = createListItem(e); ui->list->addItem(item); item->setSelected(true); + + setDirty(true); } void EditExecutablesDialog::on_remove_clicked() @@ -453,6 +480,8 @@ void EditExecutablesDialog::on_remove_clicked() } else { ui->list->item(currentRow)->setSelected(true); } + + setDirty(true); } void EditExecutablesDialog::on_up_clicked() @@ -563,7 +592,7 @@ void EditExecutablesDialog::on_browseBinary_clicked() // setting title if currently empty if (ui->title->text().isEmpty()) { const auto prefix = QFileInfo(binaryName).baseName(); - const auto newTitle = makeNonConflictingTitle(prefix); + const auto newTitle = m_executablesList.makeNonConflictingTitle(prefix); if (newTitle) { ui->title->setText(*newTitle); @@ -607,15 +636,16 @@ void EditExecutablesDialog::on_configureLibraries_clicked() } } -void EditExecutablesDialog::on_buttons_accepted() +void EditExecutablesDialog::on_buttons_clicked(QAbstractButton* b) { - commitChanges(); - accept(); -} - -void EditExecutablesDialog::on_buttons_rejected() -{ - reject(); + if (b == ui->buttons->button(QDialogButtonBox::Ok)) { + commitChanges(); + accept(); + } else if (b == ui->buttons->button(QDialogButtonBox::Apply)) { + commitChanges(); + } else { + reject(); + } } void EditExecutablesDialog::setJarBinary(const QString& binaryName) @@ -641,25 +671,6 @@ void EditExecutablesDialog::setJarBinary(const QString& binaryName) save(); } -std::optional<QString> EditExecutablesDialog::makeNonConflictingTitle( - const QString& prefix) -{ - QString title = prefix; - - for (int i=1; i<100; ++i) { - if (!m_executablesList.titleExists(title)) { - return title; - } - - title = prefix + QString(" (%1)").arg(i); - } - - qCritical().nospace() - << "ran out of executable titles for prefix '" << prefix << "'"; - - return {}; -} - void CustomOverwrites::load(Profile* p, const ExecutablesList& exes) { diff --git a/src/editexecutablesdialog.h b/src/editexecutablesdialog.h index 10a6166f..4a04ef42 100644 --- a/src/editexecutablesdialog.h +++ b/src/editexecutablesdialog.h @@ -110,6 +110,7 @@ public: private slots:
void on_list_itemSelectionChanged();
+ void on_reset_clicked();
void on_add_clicked();
void on_remove_clicked();
void on_up_clicked();
@@ -124,8 +125,7 @@ private slots: void on_browseWorkingDirectory_clicked();
void on_configureLibraries_clicked();
- void on_buttons_accepted();
- void on_buttons_rejected();
+ void on_buttons_clicked(QAbstractButton* b);
private:
std::unique_ptr<Ui::EditExecutablesDialog> ui;
@@ -140,19 +140,20 @@ private: QListWidgetItem* selectedItem();
Executable* selectedExe();
- void fillExecutableList();
+ void fillList();
QListWidgetItem* createListItem(const Executable& exe);
void updateUI(const QListWidgetItem* item, const Executable* e);
void clearEdits();
void setEdits(const Executable& e);
void setButtons(const QListWidgetItem* item, const Executable* e);
void save();
+ void saveOrder();
bool canMove(const QListWidgetItem* item, int direction);
void move(QListWidgetItem* item, int direction);
void setJarBinary(const QString& binaryName);
- std::optional<QString> makeNonConflictingTitle(const QString& prefix);
bool isTitleConflicting(const QString& s);
void commitChanges();
+ void setDirty(bool b);
};
#endif // EDITEXECUTABLESDIALOG_H
diff --git a/src/editexecutablesdialog.ui b/src/editexecutablesdialog.ui index 9b6c8153..a42dbeed 100644 --- a/src/editexecutablesdialog.ui +++ b/src/editexecutablesdialog.ui @@ -168,6 +168,26 @@ </property>
</widget>
</item>
+ <item>
+ <widget class="QToolButton" name="reset">
+ <property name="toolTip">
+ <string>Adds the executables provided by the game plugin and moves any existing executables out of the way</string>
+ </property>
+ <property name="statusTip">
+ <string>Adds the executables provided by the game plugin and moves any existing executables out of the way</string>
+ </property>
+ <property name="whatsThis">
+ <string>Adds the executables provided by the game plugin and moves any existing executables out of the way</string>
+ </property>
+ <property name="text">
+ <string>Reset</string>
+ </property>
+ <property name="icon">
+ <iconset resource="resources.qrc">
+ <normaloff>:/MO/gui/edit_clear</normaloff>:/MO/gui/edit_clear</iconset>
+ </property>
+ </widget>
+ </item>
</layout>
</item>
<item>
@@ -426,21 +446,6 @@ Right now the only case I know of where this needs to be overwritten is for the </widget>
</item>
<item>
- <widget class="QLabel" name="pluginProvidedLabel">
- <property name="font">
- <font>
- <italic>true</italic>
- </font>
- </property>
- <property name="text">
- <string>This executable is provided by the game plugin</string>
- </property>
- <property name="alignment">
- <set>Qt::AlignCenter</set>
- </property>
- </widget>
- </item>
- <item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
@@ -463,7 +468,7 @@ Right now the only case I know of where this needs to be overwritten is for the <item>
<widget class="QDialogButtonBox" name="buttons">
<property name="standardButtons">
- <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+ <set>QDialogButtonBox::Apply|QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
diff --git a/src/executableslist.cpp b/src/executableslist.cpp index 0283a845..daf200a6 100644 --- a/src/executableslist.cpp +++ b/src/executableslist.cpp @@ -74,8 +74,6 @@ void ExecutablesList::load(const MOBase::IPluginGame* game, QSettings& settings) settings.setArrayIndex(i);
Executable::Flags flags;
- if (settings.value("custom", true).toBool())
- flags |= Executable::CustomExecutable;
if (settings.value("toolbar", false).toBool())
flags |= Executable::ShowInToolbar;
if (settings.value("ownicon", false).toBool())
@@ -92,7 +90,7 @@ void ExecutablesList::load(const MOBase::IPluginGame* game, QSettings& settings) settings.endArray();
- addFromPlugin(game);
+ addFromPlugin(game, IgnoreExisting);
}
void ExecutablesList::store(QSettings& settings)
@@ -106,29 +104,33 @@ void ExecutablesList::store(QSettings& settings) settings.setArrayIndex(count++);
settings.setValue("title", item.title());
- settings.setValue("custom", item.isCustom());
settings.setValue("toolbar", item.isShownOnToolbar());
settings.setValue("ownicon", item.usesOwnIcon());
-
- if (item.isCustom()) {
- settings.setValue("binary", item.binaryInfo().absoluteFilePath());
- settings.setValue("arguments", item.arguments());
- settings.setValue("workingDirectory", item.workingDirectory());
- settings.setValue("steamAppID", item.steamAppID());
- }
+ settings.setValue("binary", item.binaryInfo().absoluteFilePath());
+ settings.setValue("arguments", item.arguments());
+ settings.setValue("workingDirectory", item.workingDirectory());
+ settings.setValue("steamAppID", item.steamAppID());
}
settings.endArray();
}
-void ExecutablesList::addFromPlugin(IPluginGame const *game)
+void ExecutablesList::resetFromPlugin(MOBase::IPluginGame const *game)
+{
+ qDebug("resetting plugin executables");
+ addFromPlugin(game, MoveExisting);
+}
+
+void ExecutablesList::addFromPlugin(IPluginGame const *game, SetFlags flags)
{
Q_ASSERT(game != nullptr);
for (const ExecutableInfo &info : game->executables()) {
- if (info.isValid()) {
- setExecutable({info, Executable::UseApplicationIcon});
+ if (!info.isValid()) {
+ continue;
}
+
+ setExecutable({info, Executable::UseApplicationIcon}, flags);
}
const QFileInfo eppBin(QCoreApplication::applicationDirPath() + "/explorer++/Explorer++.exe");
@@ -137,12 +139,14 @@ void ExecutablesList::addFromPlugin(IPluginGame const *game) const auto args = QString("\"%1\"")
.arg(QDir::toNativeSeparators(game->dataDirectory().absolutePath()));
- setExecutable(Executable()
+ const auto exe = Executable()
.title("Explore Virtual Folder")
.binaryInfo(eppBin)
.arguments(args)
.workingDirectory(eppBin.absolutePath())
- .flags(Executable::UseApplicationIcon));
+ .flags(Executable::UseApplicationIcon);
+
+ setExecutable(exe, flags);
}
}
@@ -188,28 +192,81 @@ bool ExecutablesList::titleExists(const QString &title) const return std::find_if(m_Executables.begin(), m_Executables.end(), test) != m_Executables.end();
}
-void ExecutablesList::setExecutable(const Executable &executable)
+void ExecutablesList::setExecutable(const Executable &exe)
+{
+ setExecutable(exe, MergeExisting);
+}
+
+void ExecutablesList::setExecutable(const Executable &exe, SetFlags flags)
{
- auto itor = find(executable.title());
+ auto itor = find(exe.title());
+
+ if (itor != end()) {
+ if (flags == IgnoreExisting) {
+ return;
+ }
+
+ if (flags == MoveExisting) {
+ const auto newTitle = makeNonConflictingTitle(exe.title());
+ if (!newTitle) {
+ qCritical().nospace()
+ << "executable '" << exe.title() << "' was in the way but could "
+ << "not be renamed";
+
+ return;
+ }
+
+ qWarning().nospace()
+ << "executable '" << itor->title() << "' was in the way and was "
+ << "renamed to '" << *newTitle << "'";
+
+ itor->title(*newTitle);
+ itor = end();
+ }
+ }
if (itor == m_Executables.end()) {
- m_Executables.push_back(executable);
+ m_Executables.push_back(exe);
} else {
- itor->mergeFrom(executable);
+ itor->mergeFrom(exe);
}
}
void ExecutablesList::remove(const QString &title)
{
- for (std::vector<Executable>::iterator iter = m_Executables.begin(); iter != m_Executables.end(); ++iter) {
- if (iter->isCustom() && (iter->title() == title)) {
- m_Executables.erase(iter);
- break;
+ auto itor = find(title);
+ if (itor != m_Executables.end()) {
+ m_Executables.erase(itor);
+ }
+}
+
+std::optional<QString> ExecutablesList::makeNonConflictingTitle(
+ const QString& prefix)
+{
+ const int max = 100;
+
+ QString title = prefix;
+
+ for (int i=1; i<max; ++i) {
+ if (!titleExists(title)) {
+ return title;
}
+
+ title = prefix + QString(" (%1)").arg(i);
}
+
+ qCritical().nospace()
+ << "ran out of executable titles for prefix '" << prefix << "'";
+
+ return {};
}
+Executable::Executable(QString title)
+ : m_title(title)
+{
+}
+
Executable::Executable(const MOBase::ExecutableInfo& info, Flags flags) :
m_title(info.title()),
m_binaryInfo(info.binary()),
@@ -286,11 +343,6 @@ Executable& Executable::flags(Flags f) return *this;
}
-bool Executable::isCustom() const
-{
- return m_flags.testFlag(CustomExecutable);
-}
-
bool Executable::isShownOnToolbar() const
{
return m_flags.testFlag(ShowInToolbar);
@@ -315,43 +367,13 @@ void Executable::mergeFrom(const Executable& other) // flags on plugin executables that the user is allowed to change
const auto allow = ShowInToolbar;
+ // this happens after executables are loaded from settings and plugin
+ // executables are being added, or when users are modifying executables
- if (!other.isCustom()) {
- // this happens when loading plugin executables in addFromPlugin(), replace
- // everything in case the plugin has changed
-
- // remember the flags though
- const auto flags = m_flags;
-
- // overwrite everything
- *this = other;
-
- // set the user flags
- m_flags |= (flags & allow);
- }
- else if (!isCustom()) {
- // this happens when the user is trying to modify a plugin executable
- m_flags |= (other.flags() & allow);
- } else {
- // this happens after executables are loaded from settings and plugin
- // executables are being added, or when users are modifying executables
-
- m_title = other.title();
- m_arguments = other.arguments();
- m_steamAppID = other.steamAppID();
- m_workingDirectory = other.workingDirectory();
-
- // don't overwrite a valid binary with an invalid one
- if (other.binaryInfo().exists()) {
- m_binaryInfo = other.binaryInfo();
- }
-
- if (!other.isCustom()) {
- // overwriting a custom executable with a plugin, merge all the flags
- m_flags |= other.flags();
- } else {
- // overwriting a custom with another custom, just replace the flags
- m_flags = other.flags();
- }
- }
+ m_title = other.title();
+ m_binaryInfo = other.binaryInfo();
+ m_arguments = other.arguments();
+ m_steamAppID = other.steamAppID();
+ m_workingDirectory = other.workingDirectory();
+ m_flags = other.flags();
}
diff --git a/src/executableslist.h b/src/executableslist.h index 54a105d0..61582e71 100644 --- a/src/executableslist.h +++ b/src/executableslist.h @@ -23,6 +23,7 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #include "executableinfo.h"
#include <vector>
+#include <optional>
#include <QFileInfo>
#include <QMetaType>
@@ -37,14 +38,13 @@ class Executable public:
enum Flag
{
- CustomExecutable = 0x01,
ShowInToolbar = 0x02,
UseApplicationIcon = 0x04
};
Q_DECLARE_FLAGS(Flags, Flag);
- Executable() = default;
+ Executable(QString title={});
/**
* @brief Executable from plugin
@@ -65,7 +65,6 @@ public: Executable& workingDirectory(const QString& s);
Executable& flags(Flags f);
- bool isCustom() const;
bool isShownOnToolbar() const;
void setShownOnToolbar(bool state);
bool usesOwnIcon() const;
@@ -106,6 +105,8 @@ public: */
void load(const MOBase::IPluginGame* game, QSettings& settings);
+ void resetFromPlugin(MOBase::IPluginGame const *game);
+
/**
* @brief writes the current list to the settings
*/
@@ -166,13 +167,28 @@ public: **/
void remove(const QString &title);
+ std::optional<QString> makeNonConflictingTitle(const QString& prefix);
+
private:
+ enum SetFlags
+ {
+ IgnoreExisting = 1,
+ MergeExisting,
+ MoveExisting
+ };
+
std::vector<Executable> m_Executables;
/**
* @brief add the executables preconfigured for this game
**/
- void addFromPlugin(MOBase::IPluginGame const *game);
+ void addFromPlugin(MOBase::IPluginGame const *game, SetFlags flags);
+
+ /**
+ * @brief add a new executable to the list
+ * @param executable
+ */
+ void setExecutable(const Executable &exe, SetFlags flags);
};
Q_DECLARE_OPERATORS_FOR_FLAGS(Executable::Flags)
diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 15a6eb62..b5e9c320 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -5513,8 +5513,7 @@ void MainWindow::addAsExecutable() .title(name) .binaryInfo(binaryInfo) .arguments(arguments) - .workingDirectory(targetInfo.absolutePath()) - .flags(Executable::CustomExecutable)); + .workingDirectory(targetInfo.absolutePath())); refreshExecutablesList(); } @@ -13,6 +13,7 @@ #include <list> #include <map> #include <memory> +#include <optional> #include <regex> #include <set> #include <sstream> |
