diff options
| author | isanae <14251494+isanae@users.noreply.github.com> | 2019-10-04 06:30:15 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2019-10-04 06:30:15 -0400 |
| commit | 2fe50f2ff366ea850eb70a85c6ea7d6c936bf08a (patch) | |
| tree | 77041dd84568817e0e359381e7fb78f6a1f2dd2a | |
| parent | e6a47bf8b70be2c480f77c68c08480a33e71dce3 (diff) | |
| parent | 239cfbe6854f727b5dd3e6922cacc17587361cf5 (diff) | |
Merge pull request #842 from isanae/dialog-settings
Dialog settings
| -rw-r--r-- | src/CMakeLists.txt | 3 | ||||
| -rw-r--r-- | src/colortable.cpp | 295 | ||||
| -rw-r--r-- | src/colortable.h | 39 | ||||
| -rw-r--r-- | src/icondelegate.cpp | 15 | ||||
| -rw-r--r-- | src/icondelegate.h | 18 | ||||
| -rw-r--r-- | src/mainwindow.cpp | 16 | ||||
| -rw-r--r-- | src/mainwindow.h | 1 | ||||
| -rw-r--r-- | src/moapplication.cpp | 4 | ||||
| -rw-r--r-- | src/modflagicondelegate.cpp | 112 | ||||
| -rw-r--r-- | src/modflagicondelegate.h | 11 | ||||
| -rw-r--r-- | src/organizercore.cpp | 36 | ||||
| -rw-r--r-- | src/organizercore.h | 1 | ||||
| -rw-r--r-- | src/selfupdater.cpp | 12 | ||||
| -rw-r--r-- | src/selfupdater.h | 14 | ||||
| -rw-r--r-- | src/settings.cpp | 132 | ||||
| -rw-r--r-- | src/settings.h | 62 | ||||
| -rw-r--r-- | src/settingsdialog.ui | 431 | ||||
| -rw-r--r-- | src/settingsdialoggeneral.cpp | 266 | ||||
| -rw-r--r-- | src/settingsdialoggeneral.h | 33 |
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><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> -<html><head><meta name="qrichtext" content="1" /><style type="text/css"> -p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">The display language. This will only displaye languages for which you have a translation installed.</span></p></body></html></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 "Remember selection"-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(); |
