diff options
| author | LostDragonist <lost.dragonist@gmail.com> | 2019-01-22 14:59:07 -0600 |
|---|---|---|
| committer | LostDragonist <lost.dragonist@gmail.com> | 2019-01-22 14:59:07 -0600 |
| commit | 7fd81029ce2f67aa7a6555858dfed7d6ac58c4e3 (patch) | |
| tree | 7cfca3567dbd02aee370ffa68e1cff28f4b37b1c | |
| parent | a40613f885c18a8a9f090cd88c595bcb960d97c9 (diff) | |
Reduce file I/O operations when enabling/disabling multiple mods
| -rw-r--r-- | src/mainwindow.cpp | 6 | ||||
| -rw-r--r-- | src/mainwindow.h | 1 | ||||
| -rw-r--r-- | src/modlist.cpp | 36 | ||||
| -rw-r--r-- | src/modlist.h | 13 | ||||
| -rw-r--r-- | src/modlistsortproxy.cpp | 8 | ||||
| -rw-r--r-- | src/organizercore.cpp | 190 | ||||
| -rw-r--r-- | src/organizercore.h | 3 | ||||
| -rw-r--r-- | src/profile.cpp | 31 | ||||
| -rw-r--r-- | src/profile.h | 17 |
9 files changed, 229 insertions, 76 deletions
diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index df78df82..a9dd3e51 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -2509,6 +2509,12 @@ void MainWindow::modlistChanged(const QModelIndex&, int) updateModCount();
}
+void MainWindow::modlistChanged(const QModelIndexList&, int)
+{
+ m_OrganizerCore.currentProfile()->writeModlist();
+ updateModCount();
+}
+
void MainWindow::modlistSelectionChanged(const QModelIndex ¤t, const QModelIndex&)
{
if (current.isValid()) {
diff --git a/src/mainwindow.h b/src/mainwindow.h index 23c38f19..e0311046 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -549,6 +549,7 @@ private slots: void updateStyle(const QString &style);
void modlistChanged(const QModelIndex &index, int role);
+ void modlistChanged(const QModelIndexList &indicies, int role);
void fileMoved(const QString &filePath, const QString &oldOriginName, const QString &newOriginName);
diff --git a/src/modlist.cpp b/src/modlist.cpp index 58fe95d5..cc15a111 100644 --- a/src/modlist.cpp +++ b/src/modlist.cpp @@ -527,7 +527,7 @@ bool ModList::setData(const QModelIndex &index, const QVariant &value, int role) m_Profile->setModEnabled(modID, enabled);
m_Modified = true;
m_LastCheck.restart();
- emit modlist_changed(index, role);
+ emit modlistChanged(index, role);
}
result = true;
emit dataChanged(index, index);
@@ -562,7 +562,7 @@ bool ModList::setData(const QModelIndex &index, const QVariant &value, int role) int newID = value.toInt(&ok);
if (ok) {
info->setNexusID(newID);
- emit modlist_changed(index, role);
+ emit modlistChanged(index, role);
result = true;
} else {
result = false;
@@ -1283,12 +1283,24 @@ bool ModList::toggleSelection(QAbstractItemView *itemView) QItemSelectionModel *selectionModel = itemView->selectionModel();
+ QList<unsigned int> modsToEnable;
+ QList<unsigned int> modsToDisable;
+ QModelIndexList dirtyMods;
for (QModelIndex idx : selectionModel->selectedRows()) {
int modId = idx.data(Qt::UserRole + 1).toInt();
- m_Profile->setModEnabled(modId, !m_Profile->modEnabled(modId));
- emit modlist_changed(idx, 0);
+ if (m_Profile->modEnabled(modId)) {
+ modsToDisable.append(modId);
+ dirtyMods.append(idx);
+ } else {
+ modsToEnable.append(modId);
+ dirtyMods.append(idx);
+ }
}
+ m_Profile->setModsEnabled(modsToEnable, modsToDisable);
+
+ emit modlistChanged(dirtyMods, 0);
+
m_Modified = true;
m_LastCheck.restart();
@@ -1331,13 +1343,12 @@ bool ModList::eventFilter(QObject *obj, QEvent *event) void ModList::enableSelected(const QItemSelectionModel *selectionModel)
{
if (selectionModel->hasSelection()) {
- bool dirty = false;
+ QList<unsigned int> modsToEnable;
for (auto row : selectionModel->selectedRows(COL_PRIORITY)) {
int modID = m_Profile->modIndexByPriority(row.data().toInt());
- if (!m_Profile->modEnabled(modID)) {
- m_Profile->setModEnabled(modID, true);
- }
+ modsToEnable.append(modID);
}
+ m_Profile->setModsEnabled(modsToEnable, QList<unsigned int>());
}
}
@@ -1345,14 +1356,11 @@ void ModList::enableSelected(const QItemSelectionModel *selectionModel) void ModList::disableSelected(const QItemSelectionModel *selectionModel)
{
if (selectionModel->hasSelection()) {
- bool dirty = false;
+ QList<unsigned int> modsToDisable;
for (auto row : selectionModel->selectedRows(COL_PRIORITY)) {
int modID = m_Profile->modIndexByPriority(row.data().toInt());
- if (m_Profile->modEnabled(modID)) {
- m_Profile->setModEnabled(modID, false);
- }
+ modsToDisable.append(modID);
}
-
-
+ m_Profile->setModsEnabled(QList<unsigned int>(), modsToDisable);
}
}
diff --git a/src/modlist.h b/src/modlist.h index 42269386..443d583b 100644 --- a/src/modlist.h +++ b/src/modlist.h @@ -233,9 +233,18 @@ signals: * @param role role of the field that changed
* @note this signal must only be emitted if the row really did change.
* Slots handling this signal therefore do not have to verify that a change has happened
- * @note this signal is currently only used in tutorials
**/
- void modlist_changed(const QModelIndex &index, int role);
+ void modlistChanged(const QModelIndex &index, int role);
+
+ /**
+ * @brief emitted whenever multiple row sin the list has changed
+ *
+ * @param indicies the list of indicies of the changed field
+ * @param role role of the field that changed
+ * @note this signal must only be emitted if the row really did change.
+ * Slots handling this signal therefore do not have to verify that a change has happened
+ **/
+ void modlistChanged(const QModelIndexList &indicies, int role);
/**
* @brief emitted to have all selected mods deleted
diff --git a/src/modlistsortproxy.cpp b/src/modlistsortproxy.cpp index 464f9104..5afcc26a 100644 --- a/src/modlistsortproxy.cpp +++ b/src/modlistsortproxy.cpp @@ -86,10 +86,12 @@ void ModListSortProxy::enableAllVisible() {
if (m_Profile == nullptr) return;
+ QList<unsigned int> modsToEnable;
for (int i = 0; i < this->rowCount(); ++i) {
int modID = mapToSource(index(i, 0)).data(Qt::UserRole + 1).toInt();
- m_Profile->setModEnabled(modID, true);
+ modsToEnable.append(modID);
}
+ m_Profile->setModsEnabled(modsToEnable, QList<unsigned int>());
invalidate();
}
@@ -97,10 +99,12 @@ void ModListSortProxy::disableAllVisible() {
if (m_Profile == nullptr) return;
+ QList<unsigned int> modsToDisable;
for (int i = 0; i < this->rowCount(); ++i) {
int modID = mapToSource(index(i, 0)).data(Qt::UserRole + 1).toInt();
- m_Profile->setModEnabled(modID, false);
+ modsToDisable.append(modID);
}
+ m_Profile->setModsEnabled(QList<unsigned int>(), modsToDisable);
invalidate();
}
diff --git a/src/organizercore.cpp b/src/organizercore.cpp index 90e702ef..90e5a423 100644 --- a/src/organizercore.cpp +++ b/src/organizercore.cpp @@ -542,8 +542,10 @@ void OrganizerCore::setUserInterface(IUserInterface *userInterface, m_UserInterface = userInterface;
if (widget != nullptr) {
- connect(&m_ModList, SIGNAL(modlist_changed(QModelIndex, int)), widget,
+ connect(&m_ModList, SIGNAL(modlistChanged(QModelIndex, int)), widget,
SLOT(modlistChanged(QModelIndex, int)));
+ connect(&m_ModList, SIGNAL(modlistChanged(QModelIndexList, int)), widget,
+ SLOT(modlistChanged(QModelIndexList, int)));
connect(&m_ModList, SIGNAL(showMessage(QString)), widget,
SLOT(showMessage(QString)));
connect(&m_ModList, SIGNAL(modRenamed(QString, QString)), widget,
@@ -821,8 +823,8 @@ void OrganizerCore::setCurrentProfile(const QString &profileName) m_CurrentProfile->deactivateInvalidation();
}
- connect(m_CurrentProfile, SIGNAL(modStatusChanged(uint)), this,
- SLOT(modStatusChanged(uint)));
+ connect(m_CurrentProfile, SIGNAL(modStatusChanged(uint)), this, SLOT(modStatusChanged(uint)));
+ connect(m_CurrentProfile, SIGNAL(modStatusChanged(QList<uint>)), this, SLOT(modStatusChanged(QList<uint>)));
refreshDirectoryStructure();
}
@@ -1798,60 +1800,70 @@ void OrganizerCore::refreshLists() void OrganizerCore::updateModActiveState(int index, bool active)
{
- ModInfo::Ptr modInfo = ModInfo::getByIndex(index);
- QDir dir(modInfo->absolutePath());
- for (const QString &esm :
- dir.entryList(QStringList() << "*.esm", QDir::Files)) {
- const FileEntry::Ptr file = m_DirectoryStructure->findFile(ToWString(esm));
- if (file.get() == nullptr) {
- qWarning("failed to activate %s", qUtf8Printable(esm));
- continue;
- }
+ QList<unsigned int> modsToUpdate;
+ modsToUpdate.append(index);
+ updateModsActiveState(modsToUpdate, active);
+}
- if (active != m_PluginList.isEnabled(esm)
- && file->getAlternatives().empty()) {
- m_PluginList.blockSignals(true);
- m_PluginList.enableESP(esm, active);
- m_PluginList.blockSignals(false);
- }
- }
- 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", qUtf8Printable(esl));
- continue;
- }
+void OrganizerCore::updateModsActiveState(const QList<unsigned int> &modIndices, bool active)
+{
+ int enabled = 0;
+ for (auto index : modIndices) {
+ ModInfo::Ptr modInfo = ModInfo::getByIndex(index);
+ QDir dir(modInfo->absolutePath());
+ for (const QString &esm :
+ dir.entryList(QStringList() << "*.esm", QDir::Files)) {
+ const FileEntry::Ptr file = m_DirectoryStructure->findFile(ToWString(esm));
+ if (file.get() == nullptr) {
+ qWarning("failed to activate %s", qUtf8Printable(esm));
+ continue;
+ }
- if (active != m_PluginList.isEnabled(esl)
+ if (active != m_PluginList.isEnabled(esm)
&& file->getAlternatives().empty()) {
- m_PluginList.blockSignals(true);
- m_PluginList.enableESP(esl, active);
- m_PluginList.blockSignals(false);
- ++enabled;
+ m_PluginList.blockSignals(true);
+ m_PluginList.enableESP(esm, active);
+ m_PluginList.blockSignals(false);
+ }
}
- }
- QStringList esps = dir.entryList(QStringList() << "*.esp", QDir::Files);
- for (const QString &esp : esps) {
- const FileEntry::Ptr file = m_DirectoryStructure->findFile(ToWString(esp));
- if (file.get() == nullptr) {
- qWarning("failed to activate %s", qUtf8Printable(esp));
- continue;
+
+ 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", qUtf8Printable(esl));
+ continue;
+ }
+
+ if (active != m_PluginList.isEnabled(esl)
+ && file->getAlternatives().empty()) {
+ m_PluginList.blockSignals(true);
+ m_PluginList.enableESP(esl, active);
+ m_PluginList.blockSignals(false);
+ ++enabled;
+ }
}
+ QStringList esps = dir.entryList(QStringList() << "*.esp", QDir::Files);
+ for (const QString &esp : esps) {
+ const FileEntry::Ptr file = m_DirectoryStructure->findFile(ToWString(esp));
+ if (file.get() == nullptr) {
+ qWarning("failed to activate %s", qUtf8Printable(esp));
+ continue;
+ }
- if (active != m_PluginList.isEnabled(esp)
+ if (active != m_PluginList.isEnabled(esp)
&& file->getAlternatives().empty()) {
- m_PluginList.blockSignals(true);
- m_PluginList.enableESP(esp, active);
- m_PluginList.blockSignals(false);
- ++enabled;
+ m_PluginList.blockSignals(true);
+ m_PluginList.enableESP(esp, active);
+ m_PluginList.blockSignals(false);
+ ++enabled;
+ }
}
}
if (active && (enabled > 1)) {
MessageDialog::showMessage(
- tr("Multiple esps/esls activated, please check that they don't conflict."),
- qApp->activeWindow());
+ tr("Multiple esps/esls activated, please check that they don't conflict."),
+ qApp->activeWindow());
}
m_PluginList.refreshLoadOrder();
// immediately save affected lists
@@ -1861,18 +1873,29 @@ void OrganizerCore::updateModActiveState(int index, bool active) void OrganizerCore::updateModInDirectoryStructure(unsigned int index,
ModInfo::Ptr modInfo)
{
- // add files of the bsa to the directory structure
- m_DirectoryRefresher.addModFilesToStructure(
- m_DirectoryStructure, modInfo->name(),
- m_CurrentProfile->getModPriority(index), modInfo->absolutePath(),
- modInfo->stealFiles());
+ QMap<unsigned int, ModInfo::Ptr> allModInfo;
+ allModInfo[index] = modInfo;
+ updateModsInDirectoryStructure(allModInfo);
+}
+
+void OrganizerCore::updateModsInDirectoryStructure(QMap<unsigned int, ModInfo::Ptr> modInfo)
+{
+ for (auto idx : modInfo.keys()) {
+ // add files of the bsa to the directory structure
+ m_DirectoryRefresher.addModFilesToStructure(
+ m_DirectoryStructure, modInfo[idx]->name(),
+ m_CurrentProfile->getModPriority(idx), modInfo[idx]->absolutePath(),
+ modInfo[idx]->stealFiles());
+ }
DirectoryRefresher::cleanStructure(m_DirectoryStructure);
// need to refresh plugin list now so we can activate esps
refreshESPList(true);
// activate all esps of the specified mod so the bsas get activated along with
// it
m_PluginList.blockSignals(true);
- updateModActiveState(index, true);
+ for (auto idx : modInfo.keys()) {
+ updateModActiveState(idx, true);
+ }
m_PluginList.blockSignals(false);
// now we need to refresh the bsa list and save it so there is no confusion
// about what archives are avaiable and active
@@ -1883,14 +1906,16 @@ void OrganizerCore::updateModInDirectoryStructure(unsigned int index, std::vector<QString> archives = enabledArchives();
m_DirectoryRefresher.setMods(
- m_CurrentProfile->getActiveMods(),
- std::set<QString>(archives.begin(), archives.end()));
+ m_CurrentProfile->getActiveMods(),
+ std::set<QString>(archives.begin(), archives.end()));
// finally also add files from bsas to the directory structure
- m_DirectoryRefresher.addModBSAToStructure(
- m_DirectoryStructure, modInfo->name(),
- m_CurrentProfile->getModPriority(index), modInfo->absolutePath(),
- modInfo->archives());
+ for (auto idx : modInfo.keys()) {
+ m_DirectoryRefresher.addModBSAToStructure(
+ m_DirectoryStructure, modInfo[idx]->name(),
+ m_CurrentProfile->getModPriority(idx), modInfo[idx]->absolutePath(),
+ modInfo[idx]->archives());
+ }
}
void OrganizerCore::requestDownload(const QUrl &url, QNetworkReply *reply)
@@ -2065,6 +2090,55 @@ void OrganizerCore::modStatusChanged(unsigned int index) }
}
+void OrganizerCore::modStatusChanged(QList<unsigned int> index) {
+ try {
+ QMap<unsigned int, ModInfo::Ptr> modsToEnable;
+ QMap<unsigned int, ModInfo::Ptr> modsToDisable;
+ for (auto idx : index) {
+ if (m_CurrentProfile->modEnabled(idx)) {
+ modsToEnable[idx] = ModInfo::getByIndex(idx);
+ } else {
+ modsToDisable[idx] = ModInfo::getByIndex(idx);
+ }
+ }
+ if (!modsToEnable.isEmpty()) {
+ updateModsInDirectoryStructure(modsToEnable);
+ for (auto modInfo : modsToEnable.values()) {
+ modInfo->clearCaches();
+ }
+ }
+ if (!modsToDisable.isEmpty()) {
+ updateModsActiveState(modsToDisable.keys(), false);
+ for (auto idx : modsToDisable.keys()) {
+ if (m_DirectoryStructure->originExists(ToWString(modsToDisable[idx]->name()))) {
+ FilesOrigin &origin
+ = m_DirectoryStructure->getOriginByName(ToWString(modsToDisable[idx]->name()));
+ origin.enable(false);
+ }
+ }
+ if (m_UserInterface != nullptr) {
+ m_UserInterface->archivesWriter().write();
+ }
+ }
+
+ for (unsigned int i = 0; i < m_CurrentProfile->numMods(); ++i) {
+ ModInfo::Ptr modInfo = ModInfo::getByIndex(i);
+ int priority = m_CurrentProfile->getModPriority(i);
+ if (m_DirectoryStructure->originExists(ToWString(modInfo->name()))) {
+ // priorities in the directory structure are one higher because data is
+ // 0
+ m_DirectoryStructure->getOriginByName(ToWString(modInfo->name()))
+ .setPriority(priority + 1);
+ }
+ }
+ m_DirectoryStructure->getFileRegister()->sortOrigins();
+
+ refreshLists();
+ } catch (const std::exception &e) {
+ reportError(tr("failed to update mod list: %1").arg(e.what()));
+ }
+}
+
void OrganizerCore::loginSuccessful(bool necessary)
{
if (necessary) {
diff --git a/src/organizercore.h b/src/organizercore.h index 61020acd..7a62d2c8 100644 --- a/src/organizercore.h +++ b/src/organizercore.h @@ -136,6 +136,7 @@ public: void refreshDirectoryStructure();
void updateModInDirectoryStructure(unsigned int index, ModInfo::Ptr modInfo);
+ void updateModsInDirectoryStructure(QMap<unsigned int, ModInfo::Ptr> modInfos);
void doAfterLogin(const std::function<void()> &function) { m_PostLoginTasks.append(function); }
@@ -238,6 +239,7 @@ public slots: void installDownload(int downloadIndex);
void modStatusChanged(unsigned int index);
+ void modStatusChanged(QList<unsigned int> index);
void requestDownload(const QUrl &url, QNetworkReply *reply);
void downloadRequestedNXM(const QString &url);
@@ -266,6 +268,7 @@ private: bool queryLogin(QString &username, QString &password);
void updateModActiveState(int index, bool active);
+ void updateModsActiveState(const QList<unsigned int> &modIndices, bool active);
bool testForSteam();
diff --git a/src/profile.cpp b/src/profile.cpp index afe6fdc7..629e043f 100644 --- a/src/profile.cpp +++ b/src/profile.cpp @@ -568,6 +568,37 @@ void Profile::setModEnabled(unsigned int index, bool enabled) } } +void Profile::setModsEnabled(const QList<unsigned int> &modsToEnable, const QList<unsigned int> &modsToDisable) +{ + QList<unsigned int> dirtyMods; + for (auto idx : modsToEnable) { + if (idx >= m_ModStatus.size()) { + qCritical() << tr("invalid index %1").arg(idx); + continue; + } + if (!m_ModStatus[idx].m_Enabled) { + m_ModStatus[idx].m_Enabled = true; + dirtyMods.append(idx); + } + } + for (auto idx : modsToDisable) { + if (idx >= m_ModStatus.size()) { + qCritical() << tr("invalid index %1").arg(idx); + continue; + } + if (ModInfo::getByIndex(idx)->alwaysEnabled()) { + continue; + } + if (m_ModStatus[idx].m_Enabled) { + m_ModStatus[idx].m_Enabled = false; + dirtyMods.append(idx); + } + } + if (!dirtyMods.isEmpty()) { + emit modStatusChanged(dirtyMods); + } +} + bool Profile::modEnabled(unsigned int index) const { if (index >= m_ModStatus.size()) { diff --git a/src/profile.h b/src/profile.h index dea933ad..a7ba7e91 100644 --- a/src/profile.h +++ b/src/profile.h @@ -274,6 +274,16 @@ public: void setModEnabled(unsigned int index, bool enabled); /** + * @brief enable or disable multiple mods at once + * This is an abbreviated process and should be immediately followed by a full refresh + * to maintain data consistency. + * + * @param modsToEnable list of mod indicies to enable + * @param modsToDisable list of mod indicies to disable + **/ + void setModsEnabled(const QList<unsigned int> &modsToEnable, const QList<unsigned int> &modsToDisable); + + /** * change the priority of a mod. Of course this also changes the priority of other mods. * The priority of the mods in the range ]old, new priority] are shifted so that no gaps * are possible. @@ -335,6 +345,13 @@ signals: **/ void modStatusChanged(unsigned int index); + /** + * @brief emitted whenever the status (enabled/disabled) of multiple mods change + * + * @param index list of indices of the mods that changed + **/ + void modStatusChanged(QList<unsigned int> index); + public slots: // should only be called by DelayedFileWriter, use writeModlist() and writeModlistNow() instead |
