From d08e0ebab09b0a71c3042cd20b8994ec1c10a525 Mon Sep 17 00:00:00 2001 From: Tannin Date: Sun, 1 Mar 2015 11:28:49 +0100 Subject: - some fixes to how file changes are signaled and delayed --- src/iuserinterface.h | 4 +- src/mainwindow.cpp | 31 ++++------ src/mainwindow.h | 8 ++- src/modlist.cpp | 153 ++++++++++++++++++++++++++---------------------- src/modlist.h | 8 +++ src/modlistview.cpp | 1 + src/modlistview.h | 1 - src/organizercore.cpp | 26 ++++---- src/organizercore.h | 5 ++ src/plugincontainer.cpp | 3 +- src/pluginlist.cpp | 42 +++---------- src/pluginlist.h | 10 +--- src/profile.cpp | 51 ++++------------ src/profile.h | 17 ++---- src/version.rc | 4 +- 15 files changed, 162 insertions(+), 202 deletions(-) (limited to 'src') diff --git a/src/iuserinterface.h b/src/iuserinterface.h index ff683bce..bcf800b7 100644 --- a/src/iuserinterface.h +++ b/src/iuserinterface.h @@ -5,6 +5,7 @@ #include "modinfo.h" #include #include +#include class IUserInterface @@ -27,12 +28,13 @@ public: virtual void updateBSAList(const QStringList &defaultArchives, const QStringList &activeArchives) = 0; - virtual bool saveArchiveList() = 0; + virtual MOBase::DelayedFileWriterBase &archivesWriter() = 0; virtual void lock() = 0; virtual void unlock() = 0; virtual bool unlockClicked() = 0; + }; #endif // IUSERINTERFACE_H diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index af654e2f..9aa26db6 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -160,6 +160,7 @@ MainWindow::MainWindow(const QString &exeName , m_OrganizerCore(organizerCore) , m_PluginContainer(pluginContainer) , m_DidUpdateMasterList(false) + , m_ArchiveListWriter(std::bind(&MainWindow::saveArchiveList, this)) { ui->setupUi(this); this->setWindowTitle(ToQString(GameInfo::instance().getGameName()) + " Mod Organizer v" + m_OrganizerCore.getVersion().displayString()); @@ -1846,8 +1847,8 @@ void MainWindow::modorder_changed() } } m_OrganizerCore.refreshBSAList(); - m_OrganizerCore.currentProfile()->writeModlist(); - saveArchiveList(); + m_OrganizerCore.currentProfile()->modlistWriter().write(); + m_ArchiveListWriter.write(); m_OrganizerCore.directoryStructure()->getFileRegister()->sortOrigins(); { // refresh selection @@ -1981,13 +1982,6 @@ void MainWindow::modRenamed(const QString &oldName, const QString &newName) } } - -void MainWindow::modlistChanged(int) -{ - m_ModListSortProxy->invalidate(); -} - - void MainWindow::fileMoved(const QString &filePath, const QString &oldOriginName, const QString &newOriginName) { const FileEntry::Ptr filePtr = m_OrganizerCore.directoryStructure()->findFile(ToWString(filePath)); @@ -2139,7 +2133,7 @@ void MainWindow::restoreBackup_clicked() void MainWindow::modlistChanged(const QModelIndex&, int) { - m_OrganizerCore.currentProfile()->writeModlist(); + m_OrganizerCore.currentProfile()->modlistWriter().write(); } void MainWindow::modlistSelectionChanged(const QModelIndex ¤t, const QModelIndex&) @@ -2150,10 +2144,10 @@ void MainWindow::modlistSelectionChanged(const QModelIndex ¤t, const QMode } else { m_OrganizerCore.modList()->setOverwriteMarkers(std::set(), std::set()); } - if ((m_ModListSortProxy != nullptr) +/* if ((m_ModListSortProxy != nullptr) && !m_ModListSortProxy->beingInvalidated()) { m_ModListSortProxy->invalidate(); - } + }*/ ui->modList->verticalScrollBar()->repaint(); } @@ -2727,7 +2721,7 @@ void MainWindow::savePrimaryCategory() } } -bool MainWindow::saveArchiveList() +void MainWindow::saveArchiveList() { if (m_OrganizerCore.isArchivesInit()) { SafeWriteFile archiveFile(m_OrganizerCore.currentProfile()->getArchivesFileName()); @@ -2746,12 +2740,10 @@ bool MainWindow::saveArchiveList() } if (archiveFile.commitIfDifferent(m_ArchiveListHash)) { qDebug("%s saved", qPrintable(QDir::toNativeSeparators(m_OrganizerCore.currentProfile()->getArchivesFileName()))); - return true; } } else { qWarning("archive list not initialised"); } - return false; } void MainWindow::checkModsForUpdates() @@ -3191,7 +3183,7 @@ void MainWindow::fixMods_clicked() } } - m_OrganizerCore.currentProfile()->writeModlist(); + m_OrganizerCore.currentProfile()->modlistWriter().write(); m_OrganizerCore.refreshLists(); std::set espsToActivate = dialog.getESPsToActivate(); @@ -4005,14 +3997,14 @@ void MainWindow::on_bsaList_customContextMenuRequested(const QPoint &pos) void MainWindow::bsaList_itemMoved() { - saveArchiveList(); + m_ArchiveListWriter.write(); m_CheckBSATimer.start(500); } void MainWindow::on_bsaList_itemChanged(QTreeWidgetItem*, int) { - saveArchiveList(); + m_ArchiveListWriter.write(); m_CheckBSATimer.start(500); } @@ -4528,12 +4520,13 @@ void MainWindow::on_restoreButton_clicked() void MainWindow::on_saveModsButton_clicked() { - m_OrganizerCore.currentProfile()->writeModlistNow(true); + m_OrganizerCore.currentProfile()->modlistWriter().writeImmediately(true); QDateTime now = QDateTime::currentDateTime(); if (createBackup(m_OrganizerCore.currentProfile()->getModlistFileName(), now)) { MessageDialog::showMessage(tr("Backup of modlist created"), this); } } + void MainWindow::on_restoreModsButton_clicked() { QString modlistName = m_OrganizerCore.currentProfile()->getModlistFileName(); diff --git a/src/mainwindow.h b/src/mainwindow.h index d0e3aaf5..88419594 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -53,6 +53,7 @@ along with Mod Organizer. If not, see . #include "iuserinterface.h" #include #include +#include #ifndef Q_MOC_RUN #include #endif @@ -97,7 +98,7 @@ public: void setModListSorting(int index); void setESPListSorting(int index); - bool saveArchiveList(); + void saveArchiveList(); void registerPluginTool(MOBase::IPluginTool *tool); void registerModPage(MOBase::IPluginModPage *modPage); @@ -121,6 +122,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); @@ -315,6 +318,8 @@ private: LockedDialog *m_LockDialog { nullptr }; + MOBase::DelayedFileWriter m_ArchiveListWriter; + private slots: void showMessage(const QString &message); @@ -389,7 +394,6 @@ private slots: void addPrimaryCategoryCandidates(); void modDetailsUpdated(bool success); - void modlistChanged(int row); void modInstalled(const QString &modName); diff --git a/src/modlist.cpp b/src/modlist.cpp index 250b5caf..c6beee8b 100644 --- a/src/modlist.cpp +++ b/src/modlist.cpp @@ -458,6 +458,7 @@ bool ModList::setData(const QModelIndex &index, const QVariant &value, int role) emit modlist_changed(index, role); } result = true; + emit dataChanged(index, index); } else if (role == Qt::EditRole) { switch (index.column()) { case COL_NAME: { @@ -469,7 +470,7 @@ bool ModList::setData(const QModelIndex &index, const QVariant &value, int role) if (ok) { m_Profile->setModPriority(modID, newPriority); - emit modlist_changed(index, role); + emit modorder_changed(); result = true; } else { result = false; @@ -859,13 +860,14 @@ void ModList::removeRowForce(int row, const QModelIndex &parent) bool wasEnabled = m_Profile->modEnabled(row); - beginRemoveRows(parent, row, row); m_Profile->setModEnabled(row, false); - m_Profile->cancelWriteModlist(); // don't write modlist while we're changing it + + m_Profile->modlistWriter().cancel(); + beginRemoveRows(parent, row, row); ModInfo::removeMod(row); - m_Profile->refreshModStatus(); // removes the mod from the status list endRemoveRows(); - m_Profile->writeModlist(); // this ensures the modified list gets written back before new mods can be installed + m_Profile->refreshModStatus(); // removes the mod from the status list + m_Profile->modlistWriter().write(); // this ensures the modified list gets written back before new mods can be installed if (wasEnabled) { emit removeOrigin(modInfo->name()); @@ -874,7 +876,6 @@ void ModList::removeRowForce(int row, const QModelIndex &parent) emit modUninstalled(modInfo->getInstallationFile()); } - bool ModList::removeRows(int row, int count, const QModelIndex &parent) { if (static_cast(row) >= ModInfo::getNumMods()) { @@ -903,6 +904,7 @@ bool ModList::removeRows(int row, int count, const QModelIndex &parent) removeRowForce(row + i, parent); } } + return success; } @@ -997,6 +999,76 @@ QString ModList::getColumnToolTip(int column) } +bool ModList::moveSelection(QAbstractItemView *itemView, int direction) +{ + QItemSelectionModel *selectionModel = itemView->selectionModel(); + + const QAbstractProxyModel *proxyModel = qobject_cast(selectionModel->model()); + const QSortFilterProxyModel *filterModel = nullptr; + + while ((filterModel == nullptr) && (proxyModel != nullptr)) { + filterModel = qobject_cast(proxyModel); + if (filterModel == nullptr) { + proxyModel = qobject_cast(proxyModel->sourceModel()); + } + } + if (filterModel == nullptr) { + return true; + } + + int offset = -1; + if (((direction < 0) && (filterModel->sortOrder() == Qt::DescendingOrder)) || + ((direction > 0) && (filterModel->sortOrder() == Qt::AscendingOrder))) { + offset = 1; + } + + QModelIndexList rows = selectionModel->selectedRows(); + if (direction > 0) { + for (int i = 0; i < rows.size() / 2; ++i) { + rows.swap(i, rows.size() - i - 1); + } + } + for (QModelIndex idx : rows) { + if (filterModel != nullptr) { + idx = filterModel->mapToSource(idx); + } + int newPriority = m_Profile->getModPriority(idx.row()) + offset; + if ((newPriority >= 0) && (newPriority < static_cast(m_Profile->numRegularMods()))) { + m_Profile->setModPriority(idx.row(), newPriority); + notifyChange(idx.row()); + } + } + emit modorder_changed(); + return true; +} + +bool ModList::deleteSelection(QAbstractItemView *itemView) +{ + QItemSelectionModel *selectionModel = itemView->selectionModel(); + + QModelIndexList rows = selectionModel->selectedRows(); + if (rows.count() > 1) { + emit removeSelectedMods(); + } else if (rows.count() == 1) { + removeRow(rows[0].data(Qt::UserRole + 1).toInt(), QModelIndex()); + } + return true; +} + +bool ModList::toggleSelection(QAbstractItemView *itemView) +{ + QAbstractItemModel *model = itemView->model(); + QItemSelectionModel *selectionModel = itemView->selectionModel(); + + for (QModelIndex idx : selectionModel->selectedRows()) { + int oldState = idx.data(Qt::CheckStateRole).toInt(); + model->setData(idx, oldState == Qt::Unchecked ? Qt::Checked + : Qt::Unchecked, + Qt::CheckStateRole); + } + return true; +} + bool ModList::eventFilter(QObject *obj, QEvent *event) { if (event->type() == QEvent::ContextMenu) { @@ -1010,74 +1082,15 @@ bool ModList::eventFilter(QObject *obj, QEvent *event) } else if ((event->type() == QEvent::KeyPress) && (m_Profile != nullptr)) { QAbstractItemView *itemView = qobject_cast(obj); QKeyEvent *keyEvent = static_cast(event); + if ((itemView != nullptr) && (keyEvent->modifiers() == Qt::ControlModifier) - && ((keyEvent->key() == Qt::Key_Up) - || (keyEvent->key() == Qt::Key_Down))) { - QItemSelectionModel *selectionModel = itemView->selectionModel(); - const QAbstractProxyModel *proxyModel = qobject_cast(selectionModel->model()); - const QSortFilterProxyModel *filterModel = nullptr; - while ((filterModel == nullptr) && (proxyModel != nullptr)) { - filterModel = qobject_cast(proxyModel); - if (filterModel == nullptr) { - proxyModel = qobject_cast(proxyModel->sourceModel()); - } - } - if (filterModel == nullptr) { - return true; - } - int diff = -1; - if (((keyEvent->key() == Qt::Key_Up) && (filterModel->sortOrder() == Qt::DescendingOrder)) || - ((keyEvent->key() == Qt::Key_Down) && (filterModel->sortOrder() == Qt::AscendingOrder))) { - diff = 1; - } - QModelIndexList rows = selectionModel->selectedRows(); - if (keyEvent->key() == Qt::Key_Down) { - for (int i = 0; i < rows.size() / 2; ++i) { - rows.swap(i, rows.size() - i - 1); - } - } - foreach (QModelIndex idx, rows) { - if (filterModel != nullptr) { - idx = filterModel->mapToSource(idx); - } - int newPriority = m_Profile->getModPriority(idx.row()) + diff; - if ((newPriority >= 0) && (newPriority < static_cast(m_Profile->numRegularMods()))) { - m_Profile->setModPriority(idx.row(), newPriority); - notifyChange(idx.row()); - } - } - emit modorder_changed(); - return true; + && ((keyEvent->key() == Qt::Key_Up) || (keyEvent->key() == Qt::Key_Down))) { + return moveSelection(itemView, keyEvent->key() == Qt::Key_Up ? -1 : 1); } else if (keyEvent->key() == Qt::Key_Delete) { - QItemSelectionModel *selectionModel = itemView->selectionModel(); - QModelIndexList rows = selectionModel->selectedRows(); - if (rows.count() > 1) { - emit removeSelectedMods(); - } else if (rows.count() == 1) { - removeRow(rows[0].data(Qt::UserRole + 1).toInt(), QModelIndex()); - } - return true; + return deleteSelection(itemView); } else if (keyEvent->key() == Qt::Key_Space) { - QItemSelectionModel *selectionModel = itemView->selectionModel(); - const QSortFilterProxyModel *proxyModel = qobject_cast(selectionModel->model()); - - QModelIndex minRow, maxRow; - foreach (QModelIndex idx, selectionModel->selectedRows()) { - if (proxyModel != nullptr) { - idx = proxyModel->mapToSource(idx); - } - if (!minRow.isValid() || (idx.row() < minRow.row())) { - minRow = idx; - } - if (!maxRow.isValid() || (idx.row() > maxRow.row())) { - maxRow = idx; - } - int oldState = idx.data(Qt::CheckStateRole).toInt(); - setData(idx, oldState == Qt::Unchecked ? Qt::Checked : Qt::Unchecked, Qt::CheckStateRole); - } - emit dataChanged(minRow, maxRow); - return true; + return toggleSelection(itemView); } } return QObject::eventFilter(obj, event); diff --git a/src/modlist.h b/src/modlist.h index 73a49745..6a10cb3e 100644 --- a/src/modlist.h +++ b/src/modlist.h @@ -40,6 +40,8 @@ along with Mod Organizer. If not, see . #include +class QSortFilterProxyModel; + /** * Model presenting an overview of the installed mod * This is used in a view in the main window of MO. It combines general information about @@ -261,6 +263,12 @@ private: ModStates state(unsigned int modIndex) const; + bool moveSelection(QAbstractItemView *itemView, int direction); + + bool deleteSelection(QAbstractItemView *itemView); + + bool toggleSelection(QAbstractItemView *itemView); + private slots: private: diff --git a/src/modlistview.cpp b/src/modlistview.cpp index 50a13a8c..fe2d3e57 100644 --- a/src/modlistview.cpp +++ b/src/modlistview.cpp @@ -53,3 +53,4 @@ void ModListView::setModel(QAbstractItemModel *model) QTreeView::setModel(model); setVerticalScrollBar(new ViewMarkingScrollBar(model, this)); } + diff --git a/src/modlistview.h b/src/modlistview.h index 4907225f..6cd114b0 100644 --- a/src/modlistview.h +++ b/src/modlistview.h @@ -19,7 +19,6 @@ public slots: private: ViewMarkingScrollBar *m_Scrollbar; - }; #endif // MODLISTVIEW_H diff --git a/src/organizercore.cpp b/src/organizercore.cpp index 0ea3ccb1..6a5e08d0 100644 --- a/src/organizercore.cpp +++ b/src/organizercore.cpp @@ -24,6 +24,7 @@ #include #include #include +#include using namespace MOShared; @@ -126,6 +127,7 @@ OrganizerCore::OrganizerCore(const QSettings &initSettings) , m_AskForNexusPW(false) , m_DirectoryUpdate(false) , m_ArchivesInit(false) + , m_PluginListsWriter(std::bind(&OrganizerCore::savePluginList, this)) { m_DownloadManager.setOutputDirectory(m_Settings.getDownloadDirectory()); m_DownloadManager.setPreferredServers(m_Settings.getPreferredServers()); @@ -140,13 +142,14 @@ OrganizerCore::OrganizerCore(const QSettings &initSettings) connect(&m_DirectoryRefresher, SIGNAL(refreshed()), this, SLOT(directory_refreshed())); connect(&m_ModList, SIGNAL(removeOrigin(QString)), this, SLOT(removeOrigin(QString))); - connect(&m_PluginList, SIGNAL(saveTimer()), this, SLOT(savePluginList())); connect(NexusInterface::instance()->getAccessManager(), SIGNAL(loginSuccessful(bool)), this, SLOT(loginSuccessful(bool))); connect(NexusInterface::instance()->getAccessManager(), SIGNAL(loginFailed(QString)), this, SLOT(loginFailed(QString))); connect(this, SIGNAL(managedGameChanged(MOBase::IPluginGame*)), &m_Settings, SLOT(managedGameChanged(MOBase::IPluginGame*))); + connect(&m_PluginList, &PluginList::writePluginsList, &m_PluginListsWriter, &DelayedFileWriterBase::write); + // make directory refresher run in a separate thread m_RefresherThread.start(); m_DirectoryRefresher.moveToThread(&m_RefresherThread); @@ -319,11 +322,11 @@ void OrganizerCore::setUserInterface(IUserInterface *userInterface, QWidget *wid m_UserInterface = userInterface; if (widget != nullptr) { - connect(&m_ModList, SIGNAL(modlist_changed(QModelIndex,int)), widget, SLOT(modorder_changed())); +// connect(&m_ModList, SIGNAL(modlist_changed(QModelIndex, int)), widget, SLOT(modorder_changed())); + connect(&m_ModList, SIGNAL(modlist_changed(QModelIndex, int)), widget, SLOT(modlistChanged(QModelIndex, int))); connect(&m_ModList, SIGNAL(showMessage(QString)), widget, SLOT(showMessage(QString))); connect(&m_ModList, SIGNAL(modRenamed(QString,QString)), widget, SLOT(modRenamed(QString,QString))); connect(&m_ModList, SIGNAL(modUninstalled(QString)), widget, SLOT(modRemoved(QString))); - connect(&m_ModList, SIGNAL(modlist_changed(QModelIndex, int)), widget, SLOT(modlistChanged(QModelIndex, int))); connect(&m_ModList, SIGNAL(removeSelectedMods()), widget, SLOT(removeMod_clicked())); connect(&m_ModList, SIGNAL(requestColumnSelect(QPoint)), widget, SLOT(displayColumnSelection(QPoint))); connect(&m_ModList, SIGNAL(fileMoved(QString, QString, QString)), widget, SLOT(fileMoved(QString, QString, QString))); @@ -920,7 +923,7 @@ HANDLE OrganizerCore::spawnBinaryDirect(const QFileInfo &binary, const QString & // need to make sure all data is saved before we start the application if (m_CurrentProfile != nullptr) { - m_CurrentProfile->writeModlistNow(true); + m_CurrentProfile->modlistWriter().writeImmediately(true); } // TODO: should also pass arguments @@ -1066,7 +1069,7 @@ void OrganizerCore::refreshModList(bool saveChanges) { // don't lose changes! if (saveChanges) { - m_CurrentProfile->writeModlistNow(true); + m_CurrentProfile->modlistWriter().writeImmediately(true); } ModInfo::updateFromDisc(m_Settings.getModDirectory(), &m_DirectoryStructure, m_Settings.displayForeign()); @@ -1079,7 +1082,7 @@ void OrganizerCore::refreshModList(bool saveChanges) void OrganizerCore::refreshESPList() { - m_CurrentProfile->writeModlist(); + m_CurrentProfile->modlistWriter().write(); // clear list try { @@ -1151,8 +1154,7 @@ void OrganizerCore::updateModActiveState(int index, bool active) } m_PluginList.refreshLoadOrder(); // immediately save affected lists - savePluginList(); -// refreshBSAList(); + m_PluginListsWriter.writeImmediately(false); } void OrganizerCore::updateModInDirectoryStructure(unsigned int index, ModInfo::Ptr modInfo) @@ -1172,7 +1174,7 @@ void OrganizerCore::updateModInDirectoryStructure(unsigned int index, ModInfo::P // 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->saveArchiveList(); + m_UserInterface->archivesWriter().write(); } m_DirectoryRefresher.setMods(m_CurrentProfile->getActiveMods(), enabledArchives()); @@ -1257,7 +1259,7 @@ std::set OrganizerCore::enabledArchives() void OrganizerCore::refreshDirectoryStructure() { if (!m_DirectoryUpdate) { - m_CurrentProfile->writeModlistNow(true); + m_CurrentProfile->modlistWriter().writeImmediately(true); m_DirectoryUpdate = true; std::vector > activeModList = m_CurrentProfile->getActiveMods(); @@ -1447,7 +1449,7 @@ bool OrganizerCore::saveCurrentLists() try { savePluginList(); if (m_UserInterface != nullptr) { - m_UserInterface->saveArchiveList(); + m_UserInterface->archivesWriter().write(); } } catch (const std::exception &e) { reportError(tr("failed to save load order: %1").arg(e.what())); @@ -1470,7 +1472,7 @@ void OrganizerCore::prepareStart() { if (m_CurrentProfile == nullptr) { return; } - m_CurrentProfile->writeModlist(); + m_CurrentProfile->modlistWriter().write(); m_CurrentProfile->createTweakedIniFile(); saveCurrentLists(); m_Settings.setupLoadMechanism(); diff --git a/src/organizercore.h b/src/organizercore.h index 3191e2a9..d8a3e232 100644 --- a/src/organizercore.h +++ b/src/organizercore.h @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -124,6 +125,8 @@ public: void createDefaultProfile(); + MOBase::DelayedFileWriter &pluginsWriter() { return m_PluginListsWriter; } + public: MOBase::IGameInfo &gameInfo() const; MOBase::IModRepositoryBridge *createNexusBridge() const; @@ -255,6 +258,8 @@ private: bool m_DirectoryUpdate; bool m_ArchivesInit; + MOBase::DelayedFileWriter m_PluginListsWriter; + }; #endif // ORGANIZERCORE_H diff --git a/src/plugincontainer.cpp b/src/plugincontainer.cpp index 1b06d1a6..6bc9d12b 100644 --- a/src/plugincontainer.cpp +++ b/src/plugincontainer.cpp @@ -317,7 +317,8 @@ QString PluginContainer::fullDescription(unsigned int key) const { switch (key) { case PROBLEM_PLUGINSNOTLOADED: { - QString result = tr("The following plugins could not be loaded. The reason may be missing dependencies (i.e. python) or an outdated version:") + "
    "; + QString result = tr("The following plugins could not be loaded. The reason may be missing " + "dependencies (i.e. python) or an outdated version:") + "
      "; for (const QString &plugin : m_FailedPlugins) { result += "
    • " + plugin + "
    • "; } diff --git a/src/pluginlist.cpp b/src/pluginlist.cpp index f72ab690..f8a27ef4 100644 --- a/src/pluginlist.cpp +++ b/src/pluginlist.cpp @@ -69,23 +69,12 @@ static bool ByPriority(const PluginList::ESPInfo& LHS, const PluginList::ESPInfo static bool ByDate(const PluginList::ESPInfo& LHS, const PluginList::ESPInfo& RHS) { return QFileInfo(LHS.m_FullPath).lastModified() < QFileInfo(RHS.m_FullPath).lastModified(); -/* QString lhsExtension = LHS.m_Name.right(3).toLower(); - QString rhsExtension = RHS.m_Name.right(3).toLower(); - if (lhsExtension != rhsExtension) { - return lhsExtension == "esm"; - } - - return ::CompareFileTime(&LHS.m_Time, &RHS.m_Time) < 0;*/ } PluginList::PluginList(QObject *parent) : QAbstractItemModel(parent) , m_FontMetrics(QFont()) - , m_SaveTimer(this) { - m_SaveTimer.setSingleShot(true); - connect(&m_SaveTimer, SIGNAL(timeout()), this, SIGNAL(saveTimer())); - m_Utf8Codec = QTextCodec::codecForName("utf-8"); m_LocalCodec = QTextCodec::codecForName("Windows-1252"); @@ -238,7 +227,8 @@ void PluginList::enableESP(const QString &name, bool enable) if (iter != m_ESPsByName.end()) { m_ESPs[iter->second].m_Enabled = enable; - startSaveTime(); + + emit writePluginsList(); } else { reportError(tr("esp not found: %1").arg(name)); } @@ -252,7 +242,7 @@ void PluginList::enableAll() for (std::vector::iterator iter = m_ESPs.begin(); iter != m_ESPs.end(); ++iter) { iter->m_Enabled = true; } - startSaveTime(); + emit writePluginsList(); } } @@ -266,7 +256,7 @@ void PluginList::disableAll() iter->m_Enabled = false; } } - startSaveTime(); + emit writePluginsList(); } } @@ -382,7 +372,7 @@ void PluginList::readEnabledFrom(const QString &fileName) m_ESPs[iter->second].m_Enabled = true; } else { qWarning("plugin %s not found", modName.toUtf8().constData()); - startSaveTime(); + emit writePluginsList(); } } } @@ -503,8 +493,6 @@ void PluginList::saveTo(const QString &pluginFileName } else if (QFile::exists(deleterFileName)) { shellDelete(QStringList() << deleterFileName); } - - m_SaveTimer.stop(); } @@ -581,7 +569,8 @@ void PluginList::lockESPIndex(int index, bool lock) m_LockedOrder.erase(iter); } } - startSaveTime(); +qDebug(__FUNCTION__); + emit writePluginsList(); } @@ -631,7 +620,7 @@ void PluginList::refreshLoadOrder() setPluginPriority(index, temp); m_ESPs[index].m_LoadOrder = iter->first; syncLoadOrder(); - startSaveTime(); + emit writePluginsList(); } } } @@ -897,7 +886,7 @@ bool PluginList::setData(const QModelIndex &modIndex, const QVariant &value, int emit dataChanged(modIndex, modIndex); refreshLoadOrder(); - startSaveTime(); + emit writePluginsList(); result = true; } else if (role == Qt::EditRole) { @@ -1034,21 +1023,8 @@ void PluginList::changePluginPriority(std::vector rows, int newPriority) layoutChange.finish(); refreshLoadOrder(); - - startSaveTime(); -} - - -void PluginList::startSaveTime() -{ - testMasters(); - - if (!m_SaveTimer.isActive()) { - m_SaveTimer.start(2000); - } } - bool PluginList::dropMimeData(const QMimeData *mimeData, Qt::DropAction action, int row, int, const QModelIndex &parent) { if (action == Qt::IgnoreAction) { diff --git a/src/pluginlist.h b/src/pluginlist.h index e0913840..80fcc25b 100644 --- a/src/pluginlist.h +++ b/src/pluginlist.h @@ -262,10 +262,7 @@ signals: **/ void esplist_changed(); - /** - * @brief emitted when the plugin list should be saved - */ - void saveTimer(); + void writePluginsList(); private: @@ -310,8 +307,6 @@ private: void setPluginPriority(int row, int &newPriority); void changePluginPriority(std::vector rows, int newPriority); - void startSaveTime(); - void testMasters(); private: @@ -336,14 +331,11 @@ private: QTextCodec *m_Utf8Codec; QTextCodec *m_LocalCodec; - mutable QTimer m_SaveTimer; - SignalRefreshed m_Refreshed; SignalPluginMoved m_PluginMoved; QTemporaryFile m_TempFile; - }; #endif // PLUGINLIST_H diff --git a/src/profile.cpp b/src/profile.cpp index 5d31533a..c1e6e5fc 100644 --- a/src/profile.cpp +++ b/src/profile.cpp @@ -34,6 +34,7 @@ along with Mod Organizer. If not, see . #include #include #include +#include #define WIN32_LEAN_AND_MEAN #include @@ -43,10 +44,10 @@ along with Mod Organizer. If not, see . using namespace MOBase; using namespace MOShared; + Profile::Profile() - : m_SaveTimer(nullptr) + : m_ModListWriter(std::bind(&Profile::writeModlistNow, this)) { - initTimer(); } void Profile::touchFile(QString fileName) @@ -58,10 +59,9 @@ void Profile::touchFile(QString fileName) } Profile::Profile(const QString &name, IPluginGame *gamePlugin, bool useDefaultSettings) - : m_SaveTimer(nullptr) + : m_ModListWriter(std::bind(&Profile::writeModlistNow, this)) , m_GamePlugin(gamePlugin) { - initTimer(); QString profilesDir = qApp->property("dataPath").toString() + "/" + ToQString(AppConfig::profilesPath()); QDir profileBase(profilesDir); @@ -100,10 +100,10 @@ Profile::Profile(const QString &name, IPluginGame *gamePlugin, bool useDefaultSe Profile::Profile(const QDir &directory, IPluginGame *gamePlugin) - : m_Directory(directory), m_SaveTimer(nullptr) + : m_Directory(directory) + , m_ModListWriter(std::bind(&Profile::writeModlistNow, this)) { assert(gamePlugin != nullptr); - initTimer(); if (!QFile::exists(m_Directory.filePath("modlist.txt"))) { qWarning("missing modlist.txt in %s", qPrintable(directory.path())); @@ -124,52 +124,24 @@ Profile::Profile(const QDir &directory, IPluginGame *gamePlugin) Profile::Profile(const Profile &reference) : m_Directory(reference.m_Directory) - , m_SaveTimer(nullptr) + , m_ModListWriter(std::bind(&Profile::writeModlistNow, this)) { - initTimer(); refreshModStatus(); } Profile::~Profile() { - writeModlistNow(); -} - - -void Profile::initTimer() -{ - m_SaveTimer = new QTimer(this); - m_SaveTimer->setSingleShot(true); - connect(m_SaveTimer, SIGNAL(timeout()), this, SLOT(writeModlistNow())); + m_ModListWriter.writeImmediately(true); } - bool Profile::exists() const { return m_Directory.exists(); } - -void Profile::writeModlist() const -{ - if (!m_SaveTimer->isActive()) { - m_SaveTimer->start(2000); - } -} - - -void Profile::cancelWriteModlist() const +void Profile::writeModlistNow() { - m_SaveTimer->stop(); -} - - -void Profile::writeModlistNow(bool onlyOnTimer) const -{ - if (onlyOnTimer && !m_SaveTimer->isActive()) return; - - m_SaveTimer->stop(); if (!m_Directory.exists()) return; try { @@ -366,7 +338,7 @@ void Profile::refreshModStatus() file.close(); updateIndices(); if (modStatusModified) { - writeModlist(); + m_ModListWriter.write(); } } @@ -456,7 +428,6 @@ void Profile::setModEnabled(unsigned int index, bool enabled) } } - bool Profile::modEnabled(unsigned int index) const { if (index >= m_ModStatus.size()) { @@ -508,7 +479,7 @@ void Profile::setModPriority(unsigned int index, int &newPriority) m_ModStatus.at(index).m_Priority = newPriorityTemp; updateIndices(); - writeModlist(); + m_ModListWriter.write(); } Profile *Profile::createPtrFrom(const QString &name, const Profile &reference, MOBase::IPluginGame *gamePlugin) diff --git a/src/profile.h b/src/profile.h index 5eaa1ea1..342b6fa0 100644 --- a/src/profile.h +++ b/src/profile.h @@ -23,6 +23,7 @@ along with Mod Organizer. If not, see . #include "modinfo.h" #include +#include #include #include #include @@ -89,16 +90,7 @@ public: **/ static Profile *createPtrFrom(const QString &name, const Profile &reference, MOBase::IPluginGame *gamePlugin); - /** - * @brief write out the modlist.txt - **/ - void writeModlist() const; - - /** - * cancel any potential request to write modlist.txt. This is used to ensure no invalid modlist is - * saved while it's being modified - */ - void cancelWriteModlist() const; + MOBase::DelayedFileWriter &modlistWriter() { return m_ModListWriter; } /** * @brief test if this profile uses archive invalidation @@ -283,7 +275,7 @@ signals: public slots: - void writeModlistNow(bool onlyOnTimer = false) const; + void writeModlistNow(); private: @@ -310,6 +302,7 @@ private: void mergeTweak(const QString &tweakName, const QString &tweakedIni) const; void mergeTweaks(ModInfo::Ptr modInfo, const QString &tweakedIni) const; void touchFile(QString fileName); + void finishChangeStatus() const; private: @@ -322,7 +315,7 @@ private: std::vector m_ModIndexByPriority; unsigned int m_NumRegularMods; - QTimer *m_SaveTimer; + MOBase::DelayedFileWriter m_ModListWriter; }; diff --git a/src/version.rc b/src/version.rc index 68d7cd23..d6fe2f85 100644 --- a/src/version.rc +++ b/src/version.rc @@ -1,7 +1,7 @@ #include "Winver.h" -#define VER_FILEVERSION 1,3,0,0 -#define VER_FILEVERSION_STR "1,3,0,0\0" +#define VER_FILEVERSION 1,3,1,0 +#define VER_FILEVERSION_STR "1,3,1,0\0" VS_VERSION_INFO VERSIONINFO FILEVERSION VER_FILEVERSION -- cgit v1.3.1