summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAl <26797547+Al12rs@users.noreply.github.com>2020-11-28 06:32:09 -0800
committerGitHub <noreply@github.com>2020-11-28 06:32:09 -0800
commit2c115e48cc42f89250bbca7e2b5b75d5dcad8695 (patch)
treebff3fc474a4527331c99ddb981f88c49cb7fd286
parentdffec4fd9dfa6860a62b4c59fe75c03006a37146 (diff)
parentef1188811633e8c1403f960c9196de92d0a81020 (diff)
Merge pull request #1301 from ModOrganizer2/iplugingame-saves
IPluginGame::listSaves
-rw-r--r--src/mainwindow.cpp58
-rw-r--r--src/mainwindow.h2
-rw-r--r--src/modinfowithconflictinfo.cpp4
-rw-r--r--src/modinfowithconflictinfo.h12
-rw-r--r--src/plugincontainer.cpp22
-rw-r--r--src/plugincontainer.h4
-rw-r--r--src/thread_utils.h45
-rw-r--r--src/transfersavesdialog.cpp105
-rw-r--r--src/transfersavesdialog.h7
9 files changed, 57 insertions, 202 deletions
diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp
index cdc048fd..69f90ce4 100644
--- a/src/mainwindow.cpp
+++ b/src/mainwindow.cpp
@@ -430,7 +430,10 @@ MainWindow::MainWindow(Settings &settings
this, &MainWindow::refresherProgress);
connect(m_OrganizerCore.directoryRefresher(), SIGNAL(error(QString)), this, SLOT(showError(QString)));
- connect(&m_SavesWatcher, SIGNAL(directoryChanged(QString)), this, SLOT(refreshSavesIfOpen()));
+ m_SavesWatcherTimer.setSingleShot(true);
+ m_SavesWatcherTimer.setInterval(500);
+ connect(&m_SavesWatcher, &QFileSystemWatcher::directoryChanged, [this]() { m_SavesWatcherTimer.start(); });
+ connect(&m_SavesWatcherTimer, &QTimer::timeout, this, &MainWindow::refreshSavesIfOpen);
connect(&m_OrganizerCore.settings(), SIGNAL(languageChanged(QString)), this, SLOT(languageChange(QString)));
connect(&m_OrganizerCore.settings(), SIGNAL(styleChanged(QString)), this, SIGNAL(styleChanged(QString)));
@@ -508,6 +511,7 @@ MainWindow::MainWindow(Settings &settings
m_Tutorial.expose("espList", m_OrganizerCore.pluginList());
m_OrganizerCore.setUserInterface(this);
+ m_PluginContainer.setUserInterface(this);
connect(this, &MainWindow::userInterfaceInitialized, &m_OrganizerCore, &OrganizerCore::userInterfaceInitialized);
for (const QString &fileName : m_PluginContainer.pluginFileNames()) {
installTranslator(QFileInfo(fileName).baseName());
@@ -700,7 +704,7 @@ MainWindow::~MainWindow()
try {
cleanup();
- m_PluginContainer.setUserInterface(nullptr, nullptr);
+ m_PluginContainer.setUserInterface(nullptr);
m_OrganizerCore.setUserInterface(nullptr);
if (m_IntegratedBrowser) {
@@ -1529,7 +1533,6 @@ void MainWindow::displaySaveGameInfo(QListWidgetItem *newItem)
return;
}
- QString const &save = newItem->data(Qt::UserRole).toString();
if (m_CurrentSaveView == nullptr) {
IPluginGame const *game = m_OrganizerCore.managedGame();
SaveGameInfo const *info = game->feature<SaveGameInfo>();
@@ -1540,7 +1543,7 @@ void MainWindow::displaySaveGameInfo(QListWidgetItem *newItem)
return;
}
}
- m_CurrentSaveView->setSave(save);
+ m_CurrentSaveView->setSave(*m_SaveGames[ui->savegameList->row(newItem)]);
QWindow *window = m_CurrentSaveView->window()->windowHandle();
QRect screenRect;
@@ -1674,7 +1677,6 @@ void MainWindow::updateToolMenu()
void MainWindow::registerModPage(IPluginModPage *modPage)
{
QAction *action = new QAction(modPage->icon(), modPage->displayName(), this);
- modPage->setParentWidget(this);
connect(action, &QAction::triggered, this, [this, modPage]() {
if (modPage->useIntegratedBrowser()) {
@@ -1961,36 +1963,23 @@ void MainWindow::stopMonitorSaves()
void MainWindow::refreshSaveList()
{
- ui->savegameList->clear();
+ TimeThis tt("MainWindow::refreshSaveList()");
startMonitorSaves(); // re-starts monitoring
- QStringList filters;
- filters << QString("*.") + m_OrganizerCore.managedGame()->savegameExtension();
-
QDir savesDir = currentSavesDir();
- savesDir.setNameFilters(filters);
- savesDir.setFilter(QDir::Files);
- QDirIterator it(savesDir, QDirIterator::Subdirectories);
- log::debug("reading save games from {}", savesDir.absolutePath());
-
- QFileInfoList files;
- while (it.hasNext()) {
- it.next();
- files.append(it.fileInfo());
- }
- std::sort(files.begin(), files.end(), [](auto const& lhs, auto const& rhs) {
- return lhs.fileTime(QFileDevice::FileModificationTime) > rhs.fileTime(QFileDevice::FileModificationTime);
+ MOBase::log::debug("reading save games from {}", savesDir.absolutePath());
+ m_SaveGames = m_OrganizerCore.managedGame()->listSaves(savesDir);
+ std::sort(m_SaveGames.begin(), m_SaveGames.end(), [](auto const& lhs, auto const& rhs) {
+ return lhs->getCreationTime() > rhs->getCreationTime();
});
- for (const QFileInfo &file : files) {
- QListWidgetItem *item = new QListWidgetItem(savesDir.relativeFilePath(file.absoluteFilePath()));
- item->setData(Qt::UserRole, file.absoluteFilePath());
- ui->savegameList->addItem(item);
+ ui->savegameList->clear();
+ for (auto& save: m_SaveGames) {
+ ui->savegameList->addItem(savesDir.relativeFilePath(save->getFilepath()));
}
}
-
static bool BySortValue(const std::pair<UINT32, QTreeWidgetItem*> &LHS, const std::pair<UINT32, QTreeWidgetItem*> &RHS)
{
return LHS.first < RHS.first;
@@ -4957,20 +4946,15 @@ void MainWindow::deleteSavegame_clicked()
int count = 0;
for (const QModelIndex &idx : ui->savegameList->selectionModel()->selectedIndexes()) {
- QString name = idx.data(Qt::UserRole).toString();
+
+ auto& saveGame = m_SaveGames[idx.row()];
if (count < 10) {
- savesMsgLabel += "<li>" + QFileInfo(name).completeBaseName() + "</li>";
+ savesMsgLabel += "<li>" + QFileInfo(saveGame->getFilepath()).completeBaseName() + "</li>";
}
++count;
- if (info == nullptr) {
- deleteFiles.push_back(name);
- } else {
- ISaveGame const *save = info->getSaveGameInfo(name);
- deleteFiles += save->allFiles();
- delete save;
- }
+ deleteFiles += saveGame->allFiles();
}
if (count > 10) {
@@ -5029,8 +5013,8 @@ void MainWindow::on_savegameList_customContextMenuRequested(const QPoint& pos)
QAction* action = menu.addAction(tr("Enable Mods..."));
action->setEnabled(false);
if (selection->selectedIndexes().count() == 1) {
- QString save = ui->savegameList->currentItem()->data(Qt::UserRole).toString();
- SaveGameInfo::MissingAssets missing = info->getMissingAssets(save);
+ auto& save = m_SaveGames[selection->selectedIndexes()[0].row()];
+ SaveGameInfo::MissingAssets missing = info->getMissingAssets(*save);
if (missing.size() != 0) {
connect(action, &QAction::triggered, this, [this, missing] { fixMods_clicked(missing); });
action->setEnabled(true);
diff --git a/src/mainwindow.h b/src/mainwindow.h
index e2805b25..da7bb6ee 100644
--- a/src/mainwindow.h
+++ b/src/mainwindow.h
@@ -334,6 +334,7 @@ private:
QTime m_StartTime;
//SaveGameInfoWidget *m_CurrentSaveView;
+ std::vector<std::shared_ptr<const MOBase::ISaveGame>> m_SaveGames;
MOBase::ISaveGameInfoWidget *m_CurrentSaveView;
OrganizerCore &m_OrganizerCore;
@@ -344,6 +345,7 @@ private:
std::unique_ptr<BrowserDialog> m_IntegratedBrowser;
+ QTimer m_SavesWatcherTimer;
QFileSystemWatcher m_SavesWatcher;
QByteArray m_ArchiveListHash;
diff --git a/src/modinfowithconflictinfo.cpp b/src/modinfowithconflictinfo.cpp
index 6e3f751e..ad7eda3f 100644
--- a/src/modinfowithconflictinfo.cpp
+++ b/src/modinfowithconflictinfo.cpp
@@ -15,7 +15,7 @@ namespace fs = std::filesystem;
ModInfoWithConflictInfo::ModInfoWithConflictInfo(
PluginContainer *pluginContainer, const MOBase::IPluginGame* gamePlugin, DirectoryEntry **directoryStructure)
- : ModInfo(pluginContainer), m_GamePlugin(gamePlugin),
+ : ModInfo(pluginContainer), m_GamePlugin(gamePlugin),
m_FileTree([this]() { return QDirFileTree::makeTree(absolutePath()); }),
m_Valid([this]() { return doIsValid(); }),
m_Contents([this]() { return doGetContents(); }),
@@ -27,7 +27,7 @@ void ModInfoWithConflictInfo::clearCaches()
}
std::vector<ModInfo::EFlag> ModInfoWithConflictInfo::getFlags() const
-{
+{
std::vector<ModInfo::EFlag> result = std::vector<ModInfo::EFlag>();
if (hasHiddenFiles()) {
result.push_back(ModInfo::FLAG_HIDDEN_FILES);
diff --git a/src/modinfowithconflictinfo.h b/src/modinfowithconflictinfo.h
index feded99b..0d11fcb1 100644
--- a/src/modinfowithconflictinfo.h
+++ b/src/modinfowithconflictinfo.h
@@ -3,7 +3,7 @@
#include <ifiletree.h>
-#include "thread_utils.h"
+#include "memoizedlock.h"
#include "modinfo.h"
#include <set>
@@ -34,7 +34,9 @@ public:
*
* @return true if the content is there, false otherwise.
*/
- virtual bool hasContent(int content) const override; /**
+ virtual bool hasContent(int content) const override;
+
+ /**
* @brief Retrieve a file tree corresponding to the underlying disk content
* of this mod.
*
@@ -145,9 +147,9 @@ protected:
private:
- MOShared::MemoizedLocked<std::shared_ptr<const MOBase::IFileTree>> m_FileTree;
- MOShared::MemoizedLocked<bool> m_Valid;
- MOShared::MemoizedLocked<std::set<int>> m_Contents;
+ MOBase::MemoizedLocked<std::shared_ptr<const MOBase::IFileTree>> m_FileTree;
+ MOBase::MemoizedLocked<bool> m_Valid;
+ MOBase::MemoizedLocked<std::set<int>> m_Contents;
MOShared::DirectoryEntry **m_DirectoryStructure;
diff --git a/src/plugincontainer.cpp b/src/plugincontainer.cpp
index f7a556e0..44c9a651 100644
--- a/src/plugincontainer.cpp
+++ b/src/plugincontainer.cpp
@@ -119,9 +119,7 @@ PluginRequirements::PluginRequirements(
}
void PluginRequirements::fetchRequirements() {
- for (auto* requirement : m_Plugin->requirements()) {
- m_Requirements.emplace_back(requirement);
- }
+ m_Requirements = m_Plugin->requirements();
}
IPluginProxy* PluginRequirements::proxy() const
@@ -291,15 +289,17 @@ PluginContainer::~PluginContainer() {
unloadPlugins();
}
-void PluginContainer::setUserInterface(IUserInterface *userInterface, QWidget *widget)
+void PluginContainer::setUserInterface(IUserInterface *userInterface)
{
- for (IPluginProxy *proxy : bf::at_key<IPluginProxy>(m_Plugins)) {
- proxy->setParentWidget(widget);
- }
-
- if (userInterface != nullptr) {
- for (IPluginModPage *modPage : bf::at_key<IPluginModPage>(m_Plugins)) {
- userInterface->registerModPage(modPage);
+ if (userInterface) {
+ for (IPluginProxy* proxy : bf::at_key<IPluginProxy>(m_Plugins)) {
+ proxy->setParentWidget(userInterface->mainWindow());
+ }
+ for (IPluginModPage* modPage : bf::at_key<IPluginModPage>(m_Plugins)) {
+ modPage->setParentWidget(userInterface->mainWindow());
+ }
+ for (IPluginTool* tool : bf::at_key<IPluginTool>(m_Plugins)) {
+ tool->setParentWidget(userInterface->mainWindow());
}
}
diff --git a/src/plugincontainer.h b/src/plugincontainer.h
index 36edfad9..26e12659 100644
--- a/src/plugincontainer.h
+++ b/src/plugincontainer.h
@@ -109,7 +109,7 @@ private:
MOBase::IPlugin* m_Plugin;
MOBase::IPluginProxy* m_PluginProxy;
MOBase::IPlugin* m_Master;
- std::vector<std::unique_ptr<const MOBase::IPluginRequirement>> m_Requirements;
+ std::vector<std::shared_ptr<const MOBase::IPluginRequirement>> m_Requirements;
MOBase::IOrganizer* m_Organizer;
std::vector<MOBase::IPlugin*> m_RequiredFor;
@@ -188,7 +188,7 @@ public:
PluginContainer(OrganizerCore *organizer);
virtual ~PluginContainer();
- void setUserInterface(IUserInterface *userInterface, QWidget *widget);
+ void setUserInterface(IUserInterface *userInterface);
void loadPlugins();
void unloadPlugins();
diff --git a/src/thread_utils.h b/src/thread_utils.h
index f64dd601..e816a4e2 100644
--- a/src/thread_utils.h
+++ b/src/thread_utils.h
@@ -24,51 +24,6 @@ std::thread startSafeThread(F&& f)
});
}
-
-/**
- * Class that can be used to perform thread-safe memoization.
- *
- * Each instance hold a flag indicating if the current value is up-to-date
- * or not. This flag can be reset using `invalidate()`. When the value is queried,
- * the flag is checked, and if it is not up-to-date, the given callback is used
- * to compute the value.
- *
- * The computation and update of the value is locked to avoid concurrent modifications.
- *
- * @tparam T Type of value ot memoized.
- * @tparam Fn Type of the callback.
- */
-template <class T, class Fn = std::function<T()>>
-struct MemoizedLocked {
-
- template <class Callable>
- MemoizedLocked(Callable &&callable, T value = {}) :
- m_Fn{ std::forward<Callable>(callable) }, m_Value{ std::move(value) } { }
-
- template <class... Args>
- T& value(Args&&... args) const {
- if (m_NeedUpdating) {
- std::scoped_lock lock(m_Mutex);
- if (m_NeedUpdating) {
- m_Value = std::invoke(m_Fn, std::forward<Args>(args)... );
- m_NeedUpdating = false;
- }
- }
- return m_Value;
- }
-
- void invalidate() {
- m_NeedUpdating = true;
- }
-
-private:
- mutable std::mutex m_Mutex;
- mutable std::atomic<bool> m_NeedUpdating{ true };
-
- Fn m_Fn;
- mutable T m_Value;
-};
-
/**
* @brief Apply the given callable to each element between the two given iterators
* in a parallel way.
diff --git a/src/transfersavesdialog.cpp b/src/transfersavesdialog.cpp
index f8ebbb9d..5288d408 100644
--- a/src/transfersavesdialog.cpp
+++ b/src/transfersavesdialog.cpp
@@ -42,74 +42,6 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
using namespace MOBase;
using namespace MOShared;
-//These two classes give the save-transfer box a smidgin of useful info even
-//if save game isn't supported yet.
-namespace {
-
-class DummySave : public ISaveGame
-{
-public:
- DummySave(QString const &filename) :
- m_File(filename)
- {}
-
- ~DummySave() {}
-
- virtual QString getFilename() const override
- {
- return m_File;
- }
-
- virtual QDateTime getCreationTime() const override
- {
- return QFileInfo(m_File).birthTime();
- }
-
- virtual QString getSaveGroupIdentifier() const override
- {
- return m_File;
- }
-
- virtual QStringList allFiles() const override
- {
- return { m_File };
- }
-
- virtual bool hasScriptExtenderFile() const override
- {
- return false;
- }
-
-private:
- QString m_File;
-};
-
-class DummyInfo : public SaveGameInfo
-{
-public:
- virtual MOBase::ISaveGame const *getSaveGameInfo(QString const &file) const override
- {
- return new DummySave(file);
- }
-
- virtual MissingAssets getMissingAssets(QString const &) const override
- {
- return {};
- }
-
- MOBase::ISaveGameInfoWidget *getSaveGameWidget(QWidget *) const override
- {
- return nullptr;
- }
-
- virtual bool hasScriptExtenderSave(QString const &file) const override
- {
- return false;
- }
-};
-
-} //end anonymous namespace
-
TransferSavesDialog::TransferSavesDialog(const Profile &profile, IPluginGame const *gamePlugin, QWidget *parent)
: TutorableDialog("TransferSaves", parent)
, ui(new Ui::TransferSavesDialog)
@@ -263,7 +195,7 @@ void TransferSavesDialog::on_globalCharacterList_currentTextChanged(const QStrin
SaveCollection::const_iterator saveList = m_GlobalSaves.find(currentText);
if (saveList != m_GlobalSaves.end()) {
for (SaveListItem const &save : saveList->second) {
- ui->globalSavesList->addItem(QFileInfo(save->getFilename()).fileName());
+ ui->globalSavesList->addItem(QFileInfo(save->getFilepath()).fileName());
}
}
}
@@ -276,7 +208,7 @@ void TransferSavesDialog::on_localCharacterList_currentTextChanged(const QString
SaveCollection::const_iterator saveList = m_LocalSaves.find(currentText);
if (saveList != m_LocalSaves.end()) {
for (SaveListItem const &save : saveList->second) {
- ui->localSavesList->addItem(QFileInfo(save->getFilename()).fileName());
+ ui->localSavesList->addItem(QFileInfo(save->getFilepath()).fileName());
}
}
}
@@ -285,34 +217,13 @@ void TransferSavesDialog::refreshSaves(SaveCollection &saveCollection, QString c
{
saveCollection.clear();
- SaveGameInfo const *info = m_GamePlugin->feature<SaveGameInfo>();
- if (info == nullptr) {
- static DummyInfo dummyInfo;
- info = &dummyInfo;
- }
-
- QStringList filters;
- filters << QString("*.") + m_GamePlugin->savegameExtension();
-
- QDir savesDir(savedir);
- savesDir.setNameFilters(QStringList() << QString("*.") + m_GamePlugin->savegameExtension());
- savesDir.setFilter(QDir::Files);
- QDirIterator it(savesDir, QDirIterator::Subdirectories);
- log::debug("reading save games from {}", savesDir.absolutePath());
-
- QFileInfoList files;
- while (it.hasNext()) {
- it.next();
- files.append(it.fileInfo());
- }
- std::sort(files.begin(), files.end(), [](auto const& lhs, auto const& rhs) {
- return lhs.fileTime(QFileDevice::FileModificationTime) < rhs.fileTime(QFileDevice::FileModificationTime);
+ auto saves = m_GamePlugin->listSaves(savedir);
+ std::sort(saves.begin(), saves.end(), [](auto const& lhs, auto const& rhs) {
+ return lhs->getCreationTime() > rhs->getCreationTime();
});
- for (const QFileInfo &file: files) {
- MOBase::ISaveGame const *save = info->getSaveGameInfo(file.absoluteFilePath());
- saveCollection[save->getSaveGroupIdentifier()].push_back(
- std::unique_ptr<MOBase::ISaveGame const>(save));
+ for (auto& save: saves) {
+ saveCollection[save->getSaveGroupIdentifier()].push_back(save);
}
}
@@ -334,7 +245,7 @@ void TransferSavesDialog::refreshCharacters(const SaveCollection &saveCollection
}
bool TransferSavesDialog::transferCharacters(
- QString const &character, char const *message,
+ QString const &character, char const *message,
QDir const& sourceDirectory,
SaveList &saves,
QDir const& destination,
diff --git a/src/transfersavesdialog.h b/src/transfersavesdialog.h
index b983ad9e..fe78aa83 100644
--- a/src/transfersavesdialog.h
+++ b/src/transfersavesdialog.h
@@ -80,9 +80,10 @@ private:
MOBase::IPluginGame const *m_GamePlugin;
- typedef std::unique_ptr<MOBase::ISaveGame const> SaveListItem;
- typedef std::vector<SaveListItem> SaveList;
- typedef std::map<QString, SaveList> SaveCollection;
+ using SaveListItem = std::shared_ptr<const MOBase::ISaveGame>;
+ using SaveList = std::vector<SaveListItem>;
+ using SaveCollection = std::map<QString, SaveList>;
+
SaveCollection m_GlobalSaves;
SaveCollection m_LocalSaves;