diff options
| author | isanae <14251494+isanae@users.noreply.github.com> | 2019-10-10 06:12:07 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2019-10-10 06:12:07 -0400 |
| commit | 168fc950f9b15ce89084316d96a1f613a12e3013 (patch) | |
| tree | 73b1eb1afd04830e65c25060f1ce4763db98b642 | |
| parent | 0f5ecb8b78b86f309be3ef1902dbf4ee51738fc4 (diff) | |
| parent | 4d3495b3fb00b644c57e773bbcdbfb2eee7c0ea6 (diff) | |
Merge pull request #863 from isanae/executables-fixes
Executables fixes
| -rw-r--r-- | src/editexecutablesdialog.cpp | 224 | ||||
| -rw-r--r-- | src/editexecutablesdialog.h | 22 | ||||
| -rw-r--r-- | src/editexecutablesdialog.ui | 39 | ||||
| -rw-r--r-- | src/executableslist.cpp | 16 | ||||
| -rw-r--r-- | src/executableslist.h | 6 | ||||
| -rw-r--r-- | src/mainwindow.cpp | 154 | ||||
| -rw-r--r-- | src/mainwindow.h | 5 | ||||
| -rw-r--r-- | src/modinfo.cpp | 25 | ||||
| -rw-r--r-- | src/modinfo.h | 12 | ||||
| -rw-r--r-- | src/stylesheets/Night Eyes.qss | 5 | ||||
| -rw-r--r-- | src/stylesheets/vs15 Dark-Green.qss | 7 | ||||
| -rw-r--r-- | src/stylesheets/vs15 Dark-Orange.qss | 7 | ||||
| -rw-r--r-- | src/stylesheets/vs15 Dark-Purple.qss | 7 | ||||
| -rw-r--r-- | src/stylesheets/vs15 Dark-Red.qss | 7 | ||||
| -rw-r--r-- | src/stylesheets/vs15 Dark-Yellow.qss | 7 | ||||
| -rw-r--r-- | src/stylesheets/vs15 Dark.qss | 7 |
16 files changed, 430 insertions, 120 deletions
diff --git a/src/editexecutablesdialog.cpp b/src/editexecutablesdialog.cpp index 0d6367b8..3efadc4c 100644 --- a/src/editexecutablesdialog.cpp +++ b/src/editexecutablesdialog.cpp @@ -33,7 +33,29 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. using namespace MOBase; using namespace MOShared; -EditExecutablesDialog::EditExecutablesDialog(OrganizerCore& oc, QWidget* parent) +class IgnoreChanges +{ +public: + IgnoreChanges(EditExecutablesDialog* d) + : m_dialog(d) + { + m_dialog->m_settingUI = true; + } + + ~IgnoreChanges() + { + m_dialog->m_settingUI = false; + } + + IgnoreChanges(const IgnoreChanges&) = delete; + IgnoreChanges& operator=(const IgnoreChanges&) = delete; + +private: + EditExecutablesDialog* m_dialog; +}; + + +EditExecutablesDialog::EditExecutablesDialog(OrganizerCore& oc, int sel, QWidget* parent) : TutorableDialog("EditExecutables", parent) , ui(new Ui::EditExecutablesDialog) , m_organizerCore(oc) @@ -49,10 +71,25 @@ EditExecutablesDialog::EditExecutablesDialog(OrganizerCore& oc, QWidget* parent) loadCustomOverwrites(); loadForcedLibraries(); - ui->mods->addItems(m_organizerCore.modList()->allMods()); + for (auto&& m : m_organizerCore.modList()->allMods()) { + if (ModInfo::isRegularName(m)) { + ui->mods->addItem(m); + } + } + fillList(); setDirty(false); + if (sel >= 0 && sel < ui->list->count()) { + selectIndex(sel); + } + + auto* m = new QMenu; + m->addAction(tr("Add from file..."), [&]{ addFromFile(); }); + m->addAction(tr("Add empty"), [&]{ addEmpty(); }); + m->addAction(tr("Clone selected"), [&]{ clone(); }); + ui->add->setMenu(m); + // some widgets need to do more than just save() and have their own handler connect(ui->binary, &QLineEdit::textChanged, [&]{ save(); }); connect(ui->workingDirectory, &QLineEdit::textChanged, [&]{ save(); }); @@ -60,6 +97,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(); }); + connect(ui->hide, &QCheckBox::toggled, [&]{ save(); }); connect(ui->list->model(), &QAbstractItemModel::rowsMoved, [&]{ saveOrder(); }); } @@ -168,6 +206,14 @@ void EditExecutablesDialog::setDirty(bool b) } } +void EditExecutablesDialog::selectIndex(int i) +{ + if (i >= 0 && i < ui->list->count()) { + ui->list->selectionModel()->setCurrentIndex( + ui->list->model()->index(i, 0), QItemSelectionModel::ClearAndSelect); + } +} + QListWidgetItem* EditExecutablesDialog::selectedItem() { const auto selection = ui->list->selectedItems(); @@ -206,7 +252,7 @@ void EditExecutablesDialog::fillList() // select the first one in the list, if any if (ui->list->count() > 0) { - ui->list->item(0)->setSelected(true); + selectIndex(0); } else { updateUI(nullptr, nullptr); } @@ -221,7 +267,7 @@ void EditExecutablesDialog::updateUI( const QListWidgetItem* item, const Executable* e) { // the ui is currently being set, ignore changes - m_settingUI = true; + IgnoreChanges c(this); if (e) { setEdits(*e); @@ -230,9 +276,6 @@ void EditExecutablesDialog::updateUI( } setButtons(item, e); - - // any changes from now on are from the user - m_settingUI = false; } void EditExecutablesDialog::setButtons( @@ -274,6 +317,10 @@ void EditExecutablesDialog::clearEdits() ui->configureLibraries->setEnabled(false); ui->useApplicationIcon->setEnabled(false); ui->useApplicationIcon->setChecked(false); + ui->hide->setEnabled(false); + ui->hide->setChecked(false); + + m_lastGoodTitle = ""; } void EditExecutablesDialog::setEdits(const Executable& e) @@ -286,6 +333,9 @@ void EditExecutablesDialog::setEdits(const Executable& e) ui->steamAppID->setEnabled(!e.steamAppID().isEmpty()); ui->steamAppID->setText(e.steamAppID()); ui->useApplicationIcon->setChecked(e.usesOwnIcon()); + ui->hide->setChecked(e.hide()); + + m_lastGoodTitle = e.title(); { int modIndex = -1; @@ -329,6 +379,7 @@ void EditExecutablesDialog::setEdits(const Executable& e) ui->useApplicationIcon->setEnabled(true); ui->createFilesInMod->setEnabled(true); ui->forceLoadLibraries->setEnabled(true); + ui->hide->setEnabled(true); } void EditExecutablesDialog::save() @@ -388,6 +439,12 @@ void EditExecutablesDialog::save() e->flags(e->flags() & (~Executable::UseApplicationIcon)); } + if (ui->hide->isChecked()) { + e->flags(e->flags() | Executable::Hide); + } else { + e->flags(e->flags() & (~Executable::Hide)); + } + setDirty(true); } @@ -421,13 +478,14 @@ void EditExecutablesDialog::move(QListWidgetItem* item, int direction) return; } - const auto row = ui->list->row(item); + const auto oldRow = ui->list->row(item); + const auto newRow = oldRow + (direction > 0 ? 1 : -1); // removing item - ui->list->takeItem(row); - ui->list->insertItem(row + (direction > 0 ? 1 : -1), item); - item->setSelected(true); + ui->list->takeItem(oldRow); + ui->list->insertItem(newRow, item); + selectIndex(newRow); setDirty(true); } @@ -459,20 +517,7 @@ void EditExecutablesDialog::on_reset_clicked() void EditExecutablesDialog::on_add_clicked() { - auto title = m_executablesList.makeNonConflictingTitle(tr("New Executable")); - if (!title) { - return; - } - - const Executable e(*title); - - m_executablesList.setExecutable(e); - - auto* item = createListItem(e); - ui->list->addItem(item); - item->setSelected(true); - - setDirty(true); + addFromFile(); } void EditExecutablesDialog::on_remove_clicked() @@ -505,10 +550,10 @@ void EditExecutablesDialog::on_remove_clicked() if (currentRow >= ui->list->count()) { // that was the last item, select the new list item, if any if (ui->list->count() > 0) { - ui->list->item(ui->list->count() - 1)->setSelected(true); + selectIndex(ui->list->count() - 1); } } else { - ui->list->item(currentRow)->setSelected(true); + selectIndex(currentRow); } setDirty(true); @@ -548,17 +593,26 @@ bool EditExecutablesDialog::isTitleConflicting(const QString& s) return false; } -void EditExecutablesDialog::on_title_textChanged(const QString& s) +void EditExecutablesDialog::on_title_textChanged(const QString& original) { if (m_settingUI) { return; } - // don't allow changing the title to something that already exists + auto s = original.trimmed(); + + // disallow empty names + if (s.isEmpty()) { + return; + } + + // disallow changing the title to something that already exists if (isTitleConflicting(s)) { return; } + m_lastGoodTitle = s; + // must save before modifying the item in the list widget because saving // relies on the item's text being the same as an item in m_executablesList save(); @@ -570,6 +624,11 @@ void EditExecutablesDialog::on_title_textChanged(const QString& s) } } +void EditExecutablesDialog::on_title_editingFinished() +{ + ui->title->setText(m_lastGoodTitle); +} + void EditExecutablesDialog::on_overwriteSteamAppID_toggled(bool checked) { if (m_settingUI) { @@ -602,35 +661,78 @@ void EditExecutablesDialog::on_forceLoadLibraries_toggled(bool checked) void EditExecutablesDialog::on_browseBinary_clicked() { - const QString binaryName = FileDialogMemory::getOpenFileName( - "editExecutableBinary", this, tr("Select a binary"), ui->binary->text(), - tr("Executable (%1)").arg("*.exe *.bat *.jar")); + const auto binaryName = browseBinary(ui->binary->text()); + if (binaryName.fileName().isEmpty()) { + return; + } + + setBinary(binaryName); + save(); +} + +void EditExecutablesDialog::addFromFile() +{ + const auto binary = browseBinary(ui->binary->text()); + if (binary.fileName().isEmpty()) { + return; + } + + addNew(Executable(binary.fileName())); + setBinary(binary); +} + +void EditExecutablesDialog::addEmpty() +{ + addNew(Executable(tr("New Executable"))); +} + +void EditExecutablesDialog::clone() +{ + auto* e = selectedExe(); + if (!e) { + return; + } + + addNew(*e); +} - if (binaryName.isNull()) { - // canceled +void EditExecutablesDialog::addNew(Executable e) +{ + const auto fixedTitle = m_executablesList.makeNonConflictingTitle(e.title()); + if (!fixedTitle) { return; } + e.title(*fixedTitle); + + m_executablesList.setExecutable(e); + + auto* item = createListItem(e); + ui->list->addItem(item); + + selectIndex(ui->list->count() - 1); + setDirty(true); +} + +void EditExecutablesDialog::setBinary(const QFileInfo& binary) +{ // setting binary - if (binaryName.endsWith(".jar", Qt::CaseInsensitive)) { + if (binary.suffix().compare("jar", Qt::CaseInsensitive) == 0) { // special case for jar files, uses the system java installation - setJarBinary(binaryName); + setJarBinary(binary); } else { - ui->binary->setText(QDir::toNativeSeparators(binaryName)); + ui->binary->setText(QDir::toNativeSeparators(binary.absoluteFilePath())); } - // setting title if currently empty or some variation of "New Executable" - if (ui->title->text().isEmpty() || - ui->title->text().startsWith(tr("New Executable"), Qt::CaseInsensitive)) { - const auto prefix = QFileInfo(binaryName).baseName(); + // setting title if some variation of "New Executable" + if (ui->title->text().startsWith(tr("New Executable"), Qt::CaseInsensitive)) { + const auto prefix = binary.baseName(); const auto newTitle = m_executablesList.makeNonConflictingTitle(prefix); if (newTitle) { ui->title->setText(*newTitle); } } - - save(); } void EditExecutablesDialog::on_browseWorkingDirectory_clicked() @@ -640,7 +742,7 @@ void EditExecutablesDialog::on_browseWorkingDirectory_clicked() ui->workingDirectory->text()); if (dirName.isNull()) { - // canceled + // cancelled return; } @@ -679,9 +781,26 @@ void EditExecutablesDialog::on_buttons_clicked(QAbstractButton* b) } } -void EditExecutablesDialog::setJarBinary(const QString& binaryName) +QFileInfo EditExecutablesDialog::browseBinary(const QString& initial) { - auto java = OrganizerCore::findJavaInstallation(binaryName); + const QString Filters = + tr("Executables (*.exe *.bat *.jar)") + ";;" + + tr("All Files (*.*)"); + + const auto f = FileDialogMemory::getOpenFileName( + "editExecutableBinary", this, tr("Select an executable"), + initial, Filters); + + if (f.isNull()) { + return {}; + } + + return QFileInfo(f); +} + +void EditExecutablesDialog::setJarBinary(const QFileInfo& binary) +{ + auto java = OrganizerCore::findJavaInstallation(binary.absoluteFilePath()); if (java.isEmpty()) { QMessageBox::information( @@ -691,13 +810,14 @@ void EditExecutablesDialog::setJarBinary(const QString& binaryName) "the binary.")); } - // only save once + { + // only save once + IgnoreChanges c(this); - m_settingUI = true; - ui->binary->setText(java); - ui->workingDirectory->setText(QDir::toNativeSeparators(QFileInfo(binaryName).absolutePath())); - ui->arguments->setText("-jar \"" + QDir::toNativeSeparators(binaryName) + "\""); - m_settingUI = false; + ui->binary->setText(java); + ui->workingDirectory->setText(QDir::toNativeSeparators(binary.absolutePath())); + ui->arguments->setText("-jar \"" + QDir::toNativeSeparators(binary.absoluteFilePath()) + "\""); + } save(); } diff --git a/src/editexecutablesdialog.h b/src/editexecutablesdialog.h index 494f0651..c8be0bf6 100644 --- a/src/editexecutablesdialog.h +++ b/src/editexecutablesdialog.h @@ -141,13 +141,15 @@ private: **/
class EditExecutablesDialog : public MOBase::TutorableDialog
{
- Q_OBJECT
+ Q_OBJECT;
+ friend class IgnoreChanges;
public:
using CustomOverwrites = ToggableMap<QString>;
using ForcedLibraries = ToggableMap<QList<MOBase::ExecutableForcedLoadSetting>>;
- explicit EditExecutablesDialog(OrganizerCore& oc, QWidget* parent=nullptr);
+ explicit EditExecutablesDialog(
+ OrganizerCore& oc, int selection=-1, QWidget* parent=nullptr);
~EditExecutablesDialog();
@@ -169,6 +171,7 @@ private slots: void on_down_clicked();
void on_title_textChanged(const QString& s);
+ void on_title_editingFinished();
void on_overwriteSteamAppID_toggled(bool checked);
void on_createFilesInMod_toggled(bool checked);
void on_forceLoadLibraries_toggled(bool checked);
@@ -196,6 +199,10 @@ private: // forced libraries set in the dialog
ForcedLibraries m_forcedLibraries;
+ // remembers the last executable title that made sense, reverts to this when
+ // the widget loses focus if it's empty
+ QString m_lastGoodTitle;
+
// true when the change events being triggered are in response to loading
// the executable's data into the UI, not from a user change
bool m_settingUI;
@@ -217,10 +224,19 @@ private: void saveOrder();
bool canMove(const QListWidgetItem* item, int direction);
void move(QListWidgetItem* item, int direction);
- void setJarBinary(const QString& binaryName);
bool isTitleConflicting(const QString& s);
void commitChanges();
void setDirty(bool b);
+ void selectIndex(int i);
+
+ void addFromFile();
+ void addEmpty();
+ void clone();
+ void addNew(Executable e);
+
+ QFileInfo browseBinary(const QString& initial);
+ void setBinary(const QFileInfo& binary);
+ void setJarBinary(const QFileInfo& binary);
};
#endif // EDITEXECUTABLESDIALOG_H
diff --git a/src/editexecutablesdialog.ui b/src/editexecutablesdialog.ui index c2ff7d31..6f50b3b3 100644 --- a/src/editexecutablesdialog.ui +++ b/src/editexecutablesdialog.ui @@ -106,6 +106,9 @@ <iconset resource="resources.qrc">
<normaloff>:/MO/gui/add</normaloff>:/MO/gui/add</iconset>
</property>
+ <property name="popupMode">
+ <enum>QToolButton::InstantPopup</enum>
+ </property>
</widget>
</item>
<item>
@@ -140,7 +143,7 @@ <string>Move the executable up in the list</string>
</property>
<property name="text">
- <string>Move the executable up in the list</string>
+ <string>Up</string>
</property>
<property name="icon">
<iconset resource="resources.qrc">
@@ -160,7 +163,7 @@ <string>Move the executable down in the list</string>
</property>
<property name="text">
- <string>Move the executable down in the list</string>
+ <string>Down</string>
</property>
<property name="icon">
<iconset resource="resources.qrc">
@@ -375,7 +378,7 @@ Right now the only case I know of where this needs to be overwritten is for the <string>If this is enabled, new files are created in the specified mod instead of the "Overwrite" mod.</string>
</property>
<property name="text">
- <string>Create Files in Mod instead of Overwrite (*)</string>
+ <string>Create files in mod instead of overwrite (*)</string>
</property>
</widget>
</item>
@@ -396,7 +399,7 @@ Right now the only case I know of where this needs to be overwritten is for the <string>If this is enabled, the configured libraries will be automatically loaded when this executable is launched.</string>
</property>
<property name="text">
- <string>Force Load Libraries (*)</string>
+ <string>Force load libraries (*)</string>
</property>
</widget>
</item>
@@ -428,14 +431,27 @@ Right now the only case I know of where this needs to be overwritten is for the <item>
<widget class="QCheckBox" name="useApplicationIcon">
<property name="text">
- <string>Use Application's Icon for desktop shortcuts</string>
+ <string>Use application's icon for desktop shortcuts</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="hide">
+ <property name="toolTip">
+ <string>This executable will not appear in the list, on the toolbar or in the menu. It will still be visible in this dialog.</string>
+ </property>
+ <property name="whatsThis">
+ <string>This executable will not appear in the list, on the toolbar or in the menu. It will still be visible in this dialog.</string>
+ </property>
+ <property name="text">
+ <string>Hide in user interface</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_5">
<property name="text">
- <string>(*) Profile Specific</string>
+ <string>(*) Profile specific</string>
</property>
<property name="margin">
<number>5</number>
@@ -475,14 +491,25 @@ Right now the only case I know of where this needs to be overwritten is for the </layout>
</widget>
<tabstops>
+ <tabstop>add</tabstop>
+ <tabstop>remove</tabstop>
+ <tabstop>up</tabstop>
+ <tabstop>down</tabstop>
+ <tabstop>reset</tabstop>
+ <tabstop>list</tabstop>
+ <tabstop>title</tabstop>
<tabstop>binary</tabstop>
<tabstop>browseBinary</tabstop>
<tabstop>workingDirectory</tabstop>
<tabstop>browseWorkingDirectory</tabstop>
+ <tabstop>arguments</tabstop>
<tabstop>overwriteSteamAppID</tabstop>
<tabstop>steamAppID</tabstop>
<tabstop>createFilesInMod</tabstop>
<tabstop>mods</tabstop>
+ <tabstop>forceLoadLibraries</tabstop>
+ <tabstop>configureLibraries</tabstop>
+ <tabstop>useApplicationIcon</tabstop>
</tabstops>
<resources>
<include location="resources.qrc"/>
diff --git a/src/executableslist.cpp b/src/executableslist.cpp index dce9181b..1be34b53 100644 --- a/src/executableslist.cpp +++ b/src/executableslist.cpp @@ -84,6 +84,9 @@ void ExecutablesList::load(const MOBase::IPluginGame* game, const Settings& s) if (map["ownicon"].toBool())
flags |= Executable::UseApplicationIcon;
+ if (map["hide"].toBool())
+ flags |= Executable::Hide;
+
if (map.contains("custom")) {
// the "custom" setting only exists in older versions
needsUpgrade = true;
@@ -116,6 +119,7 @@ void ExecutablesList::store(Settings& s) map["title"] = item.title();
map["toolbar"] = item.isShownOnToolbar();
map["ownicon"] = item.usesOwnIcon();
+ map["hide"] = item.hide();
map["binary"] = item.binaryInfo().absoluteFilePath();
map["arguments"] = item.arguments();
map["workingDirectory"] = item.workingDirectory();
@@ -343,6 +347,10 @@ void ExecutablesList::dump() const flags.push_back("icon");
}
+ if (e.flags() & Executable::Hide) {
+ flags.push_back("hide");
+ }
+
log::debug(
" . executable '{}'\n"
" binary: {}\n"
@@ -456,11 +464,13 @@ bool Executable::usesOwnIcon() const return m_flags.testFlag(UseApplicationIcon);
}
-void Executable::mergeFrom(const Executable& other)
+bool Executable::hide() const
{
- // flags on plugin executables that the user is allowed to change
- const auto allow = ShowInToolbar;
+ return m_flags.testFlag(Hide);
+}
+void Executable::mergeFrom(const Executable& other)
+{
// this happens after executables are loaded from settings and plugin
// executables are being added, or when users are modifying executables
diff --git a/src/executableslist.h b/src/executableslist.h index 23cf3cfe..a18042db 100644 --- a/src/executableslist.h +++ b/src/executableslist.h @@ -39,8 +39,9 @@ class Executable public:
enum Flag
{
- ShowInToolbar = 0x02,
- UseApplicationIcon = 0x04
+ ShowInToolbar = 0x02,
+ UseApplicationIcon = 0x04,
+ Hide = 0x08
};
Q_DECLARE_FLAGS(Flags, Flag);
@@ -69,6 +70,7 @@ public: bool isShownOnToolbar() const;
void setShownOnToolbar(bool state);
bool usesOwnIcon() const;
+ bool hide() const;
void mergeFrom(const Executable& other);
diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 23733cac..8d42d020 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -757,7 +757,7 @@ void MainWindow::updatePinnedExecutables() bool hasLinks = false; for (const auto& exe : *m_OrganizerCore.executablesList()) { - if (exe.isShownOnToolbar()) { + if (!exe.hide() && exe.isShownOnToolbar()) { hasLinks = true; QAction *exeAction = new QAction( @@ -1811,23 +1811,44 @@ bool MainWindow::refreshProfiles(bool selectProfile) void MainWindow::refreshExecutablesList() { - QComboBox* executablesList = findChild<QComboBox*>("executablesListBox"); - executablesList->setEnabled(false); - executablesList->clear(); - executablesList->addItem(tr("<Edit...>")); + QAbstractItemModel *model = ui->executablesListBox->model(); + + auto add = [&](const QString& title, const QFileInfo& binary) { + QIcon icon; + if (!binary.fileName().isEmpty()) { + icon = iconForExecutable(binary.filePath()); + } + + ui->executablesListBox->addItem(icon, title); + + const auto i = ui->executablesListBox->count() - 1; + + model->setData( + model->index(i, 0), + QSize(0, ui->executablesListBox->iconSize().height() + 4), + Qt::SizeHintRole); + }; - QAbstractItemModel *model = executablesList->model(); - int i = 0; + ui->executablesListBox->setEnabled(false); + ui->executablesListBox->clear(); + + add(tr("<Edit...>"), {}); + for (const auto& exe : *m_OrganizerCore.executablesList()) { - QIcon icon = iconForExecutable(exe.binaryInfo().filePath()); - executablesList->addItem(icon, exe.title()); - model->setData(model->index(i, 0), QSize(0, executablesList->iconSize().height() + 4), Qt::SizeHintRole); - ++i; + if (!exe.hide()) { + add(exe.title(), exe.binaryInfo()); + } + } + + if (ui->executablesListBox->count() == 1) { + // all executables are hidden, add an empty one to at least be able to + // switch to edit + add(tr("(no executables)"), QFileInfo(":badfile")); } ui->executablesListBox->setCurrentIndex(1); - executablesList->setEnabled(true); + ui->executablesListBox->setEnabled(true); } @@ -2344,36 +2365,51 @@ void MainWindow::installMod(QString fileName) } } -void MainWindow::on_startButton_clicked() { - ui->startButton->setEnabled(false); +void MainWindow::on_startButton_clicked() +{ try { - const Executable &selectedExecutable(getSelectedExecutable()); - QString customOverwrite = m_OrganizerCore.currentProfile()->setting("custom_overwrites", selectedExecutable.title()).toString(); - auto forcedLibraries = m_OrganizerCore.currentProfile()->determineForcedLibraries(selectedExecutable.title()); - if (!m_OrganizerCore.currentProfile()->forcedLibrariesEnabled(selectedExecutable.title())) { + const Executable* selectedExecutable = getSelectedExecutable(); + if (!selectedExecutable) { + return; + } + + ui->startButton->setEnabled(false); + + auto* profile = m_OrganizerCore.currentProfile(); + + const QString customOverwrite = profile->setting( + "custom_overwrites", selectedExecutable->title()).toString(); + + auto forcedLibraries = profile->determineForcedLibraries( + selectedExecutable->title()); + + if (!profile->forcedLibrariesEnabled(selectedExecutable->title())) { forcedLibraries.clear(); } + m_OrganizerCore.spawnBinary( - selectedExecutable.binaryInfo(), selectedExecutable.arguments(), - selectedExecutable.workingDirectory().length() != 0 - ? selectedExecutable.workingDirectory() - : selectedExecutable.binaryInfo().absolutePath(), - selectedExecutable.steamAppID(), - customOverwrite, - forcedLibraries); + selectedExecutable->binaryInfo(), + selectedExecutable->arguments(), + selectedExecutable->workingDirectory().length() != 0 ? + selectedExecutable->workingDirectory() : + selectedExecutable->binaryInfo().absolutePath(), + selectedExecutable->steamAppID(), + customOverwrite, + forcedLibraries); } catch (...) { ui->startButton->setEnabled(true); throw; } + ui->startButton->setEnabled(true); } -bool MainWindow::modifyExecutablesDialog() +bool MainWindow::modifyExecutablesDialog(int selection) { bool result = false; try { - EditExecutablesDialog dialog(m_OrganizerCore, this); + EditExecutablesDialog dialog(m_OrganizerCore, selection, this); result = (dialog.exec() == QDialog::Accepted); @@ -2398,8 +2434,14 @@ void MainWindow::on_executablesListBox_currentIndexChanged(int index) m_OldExecutableIndex = index; if (index == 0) { - modifyExecutablesDialog(); - ui->executablesListBox->setCurrentIndex(previousIndex); + modifyExecutablesDialog(previousIndex - 1); + const auto newCount = ui->executablesListBox->count(); + + if (previousIndex >= 0 && previousIndex < newCount) { + ui->executablesListBox->setCurrentIndex(previousIndex); + } else { + ui->executablesListBox->setCurrentIndex(newCount - 1); + } } } @@ -2474,8 +2516,15 @@ void MainWindow::on_actionAdd_Profile_triggered() void MainWindow::on_actionModify_Executables_triggered() { - if (modifyExecutablesDialog()) { - ui->executablesListBox->setCurrentIndex(m_OldExecutableIndex); + const auto sel = (m_OldExecutableIndex > 0 ? m_OldExecutableIndex - 1 : 0); + + if (modifyExecutablesDialog(sel)) { + const auto newCount = ui->executablesListBox->count(); + if (m_OldExecutableIndex >= 0 && m_OldExecutableIndex < newCount) { + ui->executablesListBox->setCurrentIndex(m_OldExecutableIndex); + } else { + ui->executablesListBox->setCurrentIndex(newCount - 1); + } } } @@ -4994,33 +5043,43 @@ void MainWindow::on_savegameList_customContextMenuRequested(const QPoint &pos) void MainWindow::linkToolbar() { - Executable& exe = getSelectedExecutable(); + Executable* exe = getSelectedExecutable(); + if (!exe) { + return; + } - exe.setShownOnToolbar(!exe.isShownOnToolbar()); + exe->setShownOnToolbar(!exe->isShownOnToolbar()); updatePinnedExecutables(); } void MainWindow::linkDesktop() { - env::Shortcut(getSelectedExecutable()).toggle(env::Shortcut::Desktop); + if (auto* exe=getSelectedExecutable()) { + env::Shortcut(*exe).toggle(env::Shortcut::Desktop); + } } void MainWindow::linkMenu() { - env::Shortcut(getSelectedExecutable()).toggle(env::Shortcut::StartMenu); + if (auto* exe=getSelectedExecutable()) { + env::Shortcut(*exe).toggle(env::Shortcut::StartMenu); + } } void MainWindow::on_linkButton_pressed() { - const Executable& exe = getSelectedExecutable(); + const Executable* exe = getSelectedExecutable(); + if (!exe) { + return; + } const QIcon addIcon(":/MO/gui/link"); const QIcon removeIcon(":/MO/gui/remove"); - env::Shortcut shortcut(exe); + env::Shortcut shortcut(*exe); m_LinkToolbar->setIcon( - exe.isShownOnToolbar() ? removeIcon : addIcon); + exe->isShownOnToolbar() ? removeIcon : addIcon); m_LinkDesktop->setIcon( shortcut.exists(env::Shortcut::Desktop) ? removeIcon : addIcon); @@ -6363,16 +6422,19 @@ void MainWindow::on_groupCombo_currentIndexChanged(int index) modFilterActive(m_ModListSortProxy->isFilterActive()); } -const Executable &MainWindow::getSelectedExecutable() const +Executable* MainWindow::getSelectedExecutable() { - const QString name = ui->executablesListBox->itemText(ui->executablesListBox->currentIndex()); - return m_OrganizerCore.executablesList()->get(name); -} + const QString name = ui->executablesListBox->itemText( + ui->executablesListBox->currentIndex()); -Executable &MainWindow::getSelectedExecutable() -{ - const QString name = ui->executablesListBox->itemText(ui->executablesListBox->currentIndex()); - return m_OrganizerCore.executablesList()->get(name); + try + { + return &m_OrganizerCore.executablesList()->get(name); + } + catch(std::runtime_error&) + { + return nullptr; + } } void MainWindow::on_showHiddenBox_toggled(bool checked) diff --git a/src/mainwindow.h b/src/mainwindow.h index b04096be..dbbd0bd9 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -235,7 +235,7 @@ private: QList<MOBase::IOrganizer::FileInfo> findFileInfos(const QString &path, const std::function<bool (const MOBase::IOrganizer::FileInfo &)> &filter) const; - bool modifyExecutablesDialog(); + bool modifyExecutablesDialog(int selection); void displayModInformation(int row, ModInfoTabIDs tab=ModInfoTabIDs::None); void testExtractBSA(int modIndex); @@ -396,8 +396,7 @@ private: // when painting the count QIcon m_originalNotificationIcon; - Executable const &getSelectedExecutable() const; - Executable &getSelectedExecutable(); + Executable* getSelectedExecutable(); private slots: diff --git a/src/modinfo.cpp b/src/modinfo.cpp index e3daa4fd..6e048bfb 100644 --- a/src/modinfo.cpp +++ b/src/modinfo.cpp @@ -61,17 +61,32 @@ bool ModInfo::ByName(const ModInfo::Ptr &LHS, const ModInfo::Ptr &RHS) return QString::compare(LHS->name(), RHS->name(), Qt::CaseInsensitive) < 0; } +bool ModInfo::isSeparatorName(const QString& name) +{ + static QRegExp separatorExp(".*_separator"); + return separatorExp.exactMatch(name); +} + +bool ModInfo::isBackupName(const QString& name) +{ + static QRegExp backupExp(".*backup[0-9]*"); + return backupExp.exactMatch(name); +} + +bool ModInfo::isRegularName(const QString& name) +{ + return !isSeparatorName(name) && !isBackupName(name); +} + ModInfo::Ptr ModInfo::createFrom(PluginContainer *pluginContainer, const MOBase::IPluginGame *game, const QDir &dir, DirectoryEntry **directoryStructure) { QMutexLocker locker(&s_Mutex); - // int id = s_NextID++; - static QRegExp backupExp(".*backup[0-9]*"); - static QRegExp separatorExp(".*_separator"); ModInfo::Ptr result; - if (backupExp.exactMatch(dir.dirName())) { + + if (isBackupName(dir.dirName())) { result = ModInfo::Ptr(new ModInfoBackup(pluginContainer, game, dir, directoryStructure)); - } else if(separatorExp.exactMatch(dir.dirName())){ + } else if (isSeparatorName(dir.dirName())) { result = Ptr(new ModInfoSeparator(pluginContainer, game, dir, directoryStructure)); } else { result = ModInfo::Ptr(new ModInfoRegular(pluginContainer, game, dir, directoryStructure)); diff --git a/src/modinfo.h b/src/modinfo.h index e395f45b..30a115c7 100644 --- a/src/modinfo.h +++ b/src/modinfo.h @@ -229,6 +229,18 @@ public: */ static ModInfo::Ptr createFromPlugin(const QString &modName, const QString &espName, const QStringList &bsaNames, ModInfo::EModType modType, MOShared::DirectoryEntry **directoryStructure, PluginContainer *pluginContainer); + // whether the given name is used for separators + // + static bool isSeparatorName(const QString& name); + + // whether the given name is used for backups + // + static bool isBackupName(const QString& name); + + // whether the given name is used for regular mods + // + static bool isRegularName(const QString& name); + /** * @brief retieve a name for one of the CONTENT_ enums * @param contentType the content value diff --git a/src/stylesheets/Night Eyes.qss b/src/stylesheets/Night Eyes.qss index 142acb6a..0430a8c8 100644 --- a/src/stylesheets/Night Eyes.qss +++ b/src/stylesheets/Night Eyes.qss @@ -80,6 +80,11 @@ QToolButton:pressed background: #181818; } +QToolButton::menu-indicator +{ + width: 8px; +} + /* Left Pane & File Trees ----------------------------------------------------- */ diff --git a/src/stylesheets/vs15 Dark-Green.qss b/src/stylesheets/vs15 Dark-Green.qss index 9cf26a31..88e7651f 100644 --- a/src/stylesheets/vs15 Dark-Green.qss +++ b/src/stylesheets/vs15 Dark-Green.qss @@ -209,6 +209,13 @@ QToolButton { QToolButton:pressed { background-color: #009933; } +QToolButton::menu-indicator { + image: url(./vs15/combobox-down.png); + subcontrol-origin: padding; + subcontrol-position: center right; + padding-top: 10%; + padding-right: 5%; } + /* Group Boxes #QGroupBox */ QGroupBox { border-color: #3F3F46; diff --git a/src/stylesheets/vs15 Dark-Orange.qss b/src/stylesheets/vs15 Dark-Orange.qss index 041f1b00..488da3c4 100644 --- a/src/stylesheets/vs15 Dark-Orange.qss +++ b/src/stylesheets/vs15 Dark-Orange.qss @@ -210,6 +210,13 @@ QToolButton { QToolButton:pressed { background-color: #CC6600; } +QToolButton::menu-indicator { + image: url(./vs15/combobox-down.png); + subcontrol-origin: padding; + subcontrol-position: center right; + padding-top: 10%; + padding-right: 5%; } + /* Group Boxes #QGroupBox */ QGroupBox { border-color: #3F3F46; diff --git a/src/stylesheets/vs15 Dark-Purple.qss b/src/stylesheets/vs15 Dark-Purple.qss index bc8bbcde..24c8705a 100644 --- a/src/stylesheets/vs15 Dark-Purple.qss +++ b/src/stylesheets/vs15 Dark-Purple.qss @@ -210,6 +210,13 @@ QToolButton { QToolButton:pressed { background-color: #7E2AD2; } +QToolButton::menu-indicator { + image: url(./vs15/combobox-down.png); + subcontrol-origin: padding; + subcontrol-position: center right; + padding-top: 10%; + padding-right: 5%; } + /* Group Boxes #QGroupBox */ QGroupBox { border-color: #3F3F46; diff --git a/src/stylesheets/vs15 Dark-Red.qss b/src/stylesheets/vs15 Dark-Red.qss index 0c9143cd..0c0e21a8 100644 --- a/src/stylesheets/vs15 Dark-Red.qss +++ b/src/stylesheets/vs15 Dark-Red.qss @@ -210,6 +210,13 @@ QToolButton { QToolButton:pressed { background-color: #990000; } +QToolButton::menu-indicator { + image: url(./vs15/combobox-down.png); + subcontrol-origin: padding; + subcontrol-position: center right; + padding-top: 10%; + padding-right: 5%; } + /* Group Boxes #QGroupBox */ QGroupBox { border-color: #3F3F46; diff --git a/src/stylesheets/vs15 Dark-Yellow.qss b/src/stylesheets/vs15 Dark-Yellow.qss index 2eb42534..2cf1cb2e 100644 --- a/src/stylesheets/vs15 Dark-Yellow.qss +++ b/src/stylesheets/vs15 Dark-Yellow.qss @@ -210,6 +210,13 @@ QToolButton { QToolButton:pressed { background-color: #9A9A00; } +QToolButton::menu-indicator { + image: url(./vs15/combobox-down.png); + subcontrol-origin: padding; + subcontrol-position: center right; + padding-top: 10%; + padding-right: 5%; } + /* Group Boxes #QGroupBox */ QGroupBox { border-color: #3F3F46; diff --git a/src/stylesheets/vs15 Dark.qss b/src/stylesheets/vs15 Dark.qss index d67cce35..a5781d72 100644 --- a/src/stylesheets/vs15 Dark.qss +++ b/src/stylesheets/vs15 Dark.qss @@ -209,6 +209,13 @@ QToolButton { QToolButton:pressed { background-color: #3399FF; } +QToolButton::menu-indicator { + image: url(./vs15/combobox-down.png); + subcontrol-origin: padding; + subcontrol-position: center right; + padding-top: 10%; + padding-right: 5%; } + /* Group Boxes #QGroupBox */ QGroupBox { border-color: #3F3F46; |
