From 4342fe3ce16e1e14fb44cf2676e3887002f67ec4 Mon Sep 17 00:00:00 2001 From: Jeremy Rimpo Date: Mon, 18 Sep 2023 21:30:39 -0500 Subject: Several updates * No longer cause an error when deleting a category that's being used * Add a dialog when installing a mod with no Nexus mapping (if not disabled) * Allow disabling Nexus category mapping in Settings (Nexus tab) * Add context option to remove nexus mappings in the category editor * Some clang style fixes --- src/categories.cpp | 2 + src/categories.h | 3 + src/categoriesdialog.cpp | 114 +-- src/categoriesdialog.h | 7 +- src/installationmanager.cpp | 34 +- src/mainwindow.cpp | 79 +- src/mainwindow.h | 2 + src/organizer_en.ts | 1736 +++++++++++++++++++++++++------------------ src/organizercore.cpp | 36 +- src/settings.cpp | 10 + src/settings.h | 5 + src/settingsdialog.ui | 20 +- src/settingsdialognexus.cpp | 2 + 13 files changed, 1215 insertions(+), 835 deletions(-) (limited to 'src') diff --git a/src/categories.cpp b/src/categories.cpp index 3d625791..7fd60c50 100644 --- a/src/categories.cpp +++ b/src/categories.cpp @@ -233,6 +233,8 @@ void CategoryFactory::saveCategories() nexusMapFile.write(line); } nexusMapFile.close(); + + emit categoriesSaved(); } unsigned int diff --git a/src/categories.h b/src/categories.h index 1df7295b..86e66b1c 100644 --- a/src/categories.h +++ b/src/categories.h @@ -214,6 +214,9 @@ public: */ static QString nexusMappingFilePath(); +signals: + void categoriesSaved(); + private: explicit CategoryFactory(); diff --git a/src/categoriesdialog.cpp b/src/categoriesdialog.cpp index a14ec8c2..d97edb8e 100644 --- a/src/categoriesdialog.cpp +++ b/src/categoriesdialog.cpp @@ -19,11 +19,11 @@ along with Mod Organizer. If not, see . #include "categoriesdialog.h" #include "categories.h" +#include "messagedialog.h" +#include "nexusinterface.h" #include "settings.h" #include "ui_categoriesdialog.h" #include "utility.h" -#include "nexusinterface.h" -#include "messagedialog.h" #include #include #include @@ -105,14 +105,21 @@ private: }; CategoriesDialog::CategoriesDialog(PluginContainer* pluginContainer, QWidget* parent) - : TutorableDialog("Categories", parent), ui(new Ui::CategoriesDialog), m_PluginContainer(pluginContainer) + : TutorableDialog("Categories", parent), ui(new Ui::CategoriesDialog), + m_PluginContainer(pluginContainer) { ui->setupUi(this); fillTable(); connect(ui->categoriesTable, SIGNAL(cellChanged(int, int)), this, - SLOT(cellChanged(int,int))); - connect(ui->nexusRefresh, SIGNAL(clicked()), this, SLOT(nexusRefresh_clicked())); - connect(ui->nexusImportButton, SIGNAL(clicked()), this, SLOT(nexusImport_clicked())); + SLOT(cellChanged(int, int))); + if (Settings::instance().nexus().categoryMappings()) { + connect(ui->nexusRefresh, SIGNAL(clicked()), this, SLOT(nexusRefresh_clicked())); + connect(ui->nexusImportButton, SIGNAL(clicked()), this, + SLOT(nexusImport_clicked())); + ui->nexusCategoryList->setDisabled(false); + } else { + ui->nexusCategoryList->setDisabled(true); + } } CategoriesDialog::~CategoriesDialog() @@ -141,29 +148,26 @@ void CategoriesDialog::commitChanges() for (int i = 0; i < ui->categoriesTable->rowCount(); ++i) { int index = ui->categoriesTable->verticalHeader()->logicalIndex(i); - QVariantList nexusData = ui->categoriesTable->item(index, 3)->data(Qt::UserRole).toList(); + QVariantList nexusData = + ui->categoriesTable->item(index, 3)->data(Qt::UserRole).toList(); std::vector nexusCats; for (auto nexusCat : nexusData) { - nexusCats.push_back(CategoryFactory::NexusCategory(nexusCat.toList()[0].toString(), nexusCat.toList()[1].toInt())); + nexusCats.push_back(CategoryFactory::NexusCategory( + nexusCat.toList()[0].toString(), nexusCat.toList()[1].toInt())); } - categories->addCategory( - ui->categoriesTable->item(index, 0)->text().toInt(), - ui->categoriesTable->item(index, 1)->text(), - nexusCats, - ui->categoriesTable->item(index, 2)->text().toInt()); + categories->addCategory(ui->categoriesTable->item(index, 0)->text().toInt(), + ui->categoriesTable->item(index, 1)->text(), nexusCats, + ui->categoriesTable->item(index, 2)->text().toInt()); } categories->setParents(); std::vector nexusCats; for (int i = 0; i < ui->nexusCategoryList->count(); ++i) { - nexusCats.push_back( - CategoryFactory::NexusCategory( - ui->nexusCategoryList->item(i)->data(Qt::DisplayRole).toString(), - ui->nexusCategoryList->item(i)->data(Qt::UserRole).toInt() - ) - ); + nexusCats.push_back(CategoryFactory::NexusCategory( + ui->nexusCategoryList->item(i)->data(Qt::DisplayRole).toString(), + ui->nexusCategoryList->item(i)->data(Qt::UserRole).toInt())); } categories->setNexusCategories(nexusCats); @@ -186,8 +190,8 @@ void CategoriesDialog::refreshIDs() void CategoriesDialog::fillTable() { CategoryFactory* categories = CategoryFactory::instance(); - QTableWidget* table = ui->categoriesTable; - QListWidget* list = ui->nexusCategoryList; + QTableWidget* table = ui->categoriesTable; + QListWidget* list = ui->nexusCategoryList; #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) table->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Fixed); @@ -196,12 +200,18 @@ void CategoriesDialog::fillTable() table->horizontalHeader()->setSectionResizeMode(3, QHeaderView::Stretch); table->verticalHeader()->setSectionsMovable(true); table->verticalHeader()->setSectionResizeMode(QHeaderView::Fixed); - table->setItemDelegateForColumn(0, new ValidatingDelegate(this, new NewIDValidator(m_IDs))); - table->setItemDelegateForColumn(2, new ValidatingDelegate(this, new ExistingIDValidator(m_IDs))); - table->setItemDelegateForColumn(3, new ValidatingDelegate(this, new QRegExpValidator(QRegExp("([0-9]+)?(,[0-9]+)*"), this))); + table->setItemDelegateForColumn( + 0, new ValidatingDelegate(this, new NewIDValidator(m_IDs))); + table->setItemDelegateForColumn( + 2, new ValidatingDelegate(this, new ExistingIDValidator(m_IDs))); + table->setItemDelegateForColumn( + 3, new ValidatingDelegate(this, + new QRegularExpressionValidator( + QRegularExpression("([0-9]+)?(,[0-9]+)*"), this))); int row = 0; - for (std::vector::const_iterator iter = categories->m_Categories.begin(); + for (std::vector::const_iterator iter = + categories->m_Categories.begin(); iter != categories->m_Categories.end(); ++iter, ++row) { const CategoryFactory::Category& category = *iter; if (category.m_ID == 0) { @@ -225,13 +235,12 @@ void CategoriesDialog::fillTable() table->setItem(row, 3, nexusCatItem.take()); } - for (auto nexusCat : categories->m_NexusMap) - { + for (auto nexusCat : categories->m_NexusMap) { QScopedPointer nexusItem(new QListWidgetItem()); nexusItem->setData(Qt::DisplayRole, nexusCat.second.m_Name); nexusItem->setData(Qt::UserRole, nexusCat.second.m_ID); list->addItem(nexusItem.take()); - auto item = table->item(categories->resolveNexusID(nexusCat.first)-1, 3); + auto item = table->item(categories->resolveNexusID(nexusCat.first) - 1, 3); if (item != nullptr) { auto itemData = item->data(Qt::UserRole).toList(); QVariantList newData; @@ -267,22 +276,29 @@ void CategoriesDialog::removeCategory_clicked() ui->categoriesTable->removeRow(m_ContextRow); } +void CategoriesDialog::removeNexusMap_clicked() +{ + ui->categoriesTable->item(m_ContextRow, 3)->setData(Qt::UserRole, QVariantList()); + ui->categoriesTable->item(m_ContextRow, 3)->setData(Qt::DisplayRole, QString()); + // ui->categoriesTable->update(); +} void CategoriesDialog::nexusRefresh_clicked() { - NexusInterface &nexus = NexusInterface::instance(); + NexusInterface& nexus = NexusInterface::instance(); nexus.setPluginContainer(m_PluginContainer); - nexus.requestGameInfo(Settings::instance().game().plugin()->gameShortName(), this, QVariant(), QString()); + nexus.requestGameInfo(Settings::instance().game().plugin()->gameShortName(), this, + QVariant(), QString()); } - void CategoriesDialog::nexusImport_clicked() { if (QMessageBox::question(nullptr, tr("Import Nexus Categories?"), - tr("This will overwrite your existing categories with the loaded Nexus categories."), - QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) { + tr("This will overwrite your existing categories with the " + "loaded Nexus categories."), + QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) { QTableWidget* table = ui->categoriesTable; - QListWidget* list = ui->nexusCategoryList; + QListWidget* list = ui->nexusCategoryList; table->setRowCount(0); refreshIDs(); @@ -295,7 +311,8 @@ void CategoriesDialog::nexusImport_clicked() QScopedPointer idItem(new QTableWidgetItem()); idItem->setData(Qt::DisplayRole, ++m_HighestID); - QScopedPointer nameItem(new QTableWidgetItem(list->item(i)->data(Qt::DisplayRole).toString())); + QScopedPointer nameItem( + new QTableWidgetItem(list->item(i)->data(Qt::DisplayRole).toString())); QStringList nexusLabel; QVariantList nexusData; nexusLabel.append(list->item(i)->data(Qt::DisplayRole).toString()); @@ -303,7 +320,8 @@ void CategoriesDialog::nexusImport_clicked() data.append(QVariant(list->item(i)->data(Qt::DisplayRole).toString())); data.append(QVariant(list->item(i)->data(Qt::UserRole).toInt())); nexusData.insert(nexusData.size(), data); - QScopedPointer nexusCatItem(new QTableWidgetItem(nexusLabel.join(", "))); + QScopedPointer nexusCatItem( + new QTableWidgetItem(nexusLabel.join(", "))); nexusCatItem->setData(Qt::UserRole, nexusData); QScopedPointer parentIDItem(new QTableWidgetItem()); parentIDItem->setData(Qt::DisplayRole, 0); @@ -317,13 +335,13 @@ void CategoriesDialog::nexusImport_clicked() } } - -void CategoriesDialog::nxmGameInfoAvailable(QString gameName, QVariant, QVariant resultData, int) +void CategoriesDialog::nxmGameInfoAvailable(QString gameName, QVariant, + QVariant resultData, int) { - QVariantMap result = resultData.toMap(); - QVariantList categories = result["categories"].toList(); - CategoryFactory *catFactory = CategoryFactory::instance(); - QListWidget* list = ui->nexusCategoryList; + QVariantMap result = resultData.toMap(); + QVariantList categories = result["categories"].toList(); + CategoryFactory* catFactory = CategoryFactory::instance(); + QListWidget* list = ui->nexusCategoryList; list->clear(); for (auto category : categories) { auto catMap = category.toMap(); @@ -334,19 +352,23 @@ void CategoriesDialog::nxmGameInfoAvailable(QString gameName, QVariant, QVariant } } - -void CategoriesDialog::nxmRequestFailed(QString, int, int, QVariant, int, int errorCode, const QString& errorMessage) +void CategoriesDialog::nxmRequestFailed(QString, int, int, QVariant, int, int errorCode, + const QString& errorMessage) { - MessageDialog::showMessage(tr("Error %1: Request to Nexus failed: %2").arg(errorCode).arg(errorMessage), this); + MessageDialog::showMessage( + tr("Error %1: Request to Nexus failed: %2").arg(errorCode).arg(errorMessage), + this); } - void CategoriesDialog::on_categoriesTable_customContextMenuRequested(const QPoint& pos) { m_ContextRow = ui->categoriesTable->rowAt(pos.y()); QMenu menu; menu.addAction(tr("Add"), this, SLOT(addCategory_clicked())); menu.addAction(tr("Remove"), this, SLOT(removeCategory_clicked())); + if (Settings::instance().nexus().categoryMappings()) { + menu.addAction(tr("Remove Nexus Mapping(s)"), this, SLOT(removeNexusMap_clicked())); + } menu.exec(ui->categoriesTable->mapToGlobal(pos)); } diff --git a/src/categoriesdialog.h b/src/categoriesdialog.h index a2bd7240..1bcf273c 100644 --- a/src/categoriesdialog.h +++ b/src/categoriesdialog.h @@ -20,9 +20,9 @@ along with Mod Organizer. If not, see . #ifndef CATEGORIESDIALOG_H #define CATEGORIESDIALOG_H -#include "tutorabledialog.h" #include "categories.h" #include "plugincontainer.h" +#include "tutorabledialog.h" #include namespace Ui @@ -54,7 +54,8 @@ public: public slots: void nxmGameInfoAvailable(QString gameName, QVariant, QVariant resultData, int); - void nxmRequestFailed(QString, int, int, QVariant, int, int errorCode, const QString& errorMessage); + void nxmRequestFailed(QString, int, int, QVariant, int, int errorCode, + const QString& errorMessage); signals: void refreshNexusCategories(); @@ -64,6 +65,7 @@ private slots: void on_categoriesTable_customContextMenuRequested(const QPoint& pos); void addCategory_clicked(); void removeCategory_clicked(); + void removeNexusMap_clicked(); void nexusRefresh_clicked(); void nexusImport_clicked(); void cellChanged(int row, int column); @@ -80,7 +82,6 @@ private: int m_HighestID; std::set m_IDs; std::vector m_NexusCategories; - }; #endif // CATEGORIESDIALOG_H diff --git a/src/installationmanager.cpp b/src/installationmanager.cpp index dce81bd1..901c636c 100644 --- a/src/installationmanager.cpp +++ b/src/installationmanager.cpp @@ -645,6 +645,7 @@ InstallationResult InstallationManager::install(const QString& fileName, QString gameName = ""; QString version = ""; QString newestVersion = ""; + int category = 0; int categoryID = 0; int fileCategoryID = 1; QString repository = "Nexus"; @@ -659,12 +660,33 @@ InstallationResult InstallationManager::install(const QString& fileName, modName.update(doc.toPlainText(), GUESS_FALLBACK); modName.update(metaFile.value("modName", "").toString(), GUESS_META); - version = metaFile.value("version", "").toString(); - newestVersion = metaFile.value("newestVersion", "").toString(); - unsigned int categoryIndex = CategoryFactory::instance()->resolveNexusID( - metaFile.value("category", 0).toInt()); - categoryID = CategoryFactory::instance()->getCategoryID(categoryIndex); - repository = metaFile.value("repository", "").toString(); + version = metaFile.value("version", "").toString(); + newestVersion = metaFile.value("newestVersion", "").toString(); + category = metaFile.value("category", 0).toInt(); + unsigned int categoryIndex = CategoryFactory::instance()->resolveNexusID(category); + if (category != 0 && categoryIndex == 0U && + Settings::instance().nexus().categoryMappings()) { + QMessageBox nexusQuery; + nexusQuery.setText(tr( + "This Nexus category has not yet been mapped. Do you wish to proceed without " + "setting a category, proceed and disable automatic Nexus mappings, or stop " + "and configure your category mappings?")); + nexusQuery.addButton(tr("&Proceed"), QMessageBox::YesRole); + nexusQuery.addButton(tr("&Disable"), QMessageBox::AcceptRole); + nexusQuery.addButton(tr("&Stop && Configure"), QMessageBox::DestructiveRole); + auto ret = nexusQuery.exec(); + switch (ret) { + case 1: + Settings::instance().nexus().setCategoryMappings(false); + case 0: + break; + case 2: + return MOBase::IPluginInstaller::RESULT_CATEGORYREQUESTED; + } + } else { + categoryID = CategoryFactory::instance()->getCategoryID(categoryIndex); + } + repository = metaFile.value("repository", "").toString(); fileCategoryID = metaFile.value("fileCategory", 1).toInt(); } diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 99273d46..18a288c6 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -472,6 +472,9 @@ MainWindow::MainWindow(Settings& settings, OrganizerCore& organizerCore, connect(&m_OrganizerCore, &OrganizerCore::modInstalled, this, &MainWindow::modInstalled); + connect(m_CategoryFactory, &CategoryFactory::categoriesSaved, this, + &MainWindow::categoriesSaved); + m_CheckBSATimer.setSingleShot(true); connect(&m_CheckBSATimer, SIGNAL(timeout()), this, SLOT(checkBSAList())); @@ -1286,9 +1289,12 @@ void MainWindow::showEvent(QShowEvent* event) } QMessageBox newCatDialog; - newCatDialog.setWindowTitle("Import Categories"); - newCatDialog.setText(tr("Please choose how to handle the default category setup.\n\n" - "If you've already connected to Nexus, you can automatically import Nexus categories for this game (if applicable). Otherwise, use the old Mod Organizer default category structure, or leave the categories blank.")); + newCatDialog.setWindowTitle(tr("Import Categories")); + newCatDialog.setText( + tr("Please choose how to handle the default category setup.\n\n" + "If you've already connected to Nexus, you can automatically import Nexus " + "categories for this game (if applicable). Otherwise, use the old Mod " + "Organizer default category structure, or leave the categories blank.")); QPushButton importBtn(tr("&Import Nexus Categories")); QPushButton defaultBtn(tr("Use &Default Categories")); QPushButton cancelBtn(tr("Do &Nothing")); @@ -1310,17 +1316,23 @@ void MainWindow::showEvent(QShowEvent* event) m_OrganizerCore.settings().setFirstStart(false); } else { auto& settings = m_OrganizerCore.settings(); - if (m_LastVersion < QVersionNumber(2, 5) && !GlobalSettings::hideCategoryReminder()) { + if (m_LastVersion < QVersionNumber(2, 5) && + !GlobalSettings::hideCategoryReminder()) { QMessageBox migrateCatDialog; migrateCatDialog.setWindowTitle("Category Updates"); migrateCatDialog.setText( - tr( - "This is your first time running version 2.5 or higher with an old MO2 instance. The category system now relies on an updated system to map Nexus categories.\n\n" - "In order to assign Nexus categories automatically, you will need to import the Nexus categories for the currently managed game and map them to your preferred category structure.\n\n" - "You can either manually open the category editor, via the Settings dialog or the category filter sidebar, and set up the mappings as you see fit, or you can automatically import and map the categories as defined on Nexus.\n\n" - "As a final option, you can disable Nexus category mapping altogether, which can be changed at any time in the Settings dialog." - ) - ); + tr("This is your first time running version 2.5 or higher with an old MO2 " + "instance. The category system now relies on an updated system to map " + "Nexus categories.\n\n" + "In order to assign Nexus categories automatically, you will need to " + "import the Nexus categories for the currently managed game and map " + "them to your preferred category structure.\n\n" + "You can either manually open the category editor, via the Settings " + "dialog or the category filter sidebar, and set up the mappings as you " + "see fit, or you can automatically import and map the categories as " + "defined on Nexus.\n\n" + "As a final option, you can disable Nexus category mapping altogether, " + "which can be changed at any time in the Settings dialog.")); QPushButton importBtn(tr("&Import Nexus Categories")); QPushButton openSettingsBtn(tr("&Open Categories Dialog")); QPushButton showTutorialBtn(tr("&Show Tutorial")); @@ -1329,8 +1341,10 @@ void MainWindow::showEvent(QShowEvent* event) if (NexusInterface::instance().getAccessManager()->validated()) { migrateCatDialog.addButton(&importBtn, QMessageBox::ButtonRole::AcceptRole); } - migrateCatDialog.addButton(&openSettingsBtn, QMessageBox::ButtonRole::AcceptRole); - migrateCatDialog.addButton(&showTutorialBtn, QMessageBox::ButtonRole::AcceptRole); + migrateCatDialog.addButton(&openSettingsBtn, + QMessageBox::ButtonRole::AcceptRole); + migrateCatDialog.addButton(&showTutorialBtn, + QMessageBox::ButtonRole::AcceptRole); migrateCatDialog.addButton(&closeBtn, QMessageBox::ButtonRole::RejectRole); migrateCatDialog.setCheckBox(&dontShow); migrateCatDialog.exec(); @@ -2087,8 +2101,8 @@ void MainWindow::fixCategories() for (unsigned int i = 0; i < ModInfo::getNumMods(); ++i) { ModInfo::Ptr modInfo = ModInfo::getByIndex(i); std::set categories = modInfo->getCategories(); - for (std::set::iterator iter = categories.begin(); - iter != categories.end(); ++iter) { + for (std::set::iterator iter = categories.begin(); iter != categories.end(); + ++iter) { if (!m_CategoryFactory->categoryExists(*iter)) { modInfo->setCategory(*iter, false); } @@ -2455,7 +2469,8 @@ void MainWindow::importCategories(bool) { NexusInterface& nexus = NexusInterface::instance(); nexus.setPluginContainer(&m_OrganizerCore.pluginContainer()); - nexus.requestGameInfo(Settings::instance().game().plugin()->gameShortName(), this, QVariant(), QString()); + nexus.requestGameInfo(Settings::instance().game().plugin()->gameShortName(), this, + QVariant(), QString()); } void MainWindow::showMessage(const QString& message) @@ -3916,6 +3931,17 @@ void MainWindow::onPluginRegistrationChanged() m_DownloadsTab->update(); } +void MainWindow::categoriesSaved() +{ + for (auto modName : m_OrganizerCore.modList()->allMods()) { + auto mod = ModInfo::getByName(modName); + for (auto category : mod->getCategories()) { + if (!m_CategoryFactory->categoryExists(category)) + mod->setCategory(category, false); + } + } +} + void MainWindow::on_actionNexus_triggered() { const IPluginGame* game = m_OrganizerCore.managedGame(); @@ -4583,26 +4609,19 @@ void MainWindow::nxmDownloadURLs(QString, int, int, QVariant, QVariant resultDat m_OrganizerCore.settings().network().updateServers(servers); } -void MainWindow::nxmGameInfoAvailable(QString gameName, QVariant, QVariant resultData, int) +void MainWindow::nxmGameInfoAvailable(QString gameName, QVariant, QVariant resultData, + int) { - QVariantMap result = resultData.toMap(); - QVariantList categories = result["categories"].toList(); + QVariantMap result = resultData.toMap(); + QVariantList categories = result["categories"].toList(); CategoryFactory* catFactory = CategoryFactory::instance(); catFactory->reset(); for (auto category : categories) { auto catMap = category.toMap(); std::vector nexusCat; - nexusCat.push_back( - CategoryFactory::NexusCategory( - catMap["name"].toString(), - catMap["category_id"].toInt() - ) - ); - catFactory->addCategory( - catMap["name"].toString(), - nexusCat, - 0 - ); + nexusCat.push_back(CategoryFactory::NexusCategory(catMap["name"].toString(), + catMap["category_id"].toInt())); + catFactory->addCategory(catMap["name"].toString(), nexusCat, 0); } } diff --git a/src/mainwindow.h b/src/mainwindow.h index 2db1a9d7..67e88846 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -372,6 +372,8 @@ private slots: void importCategories(bool); + void categoriesSaved(); + // update info void nxmUpdateInfoAvailable(QString gameName, QVariant userData, QVariant resultData, int requestID); diff --git a/src/organizer_en.ts b/src/organizer_en.ts index 18eaac8e..389d84ae 100644 --- a/src/organizer_en.ts +++ b/src/organizer_en.ts @@ -224,43 +224,64 @@ p, li { white-space: pre-wrap; } - + + Refresh from Nexus + + + + + <-- Import Nexus Cats + + + + ID - + Internal ID for the category. - + Internal ID for the category. The categories a mod belongs to are stored by this ID. It is recommended you use new IDs for categories you add instead of re-using existing ones. - + Name - - + + Name of the Categorie used for display. - - Nexus IDs + + Parent ID + + + + + If set, the category is defined as a sub-category of another one. Parent ID needs to be a valid category ID. + + + + + + Nexus Categories - + Comma-Separated list of Nexus IDs to be matched to the internal ID. - + <!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; } @@ -271,25 +292,108 @@ p, li { white-space: pre-wrap; } - - Parent ID + + Drag & drop nexus categories from this pane onto the target category on the left. - - If set, the category is defined as a sub-category of another one. Parent ID needs to be a valid category ID. + + Import Nexus Categories? - + + This will overwrite your existing categories with the loaded Nexus categories. + + + + + Error %1: Request to Nexus failed: %2 + + + + Add - + Remove + + + Remove Nexus Mapping(s) + + + + + CategoryFactory + + + + invalid category id {} + + + + + + invalid category line {}: {} + + + + + invalid category line {}: {} ({} cells) + + + + + invalid nexus ID {} + + + + + invalid nexus category line {}: {} ({} cells) + + + + + Failed to save custom categories + + + + + Failed to save nexus category mappings + + + + + + + + invalid category index: %1 + + + + + {} is no valid category id + + + + + invalid category id: %1 + + + + + nexus category id {} maps to internal {} + + + + + nexus category id {} not mapped + + ConflictsTab @@ -347,283 +451,303 @@ p, li { white-space: pre-wrap; } - + Creating a new instance - + <h3>What is an instance?</h3> <p>An instance is a full set of mods, downloads, profiles and configuration for a game. Each game must be managed in its own instance. Mod Organizer can freely switch between instances.</p> - + <html><head/><body><p><a href="https://github.com/ModOrganizer2/modorganizer/wiki/Instances">More information</a></p></body></html> - + Never show this page again - + <h3>Select the type of instance to create.</h3> - + Create a global instance - + Global instances are stored in %1, but some paths can be changed to be on a different drive if necessary. A single installation of Mod Organizer can manage multiple global instances. - + Create a portable instance - + A portable instance stores everything in Mod Organizer's installation folder, currently %1. There can only be one portable instance per installation of Mod Organizer. - + A portable instance already exists. - + <h3>Select the game to manage.</h3> - + Show all supported games - + Filter - + <h3>Select the game edition.</h3> - + This game has multiple variants. The correct one must be selected or Mod Organizer will not be able to launch the game properly. - + <h3>Customize the name for this <span style="white-space: nowrap;">%1</span> instance.</h3> - + Instance name - + There is already an instance with this name. - + The name contains invalid characters. It must be a valid folder name. - + + <h3>Configure your profile settings.</h3> + + + + + Use profile-specific game INI files + + + + + Use profile-specific save games + + + + + Automatic archive invalidation + + + + <h3>Select a folder where the data should be stored.</h3> - + This includes downloads, mods, profiles and overwrite for your <b>%1</b> instance. If there is enough space on this drive, you should use the default folder. - - - - - - + + + + + + ... - + Location - + Warning: This folder already exists. - - - - - - + + + + + + Folder - + Warning: The folder contains invalid characters. - + Mods - + Overwrite - + Base directory - + Warning: The folder %1 already exists. - + Downloads - + Profiles - + Use %BASE_DIR% to refer to the Base Directory. - + Warning: The folder %1 contains invalid characters. - + Show advanced options - + <h3>Link Mod Organizer with your Nexus account</h3> - + Linking with Nexus allows you to download mods directly from Mod Organizer and automatically check for updates. This is optional. - + Connect to Nexus - + Enter API Key Manually - + <h3>Confirmation</h3> - + The instance is about to be created. Review the information below and press 'Finish'. - + Instance creation log - + Launch the new instance - + < Back - + Next > - + Cancel - + Setting up instance %1 - + Setting up an instance %1 - + Creating instance... - + Writing %1... - + Format error. - + Error %1. - + Done. - + Finish @@ -1002,32 +1126,32 @@ Are you absolutely sure you want to proceed? - + failed to download %1: could not open output file: %2 - + Download again? - + A file with the same name "%1" has already been downloaded. Do you want to download it again? The new file will receive a different name. - + Wrong Game - + The download link is for a mod for "%1" but this instance of MO has been set up for "%2". - + There is already a download queued for this file. Mod %1 @@ -1035,12 +1159,12 @@ File %2 - + Already Queued - + There is already a download started for this file. Mod %1: %2 @@ -1048,287 +1172,288 @@ File %3: %4 - + Already Started - - + + remove: invalid download index %1 - + failed to delete %1 - + failed to delete meta file for %1 - + restore: invalid download index: %1 - + cancel: invalid download index %1 - + pause: invalid download index %1 - + resume: invalid download index %1 - + resume (int): invalid download index %1 - + No known download urls. Sorry, this download can't be resumed. - - + + query: invalid download index %1 - + Please enter the nexus mod id - + Mod ID: - + Please select the source game code for %1 - + Hashing download file '%1' - + Cancel - + VisitNexus: invalid download index %1 - + Nexus ID for this Mod is unknown - + OpenFile: invalid download index %1 - + OpenFileInDownloadsFolder: invalid download index %1 - + get pending: invalid download index %1 - + get path: invalid download index %1 - + Main - + Update - + Optional - + Old - + Miscellaneous - + Deleted - + Archived - + Unknown - + display name: invalid download index %1 - + file name: invalid download index %1 - + file time: invalid download index %1 - + file size: invalid download index %1 - + progress: invalid download index %1 - + state: invalid download index %1 - + infocomplete: invalid download index %1 - - - + + + + mod id: invalid download index %1 - + ishidden: invalid download index %1 - + file info: invalid download index %1 - + mark installed: invalid download index %1 - + mark uninstalled: invalid download index %1 - + %1% - %2 - ~%3 - + Memory allocation error (in processing progress event). - + Memory allocation error (in processing downloaded data). - + Information updated - - + + No matching file found on Nexus! Maybe this file is no longer available or it was renamed? - + No file on Nexus matches the selected file by name. Please manually choose the correct one. - + No download server available. Please try again later. - + Failed to request file info from nexus: %1 - + Warning: Content type is: %1 - + Download header content length: %1 downloaded file size: %2 - + Download failed: %1 (%2) - + We were unable to download the file due to errors after four retries. There may be an issue with the Nexus servers. - + failed to re-open %1 - + Unable to write download to drive (return %1). Check the drive's available storage. @@ -1977,22 +2102,22 @@ Right now the only case I know of where this needs to be overwritten is for the FilterList - + Filter separators - + Show separators - + Hide separators - + Contains %1 @@ -2317,68 +2442,88 @@ Right now the only case I know of where this needs to be overwritten is for the - + + This Nexus category has not yet been mapped. Do you wish to proceed without setting a category, proceed and disable automatic Nexus mappings, or stop and configure your category mappings? + + + + + &Proceed + + + + + &Disable + + + + + &Stop && Configure + + + + Invalid file tree returned by plugin. - + Installation failed - + Something went wrong while installing this mod. - + None of the available installer plugins were able to handle that archive. This is likely due to a corrupted or incompatible download or unrecognized archive format. - + no error - + 7z.dll not found - + 7z.dll isn't valid - + archive not found - + failed to open archive - + unsupported archive type - + internal library error - + archive invalid - + unknown archive error @@ -3188,7 +3333,7 @@ p, li { white-space: pre-wrap; } - + Name @@ -3446,7 +3591,7 @@ p, li { white-space: pre-wrap; } - + Endorse Mod Organizer @@ -3530,429 +3675,488 @@ p, li { white-space: pre-wrap; } - + Toolbar and Menu - + Desktop - + Start Menu - + There is no supported sort mechanism for this game. You will probably have to use a third-party tool. - + Crash on exit - + MO crashed while exiting. Some settings may not be saved. Error: %1 - + There are notifications to read - + There are no notifications - + Endorse - + Won't Endorse - + Help on UI - + Documentation - - + + Game Support Wiki - + Chat on Discord - + Report Issue - + Tutorials - + About - + About Qt - + Please enter a name for the new profile - + failed to create profile: %1 - + Show tutorial? - + You are starting Mod Organizer for the first time. Do you want to show a tutorial of its basic features? If you choose no you can always start the tutorial from the "Help" menu. - + Never ask to show tutorials - + Do you know how to mod this game? Do you need to learn? There's a game support wiki available! Click OK to open the wiki. In the future, you can access this link from the "Help" menu. - + + Import Categories + + + + + Please choose how to handle the default category setup. + +If you've already connected to Nexus, you can automatically import Nexus categories for this game (if applicable). Otherwise, use the old Mod Organizer default category structure, or leave the categories blank. + + + + + + &Import Nexus Categories + + + + + Use &Default Categories + + + + + Do &Nothing + + + + + This is your first time running version 2.5 or higher with an old MO2 instance. The category system now relies on an updated system to map Nexus categories. + +In order to assign Nexus categories automatically, you will need to import the Nexus categories for the currently managed game and map them to your preferred category structure. + +You can either manually open the category editor, via the Settings dialog or the category filter sidebar, and set up the mappings as you see fit, or you can automatically import and map the categories as defined on Nexus. + +As a final option, you can disable Nexus category mapping altogether, which can be changed at any time in the Settings dialog. + + + + + &Open Categories Dialog + + + + + &Show Tutorial + + + + + &Close + + + + + &Don't show this again + + + + Downloads in progress - + There are still downloads in progress, do you really want to quit? - + Plugin "%1" failed: %2 - + Plugin "%1" failed - + <Edit...> - + (no executables) - + This bsa is enabled in the ini file so it may be required! - + Activating Network Proxy - + Notice: Your current MO version (%1) is lower than the previously used one (%2). The GUI may not downgrade gracefully, so you may experience oddities. However, there should be no serious issues. - + Start Tutorial? - + You're about to start a tutorial. For technical reasons it's not possible to end the tutorial early. Continue? - + failed to change origin name: %1 - + failed to move "%1" from mod "%2" to "%3": %4 - + Open Game folder - + Open MyGames folder - + Open INIs folder - + Open Instance folder - + Open Mods folder - + Open Profile folder - + Open Downloads folder - + Open MO2 Install folder - + Open MO2 Plugins folder - + Open MO2 Stylesheets folder - + Open MO2 Logs folder - + Restart Mod Organizer - + Mod Organizer must restart to finish configuration changes - + Restart - + Continue - + Some things might be weird. - + Can't change download directory while downloads are in progress! - + Update available - + Do you want to endorse Mod Organizer on %1 now? - + Abstain from Endorsing Mod Organizer - + Are you sure you want to abstain from endorsing Mod Organizer 2? You will have to visit the mod page on the %1 Nexus site to change your mind. - + Thank you for endorsing MO2! :) - + Please reconsider endorsing MO2 on Nexus! - + None of your %1 mods appear to have had recent file updates. - + All of your mods have been checked recently. We restrict update checks to help preserve your available API requests. - + Thank you! - + Thank you for your endorsement! - + Mod ID %1 no longer seems to be available on Nexus. - + Error %1: Request to Nexus failed: %2 - - + + failed to read %1: %2 - + Error - + failed to extract %1 (errorcode %2) - + Extract BSA - + This archive contains invalid hashes. Some files may be broken. - + Extract... - + Remove '%1' from the toolbar - + 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 mod list created - + A file with the same name has already been downloaded. What would you like to do? - + Overwrite - + Rename new file - + Ignore file @@ -4701,7 +4905,7 @@ p, li { white-space: pre-wrap; } ModListChangeCategoryMenu - + Change Categories @@ -4709,236 +4913,241 @@ p, li { white-space: pre-wrap; } ModListContextMenu - + All Mods - + Collapse all - + Collapse others - + Expand all - + Information... - + Send to... - + Lowest priority - + Highest priority - + Priority... - + Separator... - + First conflict - + Last conflict - + Sync to Mods... - + Create Mod... - + Move content to Mod... - + Clear Overwrite... - - - + + + Open in Explorer - + Rename Separator... - + Remove Separator... - - + + Select Color... - - + + Reset Color - + Restore Backup - + Remove Backup... - - + + Ignore missing data - - + + Mark as converted/working - - + + Visit on Nexus - - + + Visit on %1 - + Change versioning scheme - + Force-check updates - + Un-ignore update - + Ignore update - + Enable selected - + Disable selected - + Rename Mod... - + Reinstall Mod - + Remove Mod... - + Create Backup - + Restore hidden files - + Un-Endorse - - + + Endorse - + Won't endorse - + Endorsement state unknown - + + Remap Category (From Nexus) + + + + Start tracking - + Stop tracking - + Tracked state unknown @@ -5032,11 +5241,16 @@ p, li { white-space: pre-wrap; } + Auto assign categories + + + + Refresh - + Export to csv... @@ -5044,7 +5258,7 @@ p, li { white-space: pre-wrap; } ModListPrimaryCategoryMenu - + Primary Category @@ -5099,313 +5313,313 @@ Please enter the name: ModListViewActions - + Choose Mod - + Mod Archive - - + + Create Mod... - + This will create an empty mod. Please enter a name: - - + + A mod with this name already exists - + Create Separator... - + This will create a new separator. Please enter a name: - + A separator with this name already exists - + Really enable %1 mod(s)? - + Really disable %1 mod(s)? - - - + + + Confirm - - + + You are not currently authenticated with Nexus. Please do so under Settings -> Nexus. - + Export to csv - + CSV (Comma Separated Values) is a format that can be imported in programs like Excel to create a spreadsheet. You can also use online editors and converters instead. - + Select what mods you want export: - + All installed mods - + Only active (checked) mods from your current profile - + All currently visible mods in the mod list - + Choose what Columns to export: - + Mod_Priority - + Mod_Name - + Notes_column - + Mod_Status - + Primary_Category - + Nexus_ID - + Mod_Nexus_URL - + Mod_Version - + Install_Date - + Download_File_Name - + export failed: %1 - + Failed to display overwrite dialog: %1 - + Set Priority - + Set the priority of the selected mods - + failed to rename mod: %1 - + Remove the following mods?<br><ul>%1</ul> - + failed to remove mod: %1 - + 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. - + Opening Nexus Links - + You are trying to open %1 links to Nexus Mods. Are you sure you want to do this? - - + + Opening Web Pages - - + + You are trying to open %1 Web Pages. Are you sure you want to do this? - - - + + + Failed - + Installation file no longer exists - + Mods installed with old versions of MO can't be reinstalled in this way. - + Failed to create backup. - + Restore all hidden files in the following mods?<br><ul>%1</ul> - - + + Are you sure? - + About to restore all hidden files in: - + Endorsing multiple mods will take a while. Please wait... - + Overwrite? - + This will replace the existing mod "%1". Continue? - + failed to remove mod "%1" - + failed to rename "%1" to "%2" - + Move successful. - + This will move all files from overwrite into a new, regular mod. Please enter a name: - + About to recursively delete: @@ -5470,32 +5684,32 @@ Please enter a name: NexusInterface - + Please pick the mod ID for "%1" - + You must authorize MO2 in Settings -> Nexus to use the Nexus API. - + You've exceeded the Nexus API rate limit and requests are now being throttled. Your next batch of requests will be available in approximately %1 minutes and %2 seconds. - + Aborting download: Either you clicked on a premium-only link and your account is not premium, or the download link was generated by a different account than the one stored in Mod Organizer. - + empty response - + invalid response @@ -5586,207 +5800,207 @@ Please enter a name: OrganizerCore - + File is write protected - + Invalid file format (probably a bug) - + Unknown error %1 - + Failed to write settings - + An error occurred trying to write back MO settings to %1: %2 - + Download started - + Download failed - + The selected profile '%1' does not exist. The profile '%2' will be used instead - + Installation cancelled - + Another installation is currently in progress. - + Installation successful - + Configure Mod - + This mod contains ini tweaks. Do you want to configure them now? - + mod not found: %1 - + Extraction cancelled - + The installation was cancelled while extracting files. If this was prior to a FOMOD setup, this warning may be ignored. However, if this was during installation, the mod will likely be missing files. - + file not found: %1 - + failed to generate preview for %1 - + Sorry - + Sorry, can't preview anything. This function currently does not support extracting from bsas. - + File '%1' not found. - + Failed to generate preview for %1 - + Failed to refresh list of esps: %1 - + Multiple esps/esls activated, please check that they don't conflict. - + You need to be logged in with Nexus - + 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. - + MO1 "Script Extender" load mechanism has left hook.dll in your game folder - - + + Description missing - + <a href="%1">hook.dll</a> has been found in your game folder (right click to copy the full path). This is most likely a leftover of setting the ModOrganizer 1 load mechanism to "Script Extender", in which case you must remove this file either by changing the load mechanism in ModOrganizer 1 or manually removing the file, otherwise the game is likely to crash and burn. - + failed to save load order: %1 - + Error - + The designated write target "%1" is not enabled. @@ -6007,92 +6221,97 @@ Continue? - + failed to update esp info for file %1 (source id: %2), error: %3 - + Plugin not found: %1 - + Origin - + This plugin can't be disabled (enforced by the game). - + Author - + Description - + Missing Masters - + Enabled Masters - + Loads Archives - + There are Archives connected to this plugin. Their assets will be added to your game, overwriting in case of conflicts following the plugin order. Loose files will always overwrite assets from Archives. (This flag only checks for Archives from the same mod as the plugin) - + Loads INI settings - + There is an ini file connected to this plugin. Its settings will be added to your game settings, overwriting in case of conflicts. - - This ESP is flagged as an ESL. It will adhere to the ESP load order but the records will be loaded in ESL space. + + This %1 is flagged as an ESL. It will adhere to the %1 load order but the records will be loaded in ESL space. - + + This game does not currently permit custom plugin loading. There may be manual workarounds. + + + + Incompatible with %1 - + Depends on missing %1 - + Warning - + Error - + failed to restore load order for %1 @@ -6336,61 +6555,61 @@ p, li { white-space: pre-wrap; } - + failed to write mod list: %1 - + failed to update tweaked ini file, wrong settings may be used: %1 - + failed to create tweaked ini: %1 - + failed to open %1 - + "%1" is missing or inaccessible - - - - - + + + + + invalid mod index: %1 - + A mod named "overwrite" was detected, disabled, and moved to the highest priority on the mod list. You may want to rename this mod and enable it again. - + Delete profile-specific save games? - + Do you want to delete the profile-specific save games? (If you select "No", the save games will show up again if you re-enable profile-specific save games) - + Missing profile-specific game INI files! - + Some of your profile-specific game INI files were missing. They will now be copied from the vanilla game folder. You might want to double-check your settings. Missing files: @@ -6398,12 +6617,12 @@ Missing files: - + Delete profile-specific game INI files? - + Do you want to delete the profile-specific game INI files? (If you select "No", the INI files will be used again if you re-enable profile-specific game INI files.) @@ -6693,78 +6912,60 @@ p, li { white-space: pre-wrap; } - - Failed to save custom categories - - - - - - - - invalid category index: %1 - - - - + Active - + Update available - + Has category - + Conflicted - + Has hidden files - + Endorsed - + Has backup - + Managed - + Has valid game data - + Has Nexus ID - + Tracked on Nexus - - - invalid category id: %1 - - Is overwritten (loose files) @@ -6796,25 +6997,35 @@ p, li { white-space: pre-wrap; } - + failed to start application: %1 - + Executable '%1' not found in instance '%2'. - + Failed to run '%1'. The logs might have more information. - + Failed to run '%1'. The logs might have more information. %2 + + + Download URL must start with https:// + + + + + Download started + + Creating %1 @@ -6834,7 +7045,7 @@ p, li { white-space: pre-wrap; } - + Instance type: %1 @@ -6844,81 +7055,81 @@ p, li { white-space: pre-wrap; } - + Find game installation for %1 - + Find game installation - - - + + + Unrecognized game - + The folder %1 does not seem to contain a game Mod Organizer can manage. - + See details for the list of supported games. - + No installation found - + Browse... - + The folder must contain a valid game installation - - + + Microsoft Store game - + The folder %1 seems to be a Microsoft Store game install. Games installed through the Microsoft Store are not supported by Mod Organizer and will not work properly. - - - + + + Use this folder for %1 - + Use this folder - - - + + + I know what I'm doing - - - + + + @@ -6934,69 +7145,103 @@ p, li { white-space: pre-wrap; } - + The folder %1 does not seem to contain an installation for <span style="white-space: nowrap; font-weight: bold;">%2</span> or for any other game Mod Organizer can manage. - - + + Incorrect game - + The folder %1 seems to contain an installation for <span style="white-space: nowrap; font-weight: bold;">%2</span>, not <span style="white-space: nowrap; font-weight: bold;">%3</span>. - + Manage %1 instead - + Instance location: %1 - + Instance name: %1 - - + + Profile settings: + + + + + Local INIs: %1 + + + + + + + yes + + + + + + + no + + + + + Local Saves: %1 + + + + + Automatic Archive Invalidation: %1 + + + + + Base directory: %1 - + Downloads - + Mods - + Profiles - + Overwrite - + Game: %1 - + Game location: %1 @@ -7138,7 +7383,7 @@ Destination: - + @@ -7150,7 +7395,7 @@ Destination: - + Failed to create "%1". Your user account probably lacks permission. @@ -7257,23 +7502,23 @@ Destination: - + Please use "Help" from the toolbar to get usage instructions to all elements - + Visit %1 on Nexus - - + + <Manage...> - + failed to parse profile %1: %2 @@ -7411,7 +7656,7 @@ Destination: - + One of the configured MO2 directories (profiles, mods, or overwrite) is on a path containing a symbolic (or other) link. This is likely to be incompatible with MO2's virtual filesystem. @@ -7421,12 +7666,12 @@ Destination: - + failed to access %1 - + failed to set file time %1 @@ -7479,19 +7724,19 @@ This program is known to cause issues with Mod Organizer, such as freezing or bl - - - + + + attempt to store setting for unknown plugin "%1" - + Failed - + Failed to start the helper application: %1 @@ -7528,12 +7773,12 @@ This program is known to cause issues with Mod Organizer, such as freezing or bl - + Confirm? - + This will reset all the choices you made to dialogs and make them all visible again. Continue? @@ -7552,26 +7797,26 @@ This program is known to cause issues with Mod Organizer, such as freezing or bl - - + + N/A - + Executables (*.exe) - + All Files (*.*) - + Select the browser executable @@ -7954,17 +8199,17 @@ You can restart Mod Organizer as administrator and try launching the program aga - + %1, #%2, Level %3, %4 - + failed to open %1 - + wrong file format - expected %1 got %2 @@ -8455,128 +8700,148 @@ p, li { white-space: pre-wrap; } + Profile Defaults + + + + + Local INIs + + + + + Local Saves + + + + + Automatic Archive Invalidation + + + + Miscellaneous - - + + Dialogs will always be centered on the main window, but will remember their size. - + Always center dialogs - + Show confirmation when changing instance - - + + Show the menubar when the Alt key is pressed - + Show menubar when pressing Alt - + Whether double-clicking on a file opens the preview window or launches the program associated with it. This applies to the Data tab as well as the Conflicts and Filetree tabs in the mod info window. - + Open previews on double-click - - + + Reset all choices made in dialogs. - + Reset Dialog Choices - - + + Modify the categories available to arrange your mods. - + Configure Mod Categories - + Theme - + Style - - + + Visual theme of the user interface. - + Explore... - + Colors - - + + Reset all colors to their default value. - + Reset Colors - + Mod List - - + + Colors set on separators will also be shown in the mod list scrollbar at the location of the separator. This can be useful for quickly navigating to a specific separator. - + Show mod list separator colors on the scrollbar - + 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. @@ -8584,447 +8849,452 @@ If you disable this feature, MO will only display official DLCs this way. Please - + Display mods installed outside MO - - + + Save the current filters when closing MO2 and restore them on startup. - + Remember selected filters after restarting MO - - + + Check if updates are available for mods after installing them. - + Check for updates when installing mods - - + + Automatically collapse separators, categories or nexus ids after a delay when hovering them during drag. - + Automatically collapse items during drag on hover - + Collapsible Separators - - + + Highlight collapsed separators based on conflicts and plugins from mods inside them. - + on separators - + Enable when sorting by - + Show conflicts and plugins - - + + When selecting a collapsed separator, highlight conflicting mods and plugins from mods inside the separator. - + from separators - + ascending priority - + descending priority - + Show icons on separators - + conflicts - + flags - + content - + version - - + + Do not share the collapse/expanded state of separators between profiles. - + Profile-specific collapse states for separators - + Paths - - - - - + + + + + ... - + Caches - + Overwrite - - + + Directory where downloads are stored. - + Downloads - + Profiles - + 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). - + Mods - + Managed Game - + Base Directory - + Use %BASE_DIR% to refer to the Base Directory. - + All directories must be writable. - + Nexus - + Nexus Account - + User ID: - + Name: - + Account: - + Statistics - + Daily requests: - + Hourly requests: - + Nexus Connection - + Connect to Nexus - + Manually enter the API key and try to login - + Enter API Key Manually - + Clear the stored Nexus API key and force reauthorization. - + Disconnect from Nexus - - + + Options - + Endorsement Integration - + Tracked Integration - - + + Use Nexus category mappings + + + + + <html><head/><body><p>By default, a counter is displayed in the bottom right corner. This informs the user of their remaining API requests. The Nexus API becomes unusable once these API requests run out. Checking this option will hide that counter.</p></body></html> - + Hide API Request Counter - + Associate with "Download with manager" links - + Remove cache and cookies. - + Clear Cache - + Servers - + Known Servers (updated on download) - + Preferred Servers (Drag & Drop) - + Plugins - + Author: - + Version: - + Description: - + Enabled - + Key - + Value - + No plugin found. - + Blacklisted Plugins (use <del> to remove): - + Workarounds - + 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 - + Enable parsing of Archives. This is an Experimental Feature. Has negative effects on performance and known incorrectness. - + <html><head/><body><p>By default, MO will parse archive files (BSA, BA2) to calculate conflicts between the contents of the archive files and other loose files. This process has a noticeable cost in performance.</p><p>This feature should not be confused with the archive management feature offered by MO1. MO2 will only show conflicts with archives and will NOT load them into the game or program.</p><p>If you disable this feature, MO will only display conflicts between loose files.</p></body></html> - + Enable archives parsing (experimental) - - + + Disable this to prevent the GUI from being locked when running an executable. This may result in abnormal behavior. - + Lock GUI when running executable - + Steam - + Password - + Username - + 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; } @@ -9040,68 +9310,68 @@ p, li { white-space: pre-wrap; } - + Network - + 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 System HTTP Proxy - - - - - - + + + + + + Use "%1" as a placeholder for the URL. - + Custom browser - - + + Resets the window geometries for all windows. This can be useful if a window becomes too small or too large, if a column becomes too thin or too wide, and in similar situations. - + Reset Window Geometries - + Add executables to the blacklist to prevent them from accessing the virtual file system. This is useful to prevent unintended programs from being hooked. Hooking unintended @@ -9110,54 +9380,54 @@ programs you are intentionally running. - + Add executables to the blacklist to prevent them from accessing the virtual file system. This is useful to prevent unintended programs from being hooked. Hooking unintended programs may affect the execution of these programs or the programs you are intentionally running. - + Executables Blacklist - - + + 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. - + Diagnostics - + Logs and Crashes - + 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 regular use. On the "Error" level the log file usually remains empty. @@ -9165,17 +9435,17 @@ For the other games this is not a sufficient replacement for AI! - + 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. @@ -9186,17 +9456,17 @@ For the other games this is not a sufficient replacement for AI! - + Max Dumps To Keep - + 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. @@ -9204,22 +9474,22 @@ For the other games this is not a sufficient replacement for AI! - + Integrated LOOT - + LOOT Log Level - + Hint: right click link and copy link location - + 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. diff --git a/src/organizercore.cpp b/src/organizercore.cpp index e3d1ff29..3781a4e1 100644 --- a/src/organizercore.cpp +++ b/src/organizercore.cpp @@ -1,4 +1,5 @@ #include "organizercore.h" +#include "categoriesdialog.h" #include "credentialsdialog.h" #include "delayedfilewriter.h" #include "directoryrefresher.h" @@ -759,8 +760,9 @@ OrganizerCore::doInstall(const QString& archivePath, GuessedValue modNa // this prevents issue with third-party plugins, e.g., if the installed mod is // activated before the structure is ready // - // we need to fetch modIndex() within the call back because the index is only valid - // after the call to refresh(), but we do not want to connect after refresh() + // we need to fetch modIndex() within the call back because the index is only + // valid after the call to refresh(), but we do not want to connect after + // refresh() // connect( this, &OrganizerCore::directoryStructureReady, this, @@ -801,16 +803,26 @@ OrganizerCore::doInstall(const QString& archivePath, GuessedValue modNa emit modInstalled(modName); return {modIndex, modInfo}; } else { - m_InstallationManager.notifyInstallationEnd(result, nullptr); - if (m_InstallationManager.wasCancelled()) { - QMessageBox::information( - qApp->activeWindow(), tr("Extraction cancelled"), - tr("The installation was cancelled while extracting files. " - "If this was prior to a FOMOD setup, this warning may be ignored. " - "However, if this was during installation, the mod will likely be missing " - "files."), - QMessageBox::Ok); - refresh(); + if (result.result() == MOBase::IPluginInstaller::RESULT_CATEGORYREQUESTED) { + CategoriesDialog dialog(&pluginContainer(), qApp->activeWindow()); + + if (dialog.exec() == QDialog::Accepted) { + dialog.commitChanges(); + refresh(); + } + } else { + m_InstallationManager.notifyInstallationEnd(result, nullptr); + if (m_InstallationManager.wasCancelled()) { + QMessageBox::information( + qApp->activeWindow(), tr("Extraction cancelled"), + tr("The installation was cancelled while extracting files. " + "If this was prior to a FOMOD setup, this warning may be ignored. " + "However, if this was during installation, the mod will likely be " + "missing " + "files."), + QMessageBox::Ok); + refresh(); + } } } diff --git a/src/settings.cpp b/src/settings.cpp index ec9bb362..17de38ea 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -1936,6 +1936,16 @@ void NexusSettings::setTrackedIntegration(bool b) const set(m_Settings, "Settings", "tracked_integration", b); } +bool NexusSettings::categoryMappings() const +{ + return get(m_Settings, "Settings", "category_mappings", true); +} + +void NexusSettings::setCategoryMappings(bool b) const +{ + set(m_Settings, "Settings", "category_mappings", b); +} + void NexusSettings::registerAsNXMHandler(bool force) { const auto nxmPath = QCoreApplication::applicationDirPath() + "/" + diff --git a/src/settings.h b/src/settings.h index 66dbf81c..e7ca47a9 100644 --- a/src/settings.h +++ b/src/settings.h @@ -514,6 +514,11 @@ public: bool trackedIntegration() const; void setTrackedIntegration(bool b) const; + // returns whether nexus category mappings are enabled + // + bool categoryMappings() const; + void setCategoryMappings(bool b) const; + // registers MO as the handler for nxm links // // if 'force' is true, the registration dialog will be shown even if the user diff --git a/src/settingsdialog.ui b/src/settingsdialog.ui index 27949c3a..40921d9d 100644 --- a/src/settingsdialog.ui +++ b/src/settingsdialog.ui @@ -17,7 +17,7 @@ - 0 + 4 @@ -1052,8 +1052,8 @@ If you disable this feature, MO will only display official DLCs this way. Please 0 0 - 778 - 497 + 761 + 515 @@ -1340,6 +1340,16 @@ If you disable this feature, MO will only display official DLCs this way. Please + + + + Use Nexus category mappings + + + true + + + @@ -1732,8 +1742,8 @@ If you disable this feature, MO will only display official DLCs this way. Please 0 0 - 778 - 475 + 390 + 342 diff --git a/src/settingsdialognexus.cpp b/src/settingsdialognexus.cpp index 2e706e42..abd487f1 100644 --- a/src/settingsdialognexus.cpp +++ b/src/settingsdialognexus.cpp @@ -294,6 +294,7 @@ NexusSettingsTab::NexusSettingsTab(Settings& s, SettingsDialog& d) : SettingsTab { ui->endorsementBox->setChecked(settings().nexus().endorsementIntegration()); ui->trackedBox->setChecked(settings().nexus().trackedIntegration()); + ui->categoryMappingsBox->setChecked(settings().nexus().categoryMappings()); ui->hideAPICounterBox->setChecked(settings().interface().hideAPICounter()); // display server preferences @@ -359,6 +360,7 @@ void NexusSettingsTab::update() { settings().nexus().setEndorsementIntegration(ui->endorsementBox->isChecked()); settings().nexus().setTrackedIntegration(ui->trackedBox->isChecked()); + settings().nexus().setCategoryMappings(ui->categoryMappingsBox->isChecked()); settings().interface().setHideAPICounter(ui->hideAPICounterBox->isChecked()); auto servers = settings().network().servers(); -- cgit v1.3.1