From 482f13a50b921e61d34d09f72a7fb4216efe742b Mon Sep 17 00:00:00 2001 From: Tannin Date: Mon, 8 Sep 2014 20:37:23 +0200 Subject: - re-enabled building of loot_cli and started developing against the new api - extended set of default categories - more tolerand bbcode parser - added a few colors for the bbcode parser - more fixes to qt5 compatibility - started work on ability to unloading (and thus re-loading) of plugins - names of plugins are no longer localizable (because those names are also used to store settings) - added settings to disable individual diagnosis settings - path of dependencies is now configured in a .pri file instead of environment variablees - bugfix: if the modid-input is canceled, the id was saved as -1 and wasn't re-requested from the user - bugfix: moving files with the SHFileOperation-Api didn't update the vfs correctly (still not perfect but better) - bugfix: attempt to remove the deleter-file seems to have caused error messages for some users - bugfix: fixed a couple of cases that might have caused the tutorial to hang --- src/settings.cpp | 1 - 1 file changed, 1 deletion(-) (limited to 'src/settings.cpp') diff --git a/src/settings.cpp b/src/settings.cpp index 6bf13ee0..65ea3a27 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -132,7 +132,6 @@ void Settings::registerPlugin(IPlugin *plugin) } } - QString Settings::obfuscate(const QString &password) const { QByteArray temp = password.toUtf8(); -- cgit v1.3.1 From 12a57d7f6dfbff8a5de618fc7f09066b83efa78f Mon Sep 17 00:00:00 2001 From: Tannin Date: Wed, 10 Sep 2014 20:34:31 +0200 Subject: - descriptions for plugin settings are now displayed --- src/settings.cpp | 1486 ++++++++++++++++++++++++------------------------ src/settings.h | 621 ++++++++++---------- src/settingsdialog.cpp | 355 ++++++------ 3 files changed, 1238 insertions(+), 1224 deletions(-) (limited to 'src/settings.cpp') diff --git a/src/settings.cpp b/src/settings.cpp index 65ea3a27..04a5f279 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -1,741 +1,745 @@ -/* -Copyright (C) 2012 Sebastian Herbord. All rights reserved. - -This file is part of Mod Organizer. - -Mod Organizer is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Mod Organizer is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Mod Organizer. If not, see . -*/ - -#include "settings.h" - -#include "settingsdialog.h" -#include "utility.h" -#include "helper.h" -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - - -using namespace MOBase; -using namespace MOShared; - - -template -class QListWidgetItemEx : public QListWidgetItem { -public: - QListWidgetItemEx(const QString &text, int sortRole = Qt::DisplayRole, QListWidget *parent = 0, int type = Type) - : QListWidgetItem(text, parent, type), m_SortRole(sortRole) {} - - virtual bool operator< ( const QListWidgetItem & other ) const { - return this->data(m_SortRole).value() < other.data(m_SortRole).value(); - } -private: - int m_SortRole; -}; - - -static const unsigned char Key2[20] = { 0x99, 0xb8, 0x76, 0x42, 0x3e, 0xc1, 0x60, 0xa4, 0x5b, 0x01, - 0xdb, 0xf8, 0x43, 0x3a, 0xb7, 0xb6, 0x98, 0xd4, 0x7d, 0xa2 }; - -Settings *Settings::s_Instance = NULL; - - -Settings::Settings() - : m_Settings(ToQString(GameInfo::instance().getIniFilename()), QSettings::IniFormat) -{ - if (s_Instance != NULL) { - throw std::runtime_error("second instance of \"Settings\" created"); - } else { - s_Instance = this; - } -} - - -Settings::~Settings() -{ - s_Instance = NULL; -} - - -Settings &Settings::instance() -{ - if (s_Instance == NULL) { - throw std::runtime_error("no instance of \"Settings\""); - } - return *s_Instance; -} - -void Settings::clearPlugins() -{ - m_Plugins.clear(); - m_PluginSettings.clear(); - - m_PluginBlacklist.clear(); - int count = m_Settings.beginReadArray("pluginBlacklist"); - for (int i = 0; i < count; ++i) { - m_Settings.setArrayIndex(i); - m_PluginBlacklist.insert(m_Settings.value("name").toString()); - } - m_Settings.endArray(); -} - -bool Settings::pluginBlacklisted(const QString &fileName) const -{ - return m_PluginBlacklist.contains(fileName); -} - -void Settings::registerAsNXMHandler(bool force) -{ - std::wstring nxmPath = ToWString(QCoreApplication::applicationDirPath() + "/nxmhandler.exe"); - std::wstring executable = ToWString(QCoreApplication::applicationFilePath()); - std::wstring mode = force ? L"forcereg" : L"reg"; - std::wstring parameters = mode + L" " + GameInfo::instance().getGameShortName() + L" \"" + executable + L"\""; - HINSTANCE res = ::ShellExecuteW(NULL, L"open", nxmPath.c_str(), parameters.c_str(), NULL, SW_SHOWNORMAL); - if ((int)res <= 32) { - QMessageBox::critical(NULL, tr("Failed"), - tr("Sorry, failed to start the helper application")); - } -} - -void Settings::registerPlugin(IPlugin *plugin) -{ - m_Plugins.push_back(plugin); - m_PluginSettings.insert(plugin->name(), QMap()); - foreach (const PluginSetting &setting, plugin->settings()) { - QVariant temp = m_Settings.value("Plugins/" + plugin->name() + "/" + setting.key, setting.defaultValue); - if (!temp.convert(setting.defaultValue.type())) { - qWarning("failed to interpret \"%s\" as correct type for \"%s\" in plugin \"%s\", using default", - qPrintable(temp.toString()), qPrintable(setting.key), qPrintable(plugin->name())); - temp = setting.defaultValue; - } - m_PluginSettings[plugin->name()][setting.key] = temp; - } -} - -QString Settings::obfuscate(const QString &password) const -{ - QByteArray temp = password.toUtf8(); - - QByteArray buffer; - for (int i = 0; i < temp.length(); ++i) { - buffer.append(temp.at(i) ^ Key2[i % 20]); - } - return buffer.toBase64(); -} - - -QString Settings::deObfuscate(const QString &password) const -{ - QByteArray temp(QByteArray::fromBase64(password.toUtf8())); - - QByteArray buffer; - for (int i = 0; i < temp.length(); ++i) { - buffer.append(temp.at(i) ^ Key2[i % 20]); - } - return QString::fromUtf8(buffer.constData()); -} - - -bool Settings::hideUncheckedPlugins() const -{ - return m_Settings.value("Settings/hide_unchecked_plugins", false).toBool(); -} - -bool Settings::forceEnableCoreFiles() const -{ - return m_Settings.value("Settings/force_enable_core_files", true).toBool(); -} - -bool Settings::automaticLoginEnabled() const -{ - return m_Settings.value("Settings/nexus_login", false).toBool(); -} - -QString Settings::getSteamAppID() const -{ - return m_Settings.value("Settings/app_id", ToQString(GameInfo::instance().getSteamAPPId(m_Settings.value("game_edition", 0).toInt()))).toString(); -} - -QString Settings::getDownloadDirectory() const -{ - return QDir::toNativeSeparators(m_Settings.value("Settings/download_directory", ToQString(GameInfo::instance().getDownloadDir())).toString()); -} - - -void Settings::setDownloadSpeed(const QString &serverName, int bytesPerSecond) -{ - m_Settings.beginGroup("Servers"); - - foreach (const QString &serverKey, m_Settings.childKeys()) { - QVariantMap data = m_Settings.value(serverKey).toMap(); - if (serverKey == serverName) { - data["downloadCount"] = data["downloadCount"].toInt() + 1; - data["downloadSpeed"] = data["downloadSpeed"].toDouble() + static_cast(bytesPerSecond); - m_Settings.setValue(serverKey, data); - } - } - - m_Settings.endGroup(); - m_Settings.sync(); -} - -std::map Settings::getPreferredServers() -{ - std::map result; - m_Settings.beginGroup("Servers"); - - foreach (const QString &serverKey, m_Settings.childKeys()) { - QVariantMap data = m_Settings.value(serverKey).toMap(); - int preference = data["preferred"].toInt(); - if (preference > 0) { - result[serverKey] = preference; - } - } - m_Settings.endGroup(); - - return result; -} - -QString Settings::getCacheDirectory() const -{ - return QDir::toNativeSeparators(m_Settings.value("Settings/cache_directory", ToQString(GameInfo::instance().getCacheDir())).toString()); -} - -QString Settings::getModDirectory() const -{ - return QDir::toNativeSeparators(m_Settings.value("Settings/mod_directory", ToQString(GameInfo::instance().getModsDir())).toString()); -} - -QString Settings::getNMMVersion() const -{ - static const QString MIN_NMM_VERSION = "0.47.0"; - QString result = m_Settings.value("Settings/nmm_version", MIN_NMM_VERSION).toString(); - if (VersionInfo(result) < VersionInfo(MIN_NMM_VERSION)) { - result = MIN_NMM_VERSION; - } - return result; -} - -bool Settings::getNexusLogin(QString &username, QString &password) const -{ - if (m_Settings.value("Settings/nexus_login", false).toBool()) { - username = m_Settings.value("Settings/nexus_username", "").toString(); - password = deObfuscate(m_Settings.value("Settings/nexus_password", "").toString()); - return true; - } else { - return false; - } -} - -bool Settings::compactDownloads() const -{ - return m_Settings.value("Settings/compact_downloads", false).toBool(); -} - -bool Settings::metaDownloads() const -{ - return m_Settings.value("Settings/meta_downloads", false).toBool(); -} - -bool Settings::offlineMode() const -{ - return m_Settings.value("Settings/offline_mode", false).toBool(); -} - -int Settings::logLevel() const -{ - return m_Settings.value("Settings/log_level", 0).toInt(); -} - - -void Settings::setNexusLogin(QString username, QString password) -{ - m_Settings.setValue("Settings/nexus_login", true); - m_Settings.setValue("Settings/nexus_username", username); - m_Settings.setValue("Settings/nexus_password", obfuscate(password)); -} - - -LoadMechanism::EMechanism Settings::getLoadMechanism() const -{ - switch (m_Settings.value("Settings/load_mechanism").toInt()) { - case LoadMechanism::LOAD_MODORGANIZER: return LoadMechanism::LOAD_MODORGANIZER; - case LoadMechanism::LOAD_SCRIPTEXTENDER: return LoadMechanism::LOAD_SCRIPTEXTENDER; - case LoadMechanism::LOAD_PROXYDLL: return LoadMechanism::LOAD_PROXYDLL; - } - throw std::runtime_error("invalid load mechanism"); -} - - -void Settings::setupLoadMechanism() -{ - m_LoadMechanism.activate(getLoadMechanism()); -} - - -bool Settings::useProxy() -{ - return m_Settings.value("Settings/use_proxy", false).toBool(); -} - -bool Settings::displayForeign() -{ - return m_Settings.value("Settings/display_foreign", true).toBool(); -} - -void Settings::setMotDHash(uint hash) -{ - m_Settings.setValue("motd_hash", hash); -} - -uint Settings::getMotDHash() const -{ - return m_Settings.value("motd_hash", 0).toUInt(); -} - -QVariant Settings::pluginSetting(const QString &pluginName, const QString &key) const -{ - auto iterPlugin = m_PluginSettings.find(pluginName); - if (iterPlugin == m_PluginSettings.end()) { - return QVariant(); - } - auto iterSetting = iterPlugin->find(key); - if (iterSetting == iterPlugin->end()) { - return QVariant(); - } - - return *iterSetting; -} - -void Settings::setPluginSetting(const QString &pluginName, const QString &key, const QVariant &value) -{ - auto iterPlugin = m_PluginSettings.find(pluginName); - if (iterPlugin == m_PluginSettings.end()) { - throw MyException(tr("attempt to store setting for unknown plugin \"%1\"").arg(pluginName)); - } - - // store the new setting both in memory and in the ini - m_PluginSettings[pluginName][key] = value; - m_Settings.setValue("Plugins/" + pluginName + "/" + key, value); -} - -QVariant Settings::pluginPersistent(const QString &pluginName, const QString &key, const QVariant &def) const -{ - if (!m_PluginSettings.contains(pluginName)) { - return def; - } - return m_Settings.value("PluginPersistance/" + pluginName + "/" + key, def); -} - -void Settings::setPluginPersistent(const QString &pluginName, const QString &key, const QVariant &value, bool sync) -{ - if (!m_PluginSettings.contains(pluginName)) { - throw MyException(tr("attempt to store setting for unknown plugin \"%1\"").arg(pluginName)); - } - m_Settings.setValue("PluginPersistance/" + pluginName + "/" + key, value); - if (sync) { - m_Settings.sync(); - } -} - -QString Settings::language() -{ - QString result = m_Settings.value("Settings/language", "").toString(); - if (result.isEmpty()) { - QStringList languagePreferences = QLocale::system().uiLanguages(); - if (languagePreferences.length() > 0) { - // the users most favoritest language - result = languagePreferences.at(0); - } else { - // fallback system locale - result = QLocale::system().name(); - } - } - return result; -} - -void Settings::updateServers(const QList &servers) -{ - m_Settings.beginGroup("Servers"); - QStringList oldServerKeys = m_Settings.childKeys(); - - foreach (const ServerInfo &server, servers) { - if (!oldServerKeys.contains(server.name)) { - // not yet known server - QVariantMap newVal; - newVal["premium"] = server.premium; - newVal["preferred"] = server.preferred ? 1 : 0; - newVal["lastSeen"] = server.lastSeen; - newVal["downloadCount"] = 0; - newVal["downloadSpeed"] = 0.0; - - m_Settings.setValue(server.name, newVal); - } else { - QVariantMap data = m_Settings.value(server.name).toMap(); - data["lastSeen"] = server.lastSeen; - data["premium"] = server.premium; - - m_Settings.setValue(server.name, data); - } - } - - m_Settings.endGroup(); - m_Settings.sync(); -} - -void Settings::addBlacklistPlugin(const QString &fileName) -{ - m_PluginBlacklist.insert(fileName); - writePluginBlacklist(); -} - -void Settings::writePluginBlacklist() -{ - m_Settings.beginWriteArray("pluginBlacklist"); - int idx = 0; - foreach (const QString &plugin, m_PluginBlacklist) { - m_Settings.setArrayIndex(idx++); - m_Settings.setValue("name", plugin); - } - - m_Settings.endArray(); -} - -void Settings::addLanguages(QComboBox *languageBox) -{ - languageBox->addItem("English", "en_US"); - - QDirIterator langIter(QCoreApplication::applicationDirPath() + "/translations", QDir::Files); - QString pattern = ToQString(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 = QLocale::languageToString(locale.language()); - if (locale.language() == QLocale::Chinese) { - if (languageCode == "zh_TW") { - languageString = "Chinese (traditional)"; - } else { - languageString = "Chinese (simplified)"; - } - } - languageBox->addItem(QString("%1").arg(languageString), exp.cap(1)); - } - } -} - -void Settings::addStyles(QComboBox *styleBox) -{ - styleBox->addItem("None", ""); -#if QT_VERSION >= QT_VERSION_CHECK(5,0,0) - styleBox->addItem("Fusion", "Fusion"); -#else - styleBox->addItem("Plastique", "Plastique"); - styleBox->addItem("Cleanlooks", "Cleanlooks"); -#endif - - QDirIterator langIter(QCoreApplication::applicationDirPath() + "/" + ToQString(AppConfig::stylesheetsPath()), QStringList("*.qss"), QDir::Files); - while (langIter.hasNext()) { - langIter.next(); - QString style = langIter.fileName(); - styleBox->addItem(style, style); - } -} - -void Settings::resetDialogs() -{ - m_Settings.beginGroup("DialogChoices"); - QStringList keys = m_Settings.childKeys(); - foreach (QString key, keys) { - m_Settings.remove(key); - } - - m_Settings.endGroup(); -} - - -void Settings::query(QWidget *parent) -{ - SettingsDialog dialog(parent); - - connect(&dialog, SIGNAL(resetDialogs()), this, SLOT(resetDialogs())); - - // General Page - QComboBox *languageBox = dialog.findChild("languageBox"); - QComboBox *styleBox = dialog.findChild("styleBox"); - QComboBox *logLevelBox = dialog.findChild("logLevelBox"); - QCheckBox *compactBox = dialog.findChild("compactBox"); - QCheckBox *showMetaBox = dialog.findChild("showMetaBox"); - - QLineEdit *downloadDirEdit = dialog.findChild("downloadDirEdit"); - QLineEdit *modDirEdit = dialog.findChild("modDirEdit"); - QLineEdit *cacheDirEdit = dialog.findChild("cacheDirEdit"); - - // nexus page - QCheckBox *loginCheckBox = dialog.findChild("loginCheckBox"); - QLineEdit *usernameEdit = dialog.findChild("usernameEdit"); - QLineEdit *passwordEdit = dialog.findChild("passwordEdit"); - QCheckBox *offlineBox = dialog.findChild("offlineBox"); - QCheckBox *proxyBox = dialog.findChild("proxyBox"); - - QListWidget *knownServersList = dialog.findChild("knownServersList"); - QListWidget *preferredServersList = dialog.findChild("preferredServersList"); - - // plugis page - QListWidget *pluginsList = dialog.findChild("pluginsList"); - QListWidget *pluginBlacklistList = dialog.findChild("pluginBlacklist"); - - // workarounds page - QCheckBox *forceEnableBox = dialog.findChild("forceEnableBox"); - QComboBox *mechanismBox = dialog.findChild("mechanismBox"); - QLineEdit *appIDEdit = dialog.findChild("appIDEdit"); - QLineEdit *nmmVersionEdit = dialog.findChild("nmmVersionEdit"); - QCheckBox *hideUncheckedBox = dialog.findChild("hideUncheckedBox"); - QCheckBox *displayForeignBox = dialog.findChild("displayForeignBox"); - - - // - // set up current settings - // - LoadMechanism::EMechanism mechanismID = getLoadMechanism(); - int index = 0; - - if (m_LoadMechanism.isDirectLoadingSupported()) { - mechanismBox->addItem(QObject::tr("Mod Organizer"), LoadMechanism::LOAD_MODORGANIZER); - if (mechanismID == LoadMechanism::LOAD_MODORGANIZER) { - index = mechanismBox->count() - 1; - } - } - - if (m_LoadMechanism.isScriptExtenderSupported()) { - mechanismBox->addItem(QObject::tr("Script Extender"), LoadMechanism::LOAD_SCRIPTEXTENDER); - if (mechanismID == LoadMechanism::LOAD_SCRIPTEXTENDER) { - index = mechanismBox->count() - 1; - } - } - - if (m_LoadMechanism.isProxyDLLSupported()) { - mechanismBox->addItem(QObject::tr("Proxy DLL"), LoadMechanism::LOAD_PROXYDLL); - if (mechanismID == LoadMechanism::LOAD_PROXYDLL) { - index = mechanismBox->count() - 1; - } - } - - mechanismBox->setCurrentIndex(index); - - { - addLanguages(languageBox); - QString languageCode = language(); - int currentID = 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 = languageBox->findData(languageCode.mid(0, 2)); - } - if (currentID != -1) { - languageBox->setCurrentIndex(currentID); - } - } - - { - addStyles(styleBox); - int currentID = styleBox->findData(m_Settings.value("Settings/style", "").toString()); - if (currentID != -1) { - styleBox->setCurrentIndex(currentID); - } - } - - compactBox->setChecked(compactDownloads()); - showMetaBox->setChecked(metaDownloads()); - - hideUncheckedBox->setChecked(hideUncheckedPlugins()); - displayForeignBox->setChecked(displayForeign()); - forceEnableBox->setChecked(forceEnableCoreFiles()); - - appIDEdit->setText(getSteamAppID()); - - if (automaticLoginEnabled()) { - loginCheckBox->setChecked(true); - usernameEdit->setText(m_Settings.value("Settings/nexus_username", "").toString()); - passwordEdit->setText(deObfuscate(m_Settings.value("Settings/nexus_password", "").toString())); - } - - downloadDirEdit->setText(getDownloadDirectory()); - modDirEdit->setText(getModDirectory()); - cacheDirEdit->setText(getCacheDirectory()); - offlineBox->setChecked(offlineMode()); - proxyBox->setChecked(useProxy()); - nmmVersionEdit->setText(getNMMVersion()); - logLevelBox->setCurrentIndex(logLevel()); - - // display plugin settings - foreach (IPlugin *plugin, m_Plugins) { - QListWidgetItem *listItem = new QListWidgetItem(plugin->name(), pluginsList); - listItem->setData(Qt::UserRole, QVariant::fromValue((void*)plugin)); - listItem->setData(Qt::UserRole + 1, m_PluginSettings[plugin->name()]); - pluginsList->addItem(listItem); - } - - // display plugin blacklist - foreach (const QString &pluginName, m_PluginBlacklist) { - pluginBlacklistList->addItem(pluginName); - } - - // display server preferences - m_Settings.beginGroup("Servers"); - foreach (const QString &key, m_Settings.childKeys()) { - QVariantMap val = m_Settings.value(key).toMap(); - QString type = val["premium"].toBool() ? "(premium)" : "(free)"; - - QString descriptor = key + " " + type; - if (val.contains("downloadSpeed") && val.contains("downloadCount") && (val["downloadCount"].toInt() > 0)) { - int bps = static_cast(val["downloadSpeed"].toDouble() / val["downloadCount"].toInt()); - descriptor += QString(" (%1 kbps)").arg(bps / 1024); - } - - QListWidgetItem *newItem = new QListWidgetItemEx(descriptor, Qt::UserRole + 1); - - newItem->setData(Qt::UserRole, key); - newItem->setData(Qt::UserRole + 1, val["preferred"].toInt()); - if (val["preferred"].toInt() > 0) { - preferredServersList->addItem(newItem); - } else { - knownServersList->addItem(newItem); - } - preferredServersList->sortItems(Qt::DescendingOrder); - } - m_Settings.endGroup(); - - if (dialog.exec() == QDialog::Accepted) { - // - // transfer modified settings to configuration file - // - - m_Settings.setValue("Settings/hide_unchecked_plugins", hideUncheckedBox->checkState() ? true : false); - m_Settings.setValue("Settings/force_enable_core_files", forceEnableBox->checkState() ? true : false); - m_Settings.setValue("Settings/compact_downloads", compactBox->isChecked()); - m_Settings.setValue("Settings/meta_downloads", showMetaBox->isChecked()); - m_Settings.setValue("Settings/load_mechanism", mechanismBox->itemData(mechanismBox->currentIndex()).toInt()); - - - { // advanced settings - if ((QDir::fromNativeSeparators(modDirEdit->text()) != QDir::fromNativeSeparators(getModDirectory())) && - (QMessageBox::question(NULL, tr("Confirm"), tr("Changing the mod directory affects all your profiles! " - "Mods not present (or named differently) in the new location will be disabled in all profiles. " - "There is no way to undo this unless you backed up your profiles manually. Proceed?"), - QMessageBox::Yes | QMessageBox::No) == QMessageBox::No)) { - modDirEdit->setText(getModDirectory()); - } - - if (!QDir(downloadDirEdit->text()).exists()) { - QDir().mkpath(downloadDirEdit->text()); - } - if (!QDir(cacheDirEdit->text()).exists()) { - QDir().mkpath(cacheDirEdit->text()); - } - if (!QDir(modDirEdit->text()).exists()) { - QDir().mkpath(modDirEdit->text()); - } - - m_Settings.setValue("Settings/download_directory", QDir::toNativeSeparators(downloadDirEdit->text())); - m_Settings.setValue("Settings/cache_directory", QDir::toNativeSeparators(cacheDirEdit->text())); - m_Settings.setValue("Settings/mod_directory", QDir::toNativeSeparators(modDirEdit->text())); - } - - - QString oldLanguage = m_Settings.value("Settings/language", "en_US").toString(); - QString newLanguage = languageBox->itemData(languageBox->currentIndex()).toString(); - if (newLanguage != oldLanguage) { - m_Settings.setValue("Settings/language", newLanguage); - emit languageChanged(newLanguage); - } - - QString oldStyle = m_Settings.value("Settings/style", "").toString(); - QString newStyle = styleBox->itemData(styleBox->currentIndex()).toString(); - if (oldStyle != newStyle) { - m_Settings.setValue("Settings/style", newStyle); - emit styleChanged(newStyle); - } - - m_Settings.setValue("Settings/log_level", logLevelBox->currentIndex()); - - if (appIDEdit->text() != ToQString(GameInfo::instance().getSteamAPPId())) { - m_Settings.setValue("Settings/app_id", appIDEdit->text()); - } else { - m_Settings.remove("Settings/app_id"); - } - if (loginCheckBox->isChecked()) { - m_Settings.setValue("Settings/nexus_login", true); - m_Settings.setValue("Settings/nexus_username", usernameEdit->text()); - m_Settings.setValue("Settings/nexus_password", obfuscate(passwordEdit->text())); - } else { - m_Settings.setValue("Settings/nexus_login", false); - m_Settings.remove("Settings/nexus_username"); - m_Settings.remove("Settings/nexus_password"); - } - m_Settings.setValue("Settings/offline_mode", offlineBox->isChecked()); - m_Settings.setValue("Settings/use_proxy", proxyBox->isChecked()); - m_Settings.setValue("Settings/display_foreign", displayForeignBox->isChecked()); - - m_Settings.setValue("Settings/nmm_version", nmmVersionEdit->text()); - - // transfer plugin settings to in-memory structure - for (int i = 0; i < pluginsList->count(); ++i) { - QListWidgetItem *item = pluginsList->item(i); - m_PluginSettings[item->text()] = item->data(Qt::UserRole + 1).toMap(); - } - // store plugin settings on disc - for (auto iterPlugins = m_PluginSettings.begin(); iterPlugins != m_PluginSettings.end(); ++iterPlugins) { - for (auto iterSettings = iterPlugins->begin(); iterSettings != iterPlugins->end(); ++iterSettings) { - m_Settings.setValue("Plugins/" + iterPlugins.key() + "/" + iterSettings.key(), iterSettings.value()); - } - } - - // store plugin blacklist - m_PluginBlacklist.clear(); - foreach (QListWidgetItem *item, pluginBlacklistList->findItems("*", Qt::MatchWildcard)) { - m_PluginBlacklist.insert(item->text()); - } - writePluginBlacklist(); - - // store server preference - m_Settings.beginGroup("Servers"); - for (int i = 0; i < knownServersList->count(); ++i) { - QString key = knownServersList->item(i)->data(Qt::UserRole).toString(); - QVariantMap val = m_Settings.value(key).toMap(); - val["preferred"] = 0; - m_Settings.setValue(key, val); - } - int count = preferredServersList->count(); - for (int i = 0; i < count; ++i) { - QString key = preferredServersList->item(i)->data(Qt::UserRole).toString(); - QVariantMap val = m_Settings.value(key).toMap(); - val["preferred"] = count - i; - m_Settings.setValue(key, val); - } - m_Settings.endGroup(); - } -} +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see . +*/ + +#include "settings.h" + +#include "settingsdialog.h" +#include "utility.h" +#include "helper.h" +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + + +using namespace MOBase; +using namespace MOShared; + + +template +class QListWidgetItemEx : public QListWidgetItem { +public: + QListWidgetItemEx(const QString &text, int sortRole = Qt::DisplayRole, QListWidget *parent = 0, int type = Type) + : QListWidgetItem(text, parent, type), m_SortRole(sortRole) {} + + virtual bool operator< ( const QListWidgetItem & other ) const { + return this->data(m_SortRole).value() < other.data(m_SortRole).value(); + } +private: + int m_SortRole; +}; + + +static const unsigned char Key2[20] = { 0x99, 0xb8, 0x76, 0x42, 0x3e, 0xc1, 0x60, 0xa4, 0x5b, 0x01, + 0xdb, 0xf8, 0x43, 0x3a, 0xb7, 0xb6, 0x98, 0xd4, 0x7d, 0xa2 }; + +Settings *Settings::s_Instance = NULL; + + +Settings::Settings() + : m_Settings(ToQString(GameInfo::instance().getIniFilename()), QSettings::IniFormat) +{ + if (s_Instance != NULL) { + throw std::runtime_error("second instance of \"Settings\" created"); + } else { + s_Instance = this; + } +} + + +Settings::~Settings() +{ + s_Instance = NULL; +} + + +Settings &Settings::instance() +{ + if (s_Instance == NULL) { + throw std::runtime_error("no instance of \"Settings\""); + } + return *s_Instance; +} + +void Settings::clearPlugins() +{ + m_Plugins.clear(); + m_PluginSettings.clear(); + + m_PluginBlacklist.clear(); + int count = m_Settings.beginReadArray("pluginBlacklist"); + for (int i = 0; i < count; ++i) { + m_Settings.setArrayIndex(i); + m_PluginBlacklist.insert(m_Settings.value("name").toString()); + } + m_Settings.endArray(); +} + +bool Settings::pluginBlacklisted(const QString &fileName) const +{ + return m_PluginBlacklist.contains(fileName); +} + +void Settings::registerAsNXMHandler(bool force) +{ + std::wstring nxmPath = ToWString(QCoreApplication::applicationDirPath() + "/nxmhandler.exe"); + std::wstring executable = ToWString(QCoreApplication::applicationFilePath()); + std::wstring mode = force ? L"forcereg" : L"reg"; + std::wstring parameters = mode + L" " + GameInfo::instance().getGameShortName() + L" \"" + executable + L"\""; + HINSTANCE res = ::ShellExecuteW(NULL, L"open", nxmPath.c_str(), parameters.c_str(), NULL, SW_SHOWNORMAL); + if ((int)res <= 32) { + QMessageBox::critical(NULL, tr("Failed"), + tr("Sorry, failed to start the helper application")); + } +} + +void Settings::registerPlugin(IPlugin *plugin) +{ + m_Plugins.push_back(plugin); + m_PluginSettings.insert(plugin->name(), QMap()); + m_PluginDescriptions.insert(plugin->name(), QMap()); + foreach (const PluginSetting &setting, plugin->settings()) { + QVariant temp = m_Settings.value("Plugins/" + plugin->name() + "/" + setting.key, setting.defaultValue); + if (!temp.convert(setting.defaultValue.type())) { + qWarning("failed to interpret \"%s\" as correct type for \"%s\" in plugin \"%s\", using default", + qPrintable(temp.toString()), qPrintable(setting.key), qPrintable(plugin->name())); + temp = setting.defaultValue; + } + m_PluginSettings[plugin->name()][setting.key] = temp; + m_PluginDescriptions[plugin->name()][setting.key] = QString("%1 (default: %2)").arg(setting.description).arg(setting.defaultValue.toString()); + } +} + + +QString Settings::obfuscate(const QString &password) const +{ + QByteArray temp = password.toUtf8(); + + QByteArray buffer; + for (int i = 0; i < temp.length(); ++i) { + buffer.append(temp.at(i) ^ Key2[i % 20]); + } + return buffer.toBase64(); +} + + +QString Settings::deObfuscate(const QString &password) const +{ + QByteArray temp(QByteArray::fromBase64(password.toUtf8())); + + QByteArray buffer; + for (int i = 0; i < temp.length(); ++i) { + buffer.append(temp.at(i) ^ Key2[i % 20]); + } + return QString::fromUtf8(buffer.constData()); +} + + +bool Settings::hideUncheckedPlugins() const +{ + return m_Settings.value("Settings/hide_unchecked_plugins", false).toBool(); +} + +bool Settings::forceEnableCoreFiles() const +{ + return m_Settings.value("Settings/force_enable_core_files", true).toBool(); +} + +bool Settings::automaticLoginEnabled() const +{ + return m_Settings.value("Settings/nexus_login", false).toBool(); +} + +QString Settings::getSteamAppID() const +{ + return m_Settings.value("Settings/app_id", ToQString(GameInfo::instance().getSteamAPPId(m_Settings.value("game_edition", 0).toInt()))).toString(); +} + +QString Settings::getDownloadDirectory() const +{ + return QDir::toNativeSeparators(m_Settings.value("Settings/download_directory", ToQString(GameInfo::instance().getDownloadDir())).toString()); +} + + +void Settings::setDownloadSpeed(const QString &serverName, int bytesPerSecond) +{ + m_Settings.beginGroup("Servers"); + + foreach (const QString &serverKey, m_Settings.childKeys()) { + QVariantMap data = m_Settings.value(serverKey).toMap(); + if (serverKey == serverName) { + data["downloadCount"] = data["downloadCount"].toInt() + 1; + data["downloadSpeed"] = data["downloadSpeed"].toDouble() + static_cast(bytesPerSecond); + m_Settings.setValue(serverKey, data); + } + } + + m_Settings.endGroup(); + m_Settings.sync(); +} + +std::map Settings::getPreferredServers() +{ + std::map result; + m_Settings.beginGroup("Servers"); + + foreach (const QString &serverKey, m_Settings.childKeys()) { + QVariantMap data = m_Settings.value(serverKey).toMap(); + int preference = data["preferred"].toInt(); + if (preference > 0) { + result[serverKey] = preference; + } + } + m_Settings.endGroup(); + + return result; +} + +QString Settings::getCacheDirectory() const +{ + return QDir::toNativeSeparators(m_Settings.value("Settings/cache_directory", ToQString(GameInfo::instance().getCacheDir())).toString()); +} + +QString Settings::getModDirectory() const +{ + return QDir::toNativeSeparators(m_Settings.value("Settings/mod_directory", ToQString(GameInfo::instance().getModsDir())).toString()); +} + +QString Settings::getNMMVersion() const +{ + static const QString MIN_NMM_VERSION = "0.47.0"; + QString result = m_Settings.value("Settings/nmm_version", MIN_NMM_VERSION).toString(); + if (VersionInfo(result) < VersionInfo(MIN_NMM_VERSION)) { + result = MIN_NMM_VERSION; + } + return result; +} + +bool Settings::getNexusLogin(QString &username, QString &password) const +{ + if (m_Settings.value("Settings/nexus_login", false).toBool()) { + username = m_Settings.value("Settings/nexus_username", "").toString(); + password = deObfuscate(m_Settings.value("Settings/nexus_password", "").toString()); + return true; + } else { + return false; + } +} + +bool Settings::compactDownloads() const +{ + return m_Settings.value("Settings/compact_downloads", false).toBool(); +} + +bool Settings::metaDownloads() const +{ + return m_Settings.value("Settings/meta_downloads", false).toBool(); +} + +bool Settings::offlineMode() const +{ + return m_Settings.value("Settings/offline_mode", false).toBool(); +} + +int Settings::logLevel() const +{ + return m_Settings.value("Settings/log_level", 0).toInt(); +} + + +void Settings::setNexusLogin(QString username, QString password) +{ + m_Settings.setValue("Settings/nexus_login", true); + m_Settings.setValue("Settings/nexus_username", username); + m_Settings.setValue("Settings/nexus_password", obfuscate(password)); +} + + +LoadMechanism::EMechanism Settings::getLoadMechanism() const +{ + switch (m_Settings.value("Settings/load_mechanism").toInt()) { + case LoadMechanism::LOAD_MODORGANIZER: return LoadMechanism::LOAD_MODORGANIZER; + case LoadMechanism::LOAD_SCRIPTEXTENDER: return LoadMechanism::LOAD_SCRIPTEXTENDER; + case LoadMechanism::LOAD_PROXYDLL: return LoadMechanism::LOAD_PROXYDLL; + } + throw std::runtime_error("invalid load mechanism"); +} + + +void Settings::setupLoadMechanism() +{ + m_LoadMechanism.activate(getLoadMechanism()); +} + + +bool Settings::useProxy() +{ + return m_Settings.value("Settings/use_proxy", false).toBool(); +} + +bool Settings::displayForeign() +{ + return m_Settings.value("Settings/display_foreign", true).toBool(); +} + +void Settings::setMotDHash(uint hash) +{ + m_Settings.setValue("motd_hash", hash); +} + +uint Settings::getMotDHash() const +{ + return m_Settings.value("motd_hash", 0).toUInt(); +} + +QVariant Settings::pluginSetting(const QString &pluginName, const QString &key) const +{ + auto iterPlugin = m_PluginSettings.find(pluginName); + if (iterPlugin == m_PluginSettings.end()) { + return QVariant(); + } + auto iterSetting = iterPlugin->find(key); + if (iterSetting == iterPlugin->end()) { + return QVariant(); + } + + return *iterSetting; +} + +void Settings::setPluginSetting(const QString &pluginName, const QString &key, const QVariant &value) +{ + auto iterPlugin = m_PluginSettings.find(pluginName); + if (iterPlugin == m_PluginSettings.end()) { + throw MyException(tr("attempt to store setting for unknown plugin \"%1\"").arg(pluginName)); + } + + // store the new setting both in memory and in the ini + m_PluginSettings[pluginName][key] = value; + m_Settings.setValue("Plugins/" + pluginName + "/" + key, value); +} + +QVariant Settings::pluginPersistent(const QString &pluginName, const QString &key, const QVariant &def) const +{ + if (!m_PluginSettings.contains(pluginName)) { + return def; + } + return m_Settings.value("PluginPersistance/" + pluginName + "/" + key, def); +} + +void Settings::setPluginPersistent(const QString &pluginName, const QString &key, const QVariant &value, bool sync) +{ + if (!m_PluginSettings.contains(pluginName)) { + throw MyException(tr("attempt to store setting for unknown plugin \"%1\"").arg(pluginName)); + } + m_Settings.setValue("PluginPersistance/" + pluginName + "/" + key, value); + if (sync) { + m_Settings.sync(); + } +} + +QString Settings::language() +{ + QString result = m_Settings.value("Settings/language", "").toString(); + if (result.isEmpty()) { + QStringList languagePreferences = QLocale::system().uiLanguages(); + if (languagePreferences.length() > 0) { + // the users most favoritest language + result = languagePreferences.at(0); + } else { + // fallback system locale + result = QLocale::system().name(); + } + } + return result; +} + +void Settings::updateServers(const QList &servers) +{ + m_Settings.beginGroup("Servers"); + QStringList oldServerKeys = m_Settings.childKeys(); + + foreach (const ServerInfo &server, servers) { + if (!oldServerKeys.contains(server.name)) { + // not yet known server + QVariantMap newVal; + newVal["premium"] = server.premium; + newVal["preferred"] = server.preferred ? 1 : 0; + newVal["lastSeen"] = server.lastSeen; + newVal["downloadCount"] = 0; + newVal["downloadSpeed"] = 0.0; + + m_Settings.setValue(server.name, newVal); + } else { + QVariantMap data = m_Settings.value(server.name).toMap(); + data["lastSeen"] = server.lastSeen; + data["premium"] = server.premium; + + m_Settings.setValue(server.name, data); + } + } + + m_Settings.endGroup(); + m_Settings.sync(); +} + +void Settings::addBlacklistPlugin(const QString &fileName) +{ + m_PluginBlacklist.insert(fileName); + writePluginBlacklist(); +} + +void Settings::writePluginBlacklist() +{ + m_Settings.beginWriteArray("pluginBlacklist"); + int idx = 0; + foreach (const QString &plugin, m_PluginBlacklist) { + m_Settings.setArrayIndex(idx++); + m_Settings.setValue("name", plugin); + } + + m_Settings.endArray(); +} + +void Settings::addLanguages(QComboBox *languageBox) +{ + languageBox->addItem("English", "en_US"); + + QDirIterator langIter(QCoreApplication::applicationDirPath() + "/translations", QDir::Files); + QString pattern = ToQString(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 = QLocale::languageToString(locale.language()); + if (locale.language() == QLocale::Chinese) { + if (languageCode == "zh_TW") { + languageString = "Chinese (traditional)"; + } else { + languageString = "Chinese (simplified)"; + } + } + languageBox->addItem(QString("%1").arg(languageString), exp.cap(1)); + } + } +} + +void Settings::addStyles(QComboBox *styleBox) +{ + styleBox->addItem("None", ""); +#if QT_VERSION >= QT_VERSION_CHECK(5,0,0) + styleBox->addItem("Fusion", "Fusion"); +#else + styleBox->addItem("Plastique", "Plastique"); + styleBox->addItem("Cleanlooks", "Cleanlooks"); +#endif + + QDirIterator langIter(QCoreApplication::applicationDirPath() + "/" + ToQString(AppConfig::stylesheetsPath()), QStringList("*.qss"), QDir::Files); + while (langIter.hasNext()) { + langIter.next(); + QString style = langIter.fileName(); + styleBox->addItem(style, style); + } +} + +void Settings::resetDialogs() +{ + m_Settings.beginGroup("DialogChoices"); + QStringList keys = m_Settings.childKeys(); + foreach (QString key, keys) { + m_Settings.remove(key); + } + + m_Settings.endGroup(); +} + + +void Settings::query(QWidget *parent) +{ + SettingsDialog dialog(parent); + + connect(&dialog, SIGNAL(resetDialogs()), this, SLOT(resetDialogs())); + + // General Page + QComboBox *languageBox = dialog.findChild("languageBox"); + QComboBox *styleBox = dialog.findChild("styleBox"); + QComboBox *logLevelBox = dialog.findChild("logLevelBox"); + QCheckBox *compactBox = dialog.findChild("compactBox"); + QCheckBox *showMetaBox = dialog.findChild("showMetaBox"); + + QLineEdit *downloadDirEdit = dialog.findChild("downloadDirEdit"); + QLineEdit *modDirEdit = dialog.findChild("modDirEdit"); + QLineEdit *cacheDirEdit = dialog.findChild("cacheDirEdit"); + + // nexus page + QCheckBox *loginCheckBox = dialog.findChild("loginCheckBox"); + QLineEdit *usernameEdit = dialog.findChild("usernameEdit"); + QLineEdit *passwordEdit = dialog.findChild("passwordEdit"); + QCheckBox *offlineBox = dialog.findChild("offlineBox"); + QCheckBox *proxyBox = dialog.findChild("proxyBox"); + + QListWidget *knownServersList = dialog.findChild("knownServersList"); + QListWidget *preferredServersList = dialog.findChild("preferredServersList"); + + // plugis page + QListWidget *pluginsList = dialog.findChild("pluginsList"); + QListWidget *pluginBlacklistList = dialog.findChild("pluginBlacklist"); + + // workarounds page + QCheckBox *forceEnableBox = dialog.findChild("forceEnableBox"); + QComboBox *mechanismBox = dialog.findChild("mechanismBox"); + QLineEdit *appIDEdit = dialog.findChild("appIDEdit"); + QLineEdit *nmmVersionEdit = dialog.findChild("nmmVersionEdit"); + QCheckBox *hideUncheckedBox = dialog.findChild("hideUncheckedBox"); + QCheckBox *displayForeignBox = dialog.findChild("displayForeignBox"); + + + // + // set up current settings + // + LoadMechanism::EMechanism mechanismID = getLoadMechanism(); + int index = 0; + + if (m_LoadMechanism.isDirectLoadingSupported()) { + mechanismBox->addItem(QObject::tr("Mod Organizer"), LoadMechanism::LOAD_MODORGANIZER); + if (mechanismID == LoadMechanism::LOAD_MODORGANIZER) { + index = mechanismBox->count() - 1; + } + } + + if (m_LoadMechanism.isScriptExtenderSupported()) { + mechanismBox->addItem(QObject::tr("Script Extender"), LoadMechanism::LOAD_SCRIPTEXTENDER); + if (mechanismID == LoadMechanism::LOAD_SCRIPTEXTENDER) { + index = mechanismBox->count() - 1; + } + } + + if (m_LoadMechanism.isProxyDLLSupported()) { + mechanismBox->addItem(QObject::tr("Proxy DLL"), LoadMechanism::LOAD_PROXYDLL); + if (mechanismID == LoadMechanism::LOAD_PROXYDLL) { + index = mechanismBox->count() - 1; + } + } + + mechanismBox->setCurrentIndex(index); + + { + addLanguages(languageBox); + QString languageCode = language(); + int currentID = 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 = languageBox->findData(languageCode.mid(0, 2)); + } + if (currentID != -1) { + languageBox->setCurrentIndex(currentID); + } + } + + { + addStyles(styleBox); + int currentID = styleBox->findData(m_Settings.value("Settings/style", "").toString()); + if (currentID != -1) { + styleBox->setCurrentIndex(currentID); + } + } + + compactBox->setChecked(compactDownloads()); + showMetaBox->setChecked(metaDownloads()); + + hideUncheckedBox->setChecked(hideUncheckedPlugins()); + displayForeignBox->setChecked(displayForeign()); + forceEnableBox->setChecked(forceEnableCoreFiles()); + + appIDEdit->setText(getSteamAppID()); + + if (automaticLoginEnabled()) { + loginCheckBox->setChecked(true); + usernameEdit->setText(m_Settings.value("Settings/nexus_username", "").toString()); + passwordEdit->setText(deObfuscate(m_Settings.value("Settings/nexus_password", "").toString())); + } + + downloadDirEdit->setText(getDownloadDirectory()); + modDirEdit->setText(getModDirectory()); + cacheDirEdit->setText(getCacheDirectory()); + offlineBox->setChecked(offlineMode()); + proxyBox->setChecked(useProxy()); + nmmVersionEdit->setText(getNMMVersion()); + logLevelBox->setCurrentIndex(logLevel()); + + // display plugin settings + foreach (IPlugin *plugin, m_Plugins) { + QListWidgetItem *listItem = new QListWidgetItem(plugin->name(), pluginsList); + listItem->setData(Qt::UserRole, QVariant::fromValue((void*)plugin)); + listItem->setData(Qt::UserRole + 1, m_PluginSettings[plugin->name()]); + listItem->setData(Qt::UserRole + 2, m_PluginDescriptions[plugin->name()]); + pluginsList->addItem(listItem); + } + + // display plugin blacklist + foreach (const QString &pluginName, m_PluginBlacklist) { + pluginBlacklistList->addItem(pluginName); + } + + // display server preferences + m_Settings.beginGroup("Servers"); + foreach (const QString &key, m_Settings.childKeys()) { + QVariantMap val = m_Settings.value(key).toMap(); + QString type = val["premium"].toBool() ? "(premium)" : "(free)"; + + QString descriptor = key + " " + type; + if (val.contains("downloadSpeed") && val.contains("downloadCount") && (val["downloadCount"].toInt() > 0)) { + int bps = static_cast(val["downloadSpeed"].toDouble() / val["downloadCount"].toInt()); + descriptor += QString(" (%1 kbps)").arg(bps / 1024); + } + + QListWidgetItem *newItem = new QListWidgetItemEx(descriptor, Qt::UserRole + 1); + + newItem->setData(Qt::UserRole, key); + newItem->setData(Qt::UserRole + 1, val["preferred"].toInt()); + if (val["preferred"].toInt() > 0) { + preferredServersList->addItem(newItem); + } else { + knownServersList->addItem(newItem); + } + preferredServersList->sortItems(Qt::DescendingOrder); + } + m_Settings.endGroup(); + + if (dialog.exec() == QDialog::Accepted) { + // + // transfer modified settings to configuration file + // + + m_Settings.setValue("Settings/hide_unchecked_plugins", hideUncheckedBox->checkState() ? true : false); + m_Settings.setValue("Settings/force_enable_core_files", forceEnableBox->checkState() ? true : false); + m_Settings.setValue("Settings/compact_downloads", compactBox->isChecked()); + m_Settings.setValue("Settings/meta_downloads", showMetaBox->isChecked()); + m_Settings.setValue("Settings/load_mechanism", mechanismBox->itemData(mechanismBox->currentIndex()).toInt()); + + + { // advanced settings + if ((QDir::fromNativeSeparators(modDirEdit->text()) != QDir::fromNativeSeparators(getModDirectory())) && + (QMessageBox::question(NULL, tr("Confirm"), tr("Changing the mod directory affects all your profiles! " + "Mods not present (or named differently) in the new location will be disabled in all profiles. " + "There is no way to undo this unless you backed up your profiles manually. Proceed?"), + QMessageBox::Yes | QMessageBox::No) == QMessageBox::No)) { + modDirEdit->setText(getModDirectory()); + } + + if (!QDir(downloadDirEdit->text()).exists()) { + QDir().mkpath(downloadDirEdit->text()); + } + if (!QDir(cacheDirEdit->text()).exists()) { + QDir().mkpath(cacheDirEdit->text()); + } + if (!QDir(modDirEdit->text()).exists()) { + QDir().mkpath(modDirEdit->text()); + } + + m_Settings.setValue("Settings/download_directory", QDir::toNativeSeparators(downloadDirEdit->text())); + m_Settings.setValue("Settings/cache_directory", QDir::toNativeSeparators(cacheDirEdit->text())); + m_Settings.setValue("Settings/mod_directory", QDir::toNativeSeparators(modDirEdit->text())); + } + + + QString oldLanguage = m_Settings.value("Settings/language", "en_US").toString(); + QString newLanguage = languageBox->itemData(languageBox->currentIndex()).toString(); + if (newLanguage != oldLanguage) { + m_Settings.setValue("Settings/language", newLanguage); + emit languageChanged(newLanguage); + } + + QString oldStyle = m_Settings.value("Settings/style", "").toString(); + QString newStyle = styleBox->itemData(styleBox->currentIndex()).toString(); + if (oldStyle != newStyle) { + m_Settings.setValue("Settings/style", newStyle); + emit styleChanged(newStyle); + } + + m_Settings.setValue("Settings/log_level", logLevelBox->currentIndex()); + + if (appIDEdit->text() != ToQString(GameInfo::instance().getSteamAPPId())) { + m_Settings.setValue("Settings/app_id", appIDEdit->text()); + } else { + m_Settings.remove("Settings/app_id"); + } + if (loginCheckBox->isChecked()) { + m_Settings.setValue("Settings/nexus_login", true); + m_Settings.setValue("Settings/nexus_username", usernameEdit->text()); + m_Settings.setValue("Settings/nexus_password", obfuscate(passwordEdit->text())); + } else { + m_Settings.setValue("Settings/nexus_login", false); + m_Settings.remove("Settings/nexus_username"); + m_Settings.remove("Settings/nexus_password"); + } + m_Settings.setValue("Settings/offline_mode", offlineBox->isChecked()); + m_Settings.setValue("Settings/use_proxy", proxyBox->isChecked()); + m_Settings.setValue("Settings/display_foreign", displayForeignBox->isChecked()); + + m_Settings.setValue("Settings/nmm_version", nmmVersionEdit->text()); + + // transfer plugin settings to in-memory structure + for (int i = 0; i < pluginsList->count(); ++i) { + QListWidgetItem *item = pluginsList->item(i); + m_PluginSettings[item->text()] = item->data(Qt::UserRole + 1).toMap(); + } + // store plugin settings on disc + for (auto iterPlugins = m_PluginSettings.begin(); iterPlugins != m_PluginSettings.end(); ++iterPlugins) { + for (auto iterSettings = iterPlugins->begin(); iterSettings != iterPlugins->end(); ++iterSettings) { + m_Settings.setValue("Plugins/" + iterPlugins.key() + "/" + iterSettings.key(), iterSettings.value()); + } + } + + // store plugin blacklist + m_PluginBlacklist.clear(); + foreach (QListWidgetItem *item, pluginBlacklistList->findItems("*", Qt::MatchWildcard)) { + m_PluginBlacklist.insert(item->text()); + } + writePluginBlacklist(); + + // store server preference + m_Settings.beginGroup("Servers"); + for (int i = 0; i < knownServersList->count(); ++i) { + QString key = knownServersList->item(i)->data(Qt::UserRole).toString(); + QVariantMap val = m_Settings.value(key).toMap(); + val["preferred"] = 0; + m_Settings.setValue(key, val); + } + int count = preferredServersList->count(); + for (int i = 0; i < count; ++i) { + QString key = preferredServersList->item(i)->data(Qt::UserRole).toString(); + QVariantMap val = m_Settings.value(key).toMap(); + val["preferred"] = count - i; + m_Settings.setValue(key, val); + } + m_Settings.endGroup(); + } +} diff --git a/src/settings.h b/src/settings.h index 40fd2c5a..5d398f49 100644 --- a/src/settings.h +++ b/src/settings.h @@ -1,310 +1,311 @@ -/* -Copyright (C) 2012 Sebastian Herbord. All rights reserved. - -This file is part of Mod Organizer. - -Mod Organizer is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Mod Organizer is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Mod Organizer. If not, see . -*/ - -#ifndef WORKAROUNDS_H -#define WORKAROUNDS_H - -#include "loadmechanism.h" -#include "serverinfo.h" -#include - -#include -#include -#include - - -/** - * manages the settings for Mod Organizer. The settings are not cached - * inside the class but read/written directly from/to disc - **/ -class Settings : public QObject -{ - - Q_OBJECT - -public: - - /** - * @brief constructor - **/ - Settings(); - - virtual ~Settings(); - - static Settings &instance(); - - /** - * unregister all plugins from settings - */ - void clearPlugins(); - - /** - * @brief register plugin to be configurable - * @param plugin the plugin to register - * @return true if the plugin may be registered, false if it is blacklisted - */ - void registerPlugin(MOBase::IPlugin *plugin); - - /** - * displays a SettingsDialog that allows the user to change settings. If the - * user accepts the changes, the settings are immediately written - **/ - void query(QWidget *parent); - - /** - * set up the settings for the specified plugins - **/ - void addPluginSettings(const std::vector &plugins); - - /** - * @return true if the user wants unchecked plugins (esp, esm) should be hidden from - * the virtual dat adirectory - **/ - bool hideUncheckedPlugins() const; - - /** - * @return true if files of the core game are forced-enabled so the user can't accidentally disable them - */ - bool forceEnableCoreFiles() const; - - /** - * @brief register download speed - * @param url complete download url - * @param bytesPerSecond download size in bytes per second - */ - void setDownloadSpeed(const QString &serverName, int bytesPerSecond); - - /** - * the steam appid is assigned by the steam platform to each product sold there. - * The appid may differ between different versions of a game so it may be impossible - * for Mod Organizer to automatically recognize it, though usually it does - * @return the steam appid for the game - **/ - QString getSteamAppID() const; - - /** - * retrieve the directory where downloads are stored (with native separators) - **/ - QString getDownloadDirectory() const; - - /** - * retrieve a sorted list of preferred servers - */ - std::map getPreferredServers(); - - /** - * retrieve the directory where mods are stored (with native separators) - **/ - QString getModDirectory() const; - - /** - * returns the version of nmm to impersonate when connecting to nexus - **/ - QString getNMMVersion() const; - - /** - * retrieve the directory where the web cache is stored (with native separators) - **/ - QString getCacheDirectory() const; - - /** - * @return true if the user has set up automatic login to nexus - **/ - bool automaticLoginEnabled() const; - - /** - * @brief retrieve the login information for nexus - * - * @param username (out) receives the user name for nexus - * @param password (out) received the password for nexus - * @return true if automatic login is active, false otherwise - **/ - bool getNexusLogin(QString &username, QString &password) const; - - /** - * @return true if the user disabled internet features - */ - bool offlineMode() const; - - /** - * @return true if the user chose compact downloads - */ - bool compactDownloads() const; - - /** - * @return true if the user chose meta downloads - */ - bool metaDownloads() const; - - /** - * @return the configured log level - */ - int logLevel() const; - - /** - * @brief set the nexus login information - * - * @param username username - * @param password password - */ - void setNexusLogin(QString username, QString password); - - /** - * @return the load mechanism to be used - **/ - LoadMechanism::EMechanism getLoadMechanism() const; - - /** - * @brief activate the load mechanism selected by the user - **/ - void setupLoadMechanism(); - - /** - * @return true if the user configured the use of a network proxy - */ - bool useProxy(); - - /** - * @return true if the user wants to see non-official plugins installed outside MO in his mod list - */ - bool displayForeign(); - - /** - * @brief sets the new motd hash - **/ - void setMotDHash(uint hash); - - /** - * @return hash of the last displayed message of the day - **/ - uint getMotDHash() const; - - /** - * @brief allows direct access to the wrapped QSettings object - * @return the wrapped QSettings object - */ - QSettings &directInterface() { return m_Settings; } - - /** - * @brief retrieve a setting for one of the installed plugins - * @param pluginName name of the plugin - * @param key name of the setting to retrieve - * @return the requested value as a QVariant - * @note an invalid QVariant is returned if the the plugin/setting is not declared - */ - QVariant pluginSetting(const QString &pluginName, const QString &key) const; - - /** - * @brief set a setting for one of the installed mods - * @param pluginName name of the plugin - * @param key name of the setting to change - * @param value the new value to set - * @throw an exception is thrown if pluginName is invalid - */ - void setPluginSetting(const QString &pluginName, const QString &key, const QVariant &value); - - /** - * @brief retrieve a persistent value for a plugin - * @param pluginName name of the plugin to store data for - * @param key id of the value to retrieve - * @param def default value to return if the value is not set - * @return the requested value - */ - QVariant pluginPersistent(const QString &pluginName, const QString &key, const QVariant &def) const; - - /** - * @brief set a persistent value for a plugin - * @param pluginName name of the plugin to store data for - * @param key id of the value to retrieve - * @param value value to set - * @throw an exception is thrown if pluginName is invalid - */ - void setPluginPersistent(const QString &pluginName, const QString &key, const QVariant &value, bool sync); - - /** - * @return short code of the configured language (corresponding to the translation files) - */ - QString language(); - - /** - * @brief updates the list of known servers - * @param list of servers from a recent query - */ - void updateServers(const QList &servers); - - /** - * @brief add a plugin that is to be blacklisted - * @param fileName name of the plugin to blacklist - */ - void addBlacklistPlugin(const QString &fileName); - - /** - * @brief test if a plugin is blacklisted and shouldn't be loaded - * @param fileName name of the plugin - * @return true if the file is blacklisted - */ - bool pluginBlacklisted(const QString &fileName) const; - - /** - * @return all loaded MO plugins - */ - std::vector plugins() const { return m_Plugins; } - - /** - * @brief register MO as the handler for nxm links - * @param force set to true to enforce the registration dialog to show up, - * even if the user said earlier not to - */ - void registerAsNXMHandler(bool force); -private: - - QString obfuscate(const QString &password) const; - QString deObfuscate(const QString &password) const; - - void addLanguages(QComboBox *languageBox); - void addStyles(QComboBox *styleBox); - void readPluginBlacklist(); - void writePluginBlacklist(); - -private slots: - - void resetDialogs(); - -signals: - - void languageChanged(const QString &newLanguage); - void styleChanged(const QString &newStyle); - -private: - - static Settings *s_Instance; - - QSettings m_Settings; - - LoadMechanism m_LoadMechanism; - - std::vector m_Plugins; - - QMap > m_PluginSettings; - - QSet m_PluginBlacklist; - -}; - -#endif // WORKAROUNDS_H +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see . +*/ + +#ifndef WORKAROUNDS_H +#define WORKAROUNDS_H + +#include "loadmechanism.h" +#include "serverinfo.h" +#include + +#include +#include +#include + + +/** + * manages the settings for Mod Organizer. The settings are not cached + * inside the class but read/written directly from/to disc + **/ +class Settings : public QObject +{ + + Q_OBJECT + +public: + + /** + * @brief constructor + **/ + Settings(); + + virtual ~Settings(); + + static Settings &instance(); + + /** + * unregister all plugins from settings + */ + void clearPlugins(); + + /** + * @brief register plugin to be configurable + * @param plugin the plugin to register + * @return true if the plugin may be registered, false if it is blacklisted + */ + void registerPlugin(MOBase::IPlugin *plugin); + + /** + * displays a SettingsDialog that allows the user to change settings. If the + * user accepts the changes, the settings are immediately written + **/ + void query(QWidget *parent); + + /** + * set up the settings for the specified plugins + **/ + void addPluginSettings(const std::vector &plugins); + + /** + * @return true if the user wants unchecked plugins (esp, esm) should be hidden from + * the virtual dat adirectory + **/ + bool hideUncheckedPlugins() const; + + /** + * @return true if files of the core game are forced-enabled so the user can't accidentally disable them + */ + bool forceEnableCoreFiles() const; + + /** + * @brief register download speed + * @param url complete download url + * @param bytesPerSecond download size in bytes per second + */ + void setDownloadSpeed(const QString &serverName, int bytesPerSecond); + + /** + * the steam appid is assigned by the steam platform to each product sold there. + * The appid may differ between different versions of a game so it may be impossible + * for Mod Organizer to automatically recognize it, though usually it does + * @return the steam appid for the game + **/ + QString getSteamAppID() const; + + /** + * retrieve the directory where downloads are stored (with native separators) + **/ + QString getDownloadDirectory() const; + + /** + * retrieve a sorted list of preferred servers + */ + std::map getPreferredServers(); + + /** + * retrieve the directory where mods are stored (with native separators) + **/ + QString getModDirectory() const; + + /** + * returns the version of nmm to impersonate when connecting to nexus + **/ + QString getNMMVersion() const; + + /** + * retrieve the directory where the web cache is stored (with native separators) + **/ + QString getCacheDirectory() const; + + /** + * @return true if the user has set up automatic login to nexus + **/ + bool automaticLoginEnabled() const; + + /** + * @brief retrieve the login information for nexus + * + * @param username (out) receives the user name for nexus + * @param password (out) received the password for nexus + * @return true if automatic login is active, false otherwise + **/ + bool getNexusLogin(QString &username, QString &password) const; + + /** + * @return true if the user disabled internet features + */ + bool offlineMode() const; + + /** + * @return true if the user chose compact downloads + */ + bool compactDownloads() const; + + /** + * @return true if the user chose meta downloads + */ + bool metaDownloads() const; + + /** + * @return the configured log level + */ + int logLevel() const; + + /** + * @brief set the nexus login information + * + * @param username username + * @param password password + */ + void setNexusLogin(QString username, QString password); + + /** + * @return the load mechanism to be used + **/ + LoadMechanism::EMechanism getLoadMechanism() const; + + /** + * @brief activate the load mechanism selected by the user + **/ + void setupLoadMechanism(); + + /** + * @return true if the user configured the use of a network proxy + */ + bool useProxy(); + + /** + * @return true if the user wants to see non-official plugins installed outside MO in his mod list + */ + bool displayForeign(); + + /** + * @brief sets the new motd hash + **/ + void setMotDHash(uint hash); + + /** + * @return hash of the last displayed message of the day + **/ + uint getMotDHash() const; + + /** + * @brief allows direct access to the wrapped QSettings object + * @return the wrapped QSettings object + */ + QSettings &directInterface() { return m_Settings; } + + /** + * @brief retrieve a setting for one of the installed plugins + * @param pluginName name of the plugin + * @param key name of the setting to retrieve + * @return the requested value as a QVariant + * @note an invalid QVariant is returned if the the plugin/setting is not declared + */ + QVariant pluginSetting(const QString &pluginName, const QString &key) const; + + /** + * @brief set a setting for one of the installed mods + * @param pluginName name of the plugin + * @param key name of the setting to change + * @param value the new value to set + * @throw an exception is thrown if pluginName is invalid + */ + void setPluginSetting(const QString &pluginName, const QString &key, const QVariant &value); + + /** + * @brief retrieve a persistent value for a plugin + * @param pluginName name of the plugin to store data for + * @param key id of the value to retrieve + * @param def default value to return if the value is not set + * @return the requested value + */ + QVariant pluginPersistent(const QString &pluginName, const QString &key, const QVariant &def) const; + + /** + * @brief set a persistent value for a plugin + * @param pluginName name of the plugin to store data for + * @param key id of the value to retrieve + * @param value value to set + * @throw an exception is thrown if pluginName is invalid + */ + void setPluginPersistent(const QString &pluginName, const QString &key, const QVariant &value, bool sync); + + /** + * @return short code of the configured language (corresponding to the translation files) + */ + QString language(); + + /** + * @brief updates the list of known servers + * @param list of servers from a recent query + */ + void updateServers(const QList &servers); + + /** + * @brief add a plugin that is to be blacklisted + * @param fileName name of the plugin to blacklist + */ + void addBlacklistPlugin(const QString &fileName); + + /** + * @brief test if a plugin is blacklisted and shouldn't be loaded + * @param fileName name of the plugin + * @return true if the file is blacklisted + */ + bool pluginBlacklisted(const QString &fileName) const; + + /** + * @return all loaded MO plugins + */ + std::vector plugins() const { return m_Plugins; } + + /** + * @brief register MO as the handler for nxm links + * @param force set to true to enforce the registration dialog to show up, + * even if the user said earlier not to + */ + void registerAsNXMHandler(bool force); +private: + + QString obfuscate(const QString &password) const; + QString deObfuscate(const QString &password) const; + + void addLanguages(QComboBox *languageBox); + void addStyles(QComboBox *styleBox); + void readPluginBlacklist(); + void writePluginBlacklist(); + +private slots: + + void resetDialogs(); + +signals: + + void languageChanged(const QString &newLanguage); + void styleChanged(const QString &newStyle); + +private: + + static Settings *s_Instance; + + QSettings m_Settings; + + LoadMechanism m_LoadMechanism; + + std::vector m_Plugins; + + QMap > m_PluginSettings; + QMap > m_PluginDescriptions; + + QSet m_PluginBlacklist; + +}; + +#endif // WORKAROUNDS_H diff --git a/src/settingsdialog.cpp b/src/settingsdialog.cpp index a7d44d72..d1947b5a 100644 --- a/src/settingsdialog.cpp +++ b/src/settingsdialog.cpp @@ -1,173 +1,182 @@ -/* -Copyright (C) 2012 Sebastian Herbord. All rights reserved. - -This file is part of Mod Organizer. - -Mod Organizer is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation, either version 3 of the License, or -(at your option) any later version. - -Mod Organizer is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with Mod Organizer. If not, see . -*/ - -#include "settingsdialog.h" -#include "ui_settingsdialog.h" -#include "categoriesdialog.h" -#include "helper.h" -#include "noeditdelegate.h" -#include -#include -#include -#include -#include -#define WIN32_LEAN_AND_MEAN -#include -#include "settings.h" - - -using namespace MOBase; -using namespace MOShared; - - -SettingsDialog::SettingsDialog(QWidget *parent) - : TutorableDialog("SettingsDialog", parent), ui(new Ui::SettingsDialog) -{ - ui->setupUi(this); - - QShortcut *delShortcut = new QShortcut(QKeySequence(Qt::Key_Delete), ui->pluginBlacklist); - connect(delShortcut, SIGNAL(activated()), this, SLOT(deleteBlacklistItem())); -} - -SettingsDialog::~SettingsDialog() -{ - delete ui; -} - -void SettingsDialog::addPlugins(const std::vector &plugins) -{ - foreach (IPlugin *plugin, plugins) { - ui->pluginsList->addItem(plugin->name()); - } -} - -void SettingsDialog::accept() -{ - storeSettings(ui->pluginsList->currentItem()); - TutorableDialog::accept(); -} - - -void SettingsDialog::on_loginCheckBox_toggled(bool checked) -{ - QLineEdit *usernameEdit = findChild("usernameEdit"); - QLineEdit *passwordEdit = findChild("passwordEdit"); - if (checked) { - passwordEdit->setEnabled(true); - usernameEdit->setEnabled(true); - } else { - passwordEdit->setEnabled(false); - usernameEdit->setEnabled(false); - } -} - -void SettingsDialog::on_categoriesBtn_clicked() -{ - CategoriesDialog dialog(this); - if (dialog.exec() == QDialog::Accepted) { - dialog.commitChanges(); - } -} - -void SettingsDialog::on_bsaDateBtn_clicked() -{ - Helper::backdateBSAs(GameInfo::instance().getOrganizerDirectory(), GameInfo::instance().getGameDirectory().append(L"\\data")); -} - -void SettingsDialog::on_browseDownloadDirBtn_clicked() -{ - QString temp = QFileDialog::getExistingDirectory(this, tr("Select download directory"), ui->downloadDirEdit->text()); - if (!temp.isEmpty()) { - ui->downloadDirEdit->setText(temp); - } -} - -void SettingsDialog::on_browseModDirBtn_clicked() -{ - QString temp = QFileDialog::getExistingDirectory(this, tr("Select mod directory"), ui->downloadDirEdit->text()); - if (!temp.isEmpty()) { - ui->modDirEdit->setText(temp); - } -} - -void SettingsDialog::on_browseCacheDirBtn_clicked() -{ - QString temp = QFileDialog::getExistingDirectory(this, tr("Select cache directory"), ui->cacheDirEdit->text()); - if (!temp.isEmpty()) { - ui->cacheDirEdit->setText(temp); - } -} - -void SettingsDialog::on_resetDialogsButton_clicked() -{ - if (QMessageBox::question(this, tr("Confirm?"), - tr("This will make all dialogs show up again where you checked the \"Remember selection\"-box. Continue?"), - QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) { - emit resetDialogs(); - } -} - -void SettingsDialog::storeSettings(QListWidgetItem *pluginItem) -{ - if (pluginItem != NULL) { - QMap settings = pluginItem->data(Qt::UserRole + 1).toMap(); - - for (int i = 0; i < ui->pluginSettingsList->topLevelItemCount(); ++i) { - const QTreeWidgetItem *item = ui->pluginSettingsList->topLevelItem(i); - settings[item->text(0)] = item->data(1, Qt::DisplayRole); - } - - pluginItem->setData(Qt::UserRole + 1, settings); - } -} - -void SettingsDialog::on_pluginsList_currentItemChanged(QListWidgetItem *current, QListWidgetItem *previous) -{ - storeSettings(previous); - - ui->pluginSettingsList->clear(); - IPlugin *plugin = static_cast(current->data(Qt::UserRole).value()); - ui->authorLabel->setText(plugin->author()); - ui->versionLabel->setText(plugin->version().canonicalString()); - ui->descriptionLabel->setText(plugin->description()); - - QMap settings = current->data(Qt::UserRole + 1).toMap(); - ui->pluginSettingsList->setEnabled(settings.count() != 0); - for (auto iter = settings.begin(); iter != settings.end(); ++iter) { - QTreeWidgetItem *newItem = new QTreeWidgetItem(QStringList(iter.key())); - QVariant value = *iter; - - ui->pluginSettingsList->setItemDelegateForColumn(0, new NoEditDelegate()); - newItem->setData(1, Qt::DisplayRole, value); - newItem->setData(1, Qt::EditRole, value); - - newItem->setFlags(newItem->flags() | Qt::ItemIsEditable); - ui->pluginSettingsList->addTopLevelItem(newItem); - } -} - -void SettingsDialog::deleteBlacklistItem() -{ - ui->pluginBlacklist->takeItem(ui->pluginBlacklist->currentIndex().row()); -} - -void SettingsDialog::on_associateButton_clicked() -{ - Settings::instance().registerAsNXMHandler(true); -} +/* +Copyright (C) 2012 Sebastian Herbord. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see . +*/ + +#include "settingsdialog.h" +#include "ui_settingsdialog.h" +#include "categoriesdialog.h" +#include "helper.h" +#include "noeditdelegate.h" +#include +#include +#include +#include +#include +#define WIN32_LEAN_AND_MEAN +#include +#include "settings.h" + + +using namespace MOBase; +using namespace MOShared; + + +SettingsDialog::SettingsDialog(QWidget *parent) + : TutorableDialog("SettingsDialog", parent), ui(new Ui::SettingsDialog) +{ + ui->setupUi(this); + + QShortcut *delShortcut = new QShortcut(QKeySequence(Qt::Key_Delete), ui->pluginBlacklist); + connect(delShortcut, SIGNAL(activated()), this, SLOT(deleteBlacklistItem())); +} + +SettingsDialog::~SettingsDialog() +{ + delete ui; +} + +void SettingsDialog::addPlugins(const std::vector &plugins) +{ + foreach (IPlugin *plugin, plugins) { + ui->pluginsList->addItem(plugin->name()); + } +} + +void SettingsDialog::accept() +{ + storeSettings(ui->pluginsList->currentItem()); + TutorableDialog::accept(); +} + + +void SettingsDialog::on_loginCheckBox_toggled(bool checked) +{ + QLineEdit *usernameEdit = findChild("usernameEdit"); + QLineEdit *passwordEdit = findChild("passwordEdit"); + if (checked) { + passwordEdit->setEnabled(true); + usernameEdit->setEnabled(true); + } else { + passwordEdit->setEnabled(false); + usernameEdit->setEnabled(false); + } +} + +void SettingsDialog::on_categoriesBtn_clicked() +{ + CategoriesDialog dialog(this); + if (dialog.exec() == QDialog::Accepted) { + dialog.commitChanges(); + } +} + +void SettingsDialog::on_bsaDateBtn_clicked() +{ + Helper::backdateBSAs(GameInfo::instance().getOrganizerDirectory(), GameInfo::instance().getGameDirectory().append(L"\\data")); +} + +void SettingsDialog::on_browseDownloadDirBtn_clicked() +{ + QString temp = QFileDialog::getExistingDirectory(this, tr("Select download directory"), ui->downloadDirEdit->text()); + if (!temp.isEmpty()) { + ui->downloadDirEdit->setText(temp); + } +} + +void SettingsDialog::on_browseModDirBtn_clicked() +{ + QString temp = QFileDialog::getExistingDirectory(this, tr("Select mod directory"), ui->downloadDirEdit->text()); + if (!temp.isEmpty()) { + ui->modDirEdit->setText(temp); + } +} + +void SettingsDialog::on_browseCacheDirBtn_clicked() +{ + QString temp = QFileDialog::getExistingDirectory(this, tr("Select cache directory"), ui->cacheDirEdit->text()); + if (!temp.isEmpty()) { + ui->cacheDirEdit->setText(temp); + } +} + +void SettingsDialog::on_resetDialogsButton_clicked() +{ + if (QMessageBox::question(this, tr("Confirm?"), + tr("This will make all dialogs show up again where you checked the \"Remember selection\"-box. Continue?"), + QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) { + emit resetDialogs(); + } +} + +void SettingsDialog::storeSettings(QListWidgetItem *pluginItem) +{ + if (pluginItem != NULL) { + QMap settings = pluginItem->data(Qt::UserRole + 1).toMap(); + + for (int i = 0; i < ui->pluginSettingsList->topLevelItemCount(); ++i) { + const QTreeWidgetItem *item = ui->pluginSettingsList->topLevelItem(i); + settings[item->text(0)] = item->data(1, Qt::DisplayRole); + } + + pluginItem->setData(Qt::UserRole + 1, settings); + } +} + +void SettingsDialog::on_pluginsList_currentItemChanged(QListWidgetItem *current, QListWidgetItem *previous) +{ + storeSettings(previous); + + ui->pluginSettingsList->clear(); + IPlugin *plugin = static_cast(current->data(Qt::UserRole).value()); + ui->authorLabel->setText(plugin->author()); + ui->versionLabel->setText(plugin->version().canonicalString()); + ui->descriptionLabel->setText(plugin->description()); + + QMap settings = current->data(Qt::UserRole + 1).toMap(); + QMap descriptions = current->data(Qt::UserRole + 2).toMap(); + ui->pluginSettingsList->setEnabled(settings.count() != 0); + for (auto iter = settings.begin(); iter != settings.end(); ++iter) { + QTreeWidgetItem *newItem = new QTreeWidgetItem(QStringList(iter.key())); + QVariant value = *iter; + QString description; + { + auto descriptionIter = descriptions.find(iter.key()); + if (descriptionIter != descriptions.end()) { + description = descriptionIter->toString(); + } + } + + ui->pluginSettingsList->setItemDelegateForColumn(0, new NoEditDelegate()); + newItem->setData(1, Qt::DisplayRole, value); + newItem->setData(1, Qt::EditRole, value); + newItem->setToolTip(1, description); + + newItem->setFlags(newItem->flags() | Qt::ItemIsEditable); + ui->pluginSettingsList->addTopLevelItem(newItem); + } +} + +void SettingsDialog::deleteBlacklistItem() +{ + ui->pluginBlacklist->takeItem(ui->pluginBlacklist->currentIndex().row()); +} + +void SettingsDialog::on_associateButton_clicked() +{ + Settings::instance().registerAsNXMHandler(true); +} -- cgit v1.3.1 From 93bd29c13d3355b2544c2fd40dff1f4f985f9b57 Mon Sep 17 00:00:00 2001 From: Tannin Date: Wed, 24 Sep 2014 19:51:51 +0200 Subject: - several style fixes suggested by static analysis - will now support up to 4 levels of version numbers (major.minor.subminor.subsubminor --- src/browserdialog.cpp | 2 +- src/categories.cpp | 8 +++--- src/installationmanager.h | 2 +- src/main.cpp | 11 +++----- src/mainwindow.cpp | 55 +++++++++++++++++++--------------------- src/modinfo.cpp | 2 +- src/modlist.cpp | 8 ++++-- src/modlist.h | 2 +- src/modlistsortproxy.cpp | 2 +- src/nexusinterface.cpp | 5 +++- src/pluginlist.cpp | 50 ++++++++++++++++++------------------- src/profile.cpp | 4 ++- src/selfupdater.h | 3 ++- src/settings.cpp | 2 +- src/shared/directoryentry.cpp | 6 ++--- src/shared/directoryentry.h | 2 +- src/shared/fallout3info.cpp | 21 ++++++++-------- src/shared/fallout3info.h | 6 ++--- src/shared/falloutnvinfo.cpp | 58 +++++++++++++++++++------------------------ src/shared/falloutnvinfo.h | 6 ++--- src/shared/gameinfo.cpp | 40 ++++++++--------------------- src/shared/leaktrace.cpp | 2 +- src/shared/oblivioninfo.cpp | 21 ++++++++-------- src/shared/oblivioninfo.h | 6 ++--- src/shared/skyriminfo.cpp | 53 ++++++++++++++++++--------------------- src/shared/skyriminfo.h | 8 +++--- 26 files changed, 176 insertions(+), 209 deletions(-) (limited to 'src/settings.cpp') diff --git a/src/browserdialog.cpp b/src/browserdialog.cpp index 521459d0..f93ffcae 100644 --- a/src/browserdialog.cpp +++ b/src/browserdialog.cpp @@ -22,10 +22,10 @@ along with Mod Organizer. If not, see . #include "messagedialog.h" #include "report.h" -#include "json.h" #include "persistentcookiejar.h" #include +#include "json.h" #include #include diff --git a/src/categories.cpp b/src/categories.cpp index 28b1f4a2..57e18a28 100644 --- a/src/categories.cpp +++ b/src/categories.cpp @@ -232,7 +232,7 @@ void CategoryFactory::loadDefaultCategories() int CategoryFactory::getParentID(unsigned int index) const { - if ((index < 0) || (index >= m_Categories.size())) { + if (index >= m_Categories.size()) { throw MyException(QObject::tr("invalid index %1").arg(index)); } @@ -267,7 +267,7 @@ bool CategoryFactory::isDecendantOf(int id, int parentID) const bool CategoryFactory::hasChildren(unsigned int index) const { - if ((index < 0) || (index >= m_Categories.size())) { + if (index >= m_Categories.size()) { throw MyException(QObject::tr("invalid index %1").arg(index)); } @@ -277,7 +277,7 @@ bool CategoryFactory::hasChildren(unsigned int index) const QString CategoryFactory::getCategoryName(unsigned int index) const { - if ((index < 0) || (index >= m_Categories.size())) { + if (index >= m_Categories.size()) { throw MyException(QObject::tr("invalid index %1").arg(index)); } @@ -287,7 +287,7 @@ QString CategoryFactory::getCategoryName(unsigned int index) const int CategoryFactory::getCategoryID(unsigned int index) const { - if ((index < 0) || (index >= m_Categories.size())) { + if (index >= m_Categories.size()) { throw MyException(QObject::tr("invalid index %1").arg(index)); } diff --git a/src/installationmanager.h b/src/installationmanager.h index d430c065..336c1ce3 100644 --- a/src/installationmanager.h +++ b/src/installationmanager.h @@ -55,7 +55,7 @@ public: **/ explicit InstallationManager(QWidget *parent); - ~InstallationManager(); + virtual ~InstallationManager(); /** * @brief update the directory where mods are to be installed diff --git a/src/main.cpp b/src/main.cpp index 3198208a..642bfa1a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -455,14 +455,9 @@ int main(int argc, char *argv[]) settings.setValue("gamePath", gamePath.toUtf8().constData()); } - int edition = 0; - if (settings.contains("game_edition")) { - edition = settings.value("game_edition").toInt(); - } else { + if (!settings.contains("game_edition")) { std::vector editions = GameInfo::instance().getSteamVariants(); - if (editions.size() < 2) { - edition = 0; - } else { + if (editions.size() > 1) { SelectionDialog selection(QObject::tr("Please select the game edition you have (MO can't start the game correctly if this is set incorrectly!)"), NULL); int index = 0; for (auto iter = editions.begin(); iter != editions.end(); ++iter) { @@ -475,7 +470,7 @@ int main(int argc, char *argv[]) } } } - +#pragma message("edition isn't used?") qDebug("managing game at %s", qPrintable(QDir::toNativeSeparators(gamePath))); ExecutablesList executablesList; diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index ae5c1e48..19be758e 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -1137,7 +1137,6 @@ void MainWindow::registerPluginTool(IPluginTool *tool) void MainWindow::registerModPage(IPluginModPage *modPage) { - QToolButton *browserBtn = NULL; // turn the browser action into a drop-down menu if necessary if (ui->actionNexus->menu() == NULL) { QAction *nexusAction = ui->actionNexus; @@ -1147,10 +1146,8 @@ void MainWindow::registerModPage(IPluginModPage *modPage) ui->toolBar->removeAction(nexusAction); actionToToolButton(ui->actionNexus); - browserBtn = qobject_cast(ui->toolBar->widgetForAction(ui->actionNexus)); + QToolButton *browserBtn = qobject_cast(ui->toolBar->widgetForAction(ui->actionNexus)); browserBtn->menu()->addAction(nexusAction); - } else { - browserBtn = qobject_cast(ui->toolBar->widgetForAction(ui->actionNexus)); } QAction *action = new QAction(modPage->icon(), modPage->displayName(), ui->toolBar); @@ -1434,30 +1431,32 @@ void MainWindow::spawnBinary(const QFileInfo &binary, const QString &arguments, DWORD retLen; JOBOBJECT_BASIC_PROCESS_ID_LIST info; - bool isJobHandle = true; + { + bool isJobHandle = true; - DWORD res = ::MsgWaitForMultipleObjects(1, &processHandle, false, 1000, QS_KEY | QS_MOUSE); - while ((res != WAIT_FAILED) && (res != WAIT_OBJECT_0) && !dialog->unlockClicked()) { - if (isJobHandle) { - if (::QueryInformationJobObject(processHandle, JobObjectBasicProcessIdList, &info, sizeof(info), &retLen) > 0) { - if (info.NumberOfProcessIdsInList == 0) { - break; - } - } else { - // the info-object I passed only provides space for 1 process id. but since this code only cares about whether there - // is more than one that's good enough. ERROR_MORE_DATA simply signals there are at least two processes running. - // any other error probably means the handle is a regular process handle, probably caused by running MO in a job without - // the right to break out. - if (::GetLastError() != ERROR_MORE_DATA) { - isJobHandle = false; + DWORD res = ::MsgWaitForMultipleObjects(1, &processHandle, false, 1000, QS_KEY | QS_MOUSE); + while ((res != WAIT_FAILED) && (res != WAIT_OBJECT_0) && !dialog->unlockClicked()) { + if (isJobHandle) { + if (::QueryInformationJobObject(processHandle, JobObjectBasicProcessIdList, &info, sizeof(info), &retLen) > 0) { + if (info.NumberOfProcessIdsInList == 0) { + break; + } + } else { + // the info-object I passed only provides space for 1 process id. but since this code only cares about whether there + // is more than one that's good enough. ERROR_MORE_DATA simply signals there are at least two processes running. + // any other error probably means the handle is a regular process handle, probably caused by running MO in a job without + // the right to break out. + if (::GetLastError() != ERROR_MORE_DATA) { + isJobHandle = false; + } } } - } - // keep processing events so the app doesn't appear dead - QCoreApplication::processEvents(); + // keep processing events so the app doesn't appear dead + QCoreApplication::processEvents(); - res = ::MsgWaitForMultipleObjects(1, &processHandle, false, 1000, QS_KEY | QS_MOUSE); + res = ::MsgWaitForMultipleObjects(1, &processHandle, false, 1000, QS_KEY | QS_MOUSE); + } } ::CloseHandle(processHandle); @@ -2191,11 +2190,7 @@ void MainWindow::storeSettings() QSettings::Status result = QSettings::NoError; { QSettings settings(iniFile + ".new", QSettings::IniFormat); - if (m_CurrentProfile != NULL) { - settings.setValue("selected_profile", m_CurrentProfile->getName().toUtf8().constData()); - } else { - settings.remove("selected_profile"); - } + settings.setValue("selected_profile", m_CurrentProfile->getName().toUtf8().constData()); settings.setValue("mod_list_state", ui->modList->header()->saveState()); settings.setValue("plugin_list_state", ui->espList->header()->saveState()); @@ -5560,11 +5555,11 @@ void MainWindow::on_bossButton_clicked() DWORD retLen; JOBOBJECT_BASIC_PROCESS_ID_LIST info; - bool isJobHandle = true; - ULONG lastProcessID; HANDLE processHandle = loot; if (loot != INVALID_HANDLE_VALUE) { + bool isJobHandle = true; + ULONG lastProcessID; DWORD res = ::MsgWaitForMultipleObjects(1, &loot, false, 1000, QS_KEY | QS_MOUSE); while ((res != WAIT_FAILED) && (res != WAIT_OBJECT_0)) { if (isJobHandle) { diff --git a/src/modinfo.cpp b/src/modinfo.cpp index 796dab71..189e67b2 100644 --- a/src/modinfo.cpp +++ b/src/modinfo.cpp @@ -156,7 +156,7 @@ bool ModInfo::removeMod(unsigned int index) auto iter = s_ModsByModID.find(modInfo->getNexusID()); if (iter != s_ModsByModID.end()) { std::vector indices = iter->second; - std::remove(indices.begin(), indices.end(), index); + indices.erase(std::remove(indices.begin(), indices.end(), index), indices.end()); s_ModsByModID[modInfo->getNexusID()] = indices; } diff --git a/src/modlist.cpp b/src/modlist.cpp index eedf1ec6..fb8df15e 100644 --- a/src/modlist.cpp +++ b/src/modlist.cpp @@ -49,8 +49,12 @@ using namespace MOBase; ModList::ModList(QObject *parent) - : QAbstractItemModel(parent), m_Profile(NULL), m_Modified(false), - m_FontMetrics(QFont()), m_DropOnItems(false) + : QAbstractItemModel(parent) + , m_Profile(NULL) + , m_NexusInterface(NULL) + , m_Modified(false) + , m_FontMetrics(QFont()) + , m_DropOnItems(false) { m_ContentIcons[ModInfo::CONTENT_PLUGIN] = std::make_tuple(QIcon(":/MO/gui/content/plugin"), ":/MO/gui/content/plugin", tr("Game plugins (esp/esm)")); m_ContentIcons[ModInfo::CONTENT_INTERFACE] = std::make_tuple(QIcon(":/MO/gui/content/interface"), ":/MO/gui/content/interface", tr("Interface")); diff --git a/src/modlist.h b/src/modlist.h index 632689c6..cf52b2ec 100644 --- a/src/modlist.h +++ b/src/modlist.h @@ -267,7 +267,7 @@ private: struct TModInfo { TModInfo(unsigned int index, ModInfo::Ptr modInfo) - : modInfo(modInfo), nameOrder(index) {} + : modInfo(modInfo), nameOrder(index), priorityOrder(0), modIDOrder(0), categoryOrder(0) {} ModInfo::Ptr modInfo; unsigned int nameOrder; unsigned int priorityOrder; diff --git a/src/modlistsortproxy.cpp b/src/modlistsortproxy.cpp index da5d99d5..8907e712 100644 --- a/src/modlistsortproxy.cpp +++ b/src/modlistsortproxy.cpp @@ -298,7 +298,7 @@ bool ModListSortProxy::filterMatchesModOr(ModInfo::Ptr info, bool enabled) const } break; case CategoryFactory::CATEGORY_SPECIAL_NOTENDORSED: { ModInfo::EEndorsedState state = info->endorsedState(); - if ((state == ModInfo::ENDORSED_FALSE) && (state != ModInfo::ENDORSED_NEVER)) return true; + if ((state == ModInfo::ENDORSED_FALSE) || (state == ModInfo::ENDORSED_NEVER)) return true; } break; case CategoryFactory::CATEGORY_SPECIAL_MANAGED: { if (!info->hasFlag(ModInfo::FLAG_FOREIGN)) return true; diff --git a/src/nexusinterface.cpp b/src/nexusinterface.cpp index 30221f4b..b4006097 100644 --- a/src/nexusinterface.cpp +++ b/src/nexusinterface.cpp @@ -20,7 +20,7 @@ along with Mod Organizer. If not, see . #include "nexusinterface.h" #include "nxmaccessmanager.h" #include "utility.h" -#include +#include "json.h" #include "selectiondialog.h" #include #include @@ -580,6 +580,7 @@ NexusInterface::NXMRequestInfo::NXMRequestInfo(int modID , m_URL(url) , m_SubModule(subModule) , m_NexusGameID(nexusGameId) + , m_Endorse(false) {} NexusInterface::NXMRequestInfo::NXMRequestInfo(std::vector modIDList @@ -600,6 +601,7 @@ NexusInterface::NXMRequestInfo::NXMRequestInfo(std::vector modIDList , m_URL(url) , m_SubModule(subModule) , m_NexusGameID(nexusGameId) + , m_Endorse(false) {} NexusInterface::NXMRequestInfo::NXMRequestInfo(int modID @@ -620,4 +622,5 @@ NexusInterface::NXMRequestInfo::NXMRequestInfo(int modID , m_URL(url) , m_SubModule(subModule) , m_NexusGameID(nexusGameId) + , m_Endorse(false) {} diff --git a/src/pluginlist.cpp b/src/pluginlist.cpp index ff370fa4..973e3cfc 100644 --- a/src/pluginlist.cpp +++ b/src/pluginlist.cpp @@ -685,7 +685,7 @@ QString PluginList::origin(const QString &name) const { auto iter = m_ESPsByName.find(name.toLower()); if (iter == m_ESPsByName.end()) { - return false; + return QString(); } else { return m_ESPs[iter->second].m_OriginName; } @@ -836,7 +836,7 @@ QVariant PluginList::data(const QModelIndex &modelIndex, int role) const std::set_difference(m_ESPs[index].m_Masters.begin(), m_ESPs[index].m_Masters.end(), m_ESPs[index].m_MasterUnset.begin(), m_ESPs[index].m_MasterUnset.end(), std::inserter(enabledMasters, enabledMasters.end())); - if (enabledMasters.size() > 0) { + if (!enabledMasters.empty()) { text += "
" + tr("Enabled Masters") + ": " + SetJoin(enabledMasters, ", "); } if (m_ESPs[index].m_HasIni) { @@ -1102,34 +1102,34 @@ bool PluginList::eventFilter(QObject *obj, QEvent *event) ((keyEvent->key() == Qt::Key_Up) || (keyEvent->key() == Qt::Key_Down))) { QItemSelectionModel *selectionModel = itemView->selectionModel(); const QSortFilterProxyModel *proxyModel = qobject_cast(selectionModel->model()); - int diff = -1; - if (((keyEvent->key() == Qt::Key_Up) && (proxyModel->sortOrder() == Qt::DescendingOrder)) || - ((keyEvent->key() == Qt::Key_Down) && (proxyModel->sortOrder() == Qt::AscendingOrder))) { - diff = 1; - } - QModelIndexList rows = selectionModel->selectedRows(); - // remove elements that aren't supposed to be movable - QMutableListIterator iter(rows); - while (iter.hasNext()) { - if ((iter.next().flags() & Qt::ItemIsDragEnabled) == 0) { - iter.remove(); + if (proxyModel != NULL) { + int diff = -1; + if (((keyEvent->key() == Qt::Key_Up) && (proxyModel->sortOrder() == Qt::DescendingOrder)) || + ((keyEvent->key() == Qt::Key_Down) && (proxyModel->sortOrder() == Qt::AscendingOrder))) { + diff = 1; } - } - if (keyEvent->key() == Qt::Key_Down) { - for (int i = 0; i < rows.size() / 2; ++i) { - rows.swap(i, rows.size() - i - 1); + QModelIndexList rows = selectionModel->selectedRows(); + // remove elements that aren't supposed to be movable + QMutableListIterator iter(rows); + while (iter.hasNext()) { + if ((iter.next().flags() & Qt::ItemIsDragEnabled) == 0) { + iter.remove(); + } } - } - foreach (QModelIndex idx, rows) { - if (proxyModel != NULL) { - idx = proxyModel->mapToSource(idx); + if (keyEvent->key() == Qt::Key_Down) { + for (int i = 0; i < rows.size() / 2; ++i) { + rows.swap(i, rows.size() - i - 1); + } } - int newPriority = m_ESPs[idx.row()].m_Priority + diff; - if ((newPriority >= 0) && (newPriority < rowCount())) { - setPluginPriority(idx.row(), newPriority); + foreach (QModelIndex idx, rows) { + idx = proxyModel->mapToSource(idx); + int newPriority = m_ESPs[idx.row()].m_Priority + diff; + if ((newPriority >= 0) && (newPriority < rowCount())) { + setPluginPriority(idx.row(), newPriority); + } } + refreshLoadOrder(); } - refreshLoadOrder(); return true; } else if (keyEvent->key() == Qt::Key_Space) { QItemSelectionModel *selectionModel = itemView->selectionModel(); diff --git a/src/profile.cpp b/src/profile.cpp index 77e4f813..958084d7 100644 --- a/src/profile.cpp +++ b/src/profile.cpp @@ -585,7 +585,9 @@ void Profile::mergeTweaks(ModInfo::Ptr modInfo, const QString &tweakedIni) const bool Profile::invalidationActive(bool *supported) const { if (GameInfo::instance().requiresBSAInvalidation()) { - *supported = true; + if (supported != NULL) { + *supported = true; + } wchar_t buffer[1024]; std::wstring iniFileName = ToWString(QDir::toNativeSeparators(getIniFileName())); // epic ms fail: GetPrivateProfileString uses errno (for whatever reason) to signal a fail since the return value diff --git a/src/selfupdater.h b/src/selfupdater.h index 9648f15a..75b0ff45 100644 --- a/src/selfupdater.h +++ b/src/selfupdater.h @@ -65,7 +65,8 @@ public: * @todo passing the nexus interface is unneccessary **/ SelfUpdater(NexusInterface *nexusInterface, QWidget *parent); - ~SelfUpdater(); + + virtual ~SelfUpdater(); /** * @brief start the update process diff --git a/src/settings.cpp b/src/settings.cpp index 04a5f279..0ca811a3 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -25,7 +25,7 @@ along with Mod Organizer. If not, see . #include #include #include -#include +#include "json.h" #include #include diff --git a/src/shared/directoryentry.cpp b/src/shared/directoryentry.cpp index 5d785822..24868a93 100644 --- a/src/shared/directoryentry.cpp +++ b/src/shared/directoryentry.cpp @@ -325,13 +325,13 @@ static bool ByOriginPriority(DirectoryEntry *entry, int LHS, int RHS) FileEntry::FileEntry() - : m_Index(UINT_MAX), m_Name(), m_Parent(NULL), m_LastAccessed(time(NULL)) + : m_Index(UINT_MAX), m_Name(), m_Origin(-1), m_Parent(NULL), m_LastAccessed(time(NULL)) { LEAK_TRACE; } FileEntry::FileEntry(Index index, const std::wstring &name, DirectoryEntry *parent) - : m_Index(index), m_Name(name), m_Parent(parent), m_Origin(-1), m_Archive(L""), m_LastAccessed(time(NULL)) + : m_Index(index), m_Name(name), m_Origin(-1), m_Parent(parent), m_Archive(L""), m_LastAccessed(time(NULL)) { LEAK_TRACE; } @@ -636,7 +636,7 @@ void DirectoryEntry::insertFile(const std::wstring &filePath, FilesOrigin &origi void DirectoryEntry::removeFile(FileEntry::Index index) { - if (m_Files.size() != 0) { + if (!m_Files.empty()) { auto iter = std::find_if(m_Files.begin(), m_Files.end(), [&index](const std::pair &iter) -> bool { return iter.second == index; } ); diff --git a/src/shared/directoryentry.h b/src/shared/directoryentry.h index 096f373e..d588ab02 100644 --- a/src/shared/directoryentry.h +++ b/src/shared/directoryentry.h @@ -219,7 +219,7 @@ public: void clear(); bool isPopulated() const { return m_Populated; } - bool isEmpty() const { return (m_Files.size() == 0) && (m_SubDirectories.size() == 0); } + bool isEmpty() const { return m_Files.empty() && m_SubDirectories.empty(); } const DirectoryEntry *getParent() const { return m_Parent; } diff --git a/src/shared/fallout3info.cpp b/src/shared/fallout3info.cpp index 9487d2de..22db91ac 100644 --- a/src/shared/fallout3info.cpp +++ b/src/shared/fallout3info.cpp @@ -54,15 +54,17 @@ std::wstring Fallout3Info::getRegPathStatic() 0, KEY_QUERY_VALUE, &key); if (errorcode != ERROR_SUCCESS) { - return L""; + return std::wstring(); } WCHAR temp[MAX_PATH]; DWORD bufferSize = MAX_PATH; - errorcode = ::RegQueryValueExW(key, L"Installed Path", NULL, NULL, (LPBYTE)temp, &bufferSize); - - return std::wstring(temp); + if (::RegQueryValueExW(key, L"Installed Path", NULL, NULL, (LPBYTE)temp, &bufferSize) == ERROR_SUCCESS) { + return std::wstring(temp); + } else { + return std::wstring(); + } } std::wstring Fallout3Info::getInvalidationBSA() @@ -233,15 +235,12 @@ void Fallout3Info::createProfile(const std::wstring &directory, bool useDefaults } } { // copy falloutprefs.ini-file - std::wstring target = directory.substr().append(L"\\falloutprefs.ini"); + std::wstring target = directory + L"\\falloutprefs.ini"; if (!FileExists(target)) { - std::wostringstream source; - source << getMyGamesDirectory() << L"\\Fallout3\\falloutprefs.ini"; - if (!::CopyFileW(source.str().c_str(), target.c_str(), true)) { + std::wstring source = getMyGamesDirectory() + L"\\Fallout3\\falloutprefs.ini"; + if (!::CopyFileW(source.c_str(), target.c_str(), true)) { if (::GetLastError() != ERROR_FILE_EXISTS) { - std::ostringstream stream; - stream << "failed to copy ini file: " << ToString(source.str(), false); - throw windows_error(stream.str()); + throw windows_error(std::string("failed to copy ini file: ") + ToString(source, false)); } } } diff --git a/src/shared/fallout3info.h b/src/shared/fallout3info.h index 8e4c260d..d1356de1 100644 --- a/src/shared/fallout3info.h +++ b/src/shared/fallout3info.h @@ -38,7 +38,7 @@ public: virtual unsigned long getBSAVersion(); static std::wstring getRegPathStatic(); - virtual std::wstring getRegPath() { return Fallout3Info::getRegPathStatic(); } + virtual std::wstring getRegPath() { return getRegPathStatic(); } virtual std::wstring getBinaryName() { return L"Fallout3.exe"; } virtual GameInfo::Type getType() { return TYPE_FALLOUT3; } @@ -75,9 +75,9 @@ public: virtual std::wstring getNexusPage(bool nmmScheme = true); static std::wstring getNexusInfoUrlStatic(); - virtual std::wstring getNexusInfoUrl() { return Fallout3Info::getNexusInfoUrlStatic(); } + virtual std::wstring getNexusInfoUrl() { return getNexusInfoUrlStatic(); } static int getNexusModIDStatic(); - virtual int getNexusModID() { return Fallout3Info::getNexusModIDStatic(); } + virtual int getNexusModID() { return getNexusModIDStatic(); } virtual int getNexusGameID() { return 120; } virtual void createProfile(const std::wstring &directory, bool useDefaults); diff --git a/src/shared/falloutnvinfo.cpp b/src/shared/falloutnvinfo.cpp index 9bba7fe4..0dde4db1 100644 --- a/src/shared/falloutnvinfo.cpp +++ b/src/shared/falloutnvinfo.cpp @@ -55,15 +55,17 @@ std::wstring FalloutNVInfo::getRegPathStatic() 0, KEY_QUERY_VALUE, &key); if (errorcode != ERROR_SUCCESS) { - return L""; + return std::wstring(); } WCHAR temp[MAX_PATH]; DWORD bufferSize = MAX_PATH; - errorcode = ::RegQueryValueExW(key, L"Installed Path", NULL, NULL, (LPBYTE)temp, &bufferSize); - - return std::wstring(temp); + if (::RegQueryValueExW(key, L"Installed Path", NULL, NULL, (LPBYTE)temp, &bufferSize) == ERROR_SUCCESS) { + return std::wstring(temp); + } else { + return std::wstring(); + } } std::wstring FalloutNVInfo::getInvalidationBSA() @@ -162,56 +164,46 @@ std::wstring FalloutNVInfo::getSteamAPPId(int) const void FalloutNVInfo::createProfile(const std::wstring &directory, bool useDefaults) { - std::wostringstream target; + std::wstring target = directory + L"\\plugins.txt"; // copy plugins.txt - target << directory << "\\plugins.txt"; - - if (!FileExists(target.str())) { - std::wostringstream source; - source << getLocalAppFolder() << "\\FalloutNV\\plugins.txt"; - if (!::CopyFileW(source.str().c_str(), target.str().c_str(), true)) { - HANDLE file = ::CreateFileW(target.str().c_str(), GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL); + if (!FileExists(target)) { + std::wstring source = getLocalAppFolder() + L"\\FalloutNV\\plugins.txt"; + if (!::CopyFileW(source.c_str(), target.c_str(), true)) { + HANDLE file = ::CreateFileW(target.c_str(), GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL); ::CloseHandle(file); } } // copy ini-file - target.str(L""); target.clear(); - target << directory << L"\\fallout.ini"; + target = directory + L"\\fallout.ini"; - if (!FileExists(target.str())) { - std::wostringstream source; + if (!FileExists(target)) { + std::wstring source; if (useDefaults) { - source << getGameDirectory() << L"\\fallout_default.ini"; + source = getGameDirectory() + L"\\fallout_default.ini"; } else { - source << getMyGamesDirectory() << L"\\FalloutNV"; - if (FileExists(source.str(), L"fallout.ini")) { - source << L"\\fallout.ini"; + source = getMyGamesDirectory() + L"\\FalloutNV"; + if (FileExists(source, L"fallout.ini")) { + source += L"\\fallout.ini"; } else { - source.str(L""); - source << getGameDirectory() << L"\\fallout_default.ini"; + source = getGameDirectory() + L"\\fallout_default.ini"; } } - if (!::CopyFileW(source.str().c_str(), target.str().c_str(), true)) { + if (!::CopyFileW(source.c_str(), target.c_str(), true)) { if (::GetLastError() != ERROR_FILE_EXISTS) { - std::ostringstream stream; - stream << "failed to copy ini file: " << ToString(source.str(), false); - throw windows_error(stream.str()); + throw windows_error("failed to copy ini file: " + ToString(source, false)); } } } { // copy falloutprefs.ini-file - std::wstring target = directory.substr().append(L"\\falloutprefs.ini"); + std::wstring target = directory + L"\\falloutprefs.ini"; if (!FileExists(target)) { - std::wostringstream source; - source << getMyGamesDirectory() << L"\\FalloutNV\\falloutprefs.ini"; - if (!::CopyFileW(source.str().c_str(), target.c_str(), true)) { + std::wstring source = getMyGamesDirectory() + L"\\FalloutNV\\falloutprefs.ini"; + if (!::CopyFileW(source.c_str(), target.c_str(), true)) { if (::GetLastError() != ERROR_FILE_EXISTS) { - std::ostringstream stream; - stream << "failed to copy ini file: " << ToString(source.str(), false); - throw windows_error(stream.str()); + throw windows_error("failed to copy ini file: " + ToString(source, false)); } } } diff --git a/src/shared/falloutnvinfo.h b/src/shared/falloutnvinfo.h index cfd373c7..50a0d00d 100644 --- a/src/shared/falloutnvinfo.h +++ b/src/shared/falloutnvinfo.h @@ -38,7 +38,7 @@ public: virtual unsigned long getBSAVersion(); static std::wstring getRegPathStatic(); - virtual std::wstring getRegPath() { return FalloutNVInfo::getRegPathStatic(); } + virtual std::wstring getRegPath() { return getRegPathStatic(); } virtual std::wstring getBinaryName() { return L"FalloutNV.exe"; } virtual GameInfo::Type getType() { return TYPE_FALLOUTNV; } @@ -76,9 +76,9 @@ public: virtual std::wstring getNexusPage(bool nmmScheme = true); static std::wstring getNexusInfoUrlStatic(); - virtual std::wstring getNexusInfoUrl() { return FalloutNVInfo::getNexusInfoUrlStatic(); } + virtual std::wstring getNexusInfoUrl() { return getNexusInfoUrlStatic(); } static int getNexusModIDStatic(); - virtual int getNexusModID() { return FalloutNVInfo::getNexusModIDStatic(); } + virtual int getNexusModID() { return getNexusModIDStatic(); } virtual int getNexusGameID() { return 130; } virtual void createProfile(const std::wstring &directory, bool useDefaults); diff --git a/src/shared/gameinfo.cpp b/src/shared/gameinfo.cpp index 21e9a586..5439efff 100644 --- a/src/shared/gameinfo.cpp +++ b/src/shared/gameinfo.cpp @@ -57,7 +57,7 @@ void GameInfo::identifyMyGamesDirectory(const std::wstring &file) { // this function attempts 3 (three!) ways to determine the correct "My Games" folder. wchar_t myDocuments[MAX_PATH]; - memset(myDocuments, '\0', MAX_PATH); + memset(myDocuments, '\0', MAX_PATH * sizeof(wchar_t)); m_MyGamesDirectory.clear(); @@ -137,71 +137,53 @@ std::wstring GameInfo::getGameDirectory() const std::wstring GameInfo::getModsDir() const { - std::wostringstream temp; - temp << m_OrganizerDataDirectory << L"\\mods"; - return temp.str(); + return m_OrganizerDirectory + L"\\mods"; } std::wstring GameInfo::getProfilesDir() const { - std::wostringstream temp; - temp << m_OrganizerDataDirectory << L"\\profiles"; - return temp.str(); + return m_OrganizerDirectory + L"\\profiles"; } std::wstring GameInfo::getIniFilename() const { - std::wostringstream temp; - temp << m_OrganizerDataDirectory << L"\\ModOrganizer.ini"; - return temp.str(); + return m_OrganizerDirectory + L"\\ModOrganizer.ini"; } std::wstring GameInfo::getDownloadDir() const { - std::wostringstream temp; - temp << m_OrganizerDataDirectory << L"\\downloads"; - return temp.str(); + return m_OrganizerDirectory + L"\\downloads"; } std::wstring GameInfo::getCacheDir() const { - std::wostringstream temp; - temp << m_OrganizerDataDirectory << L"\\webcache"; - return temp.str(); + return m_OrganizerDirectory + L"\\webcache"; } std::wstring GameInfo::getOverwriteDir() const { - std::wostringstream temp; - temp << m_OrganizerDataDirectory << "\\overwrite"; - return temp.str(); + return m_OrganizerDirectory + L"\\overwrite"; } std::wstring GameInfo::getLogDir() const { - std::wostringstream temp; - temp << m_OrganizerDataDirectory << "\\logs"; - return temp.str(); + return m_OrganizerDirectory + L"\\logs"; } std::wstring GameInfo::getLootDir() const { - std::wostringstream temp; - temp << m_OrganizerDirectory << "\\loot"; - return temp.str(); + return m_OrganizerDirectory + L"\\loot"; } std::wstring GameInfo::getTutorialDir() const { - std::wostringstream temp; - temp << m_OrganizerDirectory << "\\tutorials"; - return temp.str(); + return m_OrganizerDirectory + L"\\tutorials"; } @@ -219,7 +201,7 @@ std::vector GameInfo::getSteamVariants() const std::wstring GameInfo::getLocalAppFolder() const { wchar_t localAppFolder[MAX_PATH]; - memset(localAppFolder, '\0', MAX_PATH); + memset(localAppFolder, '\0', MAX_PATH * sizeof(wchar_t)); if (::SHGetFolderPathW(NULL, CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, localAppFolder) == S_OK) { return localAppFolder; diff --git a/src/shared/leaktrace.cpp b/src/shared/leaktrace.cpp index 68e57609..729eb42e 100644 --- a/src/shared/leaktrace.cpp +++ b/src/shared/leaktrace.cpp @@ -36,7 +36,7 @@ class StackData { public: StackData() - : m_FunctionName("Dummy"), m_CodeLine(0) + : m_Count(0), m_Hash(0UL), m_FunctionName("Dummy"), m_CodeLine(0) {} StackData(const char *functionName, int line) { m_Count = ::CaptureStackBackTrace(FRAMES_TO_SKIP, FRAMES_TO_CAPTURE, m_Stack, &m_Hash); diff --git a/src/shared/oblivioninfo.cpp b/src/shared/oblivioninfo.cpp index f317812f..790fcdb0 100644 --- a/src/shared/oblivioninfo.cpp +++ b/src/shared/oblivioninfo.cpp @@ -55,15 +55,17 @@ std::wstring OblivionInfo::getRegPathStatic() 0, KEY_QUERY_VALUE, &key); if (errorcode != ERROR_SUCCESS) { - return L""; + return std::wstring(); } WCHAR temp[MAX_PATH]; DWORD bufferSize = MAX_PATH; - errorcode = ::RegQueryValueExW(key, L"Installed Path", NULL, NULL, (LPBYTE)temp, &bufferSize); - - return std::wstring(temp); + if (::RegQueryValueExW(key, L"Installed Path", NULL, NULL, (LPBYTE)temp, &bufferSize) == ERROR_SUCCESS) { + return std::wstring(temp); + } else { + return std::wstring(); + } } std::wstring OblivionInfo::getInvalidationBSA() @@ -188,16 +190,13 @@ void OblivionInfo::createProfile(const std::wstring &directory, bool useDefaults } { // copy oblivionprefs.ini-file - std::wstring target = directory.substr().append(L"\\oblivionprefs.ini"); + std::wstring target = directory + L"\\oblivionprefs.ini"; if (!FileExists(target)) { - std::wostringstream source; - source << getMyGamesDirectory() << L"\\Oblivion\\oblivionprefs.ini"; - if (!::CopyFileW(source.str().c_str(), target.c_str(), true)) { + std::wstring source = getMyGamesDirectory() + L"\\Oblivion\\oblivionprefs.ini"; + if (!::CopyFileW(source.c_str(), target.c_str(), true)) { if ((::CreateFileW(target.c_str(), GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL) == INVALID_HANDLE_VALUE) && (::GetLastError() != ERROR_FILE_EXISTS)) { - std::ostringstream stream; - stream << "failed to create ini file: " << ToString(target.c_str(), false); - throw windows_error(stream.str()); + throw windows_error(std::string("failed to create ini file: ") + ToString(target, false)); } } } diff --git a/src/shared/oblivioninfo.h b/src/shared/oblivioninfo.h index 02fd90b4..e64ae37b 100644 --- a/src/shared/oblivioninfo.h +++ b/src/shared/oblivioninfo.h @@ -36,7 +36,7 @@ public: virtual unsigned long getBSAVersion(); static std::wstring getRegPathStatic(); - virtual std::wstring getRegPath() { return OblivionInfo::getRegPathStatic(); } + virtual std::wstring getRegPath() { return getRegPathStatic(); } virtual std::wstring getBinaryName() { return L"Oblivion.exe"; } virtual GameInfo::Type getType() { return TYPE_OBLIVION; } @@ -72,9 +72,9 @@ public: virtual std::wstring getNexusPage(bool nmmScheme = true); static std::wstring getNexusInfoUrlStatic(); - virtual std::wstring getNexusInfoUrl() { return OblivionInfo::getNexusInfoUrlStatic(); } + virtual std::wstring getNexusInfoUrl() { return getNexusInfoUrlStatic(); } static int getNexusModIDStatic(); - virtual int getNexusModID() { return OblivionInfo::getNexusModIDStatic(); } + virtual int getNexusModID() { return getNexusModIDStatic(); } virtual int getNexusGameID() { return 101; } virtual void createProfile(const std::wstring &directory, bool useDefaults); diff --git a/src/shared/skyriminfo.cpp b/src/shared/skyriminfo.cpp index c985fe9f..319e58d5 100644 --- a/src/shared/skyriminfo.cpp +++ b/src/shared/skyriminfo.cpp @@ -63,15 +63,17 @@ std::wstring SkyrimInfo::getRegPathStatic() 0, KEY_QUERY_VALUE, &key); if (errorcode != ERROR_SUCCESS) { - return L""; + return std::wstring(); } WCHAR temp[MAX_PATH]; DWORD bufferSize = MAX_PATH; - errorcode = ::RegQueryValueExW(key, L"Installed Path", NULL, NULL, (LPBYTE)temp, &bufferSize); - - return std::wstring(temp); + if (::RegQueryValueExW(key, L"Installed Path", NULL, NULL, (LPBYTE)temp, &bufferSize) == ERROR_SUCCESS) { + return std::wstring(temp); + } else { + return std::wstring(); + } } @@ -222,7 +224,7 @@ int SkyrimInfo::getNexusModIDStatic() void SkyrimInfo::createProfile(const std::wstring &directory, bool useDefaults) { { // copy plugins.txt - std::wstring target = directory.substr().append(L"\\plugins.txt"); + std::wstring target = directory + L"\\plugins.txt"; if (!FileExists(target)) { std::wostringstream source; source << getLocalAppFolder() << "\\Skyrim\\plugins.txt"; @@ -231,11 +233,10 @@ void SkyrimInfo::createProfile(const std::wstring &directory, bool useDefaults) ::CloseHandle(file); } } - target = directory.substr().append(L"\\loadorder.txt"); + target = directory + L"\\loadorder.txt"; if (!FileExists(target)) { - std::wostringstream source; - source << getLocalAppFolder() << "\\Skyrim\\loadorder.txt"; - if (!::CopyFileW(source.str().c_str(), target.c_str(), true)) { + std::wstring source = getLocalAppFolder() + L"\\Skyrim\\loadorder.txt"; + if (!::CopyFileW(source.c_str(), target.c_str(), true)) { HANDLE file = ::CreateFileW(target.c_str(), GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL); ::CloseHandle(file); } @@ -243,42 +244,36 @@ void SkyrimInfo::createProfile(const std::wstring &directory, bool useDefaults) } { // copy skyrim.ini-file - std::wstring target = directory.substr().append(L"\\skyrim.ini"); + std::wstring target = directory + L"\\skyrim.ini"; if (!FileExists(target)) { - std::wostringstream source; + std::wstring source; if (useDefaults) { - source << getGameDirectory() << L"\\skyrim_default.ini"; + source = getGameDirectory() + L"\\skyrim_default.ini"; } else { - source << getMyGamesDirectory() << L"\\Skyrim"; - if (FileExists(source.str(), L"skyrim.ini")) { - source << L"\\skyrim.ini"; + source = getMyGamesDirectory() + L"\\Skyrim"; + if (FileExists(source, L"skyrim.ini")) { + source += L"\\skyrim.ini"; } else { - source.str(L""); - source << getGameDirectory() << L"\\skyrim_default.ini"; + source = getGameDirectory() + L"\\skyrim_default.ini"; } } - if (!::CopyFileW(source.str().c_str(), target.c_str(), true)) { + if (!::CopyFileW(source.c_str(), target.c_str(), true)) { if (::GetLastError() != ERROR_FILE_EXISTS) { - std::ostringstream stream; - stream << "failed to copy ini file: " << ToString(source.str(), false); - throw windows_error(stream.str()); + throw windows_error(std::string("failed to copy ini file: ") + ToString(source, false)); } } } } { // copy skyrimprefs.ini-file - std::wstring target = directory.substr().append(L"\\skyrimprefs.ini"); + std::wstring target = directory + L"\\skyrimprefs.ini"; if (!FileExists(target)) { - std::wostringstream source; - source << getMyGamesDirectory() << L"\\Skyrim\\skyrimprefs.ini"; - if (!::CopyFileW(source.str().c_str(), target.c_str(), true)) { - log("failed to copy ini file %ls", source.str().c_str()); + std::wstring source = getMyGamesDirectory() + L"\\Skyrim\\skyrimprefs.ini"; + if (!::CopyFileW(source.c_str(), target.c_str(), true)) { + log("failed to copy ini file %ls", source.c_str()); // create empty if (::CreateFileW(target.c_str(), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL) == INVALID_HANDLE_VALUE) { - std::ostringstream stream; - stream << "failed to copy ini file: " << ToString(source.str(), false); - throw windows_error(stream.str()); + throw windows_error(std::string("failed to copy ini file: ") + ToString(source, false)); } } } diff --git a/src/shared/skyriminfo.h b/src/shared/skyriminfo.h index 132f2aee..a7aff8dc 100644 --- a/src/shared/skyriminfo.h +++ b/src/shared/skyriminfo.h @@ -38,7 +38,7 @@ public: virtual unsigned long getBSAVersion(); static std::wstring getRegPathStatic(); - virtual std::wstring getRegPath() { return SkyrimInfo::getRegPathStatic(); } + virtual std::wstring getRegPath() { return getRegPathStatic(); } virtual std::wstring getBinaryName() { return L"TESV.exe"; } virtual GameInfo::Type getType() { return TYPE_SKYRIM; } @@ -81,11 +81,11 @@ public: virtual std::wstring getNexusPage(bool nmmScheme = true); static std::wstring getNexusInfoUrlStatic(); - virtual std::wstring getNexusInfoUrl() { return SkyrimInfo::getNexusInfoUrlStatic(); } + virtual std::wstring getNexusInfoUrl() { return getNexusInfoUrlStatic(); } static int getNexusModIDStatic(); - virtual int getNexusModID() { return SkyrimInfo::getNexusModIDStatic(); } + virtual int getNexusModID() { return getNexusModIDStatic(); } static int getNexusGameIDStatic() { return 110; } - virtual int getNexusGameID() { return SkyrimInfo::getNexusGameIDStatic(); } + virtual int getNexusGameID() { return getNexusGameIDStatic(); } virtual void createProfile(const std::wstring &directory, bool useDefaults); virtual void repairProfile(const std::wstring &directory); -- cgit v1.3.1 From df0bd3331a4b2174f99117c5a6f21ff6bddca1ba Mon Sep 17 00:00:00 2001 From: Tannin Date: Wed, 5 Nov 2014 23:48:06 +0100 Subject: - archive library can now query for password during extraction (seems to be necessary for rars) - process blacklist is now taken from a file if there is one, not hardcoded - removed workaround for the papyrus compiler - updated loot client to work with the actual api - loot client now links with loot32.dll at runtime - loot client now produces its output in a (json-)file which includes all plugin messages and dirty flags - fomod installer now tries to parse the xml with several encodings - fomod installer will now display a diagnostics warning if the jpg imageformat isn't supported - base preview plugin now tries to be a bit smarter about resizing images to fit the screen - bugfix: fomod installer no longer tries to open an image even after detecting its invalid - bugfix: potential null-pointer dereferentiation in getprivateprofile... hooks - bugfix: potential null-pointer dereferentiation in download manager - bugfix: internal origin name showed up in one more place - bugfix: ToString function produced strings that were one (zero-termination-)character too long --- src/aboutdialog.cpp | 1 - src/dlls.manifest.debug.qt5 | 3 +++ src/downloadmanager.cpp | 2 +- src/main.cpp | 2 +- src/mainwindow.cpp | 48 ++++++++++++++++++++++++++++++++------------- src/mainwindow.h | 2 +- src/organizer.pro | 2 +- src/pluginlist.cpp | 12 +++++++++++- src/settings.cpp | 2 +- src/shared/util.cpp | 9 ++++++--- 10 files changed, 59 insertions(+), 24 deletions(-) (limited to 'src/settings.cpp') diff --git a/src/aboutdialog.cpp b/src/aboutdialog.cpp index b5bfeb04..90dcd073 100644 --- a/src/aboutdialog.cpp +++ b/src/aboutdialog.cpp @@ -41,7 +41,6 @@ AboutDialog::AboutDialog(const QString &version, QWidget *parent) addLicense("Boost Library", LICENSE_BOOST); addLicense("7-zip", LICENSE_LGPL3); addLicense("ZLib", LICENSE_ZLIB); - addLicense("NIF File Format Library", LICENSE_BSD3); addLicense("Tango Icon Theme", LICENSE_NONE); addLicense("RRZE Icon Set", LICENSE_CCBY3); addLicense("Icons by Lorc, Delapouite and sbed available on http://game-icons.net", LICENSE_CCBY3); diff --git a/src/dlls.manifest.debug.qt5 b/src/dlls.manifest.debug.qt5 index 6cc0a83d..1bbdf691 100644 --- a/src/dlls.manifest.debug.qt5 +++ b/src/dlls.manifest.debug.qt5 @@ -8,7 +8,10 @@ + + + diff --git a/src/downloadmanager.cpp b/src/downloadmanager.cpp index bc31adf4..82701a05 100644 --- a/src/downloadmanager.cpp +++ b/src/downloadmanager.cpp @@ -606,7 +606,7 @@ void DownloadManager::pauseDownload(int index) DownloadInfo *info = m_ActiveDownloads.at(index); if (info->m_State == STATE_DOWNLOADING) { - if (info->m_Reply->isRunning()) { + if ((info->m_Reply != NULL) && (info->m_Reply->isRunning())) { setState(info, STATE_PAUSING); } else { setState(info, STATE_PAUSED); diff --git a/src/main.cpp b/src/main.cpp index 642bfa1a..b4139f09 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -332,7 +332,7 @@ int main(int argc, char *argv[]) } } - application.addLibraryPath(application.applicationDirPath() + "/dlls"); + application.setLibraryPaths(QStringList() << (application.applicationDirPath() + "/dlls")); SetUnhandledExceptionFilter(MyUnhandledExceptionFilter); diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 19be758e..d9db84ae 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -103,6 +103,10 @@ along with Mod Organizer. If not, see . #include #include #include +#include +#include +#include +#include #if QT_VERSION >= QT_VERSION_CHECK(5,0,0) #include #else @@ -1268,14 +1272,14 @@ void MainWindow::unloadPlugins() ui->actionTool->menu()->clear(); } - foreach (QPluginLoader *loader, m_PluginLoaders) { - qDebug("unloading %s", qPrintable(loader->fileName())); + while (!m_PluginLoaders.empty()) { + QPluginLoader *loader = m_PluginLoaders.back(); + m_PluginLoaders.pop_back(); if (!loader->unload()) { qDebug("failed to unload %s: %s", qPrintable(loader->fileName()), qPrintable(loader->errorString())); } delete loader; } - m_PluginLoaders.clear(); } void MainWindow::loadPlugins() @@ -1322,7 +1326,7 @@ void MainWindow::loadPlugins() if (QLibrary::isLibrary(pluginName)) { QPluginLoader *pluginLoader = new QPluginLoader(pluginName, this); if (pluginLoader->instance() == NULL) { - m_UnloadedPlugins.push_back(pluginName); + m_FailedPlugins.push_back(pluginName); qCritical("failed to load plugin %s: %s", qPrintable(pluginName), qPrintable(pluginLoader->errorString())); } else { @@ -1330,7 +1334,7 @@ void MainWindow::loadPlugins() qDebug("loaded plugin \"%s\"", qPrintable(pluginName)); m_PluginLoaders.push_back(pluginLoader); } else { - m_UnloadedPlugins.push_back(pluginName); + m_FailedPlugins.push_back(pluginName); qWarning("plugin \"%s\" failed to load", qPrintable(pluginName)); } } @@ -2285,7 +2289,7 @@ void MainWindow::on_tabWidget_currentChanged(int index) std::vector MainWindow::activeProblems() const { std::vector problems; - if (m_UnloadedPlugins.size() != 0) { + if (m_FailedPlugins.size() != 0) { problems.push_back(PROBLEM_PLUGINSNOTLOADED); } if (m_PluginList.enabledCount() > 255) { @@ -2314,7 +2318,7 @@ QString MainWindow::fullDescription(unsigned int key) const switch (key) { case PROBLEM_PLUGINSNOTLOADED: { QString result = tr("The following plugins could not be loaded. The reason may be missing dependencies (i.e. python) or an outdated version:") + "
    "; - foreach (const QString &plugin, m_UnloadedPlugins) { + foreach (const QString &plugin, m_FailedPlugins) { result += "
  • " + plugin + "
  • "; } result += "
      "; @@ -5375,13 +5379,10 @@ void MainWindow::processLOOTOut(const std::string &lootOut, std::string &reportU foreach (const std::string &line, lines) { if (line.length() > 0) { - size_t progidx = line.find("[progress]"); - size_t reportidx = line.find("[Report]"); - size_t erroridx = line.find("[error]"); + size_t progidx = line.find("[progress]"); + size_t erroridx = line.find("[error]"); if (progidx != std::string::npos) { dialog.setLabelText(line.substr(progidx + 11).c_str()); - } else if (reportidx != std::string::npos) { - reportURL = line.substr(reportidx + 9); } else if (erroridx != std::string::npos) { qWarning("%s", line.c_str()); errorMessages.append(boost::algorithm::trim_copy(line.substr(erroridx + 8)) + "\n"); @@ -5525,12 +5526,15 @@ void MainWindow::on_bossButton_clicked() dialog.setMaximum(0); dialog.show(); + QString outPath = QDir::temp().absoluteFilePath("lootreport.json"); + QStringList parameters; parameters << "--unattended" << "--stdout" << "--noreport" << "--game" << ToQString(GameInfo::instance().getGameShortName()) - << "--gamePath" << QString("\"%1\"").arg(ToQString(GameInfo::instance().getGameDirectory())); + << "--gamePath" << QString("\"%1\"").arg(ToQString(GameInfo::instance().getGameDirectory())) + << "--out" << outPath; if (m_DidUpdateMasterList) { parameters << "--skipUpdateMasterlist"; @@ -5540,7 +5544,7 @@ void MainWindow::on_bossButton_clicked() HANDLE stdOutWrite = INVALID_HANDLE_VALUE; HANDLE stdOutRead = INVALID_HANDLE_VALUE; createStdoutPipe(&stdOutRead, &stdOutWrite); - HANDLE loot = startBinary(QFileInfo(qApp->applicationDirPath() + "/loot/LOOT.exe"), + HANDLE loot = startBinary(QFileInfo(qApp->applicationDirPath() + "/loot/lootcli.exe"), parameters.join(" "), m_CurrentProfile->getName(), m_Settings.logLevel(), @@ -5615,6 +5619,22 @@ void MainWindow::on_bossButton_clicked() return; } else { success = true; + QFile outFile(outPath); + outFile.open(QIODevice::ReadOnly); + QJsonDocument doc = QJsonDocument::fromJson(outFile.readAll()); + QJsonArray array = doc.array(); + for (auto iter = array.begin(); iter != array.end(); ++iter) { + QJsonObject pluginObj = (*iter).toObject(); + QJsonArray pluginMessages = pluginObj["messages"].toArray(); + for (auto msgIter = pluginMessages.begin(); msgIter != pluginMessages.end(); ++msgIter) { + QJsonObject msg = (*msgIter).toObject(); + m_PluginList.addInformation(pluginObj["name"].toString(), + QString("%1: %2").arg(msg["type"].toString(), msg["message"].toString())); + } + if (pluginObj["dirty"].toString() == "yes") + m_PluginList.addInformation(pluginObj["name"].toString(), "dirty"); + } + } } else { reportError(tr("failed to start loot")); diff --git a/src/mainwindow.h b/src/mainwindow.h index 8bd663ac..ea79fc37 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -381,7 +381,7 @@ private: std::vector m_DiagnosisPlugins; std::vector m_DiagnosisConnections; std::vector m_ModPages; - std::vector m_UnloadedPlugins; + std::vector m_FailedPlugins; std::vector m_PluginLoaders; QFile m_PluginsCheck; diff --git a/src/organizer.pro b/src/organizer.pro index b24586e6..fd1e6aad 100644 --- a/src/organizer.pro +++ b/src/organizer.pro @@ -341,7 +341,7 @@ SRCDIR ~= s,/,$$QMAKE_DIR_SEP,g DSTDIR ~= s,/,$$QMAKE_DIR_SEP,g QMAKE_POST_LINK += xcopy /y /I $$quote($$SRCDIR\\ModOrganizer*.exe) $$quote($$DSTDIR) $$escape_expand(\\n) -QMAKE_POST_LINK += xcopy /y /I $$quote($$SRCDIR\\ModOrganizer*.pdb) $$quote($$DSTDIR) $$escape_expand(\\n) +QMAKE_POST_LINK += xcopy /y /I $$quote($$SRCDIR\\ModOrganizer*.exe) $$quote($$DSTDIR) $$escape_expand(\\n) QMAKE_POST_LINK += xcopy /y /s /I $$quote($$BASEDIR\\stylesheets) $$quote($$DSTDIR)\\stylesheets $$escape_expand(\\n) QMAKE_POST_LINK += xcopy /y /s /I $$quote($$BASEDIR\\tutorials) $$quote($$DSTDIR)\\tutorials $$escape_expand(\\n) QMAKE_POST_LINK += xcopy /y /s /I $$quote($$BASEDIR\\*.qm) $$quote($$DSTDIR)\\translations $$escape_expand(\\n) diff --git a/src/pluginlist.cpp b/src/pluginlist.cpp index 973e3cfc..b2d02cd2 100644 --- a/src/pluginlist.cpp +++ b/src/pluginlist.cpp @@ -23,6 +23,7 @@ along with Mod Organizer. If not, see . #include "settings.h" #include "safewritefile.h" #include "scopeguard.h" +#include "modinfo.h" #include #include #include @@ -158,7 +159,14 @@ void PluginList::refresh(const QString &profileName, const DirectoryEntry &baseD QString iniPath = QFileInfo(filename).baseName() + ".ini"; bool hasIni = baseDirectory.findFile(ToWString(iniPath)).get() != NULL; - m_ESPs.push_back(ESPInfo(filename, forceEnabled, current->getFileTime(), ToQString(origin.getName()), ToQString(current->getFullPath()), hasIni)); + QString originName = ToQString(origin.getName()); + unsigned int modIndex = ModInfo::getIndex(originName); + if (modIndex != UINT_MAX) { + ModInfo::Ptr modInfo = ModInfo::getByIndex(modIndex); + originName = modInfo->name(); + } + + m_ESPs.push_back(ESPInfo(filename, forceEnabled, current->getFileTime(), originName, ToQString(current->getFullPath()), hasIni)); } catch (const std::exception &e) { reportError(tr("failed to update esp info for file %1 (source id: %2), error: %3").arg(filename).arg(current->getOrigin(archive)).arg(e.what())); } @@ -290,6 +298,8 @@ void PluginList::addInformation(const QString &name, const QString &message) if (iter != m_ESPsByName.end()) { m_AdditionalInfo[name.toLower()].m_Messages.append(message); + } else { + qWarning("failed to associate message for \"%s\"", qPrintable(name)); } } diff --git a/src/settings.cpp b/src/settings.cpp index 0ca811a3..274e5979 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -231,7 +231,7 @@ QString Settings::getModDirectory() const QString Settings::getNMMVersion() const { - static const QString MIN_NMM_VERSION = "0.47.0"; + static const QString MIN_NMM_VERSION = "0.52.3"; QString result = m_Settings.value("Settings/nmm_version", MIN_NMM_VERSION).toString(); if (VersionInfo(result) < VersionInfo(MIN_NMM_VERSION)) { result = MIN_NMM_VERSION; diff --git a/src/shared/util.cpp b/src/shared/util.cpp index 4bc5a8a4..d4a77929 100644 --- a/src/shared/util.cpp +++ b/src/shared/util.cpp @@ -71,7 +71,9 @@ std::string ToString(const std::wstring &source, bool utf8) if (sizeRequired == 0) { throw windows_error("failed to convert string to multibyte"); } - result.resize(sizeRequired, '\0'); + // the size returned by WideCharToMultiByte contains zero termination IF -1 is specified for the length. + // we don't want that \0 in the string because then the length field would be wrong. Because madness + result.resize(sizeRequired - 1, '\0'); ::WideCharToMultiByte(codepage, 0, &source[0], (int)source.size(), &result[0], sizeRequired, NULL, NULL); return result; } @@ -117,14 +119,15 @@ std::wstring ToLower(const std::wstring &text) VS_FIXEDFILEINFO GetFileVersion(const std::wstring &fileName) { - DWORD size = ::GetFileVersionInfoSizeW(fileName.c_str(), NULL); + DWORD handle; + DWORD size = ::GetFileVersionInfoSizeW(fileName.c_str(), &handle); if (size == 0) { throw windows_error("failed to determine file version info size"); } void *buffer = new char[size]; try { - if (!::GetFileVersionInfoW(fileName.c_str(), 0UL, size, buffer)) { + if (!::GetFileVersionInfoW(fileName.c_str(), handle, size, buffer)) { throw windows_error("failed to determine file version info"); } -- cgit v1.3.1