From 2aae65d6f6c1ab3309e54437a339d1644088c5c8 Mon Sep 17 00:00:00 2001 From: Tannin Date: Sun, 10 Jan 2016 20:19:56 +0100 Subject: made instance-switching usable this includes tons and tons of changes to how paths are determined. the profiles-dir can now also be configured --- src/settingsdialog.ui | 242 ++++++++++++++++++++++++++++++-------------------- 1 file changed, 144 insertions(+), 98 deletions(-) (limited to 'src/settingsdialog.ui') diff --git a/src/settingsdialog.ui b/src/settingsdialog.ui index b88885dc..805a5060 100644 --- a/src/settingsdialog.ui +++ b/src/settingsdialog.ui @@ -108,114 +108,60 @@ p, li { white-space: pre-wrap; } - + - Advanced - - - true - - - false + User interface - - - + + + - Directory where downloads are stored. + If checked, the download interface will be more compact. - - Directory where downloads are stored. + + Compact Download Interface - - - - - 0 - 0 - + + + + If checked, the download list will display meta information instead of file names. - ... + Download Meta Information - - - - Mod Directory + + + + + 16777215 + 16777215 + - - - - - Directory where mods are stored. + Reset stored information from dialogs. - Directory where mods are stored. Please note that changing this will break all associations of profiles with mods that don't exist in the new location (with the same name). - - - - - - - ... - - - - - - - Download Directory - - - - - - - Cache Directory + This will make all dialogs show up again where you checked the "Remember selection"-box. - - - - - - - - ... + Reset Dialogs - - - - - - - User interface - - - + - If checked, the download interface will be more compact. + Modify the categories available to arrange your mods. - - Compact Download Interface - - - - - - - If checked, the download list will display meta information instead of file names. + + Modify the categories available to arrange your mods. - Download Meta Information + Configure Mod Categories @@ -223,26 +169,132 @@ p, li { white-space: pre-wrap; } - - + + + Qt::Vertical + + - 16777215 - 16777215 + 20 + 40 + + + + - Reset stored information from dialogs. + Restart MO and choose a different set of data paths. - This will make all dialogs show up again where you checked the "Remember selection"-box. + This will restart MO and give you opportunity to switch to a different set of data paths. - Reset Dialogs + Change Instance + + + + + Paths + + - + + + + + Downloads + + + + + + + Caches + + + + + + + ... + + + + + + + + + + Directory where downloads are stored. + + + Directory where downloads are stored. + + + + + + + Mods + + + + + + + ... + + + + + + + Directory where mods are stored. + + + Directory where mods are stored. Please note that changing this will break all associations of profiles with mods that don't exist in the new location (with the same name). + + + + + + + + 0 + 0 + + + + ... + + + + + + + Profiles + + + + + + + + + + ... + + + + + + + Qt::Vertical @@ -255,15 +307,9 @@ p, li { white-space: pre-wrap; } - - - Modify the categories available to arrange your mods. - - - Modify the categories available to arrange your mods. - + - Configure Mod Categories + Important: All directories have to be writeable! -- cgit v1.3.1 From fd68248698357591f99c3091d5b15a3084fc078d Mon Sep 17 00:00:00 2001 From: Tannin Date: Tue, 9 Feb 2016 20:57:20 +0100 Subject: fixed browse-button for mod directory (in settings) --- src/settingsdialog.cpp | 10 +++++++++- src/settingsdialog.h | 3 +++ src/settingsdialog.ui | 2 +- src/spawn.cpp | 2 +- 4 files changed, 14 insertions(+), 3 deletions(-) (limited to 'src/settingsdialog.ui') diff --git a/src/settingsdialog.cpp b/src/settingsdialog.cpp index 341fa19d..5b58c9da 100644 --- a/src/settingsdialog.cpp +++ b/src/settingsdialog.cpp @@ -110,7 +110,7 @@ void SettingsDialog::on_browseDownloadDirBtn_clicked() void SettingsDialog::on_browseModDirBtn_clicked() { - QString temp = QFileDialog::getExistingDirectory(this, tr("Select mod directory"), ui->downloadDirEdit->text()); + QString temp = QFileDialog::getExistingDirectory(this, tr("Select mod directory"), ui->modDirEdit->text()); if (!temp.isEmpty()) { ui->modDirEdit->setText(temp); } @@ -124,6 +124,14 @@ void SettingsDialog::on_browseCacheDirBtn_clicked() } } +void SettingsDialog::on_browseProfilesDirBtn_clicked() +{ + QString temp = QFileDialog::getExistingDirectory(this, tr("Select profiles directory"), ui->profilesDirEdit->text()); + if (!temp.isEmpty()) { + ui->profilesDirEdit->setText(temp); + } +} + void SettingsDialog::on_resetDialogsButton_clicked() { if (QMessageBox::question(this, tr("Confirm?"), diff --git a/src/settingsdialog.h b/src/settingsdialog.h index 8bd080ab..d1a566b1 100644 --- a/src/settingsdialog.h +++ b/src/settingsdialog.h @@ -52,6 +52,9 @@ signals: void resetDialogs(); +private slots: + void on_browseProfilesDirBtn_clicked(); + private slots: void on_changeInstanceButton_clicked(); diff --git a/src/settingsdialog.ui b/src/settingsdialog.ui index 805a5060..f54ab895 100644 --- a/src/settingsdialog.ui +++ b/src/settingsdialog.ui @@ -660,7 +660,7 @@ p, li { white-space: pre-wrap; } false - 100 + 170 diff --git a/src/spawn.cpp b/src/spawn.cpp index fc0b448a..0ff64af0 100644 --- a/src/spawn.cpp +++ b/src/spawn.cpp @@ -60,7 +60,7 @@ static bool spawn(LPCWSTR binary, LPCWSTR arguments, LPCWSTR currentDirectory, si.dwFlags |= STARTF_USESTDHANDLES; } si.cb = sizeof(si); - int length = wcslen(binary) + wcslen(arguments) + 4; + size_t length = wcslen(binary) + wcslen(arguments) + 4; wchar_t *commandLine = nullptr; if (arguments[0] != L'\0') { commandLine = new wchar_t[length]; -- cgit v1.3.1 From 9df612c7ca0ba4cb0b62d958df4e2745fe0c04ec Mon Sep 17 00:00:00 2001 From: Tannin Date: Wed, 2 Mar 2016 21:28:17 +0100 Subject: more configuration options - overwrite path configurable - one can now set a base directory for all configurable paths - user can now opt in/out of receiving pre-release updates (not functional yet) --- src/settings.cpp | 129 ++++++++++++++++++++++++++++++++++++++++-------- src/settings.h | 27 ++++++++-- src/settingsdialog.cpp | 17 +++++++ src/settingsdialog.h | 6 +++ src/settingsdialog.ui | 131 +++++++++++++++++++++++++++++++++++++++---------- 5 files changed, 257 insertions(+), 53 deletions(-) (limited to 'src/settingsdialog.ui') diff --git a/src/settings.cpp b/src/settings.cpp index c99b434d..41d176ea 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -33,6 +33,7 @@ along with Mod Organizer. If not, see . #include #include #include +#include #include @@ -179,6 +180,11 @@ QString Settings::getSteamAppID() const return m_Settings.value("Settings/app_id", m_GamePlugin->steamAPPId()).toString(); } +bool Settings::usePrereleases() const +{ + return m_Settings.value("Settings/use_prereleases", false).toBool(); +} + void Settings::setDownloadSpeed(const QString &serverName, int bytesPerSecond) { m_Settings.beginGroup("Servers"); @@ -213,34 +219,55 @@ std::map Settings::getPreferredServers() return result; } -QString Settings::getConfigurablePath(const QString &key, const QString &def) const +QString Settings::getConfigurablePath(const QString &key, + const QString &def, + bool resolve) const +{ + QString result = QDir::fromNativeSeparators( + m_Settings.value(QString("settings/") + key, + qApp->property("dataPath").toString() + "/" + def) + .toString()); + if (resolve) { + result.replace("%BASE_DIR%", getBaseDirectory()); + } + return result; +} + +QString Settings::getBaseDirectory() const { - return QDir::fromNativeSeparators(m_Settings.value(QString("settings/") + key, qApp->property("dataPath").toString() + "/" + def).toString()); + return QDir::fromNativeSeparators(m_Settings.value( + "settings/base_directory", qApp->property("dataPath").toString()).toString()); } -QString Settings::getDownloadDirectory() const +QString Settings::getDownloadDirectory(bool resolve) const { - return getConfigurablePath("download_directory", ToQString(AppConfig::downloadPath())); + return getConfigurablePath("download_directory", ToQString(AppConfig::downloadPath()), resolve); } -QString Settings::getCacheDirectory() const +QString Settings::getCacheDirectory(bool resolve) const { - return getConfigurablePath("cache_directory", ToQString(AppConfig::cachePath())); + return getConfigurablePath("cache_directory", ToQString(AppConfig::cachePath()), resolve); } -QString Settings::getModDirectory() const +QString Settings::getModDirectory(bool resolve) const { - return getConfigurablePath("mod_directory", ToQString(AppConfig::modsPath())); + return getConfigurablePath("mod_directory", ToQString(AppConfig::modsPath()), resolve); } -QString Settings::getProfileDirectory() const +QString Settings::getProfileDirectory(bool resolve) const { - return getConfigurablePath("profiles_directory", ToQString(AppConfig::profilesPath())); + return getConfigurablePath("profiles_directory", ToQString(AppConfig::profilesPath()), resolve); +} + +QString Settings::getOverwriteDirectory(bool resolve) const +{ + return getConfigurablePath("overwrite_directory", + ToQString(AppConfig::overwritePath()), resolve); } QString Settings::getNMMVersion() const { - static const QString MIN_NMM_VERSION = "0.52.3"; + static const QString MIN_NMM_VERSION = "0.61.13"; QString result = m_Settings.value("Settings/nmm_version", MIN_NMM_VERSION).toString(); if (VersionInfo(result) < VersionInfo(MIN_NMM_VERSION)) { result = MIN_NMM_VERSION; @@ -508,12 +535,7 @@ void Settings::addLanguages(QComboBox *languageBox) 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()) { @@ -575,6 +597,7 @@ Settings::GeneralTab::GeneralTab(Settings *m_parent, SettingsDialog &m_dialog) , m_logLevelBox(m_dialog.findChild("logLevelBox")) , m_compactBox(m_dialog.findChild("compactBox")) , m_showMetaBox(m_dialog.findChild("showMetaBox")) + , m_usePrereleaseBox(m_dialog.findChild("usePrereleaseBox")) { // FIXME I think 'addLanguages' lives in here not in parent m_parent->addLanguages(m_languageBox); @@ -606,6 +629,7 @@ Settings::GeneralTab::GeneralTab(Settings *m_parent, SettingsDialog &m_dialog) m_logLevelBox->setCurrentIndex(m_parent->logLevel()); m_compactBox->setChecked(m_parent->compactDownloads()); m_showMetaBox->setChecked(m_parent->metaDownloads()); + m_usePrereleaseBox->setChecked(m_parent->usePrereleases()); } void Settings::GeneralTab::update() @@ -629,23 +653,53 @@ void Settings::GeneralTab::update() m_Settings.setValue("Settings/compact_downloads", m_compactBox->isChecked()); m_Settings.setValue("Settings/meta_downloads", m_showMetaBox->isChecked()); + m_Settings.setValue("Settings/use_prereleases", m_usePrereleaseBox->isChecked()); } Settings::PathsTab::PathsTab(Settings *parent, SettingsDialog &dialog) : SettingsTab(parent, dialog) + , m_baseDirEdit(m_dialog.findChild("baseDirEdit")) , m_downloadDirEdit(m_dialog.findChild("downloadDirEdit")) , m_modDirEdit(m_dialog.findChild("modDirEdit")) , m_cacheDirEdit(m_dialog.findChild("cacheDirEdit")) , m_profilesDirEdit(m_dialog.findChild("profilesDirEdit")) -{ - m_downloadDirEdit->setText(m_parent->getDownloadDirectory()); - m_modDirEdit->setText(m_parent->getModDirectory()); - m_cacheDirEdit->setText(m_parent->getCacheDirectory()); - m_profilesDirEdit->setText(m_parent->getProfileDirectory()); + , m_overwriteDirEdit(m_dialog.findChild("overwriteDirEdit")) +{ + m_baseDirEdit->setText(m_parent->getBaseDirectory()); + /* + m_downloadDirEdit->setText(m_parent->getDownloadDirectory(false)); + m_modDirEdit->setText(m_parent->getModDirectory(false)); + m_cacheDirEdit->setText(m_parent->getCacheDirectory(false)); + m_profilesDirEdit->setText(m_parent->getProfileDirectory(false)); + m_overwriteDirEdit->setText(m_parent->getOverwriteDirectory(false)); + */ + + QString basePath = parent->getBaseDirectory(); + QDir baseDir(basePath); + for (const auto &dir : { + std::make_pair(m_downloadDirEdit, m_parent->getDownloadDirectory(false)), + std::make_pair(m_modDirEdit, m_parent->getModDirectory(false)), + std::make_pair(m_cacheDirEdit, m_parent->getCacheDirectory(false)), + std::make_pair(m_profilesDirEdit, m_parent->getProfileDirectory(false)), + std::make_pair(m_overwriteDirEdit, m_parent->getOverwriteDirectory(false)) + }) { + QString storePath = baseDir.relativeFilePath(dir.second); + qDebug("%s -> %s", qPrintable(dir.second), qPrintable(storePath)); + if (storePath.startsWith("..") || QDir::isAbsolutePath(storePath)) { + storePath = dir.second; + } else { + storePath = QString("%BASE_DIR%/") + storePath; + } + dir.first->setText(storePath); + } } void Settings::PathsTab::update() { + typedef std::tuple Directory; + + QString basePath = m_parent->getBaseDirectory(); + if ((QDir::fromNativeSeparators(m_modDirEdit->text()) != QDir::fromNativeSeparators(m_parent->getModDirectory())) && (QMessageBox::question( @@ -660,6 +714,38 @@ void Settings::PathsTab::update() m_modDirEdit->setText(m_parent->getModDirectory()); } + for (const Directory &dir :{ + Directory{m_downloadDirEdit->text(), "download_directory", AppConfig::downloadPath()}, + Directory{m_cacheDirEdit->text(), "cache_directory", AppConfig::cachePath()}, + Directory{m_modDirEdit->text(), "mod_directory", AppConfig::modsPath()}, + Directory{m_overwriteDirEdit->text(), "overwrite_directory", AppConfig::overwritePath()}, + Directory{m_profilesDirEdit->text(), "profiles_directory", AppConfig::profilesPath()} + }) { + QString path, settingsKey; + std::wstring defaultName; + std::tie(path, settingsKey, defaultName) = dir; + + settingsKey = QString("Settings/%1").arg(settingsKey); + + QString realPath = path; + realPath.replace("%BASE_DIR%", m_parent->getBaseDirectory()); + + if (!QDir(realPath).exists()) { + QDir().mkpath(realPath); + } + + qDebug("%s -> %s", qPrintable(path), qPrintable(realPath)); + + if (QFileInfo(realPath) + != QFileInfo(basePath + "/" + QString::fromStdWString(defaultName))) { + m_Settings.setValue(settingsKey, path); + } else { + m_Settings.remove(settingsKey); + } + } + + +/* if (!QDir(m_downloadDirEdit->text()).exists()) { QDir().mkpath(m_downloadDirEdit->text()); } @@ -707,6 +793,7 @@ void Settings::PathsTab::update() } else { m_Settings.remove("Settings/profiles_directory"); } + */ } Settings::NexusTab::NexusTab(Settings *parent, SettingsDialog &dialog) diff --git a/src/settings.h b/src/settings.h index 85a3dac0..9676df70 100644 --- a/src/settings.h +++ b/src/settings.h @@ -105,10 +105,16 @@ public: **/ QString getSteamAppID() const; + /** + * retrieves the base directory under which the other directories usually + * reside + */ + QString getBaseDirectory() const; + /** * retrieve the directory where downloads are stored (with native separators) **/ - QString getDownloadDirectory() const; + QString getDownloadDirectory(bool resolve = true) const; /** * retrieve a sorted list of preferred servers @@ -118,7 +124,7 @@ public: /** * retrieve the directory where mods are stored (with native separators) **/ - QString getModDirectory() const; + QString getModDirectory(bool resolve = true) const; /** * returns the version of nmm to impersonate when connecting to nexus @@ -128,12 +134,18 @@ public: /** * retrieve the directory where the web cache is stored (with native separators) **/ - QString getCacheDirectory() const; + QString getCacheDirectory(bool resolve = true) const; /** * retrieve the directory where profiles stored (with native separators) **/ - QString getProfileDirectory() const; + QString getProfileDirectory(bool resolve = true) const; + + /** + * retrieve the directory were new files are stored that can't be assigned + * to a mod (with native separators) + */ + QString getOverwriteDirectory(bool resolve = true) const; /** * @return true if the user has set up automatic login to nexus @@ -295,6 +307,8 @@ public: */ std::vector plugins() const { return m_Plugins; } + bool usePrereleases() const; + /** * @brief register MO as the handler for nxm links * @param force set to true to enforce the registration dialog to show up, @@ -315,7 +329,7 @@ private: void addStyles(QComboBox *styleBox); void readPluginBlacklist(); void writePluginBlacklist(); - QString getConfigurablePath(const QString &key, const QString &def) const; + QString getConfigurablePath(const QString &key, const QString &def, bool resolve) const; class SettingsTab { @@ -346,6 +360,7 @@ private: QComboBox *m_logLevelBox; QCheckBox *m_compactBox; QCheckBox *m_showMetaBox; + QCheckBox *m_usePrereleaseBox; }; class PathsTab : public SettingsTab @@ -356,10 +371,12 @@ private: void update(); private: + QLineEdit *m_baseDirEdit; QLineEdit *m_downloadDirEdit; QLineEdit *m_modDirEdit; QLineEdit *m_cacheDirEdit; QLineEdit *m_profilesDirEdit; + QLineEdit *m_overwriteDirEdit; }; /** Display/store the configuration in the 'nexus' tab of the settings dialogue */ diff --git a/src/settingsdialog.cpp b/src/settingsdialog.cpp index 5b58c9da..d354b29b 100644 --- a/src/settingsdialog.cpp +++ b/src/settingsdialog.cpp @@ -100,6 +100,15 @@ void SettingsDialog::on_bsaDateBtn_clicked() dir.absolutePath().toStdWString()); } +void SettingsDialog::on_browseBaseDirBtn_clicked() +{ + QString temp = QFileDialog::getExistingDirectory( + this, tr("Select base directory"), ui->baseDirEdit->text()); + if (!temp.isEmpty()) { + ui->baseDirEdit->setText(temp); + } +} + void SettingsDialog::on_browseDownloadDirBtn_clicked() { QString temp = QFileDialog::getExistingDirectory(this, tr("Select download directory"), ui->downloadDirEdit->text()); @@ -132,6 +141,14 @@ void SettingsDialog::on_browseProfilesDirBtn_clicked() } } +void SettingsDialog::on_browseOverwriteDirBtn_clicked() +{ + QString temp = QFileDialog::getExistingDirectory(this, tr("Select overwrite directory"), ui->overwriteDirEdit->text()); + if (!temp.isEmpty()) { + ui->overwriteDirEdit->setText(temp); + } +} + void SettingsDialog::on_resetDialogsButton_clicked() { if (QMessageBox::question(this, tr("Confirm?"), diff --git a/src/settingsdialog.h b/src/settingsdialog.h index d1a566b1..d266488d 100644 --- a/src/settingsdialog.h +++ b/src/settingsdialog.h @@ -52,6 +52,12 @@ signals: void resetDialogs(); +private slots: + void on_browseBaseDirBtn_clicked(); + +private slots: + void on_browseOverwriteDirBtn_clicked(); + private slots: void on_browseProfilesDirBtn_clicked(); diff --git a/src/settingsdialog.ui b/src/settingsdialog.ui index f54ab895..808d8296 100644 --- a/src/settingsdialog.ui +++ b/src/settingsdialog.ui @@ -107,6 +107,36 @@ p, li { white-space: pre-wrap; } + + + + Update to non-stable releases. + + + If this is enabled, the integrated update mechanism will notify of all releases, including pre-releases (alphas, betas). + +Please use this only if you're sufficiently tech-savvy to investigate issues, look for known problems in the issue tracker and create meaningful reports. + +If you use pre-releases, never contact me directly by e-mail or via private messages! + + + Install Pre-releases (Betas) + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + @@ -204,54 +234,71 @@ p, li { white-space: pre-wrap; } - + - Downloads + Base Directory - + + + + ... + + + + + + + + + + + + + ... + + + + + + + Overwrite + + + + Caches - + ... - + - - - - Directory where downloads are stored. - - - Directory where downloads are stored. - - - - - + + - Mods + Downloads - + ... - + Directory where mods are stored. @@ -261,7 +308,7 @@ p, li { white-space: pre-wrap; } - + @@ -274,23 +321,53 @@ p, li { white-space: pre-wrap; } + + + + Directory where downloads are stored. + + + Directory where downloads are stored. + + + - + - Profiles + Mods - - - - + ... + + + + + + + Profiles + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + -- cgit v1.3.1 From 30878ae39460e14fe0a8ba0c06b3db6d16e73715 Mon Sep 17 00:00:00 2001 From: Tannin Date: Thu, 19 May 2016 19:17:15 +0200 Subject: added button to clear webcaches and cookies --- src/nexusinterface.cpp | 7 +++++++ src/nexusinterface.h | 5 +++++ src/nxmaccessmanager.cpp | 9 +++++++++ src/nxmaccessmanager.h | 2 ++ src/persistentcookiejar.cpp | 6 ++++++ src/persistentcookiejar.h | 6 ++++++ src/settingsdialog.cpp | 7 +++++++ src/settingsdialog.h | 3 +++ src/settingsdialog.ui | 31 +++++++++++++++++++++++++++++++ 9 files changed, 76 insertions(+) (limited to 'src/settingsdialog.ui') diff --git a/src/nexusinterface.cpp b/src/nexusinterface.cpp index f5baa6ab..2c690aa4 100644 --- a/src/nexusinterface.cpp +++ b/src/nexusinterface.cpp @@ -27,6 +27,7 @@ along with Mod Organizer. If not, see . #include #include +#include #include @@ -409,6 +410,12 @@ void NexusInterface::cleanup() m_DiskCache = nullptr; } +void NexusInterface::clearCache() +{ + m_DiskCache->clear(); + m_AccessManager->clearCookies(); +} + void NexusInterface::nextRequest() { if ((m_ActiveRequest.size() >= MAX_ACTIVE_DOWNLOADS) diff --git a/src/nexusinterface.h b/src/nexusinterface.h index c9a81134..9e7f3642 100644 --- a/src/nexusinterface.h +++ b/src/nexusinterface.h @@ -142,6 +142,11 @@ public: */ void cleanup(); + /** + * @brief clear webcache and cookies associated with this access manager + */ + void clearCache(); + /** * @brief request description for a mod * diff --git a/src/nxmaccessmanager.cpp b/src/nxmaccessmanager.cpp index a7dd6eef..a0b9c01f 100644 --- a/src/nxmaccessmanager.cpp +++ b/src/nxmaccessmanager.cpp @@ -110,6 +110,15 @@ void NXMAccessManager::showCookies() const } } +void NXMAccessManager::clearCookies() +{ + PersistentCookieJar *jar = qobject_cast(cookieJar()); + if (jar != nullptr) { + jar->clear(); + } else { + qWarning("failed to clear cookies, invalid cookie jar"); + } +} void NXMAccessManager::startLoginCheck() { diff --git a/src/nxmaccessmanager.h b/src/nxmaccessmanager.h index 82bd2bd5..c58c4cc3 100644 --- a/src/nxmaccessmanager.h +++ b/src/nxmaccessmanager.h @@ -52,6 +52,8 @@ public: void showCookies() const; + void clearCookies(); + QString userAgent(const QString &subModule = QString()) const; void startLoginCheck(); diff --git a/src/persistentcookiejar.cpp b/src/persistentcookiejar.cpp index 44537491..a6eb78fa 100644 --- a/src/persistentcookiejar.cpp +++ b/src/persistentcookiejar.cpp @@ -15,6 +15,12 @@ PersistentCookieJar::~PersistentCookieJar() { save(); } +void PersistentCookieJar::clear() { + for (const QNetworkCookie &cookie : allCookies()) { + deleteCookie(cookie); + } +} + void PersistentCookieJar::save() { QTemporaryFile file; if (!file.open()) { diff --git a/src/persistentcookiejar.h b/src/persistentcookiejar.h index 812b785c..0ff747ee 100644 --- a/src/persistentcookiejar.h +++ b/src/persistentcookiejar.h @@ -5,9 +5,15 @@ class PersistentCookieJar : public QNetworkCookieJar { + + Q_OBJECT + public: PersistentCookieJar(const QString &fileName, QObject *parent = 0); virtual ~PersistentCookieJar(); + + void clear(); + private: void save(); diff --git a/src/settingsdialog.cpp b/src/settingsdialog.cpp index e528f478..c66cc243 100644 --- a/src/settingsdialog.cpp +++ b/src/settingsdialog.cpp @@ -26,6 +26,7 @@ along with Mod Organizer. If not, see . #include "iplugingame.h" #include "settings.h" #include "instancemanager.h" +#include "nexusinterface.h" #include #include @@ -227,3 +228,9 @@ void SettingsDialog::on_changeInstanceButton_clicked() qApp->exit(INT_MAX); } } + +void SettingsDialog::on_clearCacheButton_clicked() +{ + QDir(Settings::instance().getCacheDirectory()).removeRecursively(); + NexusInterface::instance()->clearCache(); +} diff --git a/src/settingsdialog.h b/src/settingsdialog.h index d266488d..1ae21015 100644 --- a/src/settingsdialog.h +++ b/src/settingsdialog.h @@ -52,6 +52,9 @@ signals: void resetDialogs(); +private slots: + void on_clearCacheButton_clicked(); + private slots: void on_browseBaseDirBtn_clicked(); diff --git a/src/settingsdialog.ui b/src/settingsdialog.ui index 808d8296..2a4b5589 100644 --- a/src/settingsdialog.ui +++ b/src/settingsdialog.ui @@ -461,6 +461,37 @@ p, li { white-space: pre-wrap; } + + + + + + Remove cache and cookies. Forces a new login. + + + Clear Cache + + + + :/MO/gui/edit_clear:/MO/gui/edit_clear + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + -- cgit v1.3.1 From c3b7737ae46ad4770532e3380c9ceb6ed4d14cf7 Mon Sep 17 00:00:00 2001 From: Tannin Date: Thu, 19 May 2016 19:18:46 +0200 Subject: bugfix: incorrect url-encoding for passwords prevented login with some special characters --- src/nxmaccessmanager.cpp | 4 ++-- src/settingsdialog.ui | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) (limited to 'src/settingsdialog.ui') diff --git a/src/nxmaccessmanager.cpp b/src/nxmaccessmanager.cpp index a0b9c01f..3f90647b 100644 --- a/src/nxmaccessmanager.cpp +++ b/src/nxmaccessmanager.cpp @@ -247,8 +247,8 @@ void NXMAccessManager::pageLogin() QByteArray postDataQuery; QUrlQuery postData; postData.addQueryItem("username", m_Username); - postData.addQueryItem("password", m_Password); - postDataQuery = postData.query(QUrl::FullyEncoded).toUtf8(); + postData.addQueryItem("password", QUrl::toPercentEncoding(m_Password)); + postDataQuery = postData.query(QUrl::EncodeReserved).toUtf8(); request.setRawHeader("User-Agent", userAgent().toUtf8()); diff --git a/src/settingsdialog.ui b/src/settingsdialog.ui index 2a4b5589..9ebed3b8 100644 --- a/src/settingsdialog.ui +++ b/src/settingsdialog.ui @@ -1052,7 +1052,9 @@ For the other games this is not a sufficient replacement for AI! - + + + buttonBox -- cgit v1.3.1 From bfbb19099839019c785dc81c83b07dadbd394168 Mon Sep 17 00:00:00 2001 From: Tannin Date: Fri, 27 May 2016 14:04:00 +0200 Subject: moved button to switch instance (and to portable mode) to the main window --- src/instancemanager.cpp | 100 +++++++++++++++++++++++----------------------- src/instancemanager.h | 15 +++---- src/main.cpp | 4 +- src/mainwindow.cpp | 12 ++++++ src/mainwindow.h | 3 ++ src/mainwindow.ui | 13 ++++++ src/nxmaccessmanager.cpp | 2 - src/resources.qrc | 3 +- src/resources/mo_icon.png | Bin 0 -> 1011 bytes src/resources/package.png | Bin 0 -> 1067 bytes src/settingsdialog.cpp | 12 ------ src/settingsdialog.h | 23 ++++------- src/settingsdialog.ui | 52 ++++++------------------ 13 files changed, 109 insertions(+), 130 deletions(-) create mode 100644 src/resources/mo_icon.png create mode 100644 src/resources/package.png (limited to 'src/settingsdialog.ui') diff --git a/src/instancemanager.cpp b/src/instancemanager.cpp index c74f3c1a..f7b953ad 100644 --- a/src/instancemanager.cpp +++ b/src/instancemanager.cpp @@ -27,6 +27,7 @@ along with Mod Organizer. If not, see . #include #include #include +#include static const char COMPANY_NAME[] = "Tannin"; @@ -40,6 +41,11 @@ InstanceManager::InstanceManager() { } +InstanceManager &InstanceManager::instance() +{ + static InstanceManager s_Instance; + return s_Instance; +} QString InstanceManager::currentInstance() const { @@ -49,6 +55,7 @@ QString InstanceManager::currentInstance() const void InstanceManager::clearCurrentInstance() { setCurrentInstance(""); + m_Reset = true; } void InstanceManager::setCurrentInstance(const QString &name) @@ -81,26 +88,51 @@ QString InstanceManager::queryInstanceName() const QString InstanceManager::chooseInstance(const QStringList &instanceList) const { - SelectionDialog selection(QObject::tr("Choose Instance"), nullptr); + enum class Special : uint8_t { + NewInstance, + Portable + }; + + SelectionDialog selection( + QString("

%1


%2") + .arg(QObject::tr("Choose Instance")) + .arg(QObject::tr( + "Each Instance is a full set of MO data files (mods, " + "downloads, profiles, configuration, ...). Use multiple " + "instances for different games. If your MO folder is " + "writable, you can also store a single instance locally (called " + "a portable install).")), + nullptr); selection.disableCancel(); for (const QString &instance : instanceList) { selection.addChoice(instance, "", instance); } - selection.addChoice(QObject::tr("New"), + selection.addChoice(QIcon(":/MO/gui/add"), QObject::tr("New"), QObject::tr("Create a new instance."), - ""); + static_cast(Special::NewInstance)); + + if (QFileInfo(qApp->applicationDirPath()).isWritable()) { + selection.addChoice(QIcon(":/MO/gui/package"), QObject::tr("Portable"), + QObject::tr("Use MO folder for data."), + static_cast(Special::Portable)); + } + if (selection.exec() == QDialog::Rejected) { qDebug("rejected"); throw MOBase::MyException(QObject::tr("Canceled")); } - QString choice = selection.getChoiceData().toString(); + QVariant choice = selection.getChoiceData(); - if (choice.isEmpty()) { - return queryInstanceName(); + if (choice.type() == QVariant::String) { + return choice.toString(); } else { - return choice; + switch (choice.value()) { + case Special::NewInstance: return queryInstanceName(); + case Special::Portable: return QString(); + default: throw std::runtime_error("invalid selection"); + } } } @@ -125,27 +157,6 @@ bool InstanceManager::portableInstall() const } -InstanceManager::InstallationMode InstanceManager::queryInstallMode() const -{ - SelectionDialog selection(QObject::tr("Installation Mode"), nullptr); - selection.disableCancel(); - selection.addChoice(QObject::tr("Portable"), - QObject::tr("Everything in one directory, only one game per installation."), - 0); - selection.addChoice(QObject::tr("Regular"), - QObject::tr("Data in separate directory, multiple games supported."), - 1); - if (selection.exec() == QDialog::Rejected) { - throw MOBase::MyException(QObject::tr("Canceled")); - } - - switch (selection.getChoiceData().toInt()) { - case 0: return InstallationMode::PORTABLE; - default: return InstallationMode::REGULAR; - } -} - - void InstanceManager::createDataPath(const QString &dataPath) const { if (!QDir(dataPath).exists()) { @@ -166,31 +177,22 @@ void InstanceManager::createDataPath(const QString &dataPath) const QString InstanceManager::determineDataPath() { QString instanceId = currentInstance(); + if (instanceId.isEmpty() && portableInstall() && !m_Reset) { + // startup, apparently using portable mode before + return qApp->applicationDirPath(); + } + QString dataPath = QDir::fromNativeSeparators( QStandardPaths::writableLocation(QStandardPaths::DataLocation) + "/" + instanceId); - if ((instanceId.isEmpty() || !QFileInfo::exists(dataPath)) && !portableInstall()) { - // no portable install and no selected instance - - QStringList instanceList = instances(); - - if (instanceList.size() == 0) { - if (QFileInfo(qApp->applicationDirPath()).isWritable()) { - switch (queryInstallMode()) { - case InstallationMode::PORTABLE: { - instanceId = QString(); - } break; - case InstallationMode::REGULAR: { - instanceId = queryInstanceName(); - } break; - } - } else { - instanceId = queryInstanceName(); - } - } else { - // don't offer portable instance if we can't set one up. - instanceId = chooseInstance(instanceList); + + if (instanceId.isEmpty() || !QFileInfo::exists(dataPath)) { + instanceId = chooseInstance(instances()); + if (!instanceId.isEmpty()) { + dataPath = QDir::fromNativeSeparators( + QStandardPaths::writableLocation(QStandardPaths::DataLocation) + + "/" + instanceId); } } diff --git a/src/instancemanager.h b/src/instancemanager.h index 2e17d1c0..a0a5df09 100644 --- a/src/instancemanager.h +++ b/src/instancemanager.h @@ -27,25 +27,21 @@ along with Mod Organizer. If not, see . class InstanceManager { - enum class InstallationMode { - PORTABLE, - REGULAR - }; - public: - InstanceManager(); + static InstanceManager &instance(); QString determineDataPath(); - QStringList instances() const; void clearCurrentInstance(); private: + InstanceManager(); + QString currentInstance() const; QString instancePath() const; - bool portableInstall() const; + QStringList instances() const; void setCurrentInstance(const QString &name); @@ -53,10 +49,11 @@ private: QString chooseInstance(const QStringList &instanceList) const; void createDataPath(const QString &dataPath) const; - InstallationMode queryInstallMode() const; + bool portableInstall() const; private: QSettings m_AppSettings; + bool m_Reset {false}; }; diff --git a/src/main.cpp b/src/main.cpp index 6940e288..e289453c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -630,13 +630,12 @@ int main(int argc, char *argv[]) QString dataPath; try { - dataPath = InstanceManager().determineDataPath(); + dataPath = InstanceManager::instance().determineDataPath(); } catch (const std::exception &e) { QMessageBox::critical(nullptr, QObject::tr("Failed to set up instance"), e.what()); return 1; } - application.setProperty("dataPath", dataPath); LogBuffer::init(100, QtDebugMsg, qApp->property("dataPath").toString() + "/logs/mo_interface.log"); @@ -647,7 +646,6 @@ int main(int argc, char *argv[]) } int result = runApplication(application, instance, splash); - if (result != INT_MAX) { return result; } diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index dcff139a..66c2b557 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -37,6 +37,7 @@ along with Mod Organizer. If not, see . #include "savegameinfo.h" #include "spawn.h" #include "versioninfo.h" +#include "instancemanager.h" #include "report.h" #include "modlist.h" @@ -3883,6 +3884,17 @@ void MainWindow::on_actionProblems_triggered() } } +void MainWindow::on_actionChange_Game_triggered() +{ + if (QMessageBox::question(this, tr("Are you sure?"), + tr("This will restart MO, continue?"), + QMessageBox::Yes | QMessageBox::Cancel) + == QMessageBox::Yes) { + InstanceManager::instance().clearCurrentInstance(); + qApp->exit(INT_MAX); + } +} + void MainWindow::setCategoryListVisible(bool visible) { if (visible) { diff --git a/src/mainwindow.h b/src/mainwindow.h index 43b2bede..3364bb37 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -183,6 +183,9 @@ protected: virtual void dragEnterEvent(QDragEnterEvent *event); virtual void dropEvent(QDropEvent *event); +private slots: + void on_actionChange_Game_triggered(); + private slots: void on_clickBlankButton_clicked(); diff --git a/src/mainwindow.ui b/src/mainwindow.ui index f504994a..e30a165d 100644 --- a/src/mainwindow.ui +++ b/src/mainwindow.ui @@ -1197,6 +1197,7 @@ p, li { white-space: pre-wrap; } false + @@ -1383,6 +1384,18 @@ Right now this has very limited functionality Ctrl+C + + + + :/MO/gui/app_icon:/MO/gui/app_icon + + + Change Game + + + Open the game selection dialog + + diff --git a/src/nxmaccessmanager.cpp b/src/nxmaccessmanager.cpp index 3f90647b..17c50e35 100644 --- a/src/nxmaccessmanager.cpp +++ b/src/nxmaccessmanager.cpp @@ -215,7 +215,6 @@ void NXMAccessManager::login(const QString &username, const QString &password) emit loginSuccessful(false); return; } - m_Username = username; m_Password = password; pageLogin(); @@ -237,7 +236,6 @@ QString NXMAccessManager::userAgent(const QString &subModule) const void NXMAccessManager::pageLogin() { qDebug("logging %s in on Nexus", qPrintable(m_Username)); - QString requestString = (Nexus_Management_URL + "/Sessions/?Login&uri=%1") .arg(QString(QUrl::toPercentEncoding(Nexus_Management_URL))); diff --git a/src/resources.qrc b/src/resources.qrc index 8434b367..d357801c 100644 --- a/src/resources.qrc +++ b/src/resources.qrc @@ -26,7 +26,6 @@ resources/software-update-available.png resources/emblem-important.png resources/check.png - mo_icon.ico resources/dialog-warning.png resources/symbol-backup.png resources/applications-accessories.png @@ -68,6 +67,8 @@ resources/status_active.png resources/status_awaiting.png resources/status_inactive.png + resources/mo_icon.png + resources/package.png resources/contents/jigsaw-piece.png diff --git a/src/resources/mo_icon.png b/src/resources/mo_icon.png new file mode 100644 index 00000000..c926d722 Binary files /dev/null and b/src/resources/mo_icon.png differ diff --git a/src/resources/package.png b/src/resources/package.png new file mode 100644 index 00000000..4b55b504 Binary files /dev/null and b/src/resources/package.png differ diff --git a/src/settingsdialog.cpp b/src/settingsdialog.cpp index c66cc243..0d86018c 100644 --- a/src/settingsdialog.cpp +++ b/src/settingsdialog.cpp @@ -217,18 +217,6 @@ void SettingsDialog::on_associateButton_clicked() Settings::instance().registerAsNXMHandler(true); } -void SettingsDialog::on_changeInstanceButton_clicked() -{ - if (QMessageBox::question(this, tr("Are you sure?"), - tr("This will restart MO, continue?"), - QMessageBox::Yes | QMessageBox::Cancel) - == QMessageBox::Yes) { - InstanceManager().clearCurrentInstance(); - this->reject(); - qApp->exit(INT_MAX); - } -} - void SettingsDialog::on_clearCacheButton_clicked() { QDir(Settings::instance().getCacheDirectory()).removeRecursively(); diff --git a/src/settingsdialog.h b/src/settingsdialog.h index 1ae21015..658fbce4 100644 --- a/src/settingsdialog.h +++ b/src/settingsdialog.h @@ -52,21 +52,6 @@ signals: void resetDialogs(); -private slots: - void on_clearCacheButton_clicked(); - -private slots: - void on_browseBaseDirBtn_clicked(); - -private slots: - void on_browseOverwriteDirBtn_clicked(); - -private slots: - void on_browseProfilesDirBtn_clicked(); - -private slots: - void on_changeInstanceButton_clicked(); - private: void storeSettings(QListWidgetItem *pluginItem); @@ -92,6 +77,14 @@ private slots: void on_associateButton_clicked(); + void on_clearCacheButton_clicked(); + + void on_browseBaseDirBtn_clicked(); + + void on_browseOverwriteDirBtn_clicked(); + + void on_browseProfilesDirBtn_clicked(); + private: Ui::SettingsDialog *ui; }; diff --git a/src/settingsdialog.ui b/src/settingsdialog.ui index 9ebed3b8..1f751da8 100644 --- a/src/settingsdialog.ui +++ b/src/settingsdialog.ui @@ -124,19 +124,6 @@ If you use pre-releases, never contact me directly by e-mail or via private mess - - - - Qt::Vertical - - - - 20 - 40 - - - - @@ -182,6 +169,19 @@ If you use pre-releases, never contact me directly by e-mail or via private mess + + + + Qt::Vertical + + + + 20 + 40 + + + + @@ -198,32 +198,6 @@ If you use pre-releases, never contact me directly by e-mail or via private mess - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - Restart MO and choose a different set of data paths. - - - This will restart MO and give you opportunity to switch to a different set of data paths. - - - Change Instance - - - -- cgit v1.3.1 From bbab59f68112278bb23ff3bdc69737515b916667 Mon Sep 17 00:00:00 2001 From: Tannin Date: Fri, 27 May 2016 15:51:01 +0200 Subject: fixed handling of base dir in settings dialog (and fixed the tab order in the settings dialog) --- src/settings.cpp | 33 +++++++++------------------------ src/settingsdialog.cpp | 43 ++++++++++++++++++++++++++++++++++++++----- src/settingsdialog.h | 3 +++ src/settingsdialog.ui | 44 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 94 insertions(+), 29 deletions(-) (limited to 'src/settingsdialog.ui') diff --git a/src/settings.cpp b/src/settings.cpp index a0625c4c..d9fa833d 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -224,8 +224,7 @@ QString Settings::getConfigurablePath(const QString &key, bool resolve) const { QString result = QDir::fromNativeSeparators( - m_Settings.value(QString("settings/") + key, - qApp->property("dataPath").toString() + "/" + def) + m_Settings.value(QString("settings/") + key, QString("%BASE_DIR%/") + def) .toString()); if (resolve) { result.replace("%BASE_DIR%", getBaseDirectory()); @@ -677,12 +676,7 @@ Settings::PathsTab::PathsTab(Settings *parent, SettingsDialog &dialog) std::make_pair(m_overwriteDirEdit, m_parent->getOverwriteDirectory(false)) }) { QString storePath = baseDir.relativeFilePath(dir.second); - qDebug("%s -> %s", qPrintable(dir.second), qPrintable(storePath)); - if (storePath.startsWith("..") || QDir::isAbsolutePath(storePath)) { - storePath = dir.second; - } else { - storePath = QString("%BASE_DIR%/") + storePath; - } + storePath = dir.second; dir.first->setText(storePath); } } @@ -693,20 +687,6 @@ void Settings::PathsTab::update() QString basePath = m_parent->getBaseDirectory(); - if ((QDir::fromNativeSeparators(m_modDirEdit->text()) - != QDir::fromNativeSeparators(m_parent->getModDirectory())) - && (QMessageBox::question( - nullptr, 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)) { - m_modDirEdit->setText(m_parent->getModDirectory()); - } - for (const Directory &dir :{ Directory{m_downloadDirEdit->text(), "download_directory", AppConfig::downloadPath()}, Directory{m_cacheDirEdit->text(), "cache_directory", AppConfig::cachePath()}, @@ -727,8 +707,6 @@ void Settings::PathsTab::update() QDir().mkpath(realPath); } - qDebug("%s -> %s", qPrintable(path), qPrintable(realPath)); - if (QFileInfo(realPath) != QFileInfo(basePath + "/" + QString::fromStdWString(defaultName))) { m_Settings.setValue(settingsKey, path); @@ -736,6 +714,13 @@ void Settings::PathsTab::update() m_Settings.remove(settingsKey); } } + + if (QFileInfo(m_baseDirEdit->text()) != + QFileInfo(qApp->property("dataPath").toString())) { + m_Settings.setValue("Settings/base_directory", m_baseDirEdit->text()); + } else { + m_Settings.remove("Settings/base_directory"); + } } Settings::NexusTab::NexusTab(Settings *parent, SettingsDialog &dialog) diff --git a/src/settingsdialog.cpp b/src/settingsdialog.cpp index 0d86018c..62134c9b 100644 --- a/src/settingsdialog.cpp +++ b/src/settingsdialog.cpp @@ -65,6 +65,23 @@ void SettingsDialog::addPlugins(const std::vector &plugins) void SettingsDialog::accept() { + QString newModPath = ui->modDirEdit->text(); + newModPath.replace("%BASE_DIR%", ui->baseDirEdit->text()); + + if ((QDir::fromNativeSeparators(newModPath) != + QDir::fromNativeSeparators( + Settings::instance().getModDirectory(true))) && + (QMessageBox::question( + nullptr, 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)) { + return; + } + storeSettings(ui->pluginsList->currentItem()); TutorableDialog::accept(); } @@ -112,7 +129,10 @@ void SettingsDialog::on_browseBaseDirBtn_clicked() void SettingsDialog::on_browseDownloadDirBtn_clicked() { - QString temp = QFileDialog::getExistingDirectory(this, tr("Select download directory"), ui->downloadDirEdit->text()); + QString searchPath = ui->downloadDirEdit->text(); + searchPath.replace("%BASE_DIR%", ui->baseDirEdit->text()); + + QString temp = QFileDialog::getExistingDirectory(this, tr("Select download directory"), searchPath); if (!temp.isEmpty()) { ui->downloadDirEdit->setText(temp); } @@ -120,7 +140,10 @@ void SettingsDialog::on_browseDownloadDirBtn_clicked() void SettingsDialog::on_browseModDirBtn_clicked() { - QString temp = QFileDialog::getExistingDirectory(this, tr("Select mod directory"), ui->modDirEdit->text()); + QString searchPath = ui->modDirEdit->text(); + searchPath.replace("%BASE_DIR%", ui->baseDirEdit->text()); + + QString temp = QFileDialog::getExistingDirectory(this, tr("Select mod directory"), searchPath); if (!temp.isEmpty()) { ui->modDirEdit->setText(temp); } @@ -128,7 +151,10 @@ void SettingsDialog::on_browseModDirBtn_clicked() void SettingsDialog::on_browseCacheDirBtn_clicked() { - QString temp = QFileDialog::getExistingDirectory(this, tr("Select cache directory"), ui->cacheDirEdit->text()); + QString searchPath = ui->cacheDirEdit->text(); + searchPath.replace("%BASE_DIR%", ui->baseDirEdit->text()); + + QString temp = QFileDialog::getExistingDirectory(this, tr("Select cache directory"), searchPath); if (!temp.isEmpty()) { ui->cacheDirEdit->setText(temp); } @@ -136,7 +162,10 @@ void SettingsDialog::on_browseCacheDirBtn_clicked() void SettingsDialog::on_browseProfilesDirBtn_clicked() { - QString temp = QFileDialog::getExistingDirectory(this, tr("Select profiles directory"), ui->profilesDirEdit->text()); + QString searchPath = ui->profilesDirEdit->text(); + searchPath.replace("%BASE_DIR%", ui->baseDirEdit->text()); + + QString temp = QFileDialog::getExistingDirectory(this, tr("Select profiles directory"), searchPath); if (!temp.isEmpty()) { ui->profilesDirEdit->setText(temp); } @@ -144,7 +173,10 @@ void SettingsDialog::on_browseProfilesDirBtn_clicked() void SettingsDialog::on_browseOverwriteDirBtn_clicked() { - QString temp = QFileDialog::getExistingDirectory(this, tr("Select overwrite directory"), ui->overwriteDirEdit->text()); + QString searchPath = ui->overwriteDirEdit->text(); + searchPath.replace("%BASE_DIR%", ui->baseDirEdit->text()); + + QString temp = QFileDialog::getExistingDirectory(this, tr("Select overwrite directory"), searchPath); if (!temp.isEmpty()) { ui->overwriteDirEdit->setText(temp); } @@ -222,3 +254,4 @@ void SettingsDialog::on_clearCacheButton_clicked() QDir(Settings::instance().getCacheDirectory()).removeRecursively(); NexusInterface::instance()->clearCache(); } + diff --git a/src/settingsdialog.h b/src/settingsdialog.h index 658fbce4..e9d995d3 100644 --- a/src/settingsdialog.h +++ b/src/settingsdialog.h @@ -87,6 +87,9 @@ private slots: private: Ui::SettingsDialog *ui; + }; + + #endif // WORKAROUNDDIALOG_H diff --git a/src/settingsdialog.ui b/src/settingsdialog.ui index 1f751da8..6ae415d1 100644 --- a/src/settingsdialog.ui +++ b/src/settingsdialog.ui @@ -1026,6 +1026,50 @@ For the other games this is not a sufficient replacement for AI! + + languageBox + styleBox + logLevelBox + usePrereleaseBox + compactBox + showMetaBox + resetDialogsButton + categoriesBtn + baseDirEdit + browseBaseDirBtn + downloadDirEdit + browseDownloadDirBtn + modDirEdit + browseModDirBtn + cacheDirEdit + browseCacheDirBtn + profilesDirEdit + browseProfilesDirBtn + overwriteDirEdit + browseOverwriteDirBtn + loginCheckBox + usernameEdit + passwordEdit + clearCacheButton + offlineBox + proxyBox + associateButton + knownServersList + preferredServersList + steamUserEdit + steamPassEdit + pluginsList + pluginSettingsList + pluginBlacklist + appIDEdit + mechanismBox + nmmVersionEdit + hideUncheckedBox + forceEnableBox + displayForeignBox + bsaDateBtn + tabWidget + -- cgit v1.3.1 From 3d642563cbdb33784165e4f7d29dbaa66b455492 Mon Sep 17 00:00:00 2001 From: Tannin Date: Sun, 19 Jun 2016 15:59:50 +0200 Subject: usvfs log level can now be changed without a restart --- src/mainwindow.cpp | 2 ++ src/organizercore.cpp | 5 +++++ src/organizercore.h | 2 ++ src/settingsdialog.ui | 5 +++++ src/usvfsconnector.cpp | 16 ++++++++++++++-- src/usvfsconnector.h | 2 +- 6 files changed, 29 insertions(+), 3 deletions(-) (limited to 'src/settingsdialog.ui') diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 0668f012..c90448c2 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -3222,6 +3222,8 @@ void MainWindow::on_actionSettings_triggered() NexusInterface::instance()->setNMMVersion(m_OrganizerCore.settings().getNMMVersion()); updateDownloadListDelegate(); + + m_OrganizerCore.setLogLevel(m_OrganizerCore.settings().logLevel()); } diff --git a/src/organizercore.cpp b/src/organizercore.cpp index 1bec27bc..6ceefb4b 100644 --- a/src/organizercore.cpp +++ b/src/organizercore.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include "appconfig.h" #include #include @@ -599,6 +600,10 @@ void OrganizerCore::prepareVFS() m_USVFS.updateMapping(fileMapping(m_CurrentProfile->name(), QString())); } +void OrganizerCore::setLogLevel(int logLevel) { + m_USVFS.setLogLevel(logLevel); +} + void OrganizerCore::setCurrentProfile(const QString &profileName) { if ((m_CurrentProfile != nullptr) diff --git a/src/organizercore.h b/src/organizercore.h index cd7af1b8..ecb02d83 100644 --- a/src/organizercore.h +++ b/src/organizercore.h @@ -141,6 +141,8 @@ public: void prepareVFS(); + void setLogLevel(int logLevel); + public: MOBase::IModRepositoryBridge *createNexusBridge() const; QString profileName() const; diff --git a/src/settingsdialog.ui b/src/settingsdialog.ui index 6ae415d1..082be8a1 100644 --- a/src/settingsdialog.ui +++ b/src/settingsdialog.ui @@ -98,6 +98,11 @@ p, li { white-space: pre-wrap; } Info + + + Warning + + Error diff --git a/src/usvfsconnector.cpp b/src/usvfsconnector.cpp index d8818a9a..0fe3567c 100644 --- a/src/usvfsconnector.cpp +++ b/src/usvfsconnector.cpp @@ -22,6 +22,7 @@ along with Mod Organizer. If not, see . #include #include #include +#include #include #include #include @@ -103,10 +104,11 @@ LogLevel logLevel(int level) UsvfsConnector::UsvfsConnector() { USVFSParameters params; - USVFSInitParameters(¶ms, SHMID, false, - logLevel(Settings::instance().logLevel())); + LogLevel level = logLevel(Settings::instance().logLevel()); + USVFSInitParameters(¶ms, SHMID, false, level); InitLogging(false); ConnectVFS(¶ms); + SetLogLevel(level); BlacklistExecutable(L"TSVNCache.exe"); @@ -162,3 +164,13 @@ void UsvfsConnector::updateMapping(const MappingType &mapping) qDebug(buffer.get()); */ } + +void UsvfsConnector::setLogLevel(int logLevel) { + switch (logLevel) { + case LogLevel::Debug: SetLogLevel(LogLevel::Debug); break; + case LogLevel::Info: SetLogLevel(LogLevel::Info); break; + case LogLevel::Warning: SetLogLevel(LogLevel::Warning); break; + case LogLevel::Error: SetLogLevel(LogLevel::Error); break; + default: SetLogLevel(LogLevel::Debug); break; + } +} diff --git a/src/usvfsconnector.h b/src/usvfsconnector.h index 78bb7a49..8f723a01 100644 --- a/src/usvfsconnector.h +++ b/src/usvfsconnector.h @@ -22,7 +22,6 @@ along with Mod Organizer. If not, see . #define USVFSCONNECTOR_H -#include #include #include #include @@ -68,6 +67,7 @@ public: ~UsvfsConnector(); void updateMapping(const MappingType &mapping); + void setLogLevel(int logLevel); private: -- cgit v1.3.1 From 8a3af93b39b05b95462869fc7df7169c5862c966 Mon Sep 17 00:00:00 2001 From: Tannin Date: Thu, 23 Jun 2016 21:00:46 +0200 Subject: fixed creation of data paths after changing paths in settings and update of profile list after change --- src/main.cpp | 49 ++++++---------- src/mainwindow.cpp | 1 + src/modinfooverwrite.cpp | 3 +- src/organizer_en.ts | 149 ++++++++++++++++++++++++----------------------- src/organizercore.cpp | 35 ++++++++++- src/organizercore.h | 4 ++ src/pluginlist.cpp | 10 ++-- src/settings.cpp | 10 +++- src/settingsdialog.ui | 7 +++ 9 files changed, 154 insertions(+), 114 deletions(-) (limited to 'src/settingsdialog.ui') diff --git a/src/main.cpp b/src/main.cpp index 6b585b5c..16b6b80f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -85,38 +85,21 @@ along with Mod Organizer. If not, see . using namespace MOBase; using namespace MOShared; - -bool createAndMakeWritable(const std::wstring &subPath) -{ +bool createAndMakeWritable(const std::wstring &subPath) { QString const dataPath = qApp->property("dataPath").toString(); QString fullPath = dataPath + "/" + QString::fromStdWString(subPath); - if (!QDir(fullPath).exists()) { - QDir().mkdir(fullPath); - } - - QFileInfo fileInfo(fullPath); - if (!fileInfo.exists() || !fileInfo.isWritable()) { - if (QMessageBox::question(nullptr, QObject::tr("Permissions required"), - QObject::tr("The current user account doesn't have the required access rights to run " - "Mod Organizer. The neccessary changes can be made automatically (the MO directory " - "will be made writable for the current user account). You will be asked to run " - "\"helper.exe\" with administrative rights."), - QMessageBox::Yes | QMessageBox::Cancel) == QMessageBox::Yes) { - if (!Helper::init(qApp->applicationDirPath().toStdWString(), - dataPath.toStdWString())) { - return false; - } - } else { - return false; - } - // no matter which directory didn't exist/wasn't writable, the helper - // should have created them all so we don't have to worry this message box would appear repeatedly + if (!QDir(fullPath).exists() && !QDir().mkdir(fullPath)) { + QMessageBox::critical(nullptr, QObject::tr("Error"), + QObject::tr("Failed to create \"%1\". Your user " + "account probably lacks permission.") + .arg(fullPath)); + return false; + } else { + return true; } - return true; } - bool bootstrap() { // remove the temporary backup directory in case we're restarting after an update @@ -129,11 +112,9 @@ bool bootstrap() removeOldFiles(qApp->property("dataPath").toString() + "/" + QString::fromStdWString(AppConfig::logPath()), "usvfs*.log", 5, QDir::Name); - createAndMakeWritable(AppConfig::profilesPath()); - createAndMakeWritable(AppConfig::modsPath()); - createAndMakeWritable(AppConfig::downloadPath()); - createAndMakeWritable(AppConfig::overwritePath()); - createAndMakeWritable(AppConfig::logPath()); + if (!createAndMakeWritable(AppConfig::logPath())) { + return false; + } return true; } @@ -445,7 +426,7 @@ int runApplication(MOApplication &application, SingleInstance &instance, qDebug("data path: %s", qPrintable(dataPath)); if (!bootstrap()) { - reportError("failed to set up data path"); + reportError("failed to set up data paths"); return 1; } @@ -465,6 +446,10 @@ int runApplication(MOApplication &application, SingleInstance &instance, QSettings::IniFormat); qDebug("initializing core"); OrganizerCore organizer(settings); + if (!organizer.bootstrap()) { + reportError("failed to set up data paths"); + return 1; + } qDebug("initialize plugins"); PluginContainer pluginContainer(&organizer); pluginContainer.loadPlugins(); diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index c90448c2..b7687d2a 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -3197,6 +3197,7 @@ void MainWindow::on_actionSettings_triggered() m_OrganizerCore.installationManager()->setDownloadDirectory(m_OrganizerCore.settings().getDownloadDirectory()); fixCategories(); refreshFilters(); + refreshProfiles(); if (QDir::fromNativeSeparators(m_OrganizerCore.downloadManager()->getOutputDirectory()) != QDir::fromNativeSeparators(m_OrganizerCore.settings().getDownloadDirectory())) { if (m_OrganizerCore.downloadManager()->downloadsInProgress()) { MessageDialog::showMessage(tr("Can't change download directory while downloads are in progress!"), this); diff --git a/src/modinfooverwrite.cpp b/src/modinfooverwrite.cpp index 4380a255..0104998a 100644 --- a/src/modinfooverwrite.cpp +++ b/src/modinfooverwrite.cpp @@ -1,6 +1,7 @@ #include "modinfooverwrite.h" #include "appconfig.h" +#include "settings.h" #include #include @@ -21,7 +22,7 @@ bool ModInfoOverwrite::isEmpty() const QString ModInfoOverwrite::absolutePath() const { - return QDir::fromNativeSeparators(qApp->property("dataPath").toString() + "/" + QString::fromStdWString(AppConfig::overwritePath())); + return Settings::instance().getOverwriteDirectory(); } std::vector ModInfoOverwrite::getFlags() const diff --git a/src/organizer_en.ts b/src/organizer_en.ts index 7920c98b..686e15db 100644 --- a/src/organizer_en.ts +++ b/src/organizer_en.ts @@ -2629,62 +2629,62 @@ This function will guess the versioning scheme under the assumption that the ins ModInfo - + Plugins - + Textures - + Meshes - + BSA - + UI Changes - + Sound Effects - + Scripts - + SKSE Plugins - + SkyProc Tools - + invalid content type %1 - + invalid mod index %1 - + remove: invalid mod index %1 @@ -3225,7 +3225,7 @@ p, li { white-space: pre-wrap; } ModInfoOverwrite - + This pseudo mod contains files from the virtual data tree that got modified (i.e. by the construction kit) @@ -4630,17 +4630,17 @@ p, li { white-space: pre-wrap; } - + failed to spawn "%1" - + Elevation required - + This process requires elevation to run. This is a potential security risk so I highly advice you to investigate if "%1" @@ -4650,7 +4650,7 @@ Start elevated anyway? (you will be asked if you want to allow ModOrganizer.exe - + failed to spawn "%1": %2 @@ -5037,23 +5037,28 @@ If you use pre-releases, never contact me directly by e-mail or via private mess - + + Use %BASE_DIR% to refer to the Base Directory. + + + + Important: All directories have to be writeable! - - + + Nexus - + Allows automatic log-in when the Nexus-Page for the game is clicked. - + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } @@ -5062,144 +5067,144 @@ p, li { white-space: pre-wrap; } - + If checked and if correct credentials are entered below, log-in to Nexus (for browsing and downloading) is automatic. - + Automatically Log-In to Nexus - - + + Username - - + + Password - + Remove cache and cookies. Forces a new login. - + Clear Cache - + Disable automatic internet features - + Disable automatic internet features. This does not affect features that are explicitly invoked by the user (like checking mods for updates, endorsing, opening the web browser) - + Offline Mode - + Use a proxy for network connections. - + Use a proxy for network connections. This uses the system-wide settings which can be configured in Internet Explorer. Please note that MO will start up a few seconds slower on some systems when using a proxy. - + Use HTTP Proxy (Uses System Settings) - + Associate with "Download with manager" links - + Known Servers (updated on download) - + Preferred Servers (Drag & Drop) - + Steam - + If you save your steam user ID and password here, they will be used when logging into steam. Note, however, your password will be stored unencrypted, so make sure your computer is secure. - + Plugins - + Author: - + Version: - + Description: - + Key - + Value - + Blacklisted Plugins (use <del> to remove): - + Workarounds - + Steam App ID - + The Steam AppID for your game - + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } @@ -5215,17 +5220,17 @@ p, li { white-space: pre-wrap; } - + Load Mechanism - + Select loading mechanism. See help for details. - + Mod Organizer needs a dll to be injected into the game so all mods are visible to it. There are several means to do this: *Mod Organizer* (default) In this mode the Mod Organizer itself injects the dll. The disadvantage is that you always have to start the game through MO or a link created by it. @@ -5236,17 +5241,17 @@ If you use the Steam version of Oblivion the default will NOT work. In this case - + NMM Version - + The Version of Nexus Mod Manager to impersonate. - + Mod Organizer uses an API provided by the Nexus to provide features like checking for updates and downloading files. Unfortunately this API has not been made available officially to third party tools like MO so we have to impersonate the Nexus Mod Manager to be allowed in. On top of this Nexus has used the client identification to lock out outdated versions of NMM to force users to update. This means that MO also needs to impersonate the new version of NMM even if MO doesn't need an update. Therefore you can configure the version to identify as here. Please note that MO does identify itself as MO to the webserver, it's not lying about what it is. It is merely adding a "compatible" NMM version to the user agent. @@ -5255,44 +5260,44 @@ tl;dr-version: If Nexus-features don't work, insert the current version num - + Enforces that inactive ESPs and ESMs are never loaded. - + It seems that the Games occasionally load ESP or ESM files even if they haven't been activated as plugins. I don't yet know what the circumstances are, but user reports imply it is in some cases unwanted. If this is checked, ESPs and ESMs not checked in the List are invisible to the game and can not be loaded. - + Hide inactive ESPs/ESMs - + If checked, files (i.e. esps, esms and bsas) belonging to the core game can not be disabled in the UI. (default: on) - + If checked, files (i.e. esps, esms and bsas) belonging to the core game can not be disabled in the UI. (default: on) Uncheck this if you want to use Mod Organizer with total conversions (like Nehrim) but be aware that the game will crash if required files are not enabled. - + Force-enable game files - + Disable this to no longer display mods installed outside MO in the mod list (left pane). Assets from those mods will then be treated as having lowest mod priority together with the original game content. - + By default Mod Organizer will display esp+bsa bundles installed with foreign tools as mods (left pane). This allows you to control their priority in relation to other mods. This is particularly useful if you also use Steam Workshop to install mods. However, if you installed loose file mods outside MO which conflict with BSAs also installed outside MO those conflicts can't be resolved correctly. @@ -5300,24 +5305,24 @@ If you disable this feature, MO will only display official DLCs this way. Please - + Display mods installed outside MO - - + + For Skyrim, this can be used instead of Archive Invalidation. It should make AI redundant for all Profiles. For the other games this is not a sufficient replacement for AI! - + Back-date BSAs - + These are workarounds for problems with Mod Organizer. Please make sure you read the help text before changing anything here. @@ -5558,7 +5563,7 @@ On Windows XP: UsvfsConnector - + Preparing vfs diff --git a/src/organizercore.cpp b/src/organizercore.cpp index 6ceefb4b..b5e5118d 100644 --- a/src/organizercore.cpp +++ b/src/organizercore.cpp @@ -586,6 +586,25 @@ InstallationManager *OrganizerCore::installationManager() return &m_InstallationManager; } +bool OrganizerCore::createDirectory(const QString &path) { + if (!QDir(path).exists() && !QDir().mkpath(path)) { + QMessageBox::critical(nullptr, QObject::tr("Error"), + QObject::tr("Failed to create \"%1\". Your user " + "account probably lacks permission.") + .arg(QDir::toNativeSeparators(path))); + return false; + } else { + return true; + } +} + +bool OrganizerCore::bootstrap() { + return createDirectory(m_Settings.getProfileDirectory()) && + createDirectory(m_Settings.getModDirectory()) && + createDirectory(m_Settings.getDownloadDirectory()) && + createDirectory(m_Settings.getOverwriteDirectory()); +} + void OrganizerCore::createDefaultProfile() { QString profilesPath = settings().getProfileDirectory(); @@ -610,7 +629,19 @@ void OrganizerCore::setCurrentProfile(const QString &profileName) && (profileName == m_CurrentProfile->name())) { return; } - QString profileDir = settings().getProfileDirectory() + "/" + profileName; + + QDir profileBaseDir(settings().getProfileDirectory()); + QString profileDir = profileBaseDir.absoluteFilePath(profileName); + + if (!QDir(profileDir).exists()) { + // selected profile doesn't exist. Ensure there is at least one profile, + // then pick any one + createDefaultProfile(); + + profileDir = profileBaseDir.absoluteFilePath( + profileBaseDir.entryList(QDir::AllDirs | QDir::NoDotAndDotDot).at(0)); + } + Profile *newProfile = new Profile(QDir(profileDir), managedGame()); delete m_CurrentProfile; @@ -1870,7 +1901,7 @@ std::vector OrganizerCore::fileMapping(const QString &profileName, result.insert(result.end(), { QDir::toNativeSeparators(m_Settings.getOverwriteDirectory()), - QDir::toNativeSeparators(game->dataDirectory().absolutePath()), + dataPath, true, customOverwrite.isEmpty() }); diff --git a/src/organizercore.h b/src/organizercore.h index ecb02d83..6c882dc9 100644 --- a/src/organizercore.h +++ b/src/organizercore.h @@ -135,6 +135,8 @@ public: void loginSuccessfulUpdate(bool necessary); void loginFailedUpdate(const QString &message); + static bool createAndMakeWritable(const QString &path); + bool bootstrap(); void createDefaultProfile(); MOBase::DelayedFileWriter &pluginsWriter() { return m_PluginListsWriter; } @@ -228,6 +230,8 @@ private: bool testForSteam(); + bool createDirectory(const QString &path); + /** * @brief return a descriptor of the mappings real file->virtual file */ diff --git a/src/pluginlist.cpp b/src/pluginlist.cpp index bc6a908e..44e08023 100644 --- a/src/pluginlist.cpp +++ b/src/pluginlist.cpp @@ -237,8 +237,8 @@ void PluginList::enableAll() { if (QMessageBox::question(nullptr, tr("Confirm"), tr("Really enable all plugins?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) { - for (std::vector::iterator iter = m_ESPs.begin(); iter != m_ESPs.end(); ++iter) { - iter->m_Enabled = true; + for (ESPInfo &info : m_ESPs) { + info.m_Enabled = true; } emit writePluginsList(); } @@ -249,9 +249,9 @@ void PluginList::disableAll() { if (QMessageBox::question(nullptr, tr("Confirm"), tr("Really disable all plugins?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) { - for (std::vector::iterator iter = m_ESPs.begin(); iter != m_ESPs.end(); ++iter) { - if (!iter->m_ForceEnabled) { - iter->m_Enabled = false; + for (ESPInfo &info : m_ESPs) { + if (!info.m_ForceEnabled) { + info.m_Enabled = false; } } emit writePluginsList(); diff --git a/src/settings.cpp b/src/settings.cpp index 193c6a35..b86e2289 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -32,6 +32,7 @@ along with Mod Organizer. If not, see . #include #include #include +#include #include #include @@ -701,10 +702,15 @@ void Settings::PathsTab::update() settingsKey = QString("Settings/%1").arg(settingsKey); QString realPath = path; - realPath.replace("%BASE_DIR%", m_parent->getBaseDirectory()); + realPath.replace("%BASE_DIR%", m_baseDirEdit->text()); if (!QDir(realPath).exists()) { - QDir().mkpath(realPath); + if (!QDir().mkpath(realPath)) { + QMessageBox::warning(qApp->activeWindow(), tr("Error"), + tr("Failed to create \"%1\", you may not have the " + "necessary permission. path remains unchanged.") + .arg(realPath)); + } } if (QFileInfo(realPath) diff --git a/src/settingsdialog.ui b/src/settingsdialog.ui index 082be8a1..a38530da 100644 --- a/src/settingsdialog.ui +++ b/src/settingsdialog.ui @@ -349,6 +349,13 @@ If you use pre-releases, never contact me directly by e-mail or via private mess + + + + Use %BASE_DIR% to refer to the Base Directory. + + + -- cgit v1.3.1 From a611c355ce732961c2a9ba1a8909f0c144afa860 Mon Sep 17 00:00:00 2001 From: Jeremy Rimpo Date: Fri, 20 Oct 2017 20:27:06 -0500 Subject: Basic ESL updates --- src/activatemodsdialog.ui | 4 +- src/mainwindow.ui | 2 +- src/modinfodialog.cpp | 3 +- src/modinfodialog.ui | 4 +- src/modinforegular.cpp | 4 +- src/modlist.cpp | 4 +- src/organizer_en.ts | 691 +++++++++++----------- src/organizer_en_US.ts | 14 +- src/organizercore.cpp | 18 +- src/pluginlist.cpp | 2 +- src/settingsdialog.ui | 2 +- src/tutorials/tutorial_conflictresolution_main.js | 2 +- src/tutorials/tutorial_primer_main.js | 2 +- 13 files changed, 384 insertions(+), 368 deletions(-) (limited to 'src/settingsdialog.ui') diff --git a/src/activatemodsdialog.ui b/src/activatemodsdialog.ui index f6124bbc..cd8b0eec 100644 --- a/src/activatemodsdialog.ui +++ b/src/activatemodsdialog.ui @@ -17,14 +17,14 @@ - This is a list of esps and esms that were active when the save game was created. + This is a list of esps, esms, and esls that were active when the save game was created. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">This is a list of esps and esms that were active when the save game was created.</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">This is a list of esps, esms, and esls that were active when the save game was created.</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">For each esp, the right column contains the mod (or mods) that can be enabled to make the missing esps/esms available.</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">If you hit Ok, all the mods selected in the right columns and all missing esps that have become available will be activated.</span></p></body></html> diff --git a/src/mainwindow.ui b/src/mainwindow.ui index 4b5467ed..743ce012 100644 --- a/src/mainwindow.ui +++ b/src/mainwindow.ui @@ -846,7 +846,7 @@ p, li { white-space: pre-wrap; } <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">This list contains the esps and esms contained in the active mods. These require their own load order. Use drag&amp;drop to modify this load order. Please note that MO will only save the load order for mods that are active/checked.<br />There is a great tool named &quot;BOSS&quot; to automatically sort these files.</span></p></body></html> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">This list contains the esps, esms, and esls contained in the active mods. These require their own load order. Use drag&amp;drop to modify this load order. Please note that MO will only save the load order for mods that are active/checked.<br />There is a great tool named &quot;BOSS&quot; to automatically sort these files.</span></p></body></html> true diff --git a/src/modinfodialog.cpp b/src/modinfodialog.cpp index 0e77859a..c96c2b4a 100644 --- a/src/modinfodialog.cpp +++ b/src/modinfodialog.cpp @@ -314,7 +314,8 @@ void ModInfoDialog::refreshLists() ui->iniFileList->addItem(namePart); } } else if (fileName.endsWith(".esp", Qt::CaseInsensitive) || - fileName.endsWith(".esm", Qt::CaseInsensitive)) { + fileName.endsWith(".esm", Qt::CaseInsensitive) || + fileName.endsWith(".esl", Qt::CaseInsensitive)) { QString relativePath = fileName.mid(m_RootPath.length() + 1); if (relativePath.contains('/')) { QFileInfo fileInfo(fileName); diff --git a/src/modinfodialog.ui b/src/modinfodialog.ui index a452bc59..25822fd0 100644 --- a/src/modinfodialog.ui +++ b/src/modinfodialog.ui @@ -279,10 +279,10 @@ - List of esps and esms that can not be loaded by the game. + List of esps, esms, and esls that can not be loaded by the game. - List of esps and esms contained in this plugin that currently can not be loaded by the game. They will not even appear in the esp-list in the main MO-window. + List of esps, esms, and esls contained in this plugin that currently can not be loaded by the game. They will not even appear in the esp-list in the main MO-window. They usually contain optional functionality, see the readme. Most mods do not have optional esps, so chances are good you are looking at an empty list. diff --git a/src/modinforegular.cpp b/src/modinforegular.cpp index 231e5497..bacc21f7 100644 --- a/src/modinforegular.cpp +++ b/src/modinforegular.cpp @@ -430,7 +430,7 @@ std::vector ModInfoRegular::getContents() const if (m_LastContentCheck.isNull() || (m_LastContentCheck.secsTo(now) > 60)) { m_CachedContent.clear(); QDir dir(absolutePath()); - if (dir.entryList(QStringList() << "*.esp" << "*.esm").size() > 0) { + if (dir.entryList(QStringList() << "*.esp" << "*.esm" << "*.esl").size() > 0) { m_CachedContent.push_back(CONTENT_PLUGIN); } if (dir.entryList(QStringList() << "*.bsa" << "*.ba2").size() > 0) { @@ -476,7 +476,7 @@ int ModInfoRegular::getHighlight() const QString ModInfoRegular::getDescription() const { if (!isValid()) { - return tr("%1 contains no esp/esm and no asset (textures, meshes, interface, ...) directory").arg(name()); + return tr("%1 contains no esp/esm/esl and no asset (textures, meshes, interface, ...) directory").arg(name()); } else { const std::set &categories = getCategories(); std::wostringstream categoryString; diff --git a/src/modlist.cpp b/src/modlist.cpp index fca98aac..0aea7a98 100644 --- a/src/modlist.cpp +++ b/src/modlist.cpp @@ -60,7 +60,7 @@ ModList::ModList(QObject *parent) , m_FontMetrics(QFont()) , m_DropOnItems(false) { - m_ContentIcons[ModInfo::CONTENT_PLUGIN] = std::make_tuple(":/MO/gui/content/plugin", tr("Game plugins (esp/esm)")); + m_ContentIcons[ModInfo::CONTENT_PLUGIN] = std::make_tuple(":/MO/gui/content/plugin", tr("Game plugins (esp/esm/esl)")); m_ContentIcons[ModInfo::CONTENT_INTERFACE] = std::make_tuple(":/MO/gui/content/interface", tr("Interface")); m_ContentIcons[ModInfo::CONTENT_MESH] = std::make_tuple(":/MO/gui/content/mesh", tr("Meshes")); m_ContentIcons[ModInfo::CONTENT_BSA] = std::make_tuple(":/MO/gui/content/bsa", tr("BSA")); @@ -1026,7 +1026,7 @@ QString ModList::getColumnToolTip(int column) case COL_FLAGS: return tr("Emblemes to highlight things that might require attention."); case COL_CONTENT: return tr("Depicts the content of the mod:
" "" - "" + "" "" "" "" diff --git a/src/organizer_en.ts b/src/organizer_en.ts index da3a3c6e..f73717f2 100644 --- a/src/organizer_en.ts +++ b/src/organizer_en.ts @@ -64,7 +64,7 @@ - This is a list of esps and esms that were active when the save game was created. + This is a list of esps, esms, and esls that were active when the save game was created. @@ -73,7 +73,7 @@ <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">This is a list of esps and esms that were active when the save game was created.</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">This is a list of esps, esms, and esls that were active when the save game was created.</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">For each esp, the right column contains the mod (or mods) that can be enabled to make the missing esps/esms available.</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">If you hit Ok, all the mods selected in the right columns and all missing esps that have become available will be activated.</span></p></body></html> @@ -1325,13 +1325,13 @@ p, li { white-space: pre-wrap; } - + Restore Backup... - + Create Backup @@ -1362,8 +1362,8 @@ p, li { white-space: pre-wrap; } - - + + Namefilter @@ -1431,74 +1431,74 @@ p, li { white-space: pre-wrap; } - + List of available esp/esm files - + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">This list contains the esps and esms contained in the active mods. These require their own load order. Use drag&amp;drop to modify this load order. Please note that MO will only save the load order for mods that are active/checked.<br />There is a great tool named &quot;BOSS&quot; to automatically sort these files.</span></p></body></html> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">This list contains the esps, esms, and esls contained in the active mods. These require their own load order. Use drag&amp;drop to modify this load order. Please note that MO will only save the load order for mods that are active/checked.<br />There is a great tool named &quot;BOSS&quot; to automatically sort these files.</span></p></body></html> - + Data - + refresh data-directory overview - + Refresh the overview. This may take a moment. - - - + + + Refresh - + This is an overview of your data directory as visible to the game (and tools). - + File - + Mod - + Filter the above list so that only conflicts are displayed. - + Show only conflicts - + Saves - + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } @@ -1509,155 +1509,155 @@ p, li { white-space: pre-wrap; } - + Downloads - + This is a list of mods you downloaded from Nexus. Double click one to install it. You can also drag an archive into here. - + Show Hidden - + Tool Bar - + Install Mod - + Install &Mod - + Install a new mod from an archive - + Ctrl+M - + Profiles - + &Profiles - + Configure Profiles - + Ctrl+P - + Executables - + &Executables - + Configure the executables that can be started through Mod Organizer - + Ctrl+E - - + + Tools - + &Tools - + Ctrl+I - + Settings - + &Settings - + Configure settings and workarounds - + Ctrl+S - + Nexus - + Search nexus network for more mods - + Ctrl+N - - + + Update - + Mod Organizer is up-to-date - + No Problems - + This button will be highlighted if MO discovered potential problems in your setup and provide tips on how to fix them. !Work in progress! @@ -1665,44 +1665,44 @@ Right now this has very limited functionality - + Help - + Ctrl+H - + Endorse MO - - + + Endorse Mod Organizer - + Copy Log to Clipboard - + Ctrl+C - + Change Game - + Open the game selection dialog @@ -1817,469 +1817,469 @@ Right now this has very limited functionality - + Also in: <br> - + No conflict - + <Edit...> - + Activating Network Proxy - + Choose Mod - + Mod Archive - + Start Tutorial? - + You're about to start a tutorial. For technical reasons it's not possible to end the tutorial early. Continue? - + failed to spawn notepad.exe: %1 - + failed to open %1 - + failed to change origin name: %1 - + failed to move "%1" from mod "%2" to "%3": %4 - + <Contains %1> - + <Checked> - + <Unchecked> - + <Update> - + <Managed by MO> - + <Managed outside MO> - + <No category> - + <Conflicted> - + <Not Endorsed> - + failed to rename mod: %1 - + Overwrite? - + This will replace the existing mod "%1". Continue? - + failed to remove mod "%1" - - - + + + failed to rename "%1" to "%2" - - - - + + + + Confirm - + Remove the following mods?<br><ul>%1</ul> - + failed to remove mod: %1 - - + + Failed - + Installation file no longer exists - + Mods installed with old versions of MO can't be reinstalled in this way. - + You need to be logged in with Nexus to resume a download - - + + You need to be logged in with Nexus to endorse - + Failed to display overwrite dialog: %1 - + Nexus ID for this Mod is unknown - + Web page for this mod is unknown - - - + + + Create Mod... - + This will create an empty mod. Please enter a name: - - + + A mod with this name already exists - + This will move all files from overwrite into a new, regular mod. Please enter a name: - + Not logged in, endorsement information will be wrong - + Continue? - + The versioning scheme decides which version is considered newer than another. This function will guess the versioning scheme under the assumption that the installed version is outdated. - - + + Sorry - + I don't know a versioning scheme where %1 is newer than %2. - + Really enable all visible mods? - + Really disable all visible mods? - + Choose what to export - + Everything - + All installed mods are included in the list - + Active Mods - + Only active (checked) mods from your current profile are included - + Visible - + All mods visible in the mod list are included - + export failed: %1 - + Install Mod... - + Create empty mod - + Enable all visible - + Disable all visible - + Check all for update - + Export to csv... - + All Mods - + Sync to Mods... - + Restore Backup - + Remove Backup... - + Add/Remove Categories - + Replace Categories - + Primary Category - + Change versioning scheme - + Un-ignore update - + Ignore update - + Rename Mod... - + Remove Mod... - + Reinstall Mod - + Un-Endorse - - + + Endorse - + Won't endorse - + Endorsement state unknown - + Ignore missing data - + Visit on Nexus - + Visit web page - + Open in explorer - + Information... - - + + Exception: - - + + Unknown exception - + <All> - + <Multiple> - + %1 more - + Are you sure you want to remove the following %n save(s)?<br><ul>%1</ul><br>Removed saves will be sent to the Recycle Bin. @@ -2287,12 +2287,12 @@ This function will guess the versioning scheme under the assumption that the ins - + Enable Mods... - + Delete %n save(s) @@ -2300,319 +2300,319 @@ This function will guess the versioning scheme under the assumption that the ins - + failed to remove %1 - + failed to create %1 - + Can't change download directory while downloads are in progress! - + failed to write to file %1 - + %1 written - + Select binary - + Binary - + Enter Name - + Please enter a name for the executable - + Not an executable - + This is not a recognized executable. - - + + Replace file? - + There already is a hidden version of this file. Replace it? - - + + File operation failed - - + + Failed to remove "%1". Maybe you lack the required file permissions? - + There already is a visible version of this file. Replace it? - + file not found: %1 - + failed to generate preview for %1 - + Sorry, can't preview anything. This function currently does not support extracting from bsas. - + Update available - + Open/Execute - + Add as Executable - + Preview - + Un-Hide - + Hide - + Write To File... - + Do you want to endorse Mod Organizer on %1 now? - + Thank you! - + Thank you for your endorsement! - + Request to Nexus failed: %1 - - + + failed to read %1: %2 - - + + Error - + failed to extract %1 (errorcode %2) - + Extract BSA - + This archive contains invalid hashes. Some files may be broken. - + Are you sure? - + This will restart MO, continue? - + Edit Categories... - + Deselect filter - + Remove - + Enable all - + Disable all - + Unlock load order - + Lock load order - + depends on missing "%1" - + incompatible with "%1" - + Please wait while LOOT is running - + loot failed. Exit code was: %1 - + failed to start loot - + failed to run loot: %1 - + Errors occured - + Backup of load order created - + Choose backup to restore - + No Backups - + There are no backups to restore - - + + Restore failed - - + + Failed to restore the backup. Errorcode: %1 - + Backup of modlist created - + A file with the same name has already been downloaded. What would you like to do? - + Overwrite - + Rename new file - + Ignore file @@ -2793,12 +2793,12 @@ This function will guess the versioning scheme under the assumption that the ins - List of esps and esms that can not be loaded by the game. + List of esps, esms, and esls that can not be loaded by the game. - List of esps and esms contained in this plugin that currently can not be loaded by the game. They will not even appear in the esp-list in the main MO-window. + List of esps, esms, and esls contained in this plugin that currently can not be loaded by the game. They will not even appear in the esp-list in the main MO-window. They usually contain optional functionality, see the readme. Most mods do not have optional esps, so chances are good you are looking at an empty list. @@ -2989,227 +2989,227 @@ p, li { white-space: pre-wrap; } - + &Delete - + &Rename - + &Hide - + &Unhide - + &Open - + &New Folder - - + + Save changes? - - + + Save changes to "%1"? - + File Exists - + A file with that name exists, please enter a new one - + failed to move file - + failed to create directory "optional" - - + + Info requested, please wait - + Main - + Update - + Optional - + Old - + Misc - + Unknown - + Current Version: %1 - + No update available - + (description incomplete, please visit nexus) - + <a href="%1">Visit on Nexus</a> - + Failed to delete %1 - - + + Confirm - + Are sure you want to delete "%1"? - + Are sure you want to delete the selected files? - - + + New Folder - + Failed to create "%1" - - + + Replace file? - + There already is a hidden version of this file. Replace it? - - + + File operation failed - - + + Failed to remove "%1". Maybe you lack the required file permissions? - - + + failed to rename %1 to %2 - + There already is a visible version of this file. Replace it? - + Un-Hide - + Hide - + Name - + Please enter a name - - + + Error - + Invalid name. Must be a valid file name - + A tweak by that name exists - + Create Tweak @@ -3593,147 +3593,147 @@ p, li { white-space: pre-wrap; } - - + + Installation successful - - + + Configure Mod - - + + This mod contains ini tweaks. Do you want to configure them now? - - + + mod "%1" not found - - + + Installation cancelled - - + + The mod was not installed completely. - + Executable "%1" not found - + Start Steam? - + Steam is required to be running already to correctly start the game. Should MO try to start steam now? - + Error - + No profile set - + Failed to refresh list of esps: %1 - + Multiple esps activated, please check that they don't conflict. - + Download? - + A download has been started but no installed page plugin recognizes it. If you download anyway no information (i.e. version) will be associated with the download. Continue? - + failed to update mod list: %1 - - + + login successful - + Login failed - + Login failed, try again? - + login failed: %1. Download will not be associated with an account - + login failed: %1 - + login failed: %1. You need to log-in with Nexus to update MO. - - Too many esps and esms enabled + + Too many esps, esms, and esls enabled - - + + Description missing - + The game doesn't allow more than 255 active plugins (including the official ones) to be loaded. You have to disable some unused plugins or merge some plugins into one. You can find a guide here: <a href="http://wiki.step-project.com/Guide:Merging_Plugins">http://wiki.step-project.com/Guide:Merging_Plugins</a> - + failed to save load order: %1 - + The designated write target "%1" is not enabled. @@ -4338,7 +4338,7 @@ p, li { white-space: pre-wrap; } - + invalid game type %1 @@ -4509,7 +4509,8 @@ p, li { white-space: pre-wrap; } - ModOrganizer has crashed! Should a diagnostic file be created? If you send me this file (%1) to sherb@gmx.net, the bug is a lot more likely to be fixed. Please include a short description of what you were doing when the crash happened + ModOrganizer has crashed! Should a diagnostic file be created? If you send me this file (%1) to modorganizer@gmail.com, the bug is a lot more likely to be fixed. Please include a short description of what you were doing when the crash happened + ModOrganizer has crashed! Should a diagnostic file be created? If you send me this file (%1) to sherb@gmx.net, the bug is a lot more likely to be fixed. Please include a short description of what you were doing when the crash happened @@ -4570,13 +4571,13 @@ p, li { white-space: pre-wrap; } - - + + <Manage...> - + failed to parse profile %1: %2 @@ -4764,52 +4765,52 @@ Start elevated anyway? (you will be asked if you want to allow ModOrganizer.exe - + New update available (%1) - + Install - + Download failed - + Failed to find correct download, please try again later. - + Update - + Download in progress - + Download failed: %1 - + Failed to install update: %1 - + Failed to start %1: %2 - + Error @@ -5318,7 +5319,7 @@ Uncheck this if you want to use Mod Organizer with total conversions (like Nehri By default Mod Organizer will display esp+bsa bundles installed with foreign tools as mods (left pane). This allows you to control their priority in relation to other mods. This is particularly useful if you also use Steam Workshop to install mods. However, if you installed loose file mods outside MO which conflict with BSAs also installed outside MO those conflicts can't be resolved correctly. -If you disable this feature, MO will only display official DLCs this way. Please note that plugins (esps and esms) displayed in the right pane are completely unaffected by this feature. +If you disable this feature, MO will only display official DLCs this way. Please note that plugins (esps, esms, and esls) displayed in the right pane are completely unaffected by this feature. diff --git a/src/organizer_en_US.ts b/src/organizer_en_US.ts index 075132c2..4e657785 100644 --- a/src/organizer_en_US.ts +++ b/src/organizer_en_US.ts @@ -54,7 +54,7 @@ - This is a list of esps and esms that were active when the save game was created. + This is a list of esps, esms, and esls that were active when the save game was created. @@ -63,7 +63,7 @@ <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">This is a list of esps and esms that were active when the save game was created.</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">This is a list of esps, esms, and esls that were active when the save game was created.</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">For each esp, the right column contains the mod (or mods) that can be enabled to make the missing esps/esms available.</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">If you hit Ok, all the mods selected in the right columns and all missing esps that have become available will be activated.</span></p></body></html> @@ -1467,7 +1467,7 @@ p, li { white-space: pre-wrap; } <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">This list contains the esps and esms contained in the active mods. These require their own load order. Use drag&amp;drop to modify this load order. Please note that MO will only save the load order for mods that are active/checked.<br />There is a great tool named &quot;BOSS&quot; to automatically sort these files.</span></p></body></html> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">This list contains the esps, esms, and esls contained in the active mods. These require their own load order. Use drag&amp;drop to modify this load order. Please note that MO will only save the load order for mods that are active/checked.<br />There is a great tool named &quot;BOSS&quot; to automatically sort these files.</span></p></body></html> @@ -1993,7 +1993,7 @@ Continue? - Too many esps and esms enabled + Too many esps, esms, and esls enabled @@ -2937,12 +2937,12 @@ This function will guess the versioning scheme under the assumption that the ins - List of esps and esms that can not be loaded by the game. + List of esps, esms, and esls that can not be loaded by the game. - List of esps and esms contained in this plugin that currently can not be loaded by the game. They will not even appear in the esp-list in the main MO-window. + List of esps, esms, and esls contained in this plugin that currently can not be loaded by the game. They will not even appear in the esp-list in the main MO-window. They usually contain optional functionality, see the readme. Most mods do not have optional esps, so chances are good you are looking at an empty list. @@ -5177,7 +5177,7 @@ Uncheck this if you want to use Mod Organizer with total conversions (like Nehri By default Mod Organizer will display esp+bsa bundles installed with foreign tools as mods (left pane). This allows you to control their priority in relation to other mods. This is particularly useful if you also use Steam Workshop to install mods. However, if you installed loose file mods outside MO which conflict with BSAs also installed outside MO those conflicts can't be resolved correctly. -If you disable this feature, MO will only display official DLCs this way. Please note that plugins (esps and esms) displayed in the right pane are completely unaffected by this feature. +If you disable this feature, MO will only display official DLCs this way. Please note that plugins (esps, esms, and esls) displayed in the right pane are completely unaffected by this feature. diff --git a/src/organizercore.cpp b/src/organizercore.cpp index d9ed6ab6..c55504a8 100644 --- a/src/organizercore.cpp +++ b/src/organizercore.cpp @@ -1413,6 +1413,20 @@ void OrganizerCore::updateModActiveState(int index, bool active) m_PluginList.enableESP(esm, active); } int enabled = 0; + for (const QString &esl : + dir.entryList(QStringList() << "*.esl", QDir::Files)) { + const FileEntry::Ptr file = m_DirectoryStructure->findFile(ToWString(esl)); + if (file.get() == nullptr) { + qWarning("failed to activate %s", qPrintable(esl)); + continue; + } + + if (active != m_PluginList.isEnabled(esl) + && file->getAlternatives().empty()) { + m_PluginList.enableESP(esl, active); + ++enabled; + } + } QStringList esps = dir.entryList(QStringList() << "*.esp", QDir::Files); for (const QString &esp : esps) { const FileEntry::Ptr file = m_DirectoryStructure->findFile(ToWString(esp)); @@ -1429,7 +1443,7 @@ void OrganizerCore::updateModActiveState(int index, bool active) } if (active && (enabled > 1)) { MessageDialog::showMessage( - tr("Multiple esps activated, please check that they don't conflict."), + tr("Multiple esps/esls activated, please check that they don't conflict."), qApp->activeWindow()); } m_PluginList.refreshLoadOrder(); @@ -1723,7 +1737,7 @@ QString OrganizerCore::shortDescription(unsigned int key) const { switch (key) { case PROBLEM_TOOMANYPLUGINS: { - return tr("Too many esps and esms enabled"); + return tr("Too many esps, esms, and esls enabled"); } break; default: { return tr("Description missing"); diff --git a/src/pluginlist.cpp b/src/pluginlist.cpp index a4d8561c..f2c52d5b 100644 --- a/src/pluginlist.cpp +++ b/src/pluginlist.cpp @@ -135,7 +135,7 @@ void PluginList::refresh(const QString &profileName QString extension = filename.right(3).toLower(); - if ((extension == "esp") || (extension == "esm")) { + if ((extension == "esp") || (extension == "esm") || (extension == "esl")) { bool forceEnabled = Settings::instance().forceEnableCoreFiles() && std::find(primaryPlugins.begin(), primaryPlugins.end(), filename.toLower()) != primaryPlugins.end(); diff --git a/src/settingsdialog.ui b/src/settingsdialog.ui index a38530da..f5e37ea6 100644 --- a/src/settingsdialog.ui +++ b/src/settingsdialog.ui @@ -970,7 +970,7 @@ Uncheck this if you want to use Mod Organizer with total conversions (like Nehri By default Mod Organizer will display esp+bsa bundles installed with foreign tools as mods (left pane). This allows you to control their priority in relation to other mods. This is particularly useful if you also use Steam Workshop to install mods. However, if you installed loose file mods outside MO which conflict with BSAs also installed outside MO those conflicts can't be resolved correctly. -If you disable this feature, MO will only display official DLCs this way. Please note that plugins (esps and esms) displayed in the right pane are completely unaffected by this feature. +If you disable this feature, MO will only display official DLCs this way. Please note that plugins (esps, esms, and esls) displayed in the right pane are completely unaffected by this feature. Display mods installed outside MO diff --git a/src/tutorials/tutorial_conflictresolution_main.js b/src/tutorials/tutorial_conflictresolution_main.js index 3a7160c6..00ca8d67 100644 --- a/src/tutorials/tutorial_conflictresolution_main.js +++ b/src/tutorials/tutorial_conflictresolution_main.js @@ -93,7 +93,7 @@ function getTutorialSteps() { waitForClick() }, function() { - tutorial.text = qsTr("I told you in the \"First Steps\" tutorial how the esp/esm plugins contain changes to the game world " + tutorial.text = qsTr("I told you in the \"First Steps\" tutorial how the esp/esm/esl plugins contain changes to the game world " +"like modifications to the terrain or existing NPCs. Each change like this is stored in a record, hence the " +"name \"record conflict\". For example when two mods try to change the same location, only one change can become active.") waitForClick() diff --git a/src/tutorials/tutorial_primer_main.js b/src/tutorials/tutorial_primer_main.js index 12df2c86..7ef65df9 100644 --- a/src/tutorials/tutorial_primer_main.js +++ b/src/tutorials/tutorial_primer_main.js @@ -75,7 +75,7 @@ function setupTooptips() { switch (manager.findControl("tabWidget").currentIndex) { case 0: - tooltipWidget("espList", qsTr("Plugins (esp/esm files) of the mods in the current profile. They need to be checked to be loaded.")) + tooltipWidget("espList", qsTr("Plugins (esp/esm/esl files) of the mods in the current profile. They need to be checked to be loaded.")) tooltipWidget("bossButton", qsTr("Automatically sort plugins using the bundled LOOT application.")) tooltipWidget("espFilterEdit", qsTr("Quickly filter plugin list as you type.")) break -- cgit v1.3.1 From 54fd26fee15c320c363a4be355c80e4b7ce38164 Mon Sep 17 00:00:00 2001 From: Eran Mizrahi Date: Fri, 8 Dec 2017 11:00:57 +0200 Subject: new diagnostics settings dialog tab --- src/settings.cpp | 37 +++++++-- src/settings.h | 25 +++++- src/settingsdialog.ui | 225 ++++++++++++++++++++++++++++++++++++++++---------- 3 files changed, 237 insertions(+), 50 deletions(-) (limited to 'src/settingsdialog.ui') diff --git a/src/settings.cpp b/src/settings.cpp index fc740302..7d90d861 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -28,6 +28,7 @@ along with Mod Organizer. If not, see . #include #include #include +#include #include #include @@ -38,6 +39,7 @@ along with Mod Organizer. If not, see . #include #include #include +#include #include #include #include @@ -334,9 +336,18 @@ bool Settings::offlineMode() const int Settings::logLevel() const { - return m_Settings.value("Settings/log_level", 0).toInt(); + return m_Settings.value("Settings/log_level", static_cast(LogLevel::Info)).toInt(); } +int Settings::crashDumpsType() const +{ + return m_Settings.value("Settings/crash_dumps_type", static_cast(CrashDumpsType::Mini)).toInt(); +} + +int Settings::crashDumpsMax() const +{ + return m_Settings.value("Settings/crash_dumps_max", 5).toInt(); +} void Settings::setNexusLogin(QString username, QString password) { @@ -581,6 +592,7 @@ void Settings::query(QWidget *parent) tabs.push_back(std::unique_ptr(new GeneralTab(this, dialog))); tabs.push_back(std::unique_ptr(new PathsTab(this, dialog))); + tabs.push_back(std::unique_ptr(new DiagnosticsTab(this, dialog))); tabs.push_back(std::unique_ptr(new NexusTab(this, dialog))); tabs.push_back(std::unique_ptr(new SteamTab(this, dialog))); tabs.push_back(std::unique_ptr(new PluginsTab(this, dialog))); @@ -608,7 +620,6 @@ Settings::GeneralTab::GeneralTab(Settings *m_parent, SettingsDialog &m_dialog) : Settings::SettingsTab(m_parent, m_dialog) , m_languageBox(m_dialog.findChild("languageBox")) , m_styleBox(m_dialog.findChild("styleBox")) - , m_logLevelBox(m_dialog.findChild("logLevelBox")) , m_compactBox(m_dialog.findChild("compactBox")) , m_showMetaBox(m_dialog.findChild("showMetaBox")) , m_usePrereleaseBox(m_dialog.findChild("usePrereleaseBox")) @@ -640,7 +651,6 @@ Settings::GeneralTab::GeneralTab(Settings *m_parent, SettingsDialog &m_dialog) } } - m_logLevelBox->setCurrentIndex(m_parent->logLevel()); m_compactBox->setChecked(m_parent->compactDownloads()); m_showMetaBox->setChecked(m_parent->metaDownloads()); m_usePrereleaseBox->setChecked(m_parent->usePrereleases()); @@ -662,9 +672,6 @@ void Settings::GeneralTab::update() emit m_parent->styleChanged(newStyle); } - m_Settings.setValue("Settings/log_level", m_logLevelBox->currentIndex()); - - m_Settings.setValue("Settings/compact_downloads", m_compactBox->isChecked()); m_Settings.setValue("Settings/meta_downloads", m_showMetaBox->isChecked()); m_Settings.setValue("Settings/use_prereleases", m_usePrereleaseBox->isChecked()); @@ -743,6 +750,24 @@ void Settings::PathsTab::update() } } +Settings::DiagnosticsTab::DiagnosticsTab(Settings *m_parent, SettingsDialog &m_dialog) + : Settings::SettingsTab(m_parent, m_dialog) + , m_logLevelBox(m_dialog.findChild("logLevelBox")) + , m_dumpsTypeBox(m_dialog.findChild("dumpsTypeBox")) + , m_dumpsMaxEdit(m_dialog.findChild("dumpsMaxEdit")) +{ + m_logLevelBox->setCurrentIndex(m_parent->logLevel()); + m_dumpsTypeBox->setCurrentIndex(m_parent->crashDumpsType()); + m_dumpsMaxEdit->setValue(m_parent->crashDumpsMax()); +} + +void Settings::DiagnosticsTab::update() +{ + m_Settings.setValue("Settings/log_level", m_logLevelBox->currentIndex()); + m_Settings.setValue("Settings/crash_dumps_type", m_dumpsTypeBox->currentIndex()); + m_Settings.setValue("Settings/crash_dumps_max", m_dumpsMaxEdit->value()); +} + Settings::NexusTab::NexusTab(Settings *parent, SettingsDialog &dialog) : Settings::SettingsTab(parent, dialog) , m_loginCheckBox(dialog.findChild("loginCheckBox")) diff --git a/src/settings.h b/src/settings.h index d316c82d..9ee29ba3 100644 --- a/src/settings.h +++ b/src/settings.h @@ -38,6 +38,7 @@ along with Mod Organizer. If not, see . class QCheckBox; class QComboBox; class QLineEdit; +class QSpinBox; class QListWidget; class QWidget; @@ -204,6 +205,16 @@ public: */ int logLevel() const; + /** + * @return the configured crash dumps type + */ + int crashDumpsType() const; + + /** + * @return the configured crash dumps max + */ + int crashDumpsMax() const; + /** * @brief set the nexus login information * @@ -371,7 +382,6 @@ private: private: QComboBox *m_languageBox; QComboBox *m_styleBox; - QComboBox *m_logLevelBox; QCheckBox *m_compactBox; QCheckBox *m_showMetaBox; QCheckBox *m_usePrereleaseBox; @@ -393,6 +403,19 @@ private: QLineEdit *m_overwriteDirEdit; }; + class DiagnosticsTab : public SettingsTab + { + public: + DiagnosticsTab(Settings *parent, SettingsDialog &dialog); + + void update(); + + private: + QComboBox *m_logLevelBox; + QComboBox *m_dumpsTypeBox; + QSpinBox *m_dumpsMaxEdit; + }; + /** Display/store the configuration in the 'nexus' tab of the settings dialogue */ class NexusTab : public SettingsTab { diff --git a/src/settingsdialog.ui b/src/settingsdialog.ui index f5e37ea6..632dc6c9 100644 --- a/src/settingsdialog.ui +++ b/src/settingsdialog.ui @@ -70,48 +70,6 @@ p, li { white-space: pre-wrap; } - - - - - - Log Level - - - - - - - Decides the amount of data printed to "ModOrganizer.log" - - - Decides the amount of data printed to "ModOrganizer.log". -"Debug" produces very useful information for finding problems. There is usually no noteworthy performance impact but the file may become rather large. If this is a problem you may prefer the "Info" level for regluar use. On the "Error" level the log file usually remains empty. - - - - Debug - - - - - Info - - - - - Warning - - - - - Error - - - - - - @@ -378,7 +336,188 @@ If you use pre-releases, never contact me directly by e-mail or via private mess - + + + Diagnostics + + + + + + + + Log Level + + + + + + + Decides the amount of data printed to "ModOrganizer.log" + + + + Decides the amount of data printed to "ModOrganizer.log". + "Debug" produces very useful information for finding problems. There is usually no noteworthy performance impact but the file may become rather large. If this is a problem you may prefer the "Info" level for regluar use. On the "Error" level the log file usually remains empty. + + + + + Debug + + + + + Info (recommended) + + + + + Warning + + + + + Error + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + Crash Dumps + + + + + + + Decides which type of crash dumps are collected when injected processes crash. + + + + Decides which type of crash dumps are collected when injected processes crash. + "None" Disables the generation of crash dumps by MO. + "Mini" Default level which generates small dumps (only stack traces). + "Data" Much larger dumps with additional information which may be need (also data segments). + "Full" Even larger dumps with a full memory dump of the process. + + + + + None + + + + + Mini (recommended) + + + + + Data + + + + + Full + + + + + + + + + + + + Max Dumps To Keep + + + + + + + Qt::Horizontal + + + + 60 + 20 + + + + + + + + Maximum number of crash dumps to keep on disk. Use 0 for unlimited. + + + + Maximum number of crash dumps to keep on disk. Use 0 for unlimited. + Set "Crash Dumps" above to None to disable crash dump collection. + + + + + + + + + + + Dumps are stored in <a href="%LOCALAPPDATA%\modorganizer">%LOCALAPPDATA%\modorganizer</a>. + Sending such dumps to the developers can help solve crashes caused by MO. + It is recommended to compress the dumps before sending, especially on the larger settings. + + + + true + + + Hint: right click link and copy link location + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 232 + + + + + + + Nexus -- cgit v1.3.1 From 7ab98cb451153c541245641b984e7904bc9c575d Mon Sep 17 00:00:00 2001 From: Eran Mizrahi Date: Sun, 10 Dec 2017 21:34:19 +0200 Subject: move crash dumps to their own folder --- src/organizercore.cpp | 2 +- src/settingsdialog.ui | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'src/settingsdialog.ui') diff --git a/src/organizercore.cpp b/src/organizercore.cpp index 91330d3a..30f96caf 100644 --- a/src/organizercore.cpp +++ b/src/organizercore.cpp @@ -670,7 +670,7 @@ std::wstring OrganizerCore::crashDumpsPath() { wchar_t appDataLocal[MAX_PATH]{ 0 }; ::SHGetFolderPathW(NULL, CSIDL_LOCAL_APPDATA, NULL, 0, appDataLocal); std::wstring dumpPath{ appDataLocal }; - dumpPath += L"\\modorganizer"; + dumpPath += L"\\modorganizer\\crashDumps"; return dumpPath; } diff --git a/src/settingsdialog.ui b/src/settingsdialog.ui index 632dc6c9..6d462cfa 100644 --- a/src/settingsdialog.ui +++ b/src/settingsdialog.ui @@ -486,7 +486,7 @@ If you use pre-releases, never contact me directly by e-mail or via private mess - Dumps are stored in <a href="%LOCALAPPDATA%\modorganizer">%LOCALAPPDATA%\modorganizer</a>. + Dumps are stored in <a href="%LOCALAPPDATA%\modorganizer\crashDumps">%LOCALAPPDATA%\modorganizer\crashDumps</a>. Sending such dumps to the developers can help solve crashes caused by MO. It is recommended to compress the dumps before sending, especially on the larger settings. -- cgit v1.3.1 From 240900de39aaf1562332ed88708b4b128703ad0e Mon Sep 17 00:00:00 2001 From: Eran Mizrahi Date: Tue, 12 Dec 2017 23:22:04 +0200 Subject: Move crash dumps to instance-dependant data folder --- src/main.cpp | 5 +++-- src/organizercore.cpp | 9 ++++----- src/settings.cpp | 12 ++++++++++++ src/settings.h | 2 ++ src/settingsdialog.ui | 9 +++++---- src/shared/appconfig.inc | 1 + 6 files changed, 27 insertions(+), 11 deletions(-) (limited to 'src/settingsdialog.ui') diff --git a/src/main.cpp b/src/main.cpp index eed4dfd3..b4faf570 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -528,8 +528,6 @@ int runApplication(MOApplication &application, SingleInstance &instance, int main(int argc, char *argv[]) { - prevUnhandledExceptionFilter = SetUnhandledExceptionFilter(MyUnhandledExceptionFilter); - MOApplication application(argc, argv); QStringList arguments = application.arguments(); @@ -586,6 +584,9 @@ int main(int argc, char *argv[]) } application.setProperty("dataPath", dataPath); + // initialize dump collection only after "dataPath" since the crashes are stored under it + prevUnhandledExceptionFilter = SetUnhandledExceptionFilter(MyUnhandledExceptionFilter); + LogBuffer::init(100, QtDebugMsg, qApp->property("dataPath").toString() + "/logs/mo_interface.log"); QString splash = dataPath + "/splash.png"; diff --git a/src/organizercore.cpp b/src/organizercore.cpp index bc0578b3..deb0b718 100644 --- a/src/organizercore.cpp +++ b/src/organizercore.cpp @@ -670,11 +670,10 @@ void OrganizerCore::setGlobalCrashDumpsType(int crashDumpsType) { //static std::wstring OrganizerCore::crashDumpsPath() { - wchar_t appDataLocal[MAX_PATH]{ 0 }; - ::SHGetFolderPathW(NULL, CSIDL_LOCAL_APPDATA, NULL, 0, appDataLocal); - std::wstring dumpPath{ appDataLocal }; - dumpPath += L"\\modorganizer\\crashDumps"; - return dumpPath; + return ( + qApp->property("dataPath").toString() + "/" + + QString::fromStdWString(AppConfig::dumpsDir()) + ).toStdWString(); } void OrganizerCore::setCurrentProfile(const QString &profileName) diff --git a/src/settings.cpp b/src/settings.cpp index 05a62591..b2fc8939 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -24,6 +24,7 @@ along with Mod Organizer. If not, see . #include "settingsdialog.h" #include "versioninfo.h" #include "appconfig.h" +#include "organizercore.h" #include #include #include @@ -48,6 +49,7 @@ along with Mod Organizer. If not, see . #include #include #include +#include #include // for Qt::UserRole, etc #include // for qDebug, qWarning @@ -755,10 +757,20 @@ Settings::DiagnosticsTab::DiagnosticsTab(Settings *m_parent, SettingsDialog &m_d , m_logLevelBox(m_dialog.findChild("logLevelBox")) , m_dumpsTypeBox(m_dialog.findChild("dumpsTypeBox")) , m_dumpsMaxEdit(m_dialog.findChild("dumpsMaxEdit")) + , m_diagnosticsExplainedLabel(m_dialog.findChild("diagnosticsExplainedLabel")) { m_logLevelBox->setCurrentIndex(m_parent->logLevel()); m_dumpsTypeBox->setCurrentIndex(m_parent->crashDumpsType()); m_dumpsMaxEdit->setValue(m_parent->crashDumpsMax()); + QString logsPath = qApp->property("dataPath").toString() + + "/" + QString::fromStdWString(AppConfig::logPath()); + m_diagnosticsExplainedLabel->setText( + m_diagnosticsExplainedLabel->text() + .replace("LOGS_FULL_PATH", logsPath) + .replace("LOGS_DIR", QString::fromStdWString(AppConfig::logPath())) + .replace("DUMPS_FULL_PATH", QString::fromStdWString(OrganizerCore::crashDumpsPath())) + .replace("DUMPS_DIR", QString::fromStdWString(AppConfig::dumpsDir())) + ); } void Settings::DiagnosticsTab::update() diff --git a/src/settings.h b/src/settings.h index 9ee29ba3..ae38223f 100644 --- a/src/settings.h +++ b/src/settings.h @@ -41,6 +41,7 @@ class QLineEdit; class QSpinBox; class QListWidget; class QWidget; +class QLabel; struct ServerInfo; @@ -414,6 +415,7 @@ private: QComboBox *m_logLevelBox; QComboBox *m_dumpsTypeBox; QSpinBox *m_dumpsMaxEdit; + QLabel *m_diagnosticsExplainedLabel; }; /** Display/store the configuration in the 'nexus' tab of the settings dialogue */ diff --git a/src/settingsdialog.ui b/src/settingsdialog.ui index 6d462cfa..7a902748 100644 --- a/src/settingsdialog.ui +++ b/src/settingsdialog.ui @@ -483,12 +483,13 @@ If you use pre-releases, never contact me directly by e-mail or via private mess - + - Dumps are stored in <a href="%LOCALAPPDATA%\modorganizer\crashDumps">%LOCALAPPDATA%\modorganizer\crashDumps</a>. - Sending such dumps to the developers can help solve crashes caused by MO. - It is recommended to compress the dumps before sending, especially on the larger settings. + Logs and crash dumps are stored under your current instance in the <a href="LOGS_FULL_PATH">LOGS_DIR</a> + and <a href="DUMPS_FULL_PATH">DUMPS_DIR</a> folders. + Sending logs and/or crash dumps to the developers can help investigate issues. + It is recommended to compress large log and dmp files before sending. diff --git a/src/shared/appconfig.inc b/src/shared/appconfig.inc index e98757d3..e572a32b 100644 --- a/src/shared/appconfig.inc +++ b/src/shared/appconfig.inc @@ -8,6 +8,7 @@ APPPARAM(std::wstring, stylesheetsPath, L"stylesheets") APPPARAM(std::wstring, cachePath, L"webcache") APPPARAM(std::wstring, tutorialsPath, L"tutorials") APPPARAM(std::wstring, logPath, L"logs") +APPPARAM(std::wstring, dumpsDir, L"crashDumps") APPPARAM(std::wstring, profileTweakIni, L"profile_tweaks.ini") APPPARAM(std::wstring, logFileName, L"ModOrganizer.log") APPPARAM(std::wstring, iniFileName, L"ModOrganizer.ini") -- cgit v1.3.1 From 083d1078753698b5ff347d91aa17219fd1e1cb5a Mon Sep 17 00:00:00 2001 From: Jeremy Rimpo Date: Wed, 13 Dec 2017 03:11:03 -0600 Subject: A number of improvements and fixes * Move diagnostics tab to un-break tutorials targeting tab 3 * Restrict order locking for force-enabled plugins * Cascade locked positions in the case of a conflict * Should remove existing invalid locks * Add some info to primary plugins in plugin list * Differentiate plugin names for DLC and CC content --- src/modinfo.cpp | 7 +- src/modinfo.h | 9 +- src/modinfoforeign.cpp | 12 +- src/modinfoforeign.h | 2 +- src/pluginlist.cpp | 30 +++- src/settingsdialog.ui | 364 ++++++++++++++++++++++++------------------------- 6 files changed, 235 insertions(+), 189 deletions(-) (limited to 'src/settingsdialog.ui') diff --git a/src/modinfo.cpp b/src/modinfo.cpp index 77df6216..4f74086f 100644 --- a/src/modinfo.cpp +++ b/src/modinfo.cpp @@ -79,10 +79,11 @@ ModInfo::Ptr ModInfo::createFrom(const QDir &dir, DirectoryEntry **directoryStru ModInfo::Ptr ModInfo::createFromPlugin(const QString &modName, const QString &espName, const QStringList &bsaNames, + ModInfo::EModType modType, DirectoryEntry **directoryStructure) { QMutexLocker locker(&s_Mutex); ModInfo::Ptr result = ModInfo::Ptr( - new ModInfoForeign(modName, espName, bsaNames, directoryStructure)); + new ModInfoForeign(modName, espName, bsaNames, modType, directoryStructure)); s_Collection.push_back(result); return result; } @@ -224,9 +225,13 @@ void ModInfo::updateFromDisc(const QString &modDirectory, UnmanagedMods *unmanaged = game->feature(); if (unmanaged != nullptr) { for (const QString &modName : unmanaged->mods(!displayForeign)) { + ModInfo::EModType modType = game->DLCPlugins().contains(unmanaged->referenceFile(modName).fileName(), Qt::CaseInsensitive) ? ModInfo::EModType::MOD_DLC : + (game->CCPlugins().contains(unmanaged->referenceFile(modName).fileName(), Qt::CaseInsensitive) ? ModInfo::EModType::MOD_CC : ModInfo::EModType::MOD_DEFAULT); + createFromPlugin(unmanaged->displayName(modName), unmanaged->referenceFile(modName).absoluteFilePath(), unmanaged->secondaryFiles(modName), + modType, directoryStructure); } } diff --git a/src/modinfo.h b/src/modinfo.h index c62df549..0bdf6e43 100644 --- a/src/modinfo.h +++ b/src/modinfo.h @@ -101,6 +101,13 @@ public: ENDORSED_NEVER }; + enum EModType { + MOD_DEFAULT, + MOD_DLC, + MOD_CC + }; + + public: /** @@ -189,7 +196,7 @@ public: * @param bsaNames names of archives * @return a new mod */ - static ModInfo::Ptr createFromPlugin(const QString &modName, const QString &espName, const QStringList &bsaNames, MOShared::DirectoryEntry **directoryStructure); + static ModInfo::Ptr createFromPlugin(const QString &modName, const QString &espName, const QStringList &bsaNames, ModInfo::EModType modType, MOShared::DirectoryEntry **directoryStructure); /** * @brief retieve a name for one of the CONTENT_ enums diff --git a/src/modinfoforeign.cpp b/src/modinfoforeign.cpp index 6ad8b6d8..0bde2c30 100644 --- a/src/modinfoforeign.cpp +++ b/src/modinfoforeign.cpp @@ -50,9 +50,19 @@ QString ModInfoForeign::getDescription() const ModInfoForeign::ModInfoForeign(const QString &modName, const QString &referenceFile, const QStringList &archives, + ModInfo::EModType modType, DirectoryEntry **directoryStructure) : ModInfoWithConflictInfo(directoryStructure), m_ReferenceFile(referenceFile), m_Archives(archives) { m_CreationTime = QFileInfo(referenceFile).created(); - m_Name = "Unmanaged: " + modName; + switch (modType) { + case ModInfo::EModType::MOD_DLC: + m_Name = "DLC: " + modName; + break; + case ModInfo::EModType::MOD_CC: + m_Name = "Creation Club: " + modName; + break; + default: + m_Name = "Unmanaged: " + modName; + } } diff --git a/src/modinfoforeign.h b/src/modinfoforeign.h index 839bcdce..d60064f0 100644 --- a/src/modinfoforeign.h +++ b/src/modinfoforeign.h @@ -52,7 +52,7 @@ public: protected: ModInfoForeign(const QString &modName, const QString &referenceFile, - const QStringList &archives, + const QStringList &archives, ModInfo::EModType modType, MOShared::DirectoryEntry **directoryStructure); private: diff --git a/src/pluginlist.cpp b/src/pluginlist.cpp index 61d33fe9..6392d44b 100644 --- a/src/pluginlist.cpp +++ b/src/pluginlist.cpp @@ -347,7 +347,26 @@ void PluginList::readLockedOrderFrom(const QString &fileName) if ((line.size() > 0) && (line.at(0) != '#')) { QList fields = line.split('|'); if (fields.count() == 2) { - m_LockedOrder[QString::fromUtf8(fields.at(0))] = fields.at(1).trimmed().toInt(); + int priority = fields.at(1).trimmed().toInt(); + QString name = QString::fromUtf8(fields.at(0)); + // Avoid locking a force-enabled plugin + if (!m_ESPs[m_ESPsByName.at(name)].m_ForceEnabled) { + // Is this an open and unclaimed priority? + if (m_ESPs[m_ESPsByPriority.at(priority)].m_ForceEnabled || + std::find_if(m_LockedOrder.begin(), m_LockedOrder.end(), [&](const std::pair &a) { return a.second == priority; }) != m_LockedOrder.end()) { + // Attempt to find a priority but step over force-enabled plugins and already-set locks + int calcPriority = priority; + do { + ++calcPriority; + } while (calcPriority < m_ESPsByPriority.size() || (m_ESPs[m_ESPsByPriority.at(calcPriority)].m_ForceEnabled && + std::find_if(m_LockedOrder.begin(), m_LockedOrder.end(), [&](const std::pair &a) { return a.second == calcPriority; }) != m_LockedOrder.end())); + // If we have a match, we can reassign the priority... + if (calcPriority < m_ESPsByPriority.size()) + m_LockedOrder[name] = calcPriority; + } else { + m_LockedOrder[name] = priority; + } + } } else { reportError(tr("The file containing locked plugin indices is broken")); break; @@ -467,7 +486,10 @@ bool PluginList::isESPLocked(int index) const void PluginList::lockESPIndex(int index, bool lock) { if (lock) { - m_LockedOrder[getName(index).toLower()] = m_ESPs.at(index).m_LoadOrder; + if (!m_ESPs.at(index).m_ForceEnabled) + m_LockedOrder[getName(index).toLower()] = m_ESPs.at(index).m_LoadOrder; + else + return; } else { auto iter = m_LockedOrder.find(getName(index).toLower()); if (iter != m_LockedOrder.end()) { @@ -817,7 +839,9 @@ QVariant PluginList::data(const QModelIndex &modelIndex, int role) const } } if (m_ESPs[index].m_ForceEnabled) { - toolTip += tr("This plugin can't be disabled (enforced by the game)"); + QString text = tr("Origin: %1").arg(m_ESPs[index].m_OriginName); + text += tr("
This plugin can't be disabled (enforced by the game)."); + toolTip += text; } else { QString text = tr("Origin: %1").arg(m_ESPs[index].m_OriginName); if (m_ESPs[index].m_Author.size() > 0) { diff --git a/src/settingsdialog.ui b/src/settingsdialog.ui index 7a902748..3c47d226 100644 --- a/src/settingsdialog.ui +++ b/src/settingsdialog.ui @@ -336,188 +336,6 @@ If you use pre-releases, never contact me directly by e-mail or via private mess
- - - Diagnostics - - - - - - - - Log Level - - - - - - - Decides the amount of data printed to "ModOrganizer.log" - - - - Decides the amount of data printed to "ModOrganizer.log". - "Debug" produces very useful information for finding problems. There is usually no noteworthy performance impact but the file may become rather large. If this is a problem you may prefer the "Info" level for regluar use. On the "Error" level the log file usually remains empty. - - - - - Debug - - - - - Info (recommended) - - - - - Warning - - - - - Error - - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - - Crash Dumps - - - - - - - Decides which type of crash dumps are collected when injected processes crash. - - - - Decides which type of crash dumps are collected when injected processes crash. - "None" Disables the generation of crash dumps by MO. - "Mini" Default level which generates small dumps (only stack traces). - "Data" Much larger dumps with additional information which may be need (also data segments). - "Full" Even larger dumps with a full memory dump of the process. - - - - - None - - - - - Mini (recommended) - - - - - Data - - - - - Full - - - - - - - - - - - - Max Dumps To Keep - - - - - - - Qt::Horizontal - - - - 60 - 20 - - - - - - - - Maximum number of crash dumps to keep on disk. Use 0 for unlimited. - - - - Maximum number of crash dumps to keep on disk. Use 0 for unlimited. - Set "Crash Dumps" above to None to disable crash dump collection. - - - - - - - - - - - Logs and crash dumps are stored under your current instance in the <a href="LOGS_FULL_PATH">LOGS_DIR</a> - and <a href="DUMPS_FULL_PATH">DUMPS_DIR</a> folders. - Sending logs and/or crash dumps to the developers can help investigate issues. - It is recommended to compress large log and dmp files before sending. - - - - true - - - Hint: right click link and copy link location - - - - - - - Qt::Vertical - - - QSizePolicy::Expanding - - - - 20 - 232 - - - - - - Nexus @@ -1164,6 +982,188 @@ For the other games this is not a sufficient replacement for AI! + + + Diagnostics + + + + + + + + Log Level + + + + + + + Decides the amount of data printed to "ModOrganizer.log" + + + + Decides the amount of data printed to "ModOrganizer.log". + "Debug" produces very useful information for finding problems. There is usually no noteworthy performance impact but the file may become rather large. If this is a problem you may prefer the "Info" level for regluar use. On the "Error" level the log file usually remains empty. + + + + + Debug + + + + + Info (recommended) + + + + + Warning + + + + + Error + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + Crash Dumps + + + + + + + Decides which type of crash dumps are collected when injected processes crash. + + + + Decides which type of crash dumps are collected when injected processes crash. + "None" Disables the generation of crash dumps by MO. + "Mini" Default level which generates small dumps (only stack traces). + "Data" Much larger dumps with additional information which may be need (also data segments). + "Full" Even larger dumps with a full memory dump of the process. + + + + + None + + + + + Mini (recommended) + + + + + Data + + + + + Full + + + + + + + + + + + + Max Dumps To Keep + + + + + + + Qt::Horizontal + + + + 60 + 20 + + + + + + + + Maximum number of crash dumps to keep on disk. Use 0 for unlimited. + + + + Maximum number of crash dumps to keep on disk. Use 0 for unlimited. + Set "Crash Dumps" above to None to disable crash dump collection. + + + + + + + + + + + Logs and crash dumps are stored under your current instance in the <a href="LOGS_FULL_PATH">LOGS_DIR</a> + and <a href="DUMPS_FULL_PATH">DUMPS_DIR</a> folders. + Sending logs and/or crash dumps to the developers can help investigate issues. + It is recommended to compress large log and dmp files before sending. + + + + true + + + Hint: right click link and copy link location + + + + + + + Qt::Vertical + + + QSizePolicy::Expanding + + + + 20 + 232 + + + + + +
-- cgit v1.3.1
Game plugins (esp/esm)
Game plugins (esp/esm/esl)
Interface
Meshes
BSA