summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/CMakeLists.txt3
-rw-r--r--src/colortable.cpp295
-rw-r--r--src/colortable.h39
-rw-r--r--src/icondelegate.cpp15
-rw-r--r--src/icondelegate.h18
-rw-r--r--src/mainwindow.cpp16
-rw-r--r--src/mainwindow.h1
-rw-r--r--src/moapplication.cpp4
-rw-r--r--src/modflagicondelegate.cpp112
-rw-r--r--src/modflagicondelegate.h11
-rw-r--r--src/organizercore.cpp36
-rw-r--r--src/organizercore.h1
-rw-r--r--src/selfupdater.cpp12
-rw-r--r--src/selfupdater.h14
-rw-r--r--src/settings.cpp132
-rw-r--r--src/settings.h62
-rw-r--r--src/settingsdialog.ui431
-rw-r--r--src/settingsdialoggeneral.cpp266
-rw-r--r--src/settingsdialoggeneral.h33
19 files changed, 1029 insertions, 472 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 7c29ff48..b21d1a8b 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -141,6 +141,7 @@ SET(organizer_SRCS
envsecurity.cpp
envshortcut.cpp
envwindows.cpp
+ colortable.cpp
shared/windows_error.cpp
shared/error_report.cpp
@@ -263,6 +264,7 @@ SET(organizer_HDRS
envsecurity.h
envshortcut.h
envwindows.h
+ colortable.h
shared/windows_error.h
shared/error_report.h
@@ -473,6 +475,7 @@ set(utilities
)
set(widgets
+ colortable
genericicondelegate
filerenamer
filterwidget
diff --git a/src/colortable.cpp b/src/colortable.cpp
new file mode 100644
index 00000000..61c5ee5f
--- /dev/null
+++ b/src/colortable.cpp
@@ -0,0 +1,295 @@
+#include "colortable.h"
+#include "modflagicondelegate.h"
+#include "settings.h"
+
+class ColorItem;
+ColorItem* colorItemForRow(QTableWidget* table, int row);
+
+void paintBackground(
+ QTableWidget* table, QPainter* p, const QStyleOptionViewItem& option,
+ const QModelIndex& index);
+
+
+// delegate for the sample text column; paints the background color
+//
+class ColoredBackgroundDelegate : public QStyledItemDelegate
+{
+public:
+ ColoredBackgroundDelegate(QTableWidget* table)
+ : m_table(table)
+ {
+ }
+
+ void paint(
+ QPainter* p, const QStyleOptionViewItem& option,
+ const QModelIndex& index) const override
+ {
+ paintBackground(m_table, p, option, index);
+
+ QStyleOptionViewItem itemOption(option);
+ initStyleOption(&itemOption, index);
+
+ // paint the default stuff like text, but override the state to avoid
+ // destroying the background for selected items, etc.
+ itemOption.state = QStyle::State_Enabled;
+
+ QStyledItemDelegate::paint(p, itemOption, index);
+ }
+
+private:
+ QTableWidget* m_table;
+};
+
+
+// delegate for the icons column; paints the background and icons
+//
+class FakeModFlagIconDelegate : public ModFlagIconDelegate
+{
+public:
+ explicit FakeModFlagIconDelegate(QTableWidget* table)
+ : m_table(table)
+ {
+ }
+
+ void paint(
+ QPainter *painter, const QStyleOptionViewItem &option,
+ const QModelIndex &index) const override
+ {
+ paintBackground(m_table, painter, option, index);
+ ModFlagIconDelegate::paintIcons(painter, option, index, getIcons(index));
+ }
+
+protected:
+ QList<QString> getIcons(const QModelIndex &index) const override
+ {
+ const auto flags = {
+ ModInfo::FLAG_CONFLICT_MIXED,
+ ModInfo::FLAG_ARCHIVE_LOOSE_CONFLICT_OVERWRITE,
+ ModInfo::FLAG_ARCHIVE_LOOSE_CONFLICT_OVERWRITTEN,
+ ModInfo::FLAG_ARCHIVE_CONFLICT_MIXED,
+ ModInfo::FLAG_BACKUP,
+ ModInfo::FLAG_NOTENDORSED,
+ ModInfo::FLAG_NOTES,
+ ModInfo::FLAG_ALTERNATE_GAME
+ };
+
+ return getIconsForFlags(flags, false);
+ }
+
+ size_t getNumIcons(const QModelIndex &index) const override
+ {
+ return getIcons(index).size();
+ }
+
+private:
+ QTableWidget* m_table;
+};
+
+
+// item used in the first column of the table
+//
+class ColorItem : public QTableWidgetItem
+{
+public:
+ ColorItem(
+ QString caption, QColor defaultColor,
+ std::function<QColor ()> get,
+ std::function<void (const QColor&)> commit) :
+ m_caption(std::move(caption)), m_default(defaultColor),
+ m_get(get), m_commit(commit)
+ {
+ setText(m_caption);
+ set(get());
+ }
+
+ // color caption
+ //
+ const QString& caption() const
+ {
+ return m_caption;
+ }
+
+ // the current color
+ //
+ QColor get() const
+ {
+ return m_temp;
+ }
+
+ // sets the current color, commit() must be called to save it
+ //
+ bool set(const QColor& c)
+ {
+ if (m_temp != c) {
+ m_temp = c;
+ return true;
+ }
+
+ return false;
+ }
+
+ // resets the current color, commit() must be called to save it
+ //
+ bool reset()
+ {
+ return set(m_default);
+ }
+
+ // saves the current color
+ //
+ void commit()
+ {
+ m_commit(m_temp);
+ }
+
+private:
+ const QString m_caption;
+ const QColor m_default;
+ std::function<QColor ()> m_get;
+ std::function<void (const QColor&)> m_commit;
+ QColor m_temp;
+};
+
+
+ColorItem* colorItemForRow(QTableWidget* table, int row)
+{
+ return dynamic_cast<ColorItem*>(table->item(row, 0));
+}
+
+template <class F>
+void forEachColorItem(QTableWidget* table, F&& f)
+{
+ const auto rowCount = table->rowCount();
+
+ for (int i=0; i<rowCount; ++i) {
+ if (auto* ci=colorItemForRow(table, i)) {
+ f(ci);
+ }
+ }
+}
+
+void paintBackground(
+ QTableWidget* table, QPainter* p, const QStyleOptionViewItem& option,
+ const QModelIndex& index)
+{
+ if (auto* ci=colorItemForRow(table, index.row())) {
+ p->save();
+ p->fillRect(option.rect, ci->get());
+ p->restore();
+ }
+}
+
+
+ColorTable::ColorTable(QWidget* parent)
+ : QTableWidget(parent), m_settings(nullptr)
+{
+ setColumnCount(3);
+ setHorizontalHeaderLabels({"", "", ""});
+
+ setItemDelegateForColumn(1, new ColoredBackgroundDelegate(this));
+ setItemDelegateForColumn(2, new FakeModFlagIconDelegate(this));
+
+ connect(
+ this, &QTableWidget::cellActivated,
+ [&]{ onColorActivated(); });
+}
+
+void ColorTable::load(Settings& s)
+{
+ m_settings = &s;
+
+ addColor(
+ QObject::tr("Is overwritten (loose files)"),
+ QColor(0, 255, 0, 64),
+ [this]{ return m_settings->colors().modlistOverwrittenLoose(); },
+ [this](auto&& v){ m_settings->colors().setModlistOverwrittenLoose(v); });
+
+ addColor(
+ QObject::tr("Is overwriting (loose files)"),
+ QColor(255, 0, 0, 64),
+ [this]{ return m_settings->colors().modlistOverwritingLoose(); },
+ [this](auto&& v){ m_settings->colors().setModlistOverwritingLoose(v); });
+
+ addColor(
+ QObject::tr("Is overwritten (archives)"),
+ QColor(0, 255, 255, 64),
+ [this]{ return m_settings->colors().modlistOverwrittenArchive(); },
+ [this](auto&& v){ m_settings->colors().setModlistOverwrittenArchive(v); });
+
+ addColor(
+ QObject::tr("Is overwriting (archives)"),
+ QColor(255, 0, 255, 64),
+ [this]{ return m_settings->colors().modlistOverwritingArchive(); },
+ [this](auto&& v){ m_settings->colors().setModlistOverwritingArchive(v); });
+
+ addColor(
+ QObject::tr("Mod contains selected plugin"),
+ QColor(0, 0, 255, 64),
+ [this]{ return m_settings->colors().modlistContainsPlugin(); },
+ [this](auto&& v){ m_settings->colors().setModlistContainsPlugin(v); });
+
+ addColor(
+ QObject::tr("Plugin is contained in selected mod"),
+ QColor(0, 0, 255, 64),
+ [this]{ return m_settings->colors().pluginListContained(); },
+ [this](auto&& v){ m_settings->colors().setPluginListContained(v); });
+}
+
+void ColorTable::resetColors()
+{
+ bool changed = false;
+
+ forEachColorItem(this, [&](auto* item) {
+ if (item->reset()) {
+ changed = true;
+ }
+ });
+
+ if (changed) {
+ update();
+ }
+}
+
+void ColorTable::commitColors()
+{
+ forEachColorItem(this, [](auto* item) {
+ item->commit();
+ });
+}
+
+void ColorTable::addColor(
+ const QString& text, const QColor& defaultColor,
+ std::function<QColor ()> get,
+ std::function<void (const QColor&)> commit)
+{
+ const auto r = rowCount();
+ setRowCount(r + 1);
+
+ setItem(r, 0, new ColorItem(text, defaultColor, get, commit));
+ setItem(r, 1, new QTableWidgetItem("Text"));
+ setItem(r, 2, new QTableWidgetItem);
+
+ resizeColumnsToContents();
+}
+
+void ColorTable::onColorActivated()
+{
+ const auto rows = selectionModel()->selectedRows();
+ if (rows.isEmpty()) {
+ return;
+ }
+
+ const auto row = rows[0].row();
+ auto* ci = colorItemForRow(this, row);
+ if (!ci) {
+ return;
+ }
+
+ const QColor result = QColorDialog::getColor(
+ ci->get(), topLevelWidget(), ci->caption(), QColorDialog::ShowAlphaChannel);
+
+ if (result.isValid()) {
+ ci->set(result);
+ update(model()->index(row, 1));
+ }
+}
diff --git a/src/colortable.h b/src/colortable.h
new file mode 100644
index 00000000..039b6024
--- /dev/null
+++ b/src/colortable.h
@@ -0,0 +1,39 @@
+#ifndef COLORTABLE_H
+#define COLORTABLE_H
+
+#include <QTableWidget>
+
+class Settings;
+
+// a QTableWidget to view and modify color settings
+//
+class ColorTable : public QTableWidget
+{
+public:
+ ColorTable(QWidget* parent=nullptr);
+
+ // adds colors to the table from the settings
+ //
+ void load(Settings& s);
+
+ // resets the colors to their default values; commitColors() must be called
+ // to save them
+ //
+ void resetColors();
+
+ // commits any changes
+ //
+ void commitColors();
+
+private:
+ Settings* m_settings;
+
+ void addColor(
+ const QString& text, const QColor& defaultColor,
+ std::function<QColor ()> get,
+ std::function<void (const QColor&)> commit);
+
+ void onColorActivated();
+};
+
+#endif // COLORTABLE_H
diff --git a/src/icondelegate.cpp b/src/icondelegate.cpp
index 39038f3c..03964263 100644
--- a/src/icondelegate.cpp
+++ b/src/icondelegate.cpp
@@ -32,13 +32,10 @@ IconDelegate::IconDelegate(QObject *parent)
{
}
-
-void IconDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
+void IconDelegate::paintIcons(
+ QPainter *painter, const QStyleOptionViewItem &option,
+ const QModelIndex &index, const QList<QString>& icons)
{
- QStyledItemDelegate::paint(painter, option, index);
-
- QList<QString> icons = getIcons(index);
-
int x = 4;
painter->save();
@@ -67,3 +64,9 @@ void IconDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
painter->restore();
}
+void IconDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
+{
+ QStyledItemDelegate::paint(painter, option, index);
+ paintIcons(painter, option, index, getIcons(index));
+}
+
diff --git a/src/icondelegate.h b/src/icondelegate.h
index 39694481..bac71a62 100644
--- a/src/icondelegate.h
+++ b/src/icondelegate.h
@@ -27,25 +27,19 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
class IconDelegate : public QStyledItemDelegate
{
- Q_OBJECT
-public:
+ Q_OBJECT;
+public:
explicit IconDelegate(QObject *parent = 0);
-
virtual void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
-signals:
-
-public slots:
-
-private:
+ static void paintIcons(
+ QPainter *painter, const QStyleOptionViewItem &option,
+ const QModelIndex &index, const QList<QString>& icons);
+protected:
virtual QList<QString> getIcons(const QModelIndex &index) const = 0;
virtual size_t getNumIcons(const QModelIndex &index) const = 0;
-
-
-private:
-
};
#endif // ICONDELEGATE_H
diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp
index 91da786c..8ab28d22 100644
--- a/src/mainwindow.cpp
+++ b/src/mainwindow.cpp
@@ -263,6 +263,7 @@ MainWindow::MainWindow(Settings &settings
setupToolbar();
toggleMO2EndorseState();
+ toggleUpdateAction();
TaskProgressManager::instance().tryCreateTaskbar();
@@ -5009,6 +5010,7 @@ void MainWindow::on_actionSettings_triggered()
bool oldDisplayForeign(settings.interface().displayForeign());
bool proxy = settings.network().useProxy();
DownloadManager *dlManager = m_OrganizerCore.downloadManager();
+ const bool oldCheckForUpdates = settings.checkForUpdates();
SettingsDialog dialog(&m_PluginContainer, settings, this);
@@ -5086,6 +5088,14 @@ void MainWindow::on_actionSettings_triggered()
m_OrganizerCore.cycleDiagnostics();
toggleMO2EndorseState();
+
+ if (oldCheckForUpdates != settings.checkForUpdates()) {
+ toggleUpdateAction();
+
+ if (settings.checkForUpdates()) {
+ m_OrganizerCore.checkForUpdates();
+ }
+ }
}
void MainWindow::on_actionNexus_triggered()
@@ -5598,6 +5608,12 @@ void MainWindow::toggleMO2EndorseState()
ui->actionEndorseMO->setStatusTip(text);
}
+void MainWindow::toggleUpdateAction()
+{
+ const auto& s = m_OrganizerCore.settings();
+ ui->actionUpdate->setVisible(s.checkForUpdates());
+}
+
void MainWindow::nxmEndorsementsAvailable(QVariant userData, QVariant resultData, int)
{
QVariantList data = resultData.toList();
diff --git a/src/mainwindow.h b/src/mainwindow.h
index 1f997ab1..524e2b6e 100644
--- a/src/mainwindow.h
+++ b/src/mainwindow.h
@@ -313,6 +313,7 @@ private:
void sendSelectedPluginsToPriority(int newPriority);
void toggleMO2EndorseState();
+ void toggleUpdateAction();
private:
diff --git a/src/moapplication.cpp b/src/moapplication.cpp
index 79e931fb..a071d58b 100644
--- a/src/moapplication.cpp
+++ b/src/moapplication.cpp
@@ -132,8 +132,8 @@ bool MOApplication::notify(QObject *receiver, QEvent *event)
void MOApplication::updateStyle(const QString &fileName)
{
- if (fileName == "Fusion") {
- setStyle(QStyleFactory::create("fusion"));
+ if (QStyleFactory::keys().contains(fileName)) {
+ setStyle(QStyleFactory::create(fileName));
setStyleSheet("");
} else {
setStyle(new ProxyStyle(QStyleFactory::create(m_DefaultStyle)));
diff --git a/src/modflagicondelegate.cpp b/src/modflagicondelegate.cpp
index 7110a590..a5e9aa22 100644
--- a/src/modflagicondelegate.cpp
+++ b/src/modflagicondelegate.cpp
@@ -31,72 +31,82 @@ void ModFlagIconDelegate::columnResized(int logicalIndex, int, int newSize)
}
}
-QList<QString> ModFlagIconDelegate::getIcons(const QModelIndex &index) const {
+QList<QString> ModFlagIconDelegate::getIconsForFlags(
+ std::vector<ModInfo::EFlag> flags, bool compact)
+{
QList<QString> result;
- QVariant modid = index.data(Qt::UserRole + 1);
- if (modid.isValid()) {
- ModInfo::Ptr info = ModInfo::getByIndex(modid.toInt());
- std::vector<ModInfo::EFlag> flags = info->getFlags();
- // Don't do flags for overwrite
- if (std::find(flags.begin(), flags.end(),ModInfo::FLAG_OVERWRITE) != flags.end())
- return result;
+ // Don't do flags for overwrite
+ if (std::find(flags.begin(), flags.end(),ModInfo::FLAG_OVERWRITE) != flags.end())
+ return result;
- // insert conflict icons to provide nicer alignment
- { // insert loose file conflicts first
- auto iter = std::find_first_of(flags.begin(), flags.end(),
- m_ConflictFlags, m_ConflictFlags + 4);
- if (iter != flags.end()) {
- result.append(getFlagIcon(*iter));
- flags.erase(iter);
- } else if (!m_Compact) {
- result.append(QString());
- }
+ // insert conflict icons to provide nicer alignment
+ { // insert loose file conflicts first
+ auto iter = std::find_first_of(flags.begin(), flags.end(),
+ m_ConflictFlags, m_ConflictFlags + 4);
+ if (iter != flags.end()) {
+ result.append(getFlagIcon(*iter));
+ flags.erase(iter);
+ } else if (!compact) {
+ result.append(QString());
}
+ }
- { // insert loose vs archive overwrite second
- auto iter = std::find(flags.begin(), flags.end(),
- ModInfo::FLAG_ARCHIVE_LOOSE_CONFLICT_OVERWRITE);
- if (iter != flags.end()) {
- result.append(getFlagIcon(*iter));
- flags.erase(iter);
- } else if (!m_Compact) {
- result.append(QString());
- }
+ { // insert loose vs archive overwrite second
+ auto iter = std::find(flags.begin(), flags.end(),
+ ModInfo::FLAG_ARCHIVE_LOOSE_CONFLICT_OVERWRITE);
+ if (iter != flags.end()) {
+ result.append(getFlagIcon(*iter));
+ flags.erase(iter);
+ } else if (!compact) {
+ result.append(QString());
}
+ }
- { // insert loose vs archive overwritten third
- auto iter = std::find_first_of(flags.begin(), flags.end(),
- m_ArchiveLooseConflictFlags + 1, m_ArchiveLooseConflictFlags + 2);
- if (iter != flags.end()) {
- result.append(getFlagIcon(*iter));
- flags.erase(iter);
- } else if (!m_Compact) {
- result.append(QString());
- }
+ { // insert loose vs archive overwritten third
+ auto iter = std::find_first_of(flags.begin(), flags.end(),
+ m_ArchiveLooseConflictFlags + 1, m_ArchiveLooseConflictFlags + 2);
+ if (iter != flags.end()) {
+ result.append(getFlagIcon(*iter));
+ flags.erase(iter);
+ } else if (!compact) {
+ result.append(QString());
}
+ }
- { // insert archive conflicts last
- auto iter = std::find_first_of(flags.begin(), flags.end(),
- m_ArchiveConflictFlags, m_ArchiveConflictFlags + 3);
- if (iter != flags.end()) {
- result.append(getFlagIcon(*iter));
- flags.erase(iter);
- } else if (!m_Compact) {
- result.append(QString());
- }
+ { // insert archive conflicts last
+ auto iter = std::find_first_of(flags.begin(), flags.end(),
+ m_ArchiveConflictFlags, m_ArchiveConflictFlags + 3);
+ if (iter != flags.end()) {
+ result.append(getFlagIcon(*iter));
+ flags.erase(iter);
+ } else if (!compact) {
+ result.append(QString());
}
+ }
- for (auto iter = flags.begin(); iter != flags.end(); ++iter) {
- auto iconPath = getFlagIcon(*iter);
- if (!iconPath.isEmpty())
- result.append(iconPath);
- }
+ for (auto iter = flags.begin(); iter != flags.end(); ++iter) {
+ auto iconPath = getFlagIcon(*iter);
+ if (!iconPath.isEmpty())
+ result.append(iconPath);
}
+
return result;
}
-QString ModFlagIconDelegate::getFlagIcon(ModInfo::EFlag flag) const
+QList<QString> ModFlagIconDelegate::getIcons(const QModelIndex &index) const
+{
+ QVariant modid = index.data(Qt::UserRole + 1);
+
+ if (modid.isValid()) {
+ ModInfo::Ptr info = ModInfo::getByIndex(modid.toInt());
+ return getIconsForFlags(info->getFlags(), m_Compact);
+ }
+
+ return {};
+}
+
+QString ModFlagIconDelegate::getFlagIcon(ModInfo::EFlag flag)
{
switch (flag) {
case ModInfo::FLAG_BACKUP: return QStringLiteral(":/MO/gui/emblem_backup");
diff --git a/src/modflagicondelegate.h b/src/modflagicondelegate.h
index eb6a76ab..4f22dd90 100644
--- a/src/modflagicondelegate.h
+++ b/src/modflagicondelegate.h
@@ -5,21 +5,24 @@
class ModFlagIconDelegate : public IconDelegate
{
-Q_OBJECT
+ Q_OBJECT;
public:
explicit ModFlagIconDelegate(QObject *parent = 0, int logicalIndex = -1, int compactSize = 120);
virtual QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const;
+ static QList<QString> getIconsForFlags(
+ std::vector<ModInfo::EFlag> flags, bool compact);
+
+ static QString getFlagIcon(ModInfo::EFlag flag);
+
public slots:
void columnResized(int logicalIndex, int oldSize, int newSize);
-private:
+protected:
virtual QList<QString> getIcons(const QModelIndex &index) const;
virtual size_t getNumIcons(const QModelIndex &index) const;
- QString getFlagIcon(ModInfo::EFlag flag) const;
-
private:
static ModInfo::EFlag m_ConflictFlags[4];
static ModInfo::EFlag m_ArchiveLooseConflictFlags[2];
diff --git a/src/organizercore.cpp b/src/organizercore.cpp
index 0da5b604..a4a89c99 100644
--- a/src/organizercore.cpp
+++ b/src/organizercore.cpp
@@ -74,25 +74,6 @@ using namespace MOBase;
//static
CrashDumpsType OrganizerCore::m_globalCrashDumpsType = CrashDumpsType::None;
-static bool isOnline()
-{
- const auto runningFlags =
- QNetworkInterface::IsUp | QNetworkInterface::IsRunning;
-
- for (auto&& i : QNetworkInterface::allInterfaces()) {
- if (!(i.flags() & QNetworkInterface::IsLoopBack)) {
- if (i.flags() & runningFlags) {
- auto addresses = i.addressEntries();
- if (!addresses.empty()) {
- return true;
- }
- }
- }
- }
-
- return false;
-}
-
static std::wstring getProcessName(HANDLE process)
{
wchar_t buffer[MAX_PATH];
@@ -307,14 +288,15 @@ void OrganizerCore::setUserInterface(IUserInterface *userInterface,
m_InstallationManager.setParentWidget(widget);
m_Updater.setUserInterface(widget);
- if (userInterface != nullptr) {
- // this currently wouldn't work reliably if the ui isn't initialized yet to
- // display the result
- if (isOnline() && !m_Settings.network().offlineMode()) {
- m_Updater.testForUpdate();
- } else {
- log::debug("user doesn't seem to be connected to the internet");
- }
+ checkForUpdates();
+}
+
+void OrganizerCore::checkForUpdates()
+{
+ // this currently wouldn't work reliably if the ui isn't initialized yet to
+ // display the result
+ if (m_UserInterface != nullptr) {
+ m_Updater.testForUpdate(m_Settings);
}
}
diff --git a/src/organizercore.h b/src/organizercore.h
index a14d79a9..5de550df 100644
--- a/src/organizercore.h
+++ b/src/organizercore.h
@@ -109,6 +109,7 @@ public:
void updateExecutablesList();
+ void checkForUpdates();
void startMOUpdate();
Settings &settings();
diff --git a/src/selfupdater.cpp b/src/selfupdater.cpp
index 0ca39b19..8887927a 100644
--- a/src/selfupdater.cpp
+++ b/src/selfupdater.cpp
@@ -122,8 +122,18 @@ void SelfUpdater::setPluginContainer(PluginContainer *pluginContainer)
m_Interface->setPluginContainer(pluginContainer);
}
-void SelfUpdater::testForUpdate()
+void SelfUpdater::testForUpdate(const Settings& settings)
{
+ if (settings.network().offlineMode()) {
+ log::debug("not checking for updates, in offline mode");
+ return;
+ }
+
+ if (!settings.checkForUpdates()) {
+ log::debug("not checking for updates, disabled");
+ return;
+ }
+
// TODO: if prereleases are disabled we could just request the latest release
// directly
try {
diff --git a/src/selfupdater.h b/src/selfupdater.h
index bce49495..0c81efc5 100644
--- a/src/selfupdater.h
+++ b/src/selfupdater.h
@@ -37,7 +37,7 @@ namespace MOBase { class IPluginGame; }
class QNetworkReply;
class QProgressDialog;
-
+class Settings;
/**
* @brief manages updates for Mod Organizer itself
@@ -81,6 +81,11 @@ public:
void setPluginContainer(PluginContainer *pluginContainer);
/**
+ * @brief request information about the current version
+ **/
+ void testForUpdate(const Settings& settings);
+
+ /**
* @brief start the update process
* @note this should not be called if there is no update available
**/
@@ -91,13 +96,6 @@ public:
**/
MOBase::VersionInfo getVersion() const { return m_MOVersion; }
-public slots:
-
- /**
- * @brief request information about the current version
- **/
- void testForUpdate();
-
signals:
/**
diff --git a/src/settings.cpp b/src/settings.cpp
index 7cea52fb..462cd92a 100644
--- a/src/settings.cpp
+++ b/src/settings.cpp
@@ -22,7 +22,9 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#include "serverinfo.h"
#include "executableslist.h"
#include "appconfig.h"
-#include "expanderwidget.h"
+#include "env.h"
+#include "envmetrics.h"
+#include <expanderwidget.h>
#include <utility.h>
#include <iplugingame.h>
@@ -176,6 +178,16 @@ QString Settings::filename() const
return m_Settings.fileName();
}
+bool Settings::checkForUpdates() const
+{
+ return get<bool>(m_Settings, "Settings", "check_for_updates", true);
+}
+
+void Settings::setCheckForUpdates(bool b)
+{
+ set(m_Settings, "Settings", "check_for_updates", b);
+}
+
bool Settings::usePrereleases() const
{
return get<bool>(m_Settings, "Settings", "use_prereleases", false);
@@ -604,21 +616,86 @@ void GeometrySettings::resetIfNeeded()
removeSection(m_Settings, "Geometry");
}
-void GeometrySettings::saveGeometry(const QWidget* w)
+void GeometrySettings::saveGeometry(const QMainWindow* w)
+{
+ saveWindowGeometry(w);
+}
+
+bool GeometrySettings::restoreGeometry(QMainWindow* w) const
+{
+ return restoreWindowGeometry(w);
+}
+
+void GeometrySettings::saveGeometry(const QDialog* d)
+{
+ saveWindowGeometry(d);
+}
+
+bool GeometrySettings::restoreGeometry(QDialog* d) const
+{
+ const auto r = restoreWindowGeometry(d);
+
+ if (centerDialogs()) {
+ centerOnParent(d);
+ }
+
+ return r;
+}
+
+void GeometrySettings::saveWindowGeometry(const QWidget* w)
{
set(m_Settings, "Geometry", geoSettingName(w), w->saveGeometry());
}
-bool GeometrySettings::restoreGeometry(QWidget* w) const
+bool GeometrySettings::restoreWindowGeometry(QWidget* w) const
{
if (auto v=getOptional<QByteArray>(m_Settings, "Geometry", geoSettingName(w))) {
w->restoreGeometry(*v);
+ ensureWindowOnScreen(w);
return true;
}
return false;
}
+void GeometrySettings::ensureWindowOnScreen(QWidget* w) const
+{
+ // users report that the main window and/or dialogs are displayed off-screen;
+ // the usual workaround is keyboard navigation to move it
+ //
+ // qt should have code that deals with multiple monitors and off-screen
+ // geometries, but there seems to be bugs or inconsistencies that can't be
+ // reproduced
+ //
+ // the closest would probably be https://bugreports.qt.io/browse/QTBUG-64498,
+ // which is about multiple monitors and high dpi, but it seems fixed as of
+ // 5.12.4, which is shipped with 2.2.1
+ //
+ // without being to reproduce the problem, some simple checks are made in a
+ // timer, which may mitigate the issues
+
+ QTimer::singleShot(100, w, [w] {
+ const auto borders = 20;
+
+ // desktop geometry, made smaller to make sure there isn't just a few pixels
+ const auto originalDg = env::Environment().metrics().desktopGeometry();
+ const auto dg = originalDg.adjusted(borders, borders, -borders, -borders);
+
+ const auto g = w->geometry();
+
+ if (!dg.intersects(g)) {
+ log::warn(
+ "window '{}' is offscreen, moving to main monitor; geo={}, desktop={}",
+ w->objectName(), g, originalDg);
+
+ // widget is off-screen, center it on main monitor
+ centerOnMonitor(w, -1);
+
+ log::warn("window '{}' now at {}", w->objectName(), w->geometry());
+ }
+ });
+}
+
void GeometrySettings::saveState(const QMainWindow* w)
{
set(m_Settings, "Geometry", stateSettingName(w), w->saveState());
@@ -768,15 +845,30 @@ void GeometrySettings::setModInfoTabOrder(const QString& names)
set(m_Settings, "Widgets", "ModInfoTabOrder", names);
}
+bool GeometrySettings::centerDialogs() const
+{
+ return get<bool>(m_Settings, "Settings", "center_dialogs", false);
+}
+
+void GeometrySettings::setCenterDialogs(bool b)
+{
+ set(m_Settings, "Settings", "center_dialogs", b);
+}
+
void GeometrySettings::centerOnMainWindowMonitor(QWidget* w)
{
const auto monitor = getOptional<int>(
- m_Settings, "Geometry", "MainWindow_monitor");
+ m_Settings, "Geometry", "MainWindow_monitor").value_or(-1);
+ centerOnMonitor(w, monitor);
+}
+
+void GeometrySettings::centerOnMonitor(QWidget* w, int monitor)
+{
QPoint center;
- if (monitor && QGuiApplication::screens().size() > *monitor) {
- center = QGuiApplication::screens().at(*monitor)->geometry().center();
+ if (monitor >= 0 && monitor < QGuiApplication::screens().size()) {
+ center = QGuiApplication::screens().at(monitor)->geometry().center();
} else {
center = QGuiApplication::primaryScreen()->geometry().center();
}
@@ -784,6 +876,22 @@ void GeometrySettings::centerOnMainWindowMonitor(QWidget* w)
w->move(center - w->rect().center());
}
+void GeometrySettings::centerOnParent(QWidget* w, QWidget* parent)
+{
+ if (!parent) {
+ parent = w->parentWidget();
+
+ if (!parent) {
+ parent = qApp->activeWindow();
+ }
+ }
+
+ if (parent && parent->isVisible()) {
+ const auto pr = parent->geometry();
+ w->move(pr.center() - w->rect().center());
+ }
+}
+
void GeometrySettings::saveMainWindowMonitor(const QMainWindow* w)
{
if (auto* handle=w->windowHandle()) {
@@ -1887,15 +1995,3 @@ void DiagnosticsSettings::setCrashDumpsMax(int n)
{
set(m_Settings, "Settings", "crash_dumps_max", n);
}
-
-
-GeometrySaver::GeometrySaver(Settings& s, QDialog* dialog)
- : m_settings(s), m_dialog(dialog)
-{
- m_settings.geometry().restoreGeometry(m_dialog);
-}
-
-GeometrySaver::~GeometrySaver()
-{
- m_settings.geometry().saveGeometry(m_dialog);
-}
diff --git a/src/settings.h b/src/settings.h
index cd478a5b..1556ba1e 100644
--- a/src/settings.h
+++ b/src/settings.h
@@ -41,20 +41,6 @@ class ServerList;
class Settings;
-// helper class that calls restoreGeometry() in the constructor and
-// saveGeometry() in the destructor
-//
-class GeometrySaver
-{
-public:
- GeometrySaver(Settings& s, QDialog* dialog);
- ~GeometrySaver();
-
-private:
- Settings& m_settings;
- QDialog* m_dialog;
-};
-
// setting for the currently managed game
//
@@ -141,8 +127,11 @@ public:
void resetIfNeeded();
- void saveGeometry(const QWidget* w);
- bool restoreGeometry(QWidget* w) const;
+ void saveGeometry(const QMainWindow* w);
+ bool restoreGeometry(QMainWindow* w) const;
+
+ void saveGeometry(const QDialog* d);
+ bool restoreGeometry(QDialog* d) const;
void saveState(const QMainWindow* window);
bool restoreState(QMainWindow* window) const;
@@ -171,6 +160,11 @@ public:
QStringList modInfoTabOrder() const;
void setModInfoTabOrder(const QString& names);
+ // whether dialogs should be centered on their parent
+ //
+ bool centerDialogs() const;
+ void setCenterDialogs(bool b);
+
// assumes the given widget is a top-level
//
void centerOnMainWindowMonitor(QWidget* w);
@@ -182,6 +176,13 @@ public:
private:
QSettings& m_Settings;
bool m_Reset;
+
+ void saveWindowGeometry(const QWidget* w);
+ bool restoreWindowGeometry(QWidget* w) const;
+
+ void ensureWindowOnScreen(QWidget* w) const;
+ static void centerOnMonitor(QWidget* w, int monitor);
+ static void centerOnParent(QWidget* w, QWidget* parent=nullptr);
};
@@ -691,6 +692,11 @@ public:
bool archiveParsing() const;
void setArchiveParsing(bool b);
+ // whether the user wants to check for updates
+ //
+ bool checkForUpdates() const;
+ void setCheckForUpdates(bool b);
+
// whether the user wants to upgrade to pre-releases
//
bool usePrereleases() const;
@@ -764,4 +770,28 @@ private:
DiagnosticsSettings m_Diagnostics;
};
+
+// helper class that calls restoreGeometry() in the constructor and
+// saveGeometry() in the destructor
+//
+template <class W>
+class GeometrySaver
+{
+public:
+ GeometrySaver(Settings& s, W* w)
+ : m_settings(s), m_widget(w)
+ {
+ m_settings.geometry().restoreGeometry(m_widget);
+ }
+
+ ~GeometrySaver()
+ {
+ m_settings.geometry().saveGeometry(m_widget);
+ }
+
+private:
+ Settings& m_settings;
+ W* m_widget;
+};
+
#endif // SETTINGS_H
diff --git a/src/settingsdialog.ui b/src/settingsdialog.ui
index 40079441..0ecbd101 100644
--- a/src/settingsdialog.ui
+++ b/src/settingsdialog.ui
@@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>586</width>
- <height>486</height>
+ <height>491</height>
</rect>
</property>
<property name="windowTitle">
@@ -23,160 +23,92 @@
<attribute name="title">
<string>General</string>
</attribute>
- <layout class="QVBoxLayout" name="verticalLayout_3">
- <item>
- <layout class="QHBoxLayout" name="horizontalLayout_3">
- <item>
- <widget class="QLabel" name="label_5">
- <property name="text">
- <string>Language</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QComboBox" name="languageBox">
- <property name="toolTip">
- <string>The display language</string>
- </property>
- <property name="whatsThis">
- <string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
-&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
-p, li { white-space: pre-wrap; }
-&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;&quot;&gt;
-&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:8pt;&quot;&gt;The display language. This will only displaye languages for which you have a translation installed.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
- </property>
- </widget>
- </item>
- </layout>
- </item>
- <item>
- <layout class="QHBoxLayout" name="horizontalLayout_4">
- <item>
- <widget class="QLabel" name="label_10">
- <property name="text">
- <string>Style</string>
- </property>
- </widget>
- </item>
- <item>
- <widget class="QComboBox" name="styleBox">
- <property name="toolTip">
- <string>graphical style</string>
- </property>
- <property name="whatsThis">
- <string>graphical style of the MO user interface</string>
- </property>
- </widget>
- </item>
- </layout>
- </item>
- <item>
- <widget class="QCheckBox" name="usePrereleaseBox">
- <property name="toolTip">
- <string>Update to non-stable releases.</string>
- </property>
- <property name="whatsThis">
- <string>If this is enabled, the integrated update mechanism will notify of all releases, including pre-releases (alphas, betas). Please use this only if you're sufficiently tech-savvy to investigate issues, look for known problems in the issue tracker and create meaningful reports.</string>
+ <layout class="QGridLayout" name="gridLayout" rowstretch="0,0,0,0,0,1">
+ <item row="5" column="0" colspan="2">
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
</property>
- <property name="text">
- <string>Install Pre-releases (Betas)</string>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>0</width>
+ <height>0</height>
+ </size>
</property>
- </widget>
+ </spacer>
</item>
- <item>
+ <item row="0" column="0" rowspan="2">
<widget class="QGroupBox" name="groupBox">
<property name="title">
- <string>User interface</string>
+ <string>User Interface</string>
</property>
- <layout class="QGridLayout" name="gridLayout">
- <item row="2" column="0" colspan="2">
- <widget class="QGroupBox" name="ModlistGroupBox">
- <property name="title">
- <string>Colors</string>
- </property>
- <layout class="QGridLayout" name="gridLayout_5">
- <item row="6" column="0">
- <widget class="QCheckBox" name="colorSeparatorsBox">
- <property name="toolTip">
- <string>When this is enabled, the color defined for a separator will be shown on the mod list scrollbar at the location of the separator. This can be useful for quick navigation between separator sections or to a specific separator section.</string>
- </property>
- <property name="whatsThis">
- <string>When this is enabled, the color defined for a separator will be shown on the mod list scrollbar at the location of the separator. This can be useful for quick navigation between separator sections or to a specific separator section.</string>
- </property>
+ <layout class="QVBoxLayout" name="verticalLayout_14">
+ <item>
+ <widget class="QWidget" name="widget_6" native="true">
+ <layout class="QFormLayout" name="formLayout_4">
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item row="0" column="0">
+ <widget class="QLabel" name="label_5">
<property name="text">
- <string>Show mod list separator colors on the scrollbar</string>
- </property>
- <property name="checked">
- <bool>true</bool>
+ <string>Language</string>
</property>
</widget>
</item>
- <item row="4" column="0" colspan="2">
- <widget class="QPushButton" name="containedBtn">
- <property name="text">
- <string>Plugin is Contained in selected Mod</string>
+ <item row="0" column="1">
+ <widget class="QComboBox" name="languageBox">
+ <property name="toolTip">
+ <string>The language of the user interface.</string>
+ </property>
+ <property name="whatsThis">
+ <string>The language of the user interface.</string>
</property>
</widget>
</item>
<item row="1" column="0">
- <widget class="QPushButton" name="overwrittenBtn">
+ <widget class="QLabel" name="label_10">
<property name="text">
- <string>Is overwritten (loose files)</string>
+ <string>Style</string>
</property>
</widget>
</item>
<item row="1" column="1">
- <widget class="QPushButton" name="overwritingBtn">
- <property name="text">
- <string>Is overwriting (loose files)</string>
- </property>
- </widget>
- </item>
- <item row="5" column="0" colspan="2">
- <widget class="QPushButton" name="resetColorsBtn">
- <property name="text">
- <string>Reset Colors</string>
- </property>
- </widget>
- </item>
- <item row="3" column="0" colspan="2">
- <widget class="QPushButton" name="containsBtn">
- <property name="text">
- <string>Mod Contains selected Plugin</string>
- </property>
- </widget>
- </item>
- <item row="2" column="0">
- <widget class="QPushButton" name="overwrittenArchiveBtn">
- <property name="text">
- <string>Is overwritten (archive files)</string>
+ <widget class="QComboBox" name="styleBox">
+ <property name="toolTip">
+ <string>Visual theme of the user interface.</string>
</property>
- </widget>
- </item>
- <item row="2" column="1">
- <widget class="QPushButton" name="overwritingArchiveBtn">
- <property name="text">
- <string>Is overwriting (archive files)</string>
+ <property name="whatsThis">
+ <string>Visual theme of the user interface.</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
- <item row="6" column="0" colspan="2">
- <widget class="QPushButton" name="categoriesBtn">
+ <item>
+ <widget class="QCheckBox" name="centerDialogs">
<property name="toolTip">
- <string>Modify the categories available to arrange your mods.</string>
+ <string>Dialogs will always be centered on the main window, but will remember their size.</string>
</property>
<property name="whatsThis">
- <string>Modify the categories available to arrange your mods.</string>
+ <string>Dialogs will always be centered on the main window, but will remember their size.</string>
</property>
<property name="text">
- <string>Configure Mod Categories</string>
+ <string>Always center dialogs</string>
</property>
</widget>
</item>
- <item row="5" column="0" colspan="2">
+ <item>
<widget class="QPushButton" name="resetDialogsButton">
<property name="maximumSize">
<size>
@@ -185,49 +117,238 @@ p, li { white-space: pre-wrap; }
</size>
</property>
<property name="toolTip">
- <string>Reset stored information from dialogs.</string>
+ <string>Reset all choices made in dialogs.</string>
</property>
<property name="whatsThis">
- <string>This will make all dialogs show up again where you checked the &quot;Remember selection&quot;-box.</string>
+ <string>Reset all choices made in dialogs.</string>
</property>
<property name="text">
<string>Reset Dialog Choices</string>
</property>
</widget>
</item>
- <item row="0" column="0">
- <widget class="QCheckBox" name="compactBox">
+ <item>
+ <widget class="QPushButton" name="categoriesBtn">
<property name="toolTip">
- <string>If checked, the download interface will be more compact.</string>
+ <string>Modify the categories available to arrange your mods.</string>
+ </property>
+ <property name="whatsThis">
+ <string>Modify the categories available to arrange your mods.</string>
</property>
<property name="text">
- <string>Compact Download Interface</string>
+ <string>Configure Mod Categories</string>
</property>
</widget>
</item>
- <item row="4" column="0" colspan="2">
- <spacer name="verticalSpacer">
+ <item>
+ <spacer name="verticalSpacer_11">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
- <width>20</width>
- <height>40</height>
+ <width>0</width>
+ <height>0</height>
</size>
</property>
</spacer>
</item>
- <item row="0" column="1">
+ </layout>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QGroupBox" name="groupBox_5">
+ <property name="title">
+ <string>Download List</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_2">
+ <item>
<widget class="QCheckBox" name="showMetaBox">
<property name="toolTip">
- <string>If checked, the download list will display meta information instead of file names.</string>
+ <string>Show meta information instead of file names in the download list.</string>
+ </property>
+ <property name="whatsThis">
+ <string>Show meta information instead of file names in the download list.</string>
</property>
<property name="text">
- <string>Download Meta Information</string>
+ <string>Show Meta Information</string>
</property>
</widget>
</item>
+ <item>
+ <widget class="QCheckBox" name="compactBox">
+ <property name="toolTip">
+ <string>Make the download list more compact.</string>
+ </property>
+ <property name="whatsThis">
+ <string>Make the download list more compact.</string>
+ </property>
+ <property name="text">
+ <string>Compact List</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacer_5">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>0</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item row="3" column="0" colspan="2">
+ <widget class="QGroupBox" name="ModlistGroupBox">
+ <property name="title">
+ <string>Colors</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_13">
+ <item>
+ <widget class="ColorTable" name="colorTable">
+ <property name="editTriggers">
+ <set>QAbstractItemView::NoEditTriggers</set>
+ </property>
+ <property name="selectionMode">
+ <enum>QAbstractItemView::SingleSelection</enum>
+ </property>
+ <property name="selectionBehavior">
+ <enum>QAbstractItemView::SelectRows</enum>
+ </property>
+ <property name="verticalScrollMode">
+ <enum>QAbstractItemView::ScrollPerPixel</enum>
+ </property>
+ <property name="cornerButtonEnabled">
+ <bool>false</bool>
+ </property>
+ <attribute name="horizontalHeaderVisible">
+ <bool>false</bool>
+ </attribute>
+ <attribute name="horizontalHeaderHighlightSections">
+ <bool>false</bool>
+ </attribute>
+ <attribute name="horizontalHeaderStretchLastSection">
+ <bool>true</bool>
+ </attribute>
+ <attribute name="verticalHeaderVisible">
+ <bool>false</bool>
+ </attribute>
+ </widget>
+ </item>
+ <item>
+ <widget class="QWidget" name="widget_5" native="true">
+ <layout class="QHBoxLayout" name="horizontalLayout_3">
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QCheckBox" name="colorSeparatorsBox">
+ <property name="toolTip">
+ <string>Colors set on separators will also be shown in the mod list scrollbar at the location of the separator. This can be useful for quickly navigating to a specific separator.</string>
+ </property>
+ <property name="whatsThis">
+ <string>Colors set on separators will also be shown in the mod list scrollbar at the location of the separator. This can be useful for quickly navigating to a specific separator.</string>
+ </property>
+ <property name="text">
+ <string>Show mod list separator colors on the scrollbar</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_2">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="resetColorsBtn">
+ <property name="toolTip">
+ <string>Reset all colors to their default value.</string>
+ </property>
+ <property name="whatsThis">
+ <string>Reset all colors to their default value.</string>
+ </property>
+ <property name="text">
+ <string>Reset Colors</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QGroupBox" name="groupBox_6">
+ <property name="title">
+ <string>Updates</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_3">
+ <item>
+ <widget class="QCheckBox" name="checkForUpdates">
+ <property name="toolTip">
+ <string>Check for Mod Organizer updates on Github on startup.</string>
+ </property>
+ <property name="whatsThis">
+ <string>Check for Mod Organizer updates on Github on startup.</string>
+ </property>
+ <property name="text">
+ <string>Check for updates</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="usePrereleaseBox">
+ <property name="toolTip">
+ <string>Update to non-stable releases.</string>
+ </property>
+ <property name="whatsThis">
+ <string>Update to non-stable releases.</string>
+ </property>
+ <property name="text">
+ <string>Install Pre-releases (Betas)</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacer_9">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>0</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
</layout>
</widget>
</item>
@@ -1406,13 +1527,27 @@ programs you are intentionally running.</string>
</item>
</layout>
</widget>
+ <customwidgets>
+ <customwidget>
+ <class>ColorTable</class>
+ <extends>QTableWidget</extends>
+ <header>colortable.h</header>
+ </customwidget>
+ </customwidgets>
<tabstops>
+ <tabstop>tabWidget</tabstop>
<tabstop>languageBox</tabstop>
<tabstop>styleBox</tabstop>
- <tabstop>logLevelBox</tabstop>
- <tabstop>usePrereleaseBox</tabstop>
- <tabstop>compactBox</tabstop>
+ <tabstop>centerDialogs</tabstop>
+ <tabstop>resetDialogsButton</tabstop>
<tabstop>categoriesBtn</tabstop>
+ <tabstop>showMetaBox</tabstop>
+ <tabstop>compactBox</tabstop>
+ <tabstop>checkForUpdates</tabstop>
+ <tabstop>usePrereleaseBox</tabstop>
+ <tabstop>colorTable</tabstop>
+ <tabstop>colorSeparatorsBox</tabstop>
+ <tabstop>resetColorsBtn</tabstop>
<tabstop>baseDirEdit</tabstop>
<tabstop>browseBaseDirBtn</tabstop>
<tabstop>downloadDirEdit</tabstop>
@@ -1425,7 +1560,18 @@ programs you are intentionally running.</string>
<tabstop>browseProfilesDirBtn</tabstop>
<tabstop>overwriteDirEdit</tabstop>
<tabstop>browseOverwriteDirBtn</tabstop>
+ <tabstop>managedGameDirEdit</tabstop>
+ <tabstop>browseGameDirBtn</tabstop>
+ <tabstop>nexusConnect</tabstop>
+ <tabstop>nexusManualKey</tabstop>
+ <tabstop>nexusDisconnect</tabstop>
+ <tabstop>nexusLog</tabstop>
+ <tabstop>offlineBox</tabstop>
+ <tabstop>endorsementBox</tabstop>
+ <tabstop>proxyBox</tabstop>
+ <tabstop>hideAPICounterBox</tabstop>
<tabstop>associateButton</tabstop>
+ <tabstop>clearCacheButton</tabstop>
<tabstop>knownServersList</tabstop>
<tabstop>preferredServersList</tabstop>
<tabstop>steamUserEdit</tabstop>
@@ -1435,8 +1581,17 @@ programs you are intentionally running.</string>
<tabstop>pluginBlacklist</tabstop>
<tabstop>appIDEdit</tabstop>
<tabstop>mechanismBox</tabstop>
+ <tabstop>hideUncheckedBox</tabstop>
+ <tabstop>forceEnableBox</tabstop>
+ <tabstop>lockGUIBox</tabstop>
+ <tabstop>displayForeignBox</tabstop>
+ <tabstop>enableArchiveParsingBox</tabstop>
<tabstop>bsaDateBtn</tabstop>
- <tabstop>tabWidget</tabstop>
+ <tabstop>execBlacklistBtn</tabstop>
+ <tabstop>resetGeometryBtn</tabstop>
+ <tabstop>logLevelBox</tabstop>
+ <tabstop>dumpsTypeBox</tabstop>
+ <tabstop>dumpsMaxEdit</tabstop>
</tabstops>
<resources>
<include location="resources.qrc"/>
diff --git a/src/settingsdialoggeneral.cpp b/src/settingsdialoggeneral.cpp
index 8ecdcbb9..e21fc5d0 100644
--- a/src/settingsdialoggeneral.cpp
+++ b/src/settingsdialoggeneral.cpp
@@ -2,75 +2,45 @@
#include "ui_settingsdialog.h"
#include "appconfig.h"
#include "categoriesdialog.h"
+#include "colortable.h"
#include <questionboxmemory.h>
-using MOBase::QuestionBoxMemory;
-
GeneralSettingsTab::GeneralSettingsTab(Settings& s, SettingsDialog& d)
: SettingsTab(s, d)
{
addLanguages();
- {
- QString languageCode = settings().interface().language();
- int currentID = ui->languageBox->findData(languageCode);
- // I made a mess. :( Most languages are stored with only the iso country
- // code (2 characters like "de") but chinese
- // with the exact language variant (zh_TW) so I have to search for both
- // variants
- if (currentID == -1) {
- currentID = ui->languageBox->findData(languageCode.mid(0, 2));
- }
- if (currentID != -1) {
- ui->languageBox->setCurrentIndex(currentID);
- }
- }
+ selectLanguage();
addStyles();
+ selectStyle();
- {
- const int currentID = ui->styleBox->findData(
- settings().interface().styleName().value_or(""));
-
- if (currentID != -1) {
- ui->styleBox->setCurrentIndex(currentID);
- }
- }
-
- //version with stylesheet
- setButtonColor(ui->overwritingBtn, settings().colors().modlistOverwritingLoose());
- setButtonColor(ui->overwrittenBtn, settings().colors().modlistOverwrittenLoose());
- setButtonColor(ui->overwritingArchiveBtn, settings().colors().modlistOverwritingArchive());
- setButtonColor(ui->overwrittenArchiveBtn, settings().colors().modlistOverwrittenArchive());
- setButtonColor(ui->containsBtn, settings().colors().modlistContainsPlugin());
- setButtonColor(ui->containedBtn, settings().colors().pluginListContained());
-
- setOverwritingColor(settings().colors().modlistOverwritingLoose());
- setOverwrittenColor(settings().colors().modlistOverwrittenLoose());
- setOverwritingArchiveColor(settings().colors().modlistOverwritingArchive());
- setOverwrittenArchiveColor(settings().colors().modlistOverwrittenArchive());
- setContainsColor(settings().colors().modlistContainsPlugin());
- setContainedColor(settings().colors().pluginListContained());
+ ui->colorTable->load(s);
+ ui->centerDialogs->setChecked(settings().geometry().centerDialogs());
ui->compactBox->setChecked(settings().interface().compactDownloads());
ui->showMetaBox->setChecked(settings().interface().metaDownloads());
+ ui->checkForUpdates->setChecked(settings().checkForUpdates());
ui->usePrereleaseBox->setChecked(settings().usePrereleases());
ui->colorSeparatorsBox->setChecked(settings().colors().colorSeparatorScrollbar());
- QObject::connect(ui->overwritingArchiveBtn, &QPushButton::clicked, [&]{ on_overwritingArchiveBtn_clicked(); });
- QObject::connect(ui->overwritingBtn, &QPushButton::clicked, [&]{ on_overwritingBtn_clicked(); });
- QObject::connect(ui->overwrittenArchiveBtn, &QPushButton::clicked, [&]{ on_overwrittenArchiveBtn_clicked(); });
- QObject::connect(ui->overwrittenBtn, &QPushButton::clicked, [&]{ on_overwrittenBtn_clicked(); });
- QObject::connect(ui->containedBtn, &QPushButton::clicked, [&]{ on_containedBtn_clicked(); });
- QObject::connect(ui->containsBtn, &QPushButton::clicked, [&]{ on_containsBtn_clicked(); });
- QObject::connect(ui->categoriesBtn, &QPushButton::clicked, [&]{ on_categoriesBtn_clicked(); });
- QObject::connect(ui->resetColorsBtn, &QPushButton::clicked, [&]{ on_resetColorsBtn_clicked(); });
- QObject::connect(ui->resetDialogsButton, &QPushButton::clicked, [&]{ on_resetDialogsButton_clicked(); });
+ QObject::connect(
+ ui->categoriesBtn, &QPushButton::clicked,
+ [&]{ on_categoriesBtn_clicked(); });
+
+ QObject::connect(
+ ui->resetColorsBtn, &QPushButton::clicked,
+ [&]{ on_resetColorsBtn_clicked(); });
+
+ QObject::connect(
+ ui->resetDialogsButton, &QPushButton::clicked,
+ [&]{ on_resetDialogsButton_clicked(); });
}
void GeneralSettingsTab::update()
{
const QString oldLanguage = settings().interface().language();
- const QString newLanguage = ui->languageBox->itemData(ui->languageBox->currentIndex()).toString();
+ const QString newLanguage = ui->languageBox->itemData(
+ ui->languageBox->currentIndex()).toString();
if (newLanguage != oldLanguage) {
settings().interface().setLanguage(newLanguage);
@@ -78,172 +48,147 @@ void GeneralSettingsTab::update()
}
const QString oldStyle = settings().interface().styleName().value_or("");
- const QString newStyle = ui->styleBox->itemData(ui->styleBox->currentIndex()).toString();
+ const QString newStyle = ui->styleBox->itemData(
+ ui->styleBox->currentIndex()).toString();
+
if (oldStyle != newStyle) {
settings().interface().setStyleName(newStyle);
emit settings().styleChanged(newStyle);
}
- settings().colors().setModlistOverwritingLoose(getOverwritingColor());
- settings().colors().setModlistOverwrittenLoose(getOverwrittenColor());
- settings().colors().setModlistOverwritingArchive(getOverwritingArchiveColor());
- settings().colors().setModlistOverwrittenArchive(getOverwrittenArchiveColor());
- settings().colors().setModlistContainsPlugin(getContainsColor());
- settings().colors().setPluginListContained(getContainedColor());
+ ui->colorTable->commitColors();
+ settings().geometry().setCenterDialogs(ui->centerDialogs->isChecked());
settings().interface().setCompactDownloads(ui->compactBox->isChecked());
settings().interface().setMetaDownloads(ui->showMetaBox->isChecked());
+ settings().setCheckForUpdates(ui->checkForUpdates->isChecked());
settings().setUsePrereleases(ui->usePrereleaseBox->isChecked());
settings().colors().setColorSeparatorScrollbar(ui->colorSeparatorsBox->isChecked());
}
void GeneralSettingsTab::addLanguages()
{
+ // matches the end of filenames for something like "_en.qm" or "_zh_CN.qm"
+ const QString pattern =
+ QString::fromStdWString(AppConfig::translationPrefix()) +
+ "_([a-z]{2,3}(_[A-Z]{2,2})?).qm";
+
+ const QRegExp exp(pattern);
+
+ QDirIterator iter(
+ QCoreApplication::applicationDirPath() + "/translations",
+ QDir::Files);
+
std::vector<std::pair<QString, QString>> languages;
- QDirIterator langIter(QCoreApplication::applicationDirPath() + "/translations", QDir::Files);
- QString pattern = QString::fromStdWString(AppConfig::translationPrefix()) + "_([a-z]{2,3}(_[A-Z]{2,2})?).qm";
- QRegExp exp(pattern);
- while (langIter.hasNext()) {
- langIter.next();
- QString file = langIter.fileName();
- if (exp.exactMatch(file)) {
- QString languageCode = exp.cap(1);
- QLocale locale(languageCode);
- QString languageString = QString("%1 (%2)").arg(locale.nativeLanguageName()).arg(locale.nativeCountryName()); //QLocale::languageToString(locale.language());
- if (locale.language() == QLocale::Chinese) {
- if (languageCode == "zh_TW") {
- languageString = "Chinese (traditional)";
- } else {
- languageString = "Chinese (simplified)";
- }
+ while (iter.hasNext()) {
+ iter.next();
+
+ const QString file = iter.fileName();
+ if (!exp.exactMatch(file)) {
+ continue;
+ }
+
+ const QString languageCode = exp.cap(1);
+ const QLocale locale(languageCode);
+
+ QString languageString = QString("%1 (%2)")
+ .arg(locale.nativeLanguageName())
+ .arg(locale.nativeCountryName());
+
+ if (locale.language() == QLocale::Chinese) {
+ if (languageCode == "zh_TW") {
+ languageString = "Chinese (Traditional)";
+ } else {
+ languageString = "Chinese (Simplified)";
}
- languages.push_back(std::make_pair(QString("%1").arg(languageString), exp.cap(1)));
}
+
+ languages.push_back({languageString, exp.cap(1)});
}
+
if (!ui->languageBox->findText("English")) {
- languages.push_back(std::make_pair(QString("English"), QString("en_US")));
+ languages.push_back({QString("English"), QString("en_US")});
}
+
std::sort(languages.begin(), languages.end());
- for (const auto &lang : languages) {
+
+ for (const auto& lang : languages) {
ui->languageBox->addItem(lang.first, lang.second);
}
}
-void GeneralSettingsTab::addStyles()
+void GeneralSettingsTab::selectLanguage()
{
- ui->styleBox->addItem("None", "");
- ui->styleBox->addItem("Fusion", "Fusion");
-
- QDirIterator langIter(QCoreApplication::applicationDirPath() + "/" + QString::fromStdWString(AppConfig::stylesheetsPath()), QStringList("*.qss"), QDir::Files);
- while (langIter.hasNext()) {
- langIter.next();
- QString style = langIter.fileName();
- ui->styleBox->addItem(style, style);
+ QString languageCode = settings().interface().language();
+ int currentID = ui->languageBox->findData(languageCode);
+ // I made a mess. :( Most languages are stored with only the iso country
+ // code (2 characters like "de") but chinese
+ // with the exact language variant (zh_TW) so I have to search for both
+ // variants
+ if (currentID == -1) {
+ currentID = ui->languageBox->findData(languageCode.mid(0, 2));
+ }
+ if (currentID != -1) {
+ ui->languageBox->setCurrentIndex(currentID);
}
}
-void GeneralSettingsTab::resetDialogs()
+void GeneralSettingsTab::addStyles()
{
- settings().widgets().resetQuestionButtons();
-}
+ ui->styleBox->addItem("None", "");
+ for (auto&& key : QStyleFactory::keys()) {
+ ui->styleBox->addItem(key, key);
+ }
-void GeneralSettingsTab::setButtonColor(QPushButton *button, const QColor &color)
-{
- button->setStyleSheet(
- QString("QPushButton {"
- "background-color: rgba(%1, %2, %3, %4);"
- "color: %5;"
- "border: 1px solid;"
- "padding: 3px;"
- "}")
- .arg(color.red())
- .arg(color.green())
- .arg(color.blue())
- .arg(color.alpha())
- .arg(ColorSettings::idealTextColor(color).name())
- );
-};
+ ui->styleBox->insertSeparator(ui->styleBox->count());
-void GeneralSettingsTab::on_containsBtn_clicked()
-{
- QColor result = QColorDialog::getColor(m_ContainsColor, &dialog(), "Color Picker: Mod contains selected plugin", QColorDialog::ShowAlphaChannel);
- if (result.isValid()) {
- m_ContainsColor = result;
- setButtonColor(ui->containsBtn, result);
- }
-}
+ QDirIterator iter(
+ QCoreApplication::applicationDirPath() + "/" +
+ QString::fromStdWString(AppConfig::stylesheetsPath()),
+ QStringList("*.qss"),
+ QDir::Files);
-void GeneralSettingsTab::on_containedBtn_clicked()
-{
- QColor result = QColorDialog::getColor(m_ContainedColor, &dialog(), "ColorPicker: Plugin is Contained in selected Mod", QColorDialog::ShowAlphaChannel);
- if (result.isValid()) {
- m_ContainedColor = result;
- setButtonColor(ui->containedBtn, result);
- }
-}
+ while (iter.hasNext()) {
+ iter.next();
-void GeneralSettingsTab::on_overwrittenBtn_clicked()
-{
- QColor result = QColorDialog::getColor(m_OverwrittenColor, &dialog(), "ColorPicker: Is overwritten (loose files)", QColorDialog::ShowAlphaChannel);
- if (result.isValid()) {
- m_OverwrittenColor = result;
- setButtonColor(ui->overwrittenBtn, result);
+ ui->styleBox->addItem(
+ iter.fileInfo().completeBaseName(),
+ iter.fileName());
}
}
-void GeneralSettingsTab::on_overwritingBtn_clicked()
+void GeneralSettingsTab::selectStyle()
{
- QColor result = QColorDialog::getColor(m_OverwritingColor, &dialog(), "ColorPicker: Is overwriting (loose files)", QColorDialog::ShowAlphaChannel);
- if (result.isValid()) {
- m_OverwritingColor = result;
- setButtonColor(ui->overwritingBtn, result);
- }
-}
+ const int currentID = ui->styleBox->findData(
+ settings().interface().styleName().value_or(""));
-void GeneralSettingsTab::on_overwrittenArchiveBtn_clicked()
-{
- QColor result = QColorDialog::getColor(m_OverwrittenArchiveColor, &dialog(), "ColorPicker: Is overwritten (archive files)", QColorDialog::ShowAlphaChannel);
- if (result.isValid()) {
- m_OverwrittenArchiveColor = result;
- setButtonColor(ui->overwrittenArchiveBtn, result);
+ if (currentID != -1) {
+ ui->styleBox->setCurrentIndex(currentID);
}
}
-void GeneralSettingsTab::on_overwritingArchiveBtn_clicked()
+void GeneralSettingsTab::resetDialogs()
{
- QColor result = QColorDialog::getColor(m_OverwritingArchiveColor, &dialog(), "ColorPicker: Is overwriting (archive files)", QColorDialog::ShowAlphaChannel);
- if (result.isValid()) {
- m_OverwritingArchiveColor = result;
- setButtonColor(ui->overwritingArchiveBtn, result);
- }
+ settings().widgets().resetQuestionButtons();
}
void GeneralSettingsTab::on_resetColorsBtn_clicked()
{
- m_OverwritingColor = QColor(255, 0, 0, 64);
- m_OverwrittenColor = QColor(0, 255, 0, 64);
- m_OverwritingArchiveColor = QColor(255, 0, 255, 64);
- m_OverwrittenArchiveColor = QColor(0, 255, 255, 64);
- m_ContainsColor = QColor(0, 0, 255, 64);
- m_ContainedColor = QColor(0, 0, 255, 64);
-
- setButtonColor(ui->overwritingBtn, m_OverwritingColor);
- setButtonColor(ui->overwrittenBtn, m_OverwrittenColor);
- setButtonColor(ui->overwritingArchiveBtn, m_OverwritingArchiveColor);
- setButtonColor(ui->overwrittenArchiveBtn, m_OverwrittenArchiveColor);
- setButtonColor(ui->containsBtn, m_ContainsColor);
- setButtonColor(ui->containedBtn, m_ContainedColor);
+ ui->colorTable->resetColors();
}
void GeneralSettingsTab::on_resetDialogsButton_clicked()
{
- if (QMessageBox::question(
- parentWidget(), QObject::tr("Confirm?"),
+ const auto r = QMessageBox::question(
+ parentWidget(),
+ QObject::tr("Confirm?"),
QObject::tr(
"This will reset all the choices you made to dialogs and make them all "
"visible again. Continue?"),
- QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {
+ QMessageBox::Yes | QMessageBox::No);
+
+ if (r == QMessageBox::Yes) {
resetDialogs();
}
}
@@ -251,6 +196,7 @@ void GeneralSettingsTab::on_resetDialogsButton_clicked()
void GeneralSettingsTab::on_categoriesBtn_clicked()
{
CategoriesDialog dialog(&dialog());
+
if (dialog.exec() == QDialog::Accepted) {
dialog.commitChanges();
}
diff --git a/src/settingsdialoggeneral.h b/src/settingsdialoggeneral.h
index 2038ba31..706ba9ef 100644
--- a/src/settingsdialoggeneral.h
+++ b/src/settingsdialoggeneral.h
@@ -12,38 +12,13 @@ public:
void update();
private:
- QColor m_OverwritingColor;
- QColor m_OverwrittenColor;
- QColor m_OverwritingArchiveColor;
- QColor m_OverwrittenArchiveColor;
- QColor m_ContainsColor;
- QColor m_ContainedColor;
-
void addLanguages();
- void addStyles();
- void resetDialogs();
- void setButtonColor(QPushButton *button, const QColor &color);
+ void selectLanguage();
- QColor getOverwritingColor() { return m_OverwritingColor; }
- QColor getOverwrittenColor() { return m_OverwrittenColor; }
- QColor getOverwritingArchiveColor() { return m_OverwritingArchiveColor; }
- QColor getOverwrittenArchiveColor() { return m_OverwrittenArchiveColor; }
- QColor getContainsColor() { return m_ContainsColor; }
- QColor getContainedColor() { return m_ContainedColor; }
-
- void setOverwritingColor(QColor col) { m_OverwritingColor = col; }
- void setOverwrittenColor(QColor col) { m_OverwrittenColor = col; }
- void setOverwritingArchiveColor(QColor col) { m_OverwritingArchiveColor = col; }
- void setOverwrittenArchiveColor(QColor col) { m_OverwrittenArchiveColor = col; }
- void setContainsColor(QColor col) { m_ContainsColor = col; }
- void setContainedColor(QColor col) { m_ContainedColor = col; }
+ void addStyles();
+ void selectStyle();
- void on_overwritingArchiveBtn_clicked();
- void on_overwritingBtn_clicked();
- void on_overwrittenArchiveBtn_clicked();
- void on_overwrittenBtn_clicked();
- void on_containedBtn_clicked();
- void on_containsBtn_clicked();
+ void resetDialogs();
void on_categoriesBtn_clicked();
void on_resetColorsBtn_clicked();