summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/iuserinterface.h4
-rw-r--r--src/mainwindow.cpp191
-rw-r--r--src/mainwindow.h13
-rw-r--r--src/mainwindow.ui107
-rw-r--r--src/modinfo.cpp2
-rw-r--r--src/modinfooverwrite.cpp2
-rw-r--r--src/modinforegular.cpp2
-rw-r--r--src/modlist.cpp2
-rw-r--r--src/organizercore.cpp13
-rw-r--r--src/organizercore.h1
10 files changed, 331 insertions, 6 deletions
diff --git a/src/iuserinterface.h b/src/iuserinterface.h
index 255c7ac0..7ce71c24 100644
--- a/src/iuserinterface.h
+++ b/src/iuserinterface.h
@@ -28,6 +28,10 @@ public:
virtual void displayModInformation(ModInfo::Ptr modInfo, unsigned int index, int tab) = 0;
+ virtual void updateBSAList(const QStringList &defaultArchives, const QStringList &activeArchives) = 0;
+
+ virtual MOBase::DelayedFileWriterBase &archivesWriter() = 0;
+
virtual ILockedWaitingForProcess* lock() = 0;
virtual void unlock() = 0;
};
diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp
index 85808e8d..141bcf2a 100644
--- a/src/mainwindow.cpp
+++ b/src/mainwindow.cpp
@@ -200,6 +200,7 @@ MainWindow::MainWindow(QSettings &initSettings
, m_OrganizerCore(organizerCore)
, m_PluginContainer(pluginContainer)
, m_DidUpdateMasterList(false)
+ , m_ArchiveListWriter(std::bind(&MainWindow::saveArchiveList, this))
{
QWebEngineProfile::defaultProfile()->setPersistentCookiesPolicy(QWebEngineProfile::NoPersistentCookies);
QWebEngineProfile::defaultProfile()->setHttpCacheMaximumSize(52428800);
@@ -278,6 +279,8 @@ MainWindow::MainWindow(QSettings &initSettings
ui->espList->setItemDelegateForColumn(PluginList::COL_FLAGS, new GenericIconDelegate(ui->espList));
ui->espList->installEventFilter(m_OrganizerCore.pluginList());
+ ui->bsaList->setLocalMoveOnly(true);
+
bool pluginListAdjusted = registerWidgetState(ui->espList->objectName(), ui->espList->header(), "plugin_list_state");
registerWidgetState(ui->dataTree->objectName(), ui->dataTree->header());
registerWidgetState(ui->downloadView->objectName(),
@@ -358,6 +361,9 @@ MainWindow::MainWindow(QSettings &initSettings
connect(this, SIGNAL(styleChanged(QString)), this, SLOT(updateStyle(QString)));
+ m_CheckBSATimer.setSingleShot(true);
+ connect(&m_CheckBSATimer, SIGNAL(timeout()), this, SLOT(checkBSAList()));
+
connect(ui->espList->selectionModel(), SIGNAL(selectionChanged(QItemSelection, QItemSelection)), this, SLOT(esplistSelectionsChanged(QItemSelection)));
connect(ui->modList->selectionModel(), SIGNAL(selectionChanged(QItemSelection, QItemSelection)), this, SLOT(modlistSelectionsChanged(QItemSelection)));
@@ -1378,6 +1384,147 @@ static QStringList toStringList(InputIterator current, InputIterator end)
return result;
}
+void MainWindow::updateBSAList(const QStringList &defaultArchives, const QStringList &activeArchives)
+{
+ m_DefaultArchives = defaultArchives;
+ ui->bsaList->clear();
+ ui->bsaList->header()->setSectionResizeMode(QHeaderView::ResizeToContents);
+ std::vector<std::pair<UINT32, QTreeWidgetItem*>> items;
+
+ BSAInvalidation * invalidation = m_OrganizerCore.managedGame()->feature<BSAInvalidation>();
+ std::vector<FileEntry::Ptr> files = m_OrganizerCore.directoryStructure()->getFiles();
+
+ QStringList plugins = m_OrganizerCore.findFiles("", [](const QString &fileName) -> bool {
+ return fileName.endsWith(".esp", Qt::CaseInsensitive)
+ || fileName.endsWith(".esm", Qt::CaseInsensitive);
+ });
+
+ auto hasAssociatedPlugin = [&](const QString &bsaName) -> bool {
+ for (const QString &pluginName : plugins) {
+ QFileInfo pluginInfo(pluginName);
+ if (bsaName.startsWith(QFileInfo(pluginName).baseName(), Qt::CaseInsensitive)
+ && (m_OrganizerCore.pluginList()->state(pluginInfo.fileName()) == IPluginList::STATE_ACTIVE)) {
+ return true;
+ }
+ }
+ return false;
+ };
+
+ for (FileEntry::Ptr current : files) {
+ QFileInfo fileInfo(ToQString(current->getName().c_str()));
+
+ if (fileInfo.suffix().toLower() == "bsa" || fileInfo.suffix().toLower() == "ba2") {
+ int index = activeArchives.indexOf(fileInfo.fileName());
+ if (index == -1) {
+ index = 0xFFFF;
+ }
+ else {
+ index += 2;
+ }
+
+ if ((invalidation != nullptr) && invalidation->isInvalidationBSA(fileInfo.fileName())) {
+ index = 1;
+ }
+
+ int originId = current->getOrigin();
+ FilesOrigin & origin = m_OrganizerCore.directoryStructure()->getOriginByID(originId);
+
+ QTreeWidgetItem * newItem = new QTreeWidgetItem(QStringList()
+ << fileInfo.fileName()
+ << ToQString(origin.getName()));
+ newItem->setData(0, Qt::UserRole, index);
+ newItem->setData(1, Qt::UserRole, originId);
+ newItem->setFlags(newItem->flags() & ~Qt::ItemIsDropEnabled | Qt::ItemIsUserCheckable);
+ newItem->setCheckState(0, (index != -1) ? Qt::Checked : Qt::Unchecked);
+ newItem->setData(0, Qt::UserRole, false);
+ if (m_OrganizerCore.settings().forceEnableCoreFiles()
+ && defaultArchives.contains(fileInfo.fileName())) {
+ newItem->setCheckState(0, Qt::Checked);
+ newItem->setDisabled(true);
+ newItem->setData(0, Qt::UserRole, true);
+ } else if (fileInfo.fileName().compare("update.bsa", Qt::CaseInsensitive) == 0) {
+ newItem->setCheckState(0, Qt::Checked);
+ newItem->setDisabled(true);
+ } else if (hasAssociatedPlugin(fileInfo.fileName())) {
+ newItem->setCheckState(0, Qt::Checked);
+ newItem->setDisabled(true);
+ }
+ if (index < 0) index = 0;
+
+ UINT32 sortValue = ((origin.getPriority() & 0xFFFF) << 16) | (index & 0xFFFF);
+ items.push_back(std::make_pair(sortValue, newItem));
+ }
+ }
+ std::sort(items.begin(), items.end(), BySortValue);
+
+ for (auto iter = items.begin(); iter != items.end(); ++iter) {
+ int originID = iter->second->data(1, Qt::UserRole).toInt();
+
+ FilesOrigin origin = m_OrganizerCore.directoryStructure()->getOriginByID(originID);
+ QString modName("data");
+ unsigned int modIndex = ModInfo::getIndex(ToQString(origin.getName()));
+ if (modIndex != UINT_MAX) {
+ ModInfo::Ptr modInfo = ModInfo::getByIndex(modIndex);
+ modName = modInfo->name();
+ }
+ QList<QTreeWidgetItem*> items = ui->bsaList->findItems(modName, Qt::MatchFixedString);
+ QTreeWidgetItem * subItem = nullptr;
+ if (items.length() > 0) {
+ subItem = items.at(0);
+ }
+ else {
+ subItem = new QTreeWidgetItem(QStringList(modName));
+ subItem->setFlags(subItem->flags() & ~Qt::ItemIsDragEnabled);
+ ui->bsaList->addTopLevelItem(subItem);
+ }
+ subItem->addChild(iter->second);
+ subItem->setExpanded(true);
+ }
+ checkBSAList();
+}
+
+void MainWindow::checkBSAList()
+{
+ DataArchives * archives = m_OrganizerCore.managedGame()->feature<DataArchives>();
+
+ if (archives != nullptr) {
+ ui->bsaList->blockSignals(true);
+ ON_BLOCK_EXIT([&]() { ui->bsaList->blockSignals(false); });
+
+ QStringList defaultArchives = archives->archives(m_OrganizerCore.currentProfile());
+
+ bool warning = false;
+
+ for (int i = 0; i < ui->bsaList->topLevelItemCount(); ++i) {
+ bool modWarning = false;
+ QTreeWidgetItem * tlItem = ui->bsaList->topLevelItem(i);
+ for (int j = 0; j < tlItem->childCount(); ++j) {
+ QTreeWidgetItem * item = tlItem->child(j);
+ QString filename = item->text(0);
+ item->setIcon(0, QIcon());
+ item->setToolTip(0, QString());
+
+ if (item->checkState(0) == Qt::Unchecked) {
+ if (defaultArchives.contains(filename)) {
+ item->setIcon(0, QIcon(":/MO/gui/warning"));
+ item->setToolTip(0, tr("This bsa is enabled in the ini file so it may be required!"));
+ modWarning = true;
+ }
+ }
+ }
+ if (modWarning) {
+ ui->bsaList->expandItem(ui->bsaList->topLevelItem(i));
+ warning = true;
+ }
+ }
+ if (warning) {
+ ui->tabWidget->setTabIcon(1, QIcon(":/MO/gui/warning"));
+ } else {
+ ui->tabWidget->setTabIcon(1, QIcon());
+ }
+ }
+}
+
void MainWindow::saveModMetas()
{
for (unsigned int i = 0; i < ModInfo::getNumMods(); ++i) {
@@ -1524,10 +1671,12 @@ void MainWindow::on_tabWidget_currentChanged(int index)
if (index == 0) {
m_OrganizerCore.refreshESPList();
} else if (index == 1) {
- refreshDataTree();
+ m_OrganizerCore.refreshBSAList();
} else if (index == 2) {
- refreshSaveList();
+ refreshDataTree();
} else if (index == 3) {
+ refreshSaveList();
+ } else if (index == 4) {
ui->downloadView->scrollToBottom();
}
}
@@ -1806,6 +1955,7 @@ void MainWindow::modorder_changed()
}
m_OrganizerCore.refreshBSAList();
m_OrganizerCore.currentProfile()->modlistWriter().write();
+ m_ArchiveListWriter.write();
m_OrganizerCore.directoryStructure()->getFileRegister()->sortOrigins();
{ // refresh selection
@@ -2741,6 +2891,31 @@ void MainWindow::replaceCategories_MenuHandler() {
refreshFilters();
}
+void MainWindow::saveArchiveList()
+{
+ if (m_OrganizerCore.isArchivesInit()) {
+ SafeWriteFile archiveFile(m_OrganizerCore.currentProfile()->getArchivesFileName());
+ for (int i = 0; i < ui->bsaList->topLevelItemCount(); ++i) {
+ QTreeWidgetItem * tlItem = ui->bsaList->topLevelItem(i);
+ for (int j = 0; j < tlItem->childCount(); ++j) {
+ QTreeWidgetItem * item = tlItem->child(j);
+ if (item->checkState(0) == Qt::Checked) {
+ // in managed mode, "register" all enabled archives, otherwise register only the files registered in the ini
+ if (ui->manageArchivesBox->isChecked() ||
+ item->data(0, Qt::UserRole).toBool()) {
+ archiveFile->write(item->text(0).toUtf8().append("\r\n"));
+ }
+ }
+ }
+ }
+ if (archiveFile.commitIfDifferent(m_ArchiveListHash)) {
+ qDebug("%s saved", qPrintable(QDir::toNativeSeparators(m_OrganizerCore.currentProfile()->getArchivesFileName())));
+ }
+ } else {
+ qWarning("archive list not initialised");
+ }
+}
+
void MainWindow::checkModsForUpdates()
{
statusBar()->show();
@@ -3957,6 +4132,12 @@ void MainWindow::displayColumnSelection(const QPoint &pos)
}
}
+void MainWindow::on_bsaList_itemChanged(QTreeWidgetItem*, int)
+{
+ m_ArchiveListWriter.write();
+ m_CheckBSATimer.start(500);
+}
+
void MainWindow::on_actionProblems_triggered()
{
ProblemsDialog problems(m_PluginContainer.plugins<IPluginDiagnose>(), this);
@@ -4543,6 +4724,12 @@ void MainWindow::on_categoriesOrBtn_toggled(bool checked)
}
}
+void MainWindow::on_managedArchiveLabel_linkHovered(const QString&)
+{
+ QToolTip::showText(QCursor::pos(),
+ ui->managedArchiveLabel->toolTip());
+}
+
void MainWindow::dragEnterEvent(QDragEnterEvent *event)
{
//Accept copy or move drags to the download window. Link drags are not
diff --git a/src/mainwindow.h b/src/mainwindow.h
index 575bf020..45a41137 100644
--- a/src/mainwindow.h
+++ b/src/mainwindow.h
@@ -120,12 +120,15 @@ public:
virtual void unlock() override;
bool addProfile();
+ void updateBSAList(const QStringList &defaultArchives, const QStringList &activeArchives);
void refreshDataTree();
void refreshSaveList();
void setModListSorting(int index);
void setESPListSorting(int index);
+ void saveArchiveList();
+
void registerPluginTool(MOBase::IPluginTool *tool);
void registerModPage(MOBase::IPluginModPage *modPage);
@@ -148,6 +151,8 @@ public:
virtual bool closeWindow();
virtual void setWindowEnabled(bool enabled);
+ virtual MOBase::DelayedFileWriterBase &archivesWriter() override { return m_ArchiveListWriter; }
+
public slots:
void displayColumnSelection(const QPoint &pos);
@@ -346,6 +351,8 @@ private:
std::vector<QTreeWidgetItem*> m_RemoveWidget;
+ QByteArray m_ArchiveListHash;
+
bool m_DidUpdateMasterList;
LockedDialogBase *m_LockDialog { nullptr };
@@ -355,6 +362,8 @@ private:
std::vector<std::pair<QString, QHeaderView*>> m_PersistedGeometry;
+ MOBase::DelayedFileWriter m_ArchiveListWriter;
+
enum class ShortcutType {
Toolbar,
Desktop,
@@ -478,6 +487,8 @@ private slots:
void startExeAction();
+ void checkBSAList();
+
void updateProblemsButton();
void saveModMetas();
@@ -552,6 +563,7 @@ private slots: // ui slots
void on_categoriesList_itemSelectionChanged();
void on_linkButton_pressed();
void on_showHiddenBox_toggled(bool checked);
+ void on_bsaList_itemChanged(QTreeWidgetItem *item, int column);
void on_bossButton_clicked();
void on_saveButton_clicked();
@@ -561,6 +573,7 @@ private slots: // ui slots
void on_actionCopy_Log_to_Clipboard_triggered();
void on_categoriesAndBtn_toggled(bool checked);
void on_categoriesOrBtn_toggled(bool checked);
+ void on_managedArchiveLabel_linkHovered(const QString &link);
};
diff --git a/src/mainwindow.ui b/src/mainwindow.ui
index 26b9e375..1e7339b8 100644
--- a/src/mainwindow.ui
+++ b/src/mainwindow.ui
@@ -902,6 +902,113 @@ p, li { white-space: pre-wrap; }
</item>
</layout>
</widget>
+ <widget class="QWidget" name="bsaTab">
+ <attribute name="title">
+ <string>Archives</string>
+ </attribute>
+ <layout class="QVBoxLayout" name="verticalLayout_9">
+ <property name="leftMargin">
+ <number>6</number>
+ </property>
+
+ <property name="topMargin">
+ <number>6</number>
+ </property>
+ <property name="rightMargin">
+ <number>6</number>
+ </property>
+ <property name="bottomMargin">
+ <number>6</number>
+ </property>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_9" stretch="0,1">
+ <item>
+ <widget class="QCheckBox" name="manageArchivesBox">
+ <property name="text">
+ <string/>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="managedArchiveLabel">
+ <property name="toolTip">
+ <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;BSAs are bundles of game assets (textures, scripts, ...). By default, the engine loads these bundles in a separate step from loose files. MO can manage those archives to align their load order with that of loose files:&lt;/p&gt;&lt;p&gt;If archives are &lt;span style=&quot; font-weight:600;&quot;&gt;managed&lt;/span&gt;, their load order is specified by the priority of the corresponding mod (left pane), the same as the loose files. You can manually enable any BSA that has no corresponding plugin active.&lt;br/&gt;&lt;/p&gt;&lt;p&gt;If archives are &lt;span style=&quot; font-weight:600;&quot;&gt;not managed&lt;/span&gt; their load order is specified by the priority of the corresponding plugin (right pane, plugins tab). You can then not manually enable BSAs where the plugin isn't active.&lt;/p&gt;&lt;p&gt;In either case you can not disable archives if there is a matching plugin, the game will load them no matter what.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+ </property>
+ <property name="text">
+ <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Have MO manage archives (&lt;a href=&quot;#&quot;&gt;&lt;span style=&quot; text-decoration: underline; color:#0000ff;&quot;&gt;read more&lt;/span&gt;&lt;/a&gt;)&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+ </property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="MOBase::SortableTreeWidget" name="bsaList">
+ <property name="contextMenuPolicy">
+ <enum>Qt::CustomContextMenu</enum>
+ </property>
+ <property name="toolTip">
+ <string>List of available BS Archives. Archives not checked here are not managed by MO and ignore installation order.</string>
+ </property>
+ <property name="whatsThis">
+ <string>BSA files are archives (comparable to .zip files) that contain data assets (meshes, textures, ...) to be used by the game. As such they &quot;compete&quot; with loose files in your data directory over which is loaded.
+ By default, BSAs that share their base name with an enabled ESP (i.e. plugin.esp and plugin.bsa) are automatically loaded and will have precedence over all loose files, the installation order you set up to the left is then ignored!
+
+ BSAs checked here are loaded in such a way that your installation order is obeyed properly.</string>
+ </property>
+ <property name="editTriggers">
+ <set>QAbstractItemView::NoEditTriggers</set>
+ </property>
+ <property name="showDropIndicator" stdset="0">
+ <bool>true</bool>
+ </property>
+ <property name="dragEnabled">
+ <bool>false</bool>
+ </property>
+ <property name="dragDropOverwriteMode">
+ <bool>false</bool>
+ </property>
+ <property name="dragDropMode">
+ <enum>QAbstractItemView::DragDrop</enum>
+ </property>
+ <property name="defaultDropAction">
+ <enum>Qt::MoveAction</enum>
+ </property>
+ <property name="selectionMode">
+ <enum>QAbstractItemView::SingleSelection</enum>
+ </property>
+ <property name="selectionBehavior">
+ <enum>QAbstractItemView::SelectRows</enum>
+ </property>
+ <property name="indentation">
+ <number>20</number>
+ </property>
+ <property name="itemsExpandable">
+ <bool>true</bool>
+ </property>
+ <property name="columnCount">
+ <number>1</number>
+ </property>
+ <attribute name="headerVisible">
+ <bool>false</bool>
+ </attribute>
+ <attribute name="headerDefaultSectionSize">
+ <number>200</number>
+ </attribute>
+ <column>
+ <property name="text">
+ <string>File</string>
+ </property>
+ </column>
+ </widget>
+ </item>
+ </layout>
+ </widget>
<widget class="QWidget" name="dataTab">
<attribute name="title">
<string>Data</string>
diff --git a/src/modinfo.cpp b/src/modinfo.cpp
index 4f74086f..d3687d31 100644
--- a/src/modinfo.cpp
+++ b/src/modinfo.cpp
@@ -94,7 +94,7 @@ QString ModInfo::getContentTypeName(int contentType)
case CONTENT_PLUGIN: return tr("Plugins");
case CONTENT_TEXTURE: return tr("Textures");
case CONTENT_MESH: return tr("Meshes");
- case CONTENT_BSA: return tr("BSA");
+ case CONTENT_BSA: return tr("Bethesda Archive");
case CONTENT_INTERFACE: return tr("UI Changes");
case CONTENT_SOUND: return tr("Sound Effects");
case CONTENT_SCRIPT: return tr("Scripts");
diff --git a/src/modinfooverwrite.cpp b/src/modinfooverwrite.cpp
index 6b8c9bd9..360212c0 100644
--- a/src/modinfooverwrite.cpp
+++ b/src/modinfooverwrite.cpp
@@ -53,7 +53,7 @@ QStringList ModInfoOverwrite::archives() const
{
QStringList result;
QDir dir(this->absolutePath());
- for (const QString &archive : dir.entryList(QStringList("*.bsa"))) {
+ for (const QString &archive : dir.entryList(QStringList({ "*.bsa", "*.ba2" }))) {
result.append(this->absolutePath() + "/" + archive);
}
return result;
diff --git a/src/modinforegular.cpp b/src/modinforegular.cpp
index 9d94002b..5486bb2c 100644
--- a/src/modinforegular.cpp
+++ b/src/modinforegular.cpp
@@ -551,7 +551,7 @@ QStringList ModInfoRegular::archives() const
{
QStringList result;
QDir dir(this->absolutePath());
- for (const QString &archive : dir.entryList(QStringList("*.bsa"))) {
+ for (const QString &archive : dir.entryList(QStringList({ "*.bsa", "*.ba2" }))) {
result.append(this->absolutePath() + "/" + archive);
}
return result;
diff --git a/src/modlist.cpp b/src/modlist.cpp
index 53350c59..d7b5f471 100644
--- a/src/modlist.cpp
+++ b/src/modlist.cpp
@@ -64,7 +64,7 @@ ModList::ModList(QObject *parent)
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"));
+ m_ContentIcons[ModInfo::CONTENT_BSA] = std::make_tuple(":/MO/gui/content/bsa", tr("Bethesda Archive"));
m_ContentIcons[ModInfo::CONTENT_SCRIPT] = std::make_tuple(":/MO/gui/content/script", tr("Scripts (Papyrus)"));
m_ContentIcons[ModInfo::CONTENT_SKSE] = std::make_tuple(":/MO/gui/content/skse", tr("Script Extender Plugin"));
m_ContentIcons[ModInfo::CONTENT_SKYPROC] = std::make_tuple(":/MO/gui/content/skyproc", tr("SkyProc Patcher"));
diff --git a/src/organizercore.cpp b/src/organizercore.cpp
index dd77f19a..1a336d91 100644
--- a/src/organizercore.cpp
+++ b/src/organizercore.cpp
@@ -1494,6 +1494,10 @@ void OrganizerCore::refreshBSAList()
if (m_ActiveArchives.isEmpty()) {
m_ActiveArchives = m_DefaultArchives;
}
+
+ if (m_UserInterface != nullptr) {
+ m_UserInterface->updateBSAList(m_DefaultArchives, m_ActiveArchives);
+ }
m_ArchivesInit = true;
}
@@ -1572,6 +1576,9 @@ void OrganizerCore::updateModInDirectoryStructure(unsigned int index,
// now we need to refresh the bsa list and save it so there is no confusion
// about what archives are avaiable and active
refreshBSAList();
+ if (m_UserInterface != nullptr) {
+ m_UserInterface->archivesWriter().writeImmediately(false);
+ }
std::vector<QString> archives = enabledArchives();
m_DirectoryRefresher.setMods(
@@ -1729,6 +1736,9 @@ void OrganizerCore::modStatusChanged(unsigned int index)
= m_DirectoryStructure->getOriginByName(ToWString(modInfo->name()));
origin.enable(false);
}
+ if (m_UserInterface != nullptr) {
+ m_UserInterface->archivesWriter().write();
+ }
}
modInfo->clearCaches();
@@ -1885,6 +1895,9 @@ bool OrganizerCore::saveCurrentLists()
try {
savePluginList();
+ if (m_UserInterface != nullptr) {
+ m_UserInterface->archivesWriter().write();
+ }
} catch (const std::exception &e) {
reportError(tr("failed to save load order: %1").arg(e.what()));
}
diff --git a/src/organizercore.h b/src/organizercore.h
index cf030e0a..decb3d01 100644
--- a/src/organizercore.h
+++ b/src/organizercore.h
@@ -315,6 +315,7 @@ private:
ModList m_ModList;
PluginList m_PluginList;
+
QList<std::function<void()>> m_PostLoginTasks;
QList<std::function<void()>> m_PostRefreshTasks;