summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMikaël Capelle <capelle.mikael@gmail.com>2020-05-24 13:27:40 +0200
committerMikaël Capelle <capelle.mikael@gmail.com>2020-05-24 13:27:40 +0200
commit9fb639a00e1a809a9ea9b5e68777ec46f534761c (patch)
tree9f72cebe6ba9825a0330fefe60a0b55de2392a2e /src
parent08ae9db2fd2a07acb2433275fc84c2ca47267a92 (diff)
Update ModInfo to use a single file tree for all content-related operations.
Diffstat (limited to 'src')
-rw-r--r--src/mainwindow.cpp4
-rw-r--r--src/modinfo.cpp7
-rw-r--r--src/modinfo.h23
-rw-r--r--src/modinfooverwrite.cpp1
-rw-r--r--src/modinforegular.cpp90
-rw-r--r--src/modinforegular.h3
-rw-r--r--src/modinfowithconflictinfo.cpp18
-rw-r--r--src/modinfowithconflictinfo.h38
-rw-r--r--src/modlist.cpp4
-rw-r--r--src/modlist.h2
-rw-r--r--src/organizercore.cpp2
11 files changed, 112 insertions, 80 deletions
diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp
index b5beb229..cc681dba 100644
--- a/src/mainwindow.cpp
+++ b/src/mainwindow.cpp
@@ -3062,7 +3062,7 @@ void MainWindow::ignoreMissingData_clicked()
int row_idx = idx.data(Qt::UserRole + 1).toInt();
ModInfo::Ptr info = ModInfo::getByIndex(row_idx);
//QDir(info->absolutePath()).mkdir("textures");
- info->testValid();
+ info->diskContentModified();
info->markValidated(true);
connect(this, SIGNAL(modListDataChanged(QModelIndex, QModelIndex)), m_OrganizerCore.modList(), SIGNAL(dataChanged(QModelIndex, QModelIndex)));
@@ -3071,7 +3071,7 @@ void MainWindow::ignoreMissingData_clicked()
} else {
ModInfo::Ptr info = ModInfo::getByIndex(m_ContextRow);
//QDir(info->absolutePath()).mkdir("textures");
- info->testValid();
+ info->diskContentModified();
info->markValidated(true);
connect(this, SIGNAL(modListDataChanged(QModelIndex, QModelIndex)), m_OrganizerCore.modList(), SIGNAL(dataChanged(QModelIndex, QModelIndex)));
diff --git a/src/modinfo.cpp b/src/modinfo.cpp
index 379fa071..0dd113c5 100644
--- a/src/modinfo.cpp
+++ b/src/modinfo.cpp
@@ -306,7 +306,7 @@ void ModInfo::updateIndices()
ModInfo::ModInfo(PluginContainer *pluginContainer)
- : m_Valid(false), m_PrimaryCategory(-1)
+ : m_PrimaryCategory(-1)
{
}
@@ -528,11 +528,6 @@ bool ModInfo::categorySet(int categoryID) const
return false;
}
-void ModInfo::testValid()
-{
- m_Valid = doTestValid();
-}
-
QUrl ModInfo::parseCustomURL() const
{
if (!hasCustomURL() || getCustomURL().isEmpty()) {
diff --git a/src/modinfo.h b/src/modinfo.h
index f582cc32..b3e75bc4 100644
--- a/src/modinfo.h
+++ b/src/modinfo.h
@@ -702,7 +702,7 @@ public:
/**
* @return true if this mod is considered "valid", that is: it contains data used by the game
**/
- virtual bool isValid() const { return m_Valid; }
+ virtual bool isValid() const = 0;
/**
* @return true if the file has been endorsed on nexus
@@ -715,11 +715,6 @@ public:
virtual ETrackedState trackedState() const { return TRACKED_FALSE; }
/**
- * @brief updates the valid-flag for this mod
- */
- void testValid();
-
- /**
* @brief updates the mod to flag it as converted in order to ignore the alternate game warning
*/
virtual void markConverted(bool) {}
@@ -801,6 +796,13 @@ public:
**/
QUrl parseCustomURL() const;
+public slots:
+
+ /**
+ * @brief Notify this mod that the content of the disk may have changed.
+ */
+ virtual void diskContentModified() = 0;
+
signals:
/**
@@ -817,13 +819,6 @@ protected:
static void updateIndices();
static bool ByName(const ModInfo::Ptr &LHS, const ModInfo::Ptr &RHS);
- /**
- * @brief check if the content of this mod is valid.
- *
- * @return true if the content is valid, false otherwize.
- **/
- virtual bool doTestValid() const = 0;
-
private:
static void createFromOverwrite(PluginContainer *pluginContainer,
@@ -848,8 +843,6 @@ private:
static std::map<std::pair<QString, int>, std::vector<unsigned int> > s_ModsByModID;
static int s_NextID;
- bool m_Valid;
-
};
diff --git a/src/modinfooverwrite.cpp b/src/modinfooverwrite.cpp
index 3b914134..8aad6209 100644
--- a/src/modinfooverwrite.cpp
+++ b/src/modinfooverwrite.cpp
@@ -9,7 +9,6 @@
ModInfoOverwrite::ModInfoOverwrite(PluginContainer *pluginContainer, const MOBase::IPluginGame *game, MOShared::DirectoryEntry **directoryStructure)
: ModInfoWithConflictInfo(pluginContainer, game, directoryStructure)
{
- testValid();
}
bool ModInfoOverwrite::isEmpty() const
diff --git a/src/modinforegular.cpp b/src/modinforegular.cpp
index d89716da..3c1d49ea 100644
--- a/src/modinforegular.cpp
+++ b/src/modinforegular.cpp
@@ -38,7 +38,6 @@ ModInfoRegular::ModInfoRegular(PluginContainer *pluginContainer, const IPluginGa
, m_TrackedState(TRACKED_UNKNOWN)
, m_NexusBridge(pluginContainer)
{
- testValid();
m_CreationTime = QFileInfo(path.absolutePath()).birthTime();
// read out the meta-file for information
readMeta();
@@ -656,58 +655,59 @@ std::vector<ModInfo::EFlag> ModInfoRegular::getFlags() const
std::vector<ModInfo::EContent> ModInfoRegular::getContents() const
{
- QTime now = QTime::currentTime();
- if (m_LastContentCheck.isNull() || (m_LastContentCheck.secsTo(now) > 60)) {
- m_CachedContent.clear();
- QDir dir(absolutePath());
- if (dir.entryList(QStringList() << "*.esp" << "*.esm" << "*.esl").size() > 0) {
- m_CachedContent.push_back(CONTENT_PLUGIN);
- }
- if (dir.entryList(QStringList() << "*.bsa" << "*.ba2").size() > 0) {
- m_CachedContent.push_back(CONTENT_BSA);
- }
- //use >1 for ini files since there is meta.ini in all mods already.
- if (dir.entryList(QStringList() << "*.ini").size() > 1) {
- m_CachedContent.push_back(CONTENT_INI);
- }
+ auto tree = contentFileTree();
+ std::vector<ModInfo::EContent> contents;
- if (dir.entryList(QStringList() << "*.modgroups").size() > 0) {
- m_CachedContent.push_back(CONTENT_MODGROUP);
+ for (auto e : *tree) {
+ if (e->isFile()) {
+ auto suffix = e->suffix();
+ if (suffix == "esp" || suffix == "esm" || suffix == "esl") {
+ contents.push_back(CONTENT_PLUGIN);
+ }
+ else if (suffix == "bsa" || suffix == "ba2") {
+ contents.push_back(CONTENT_BSA);
+ }
+ //use >1 for ini files since there is meta.ini in all mods already.
+ else if (suffix == "ini" && e->compare("meta.ini") != 0) {
+ contents.push_back(CONTENT_INI);
+ }
+ else if (suffix == "modgroups") {
+ contents.push_back(CONTENT_MODGROUP);
+ }
}
+ else {
+ if (e->compare("textures") == 0 || e->compare("icons") == 0 || e->compare("bookart") == 0)
+ contents.push_back(CONTENT_TEXTURE);
+ if (e->compare("meshes") == 0)
+ contents.push_back(CONTENT_MESH);
+ if (e->compare("interface") == 0 || e->compare("menus") == 0)
+ contents.push_back(CONTENT_INTERFACE);
+ if (e->compare("music") == 0 || e->compare("sound") == 0)
+ contents.push_back(CONTENT_SOUND);
+ if (e->compare("scripts") == 0)
+ contents.push_back(CONTENT_SCRIPT);
+ if (e->compare("SkyProc Patchers") == 0)
+ contents.push_back(CONTENT_SKYPROC);
+ if (e->compare("MCM") == 0)
+ contents.push_back(CONTENT_MCM);
+ }
+ }
- ScriptExtender *extender = qApp->property("managed_game")
- .value<IPluginGame *>()
- ->feature<ScriptExtender>();
-
- if (extender != nullptr) {
- QString sePluginPath = extender->PluginPath();
- if (dir.exists(sePluginPath)) {
- m_CachedContent.push_back(CONTENT_SKSEFILES);
- QDir sePluginDir(absolutePath() + "/" + sePluginPath);
- if (sePluginDir.entryList(QStringList() << "*.dll").size() > 0) {
- m_CachedContent.push_back(CONTENT_SKSE);
+ ScriptExtender* extender = m_GamePlugin->feature<ScriptExtender>();
+ if (extender != nullptr) {
+ auto e = tree->findDirectory(extender->PluginPath());
+ if (e) {
+ contents.push_back(CONTENT_SKSEFILES);
+ for (auto f : *e) {
+ if (e->suffix().compare("dll") == 0) {
+ contents.push_back(CONTENT_SKSE);
+ break;
}
}
}
- if (dir.exists("textures") || dir.exists("icons") || dir.exists("bookart"))
- m_CachedContent.push_back(CONTENT_TEXTURE);
- if (dir.exists("meshes"))
- m_CachedContent.push_back(CONTENT_MESH);
- if (dir.exists("interface") || dir.exists("menus"))
- m_CachedContent.push_back(CONTENT_INTERFACE);
- if (dir.exists("music") || dir.exists("sound"))
- m_CachedContent.push_back(CONTENT_SOUND);
- if (dir.exists("scripts"))
- m_CachedContent.push_back(CONTENT_SCRIPT);
- if (dir.exists("SkyProc Patchers"))
- m_CachedContent.push_back(CONTENT_SKYPROC);
- if (dir.exists("MCM"))
- m_CachedContent.push_back(CONTENT_MCM);
-
- m_LastContentCheck = QTime::currentTime();
}
- return m_CachedContent;
+ return contents;
}
diff --git a/src/modinforegular.h b/src/modinforegular.h
index 0f22b6cb..08546c69 100644
--- a/src/modinforegular.h
+++ b/src/modinforegular.h
@@ -462,9 +462,6 @@ private:
NexusBridge m_NexusBridge;
- mutable std::vector<ModInfo::EContent> m_CachedContent;
- mutable QTime m_LastContentCheck;
-
bool needsDescriptionUpdate() const;
};
diff --git a/src/modinfowithconflictinfo.cpp b/src/modinfowithconflictinfo.cpp
index 0c67b4f7..45ecffb7 100644
--- a/src/modinfowithconflictinfo.cpp
+++ b/src/modinfowithconflictinfo.cpp
@@ -296,14 +296,30 @@ bool ModInfoWithConflictInfo::hasHiddenFiles() const
return m_HasHiddenFiles;
}
+void ModInfoWithConflictInfo::diskContentModified() {
+ std::unique_lock lock(m_Mutex);
+ m_FileTree = nullptr;
+}
+
+std::shared_ptr<const IFileTree> ModInfoWithConflictInfo::contentFileTree() const {
+ std::unique_lock lock(m_Mutex);
+ if (!m_FileTree) {
+ m_FileTree = QDirFileTree::makeTree(absolutePath());
+ }
+ return m_FileTree;
+}
bool ModInfoWithConflictInfo::doTestValid() const {
auto mdc = m_GamePlugin->feature<ModDataChecker>();
if (mdc) {
- auto qdirfiletree = QDirFileTree::makeTree(absolutePath());
+ auto qdirfiletree = contentFileTree();
return mdc->dataLooksValid(qdirfiletree);
}
return true;
}
+
+bool ModInfoWithConflictInfo::isValid() const {
+ return doTestValid();
+}
diff --git a/src/modinfowithconflictinfo.h b/src/modinfowithconflictinfo.h
index 94a61c62..5bc1d585 100644
--- a/src/modinfowithconflictinfo.h
+++ b/src/modinfowithconflictinfo.h
@@ -1,6 +1,8 @@
#ifndef MODINFOWITHCONFLICTINFO_H
#define MODINFOWITHCONFLICTINFO_H
+#include <ifiletree.h>
+
#include "modinfo.h"
#include <QTime>
@@ -14,6 +16,11 @@ public:
virtual std::vector<ModInfo::EFlag> getFlags() const override;
/**
+ * @return true if this mod is considered "valid", that is: it contains data used by the game
+ **/
+ virtual bool isValid() const override;
+
+ /**
* @brief clear all caches held for this mod
*/
virtual void clearCaches() override;
@@ -32,6 +39,13 @@ public:
virtual void doConflictCheck() const override;
+public slots:
+
+ /**
+ * @brief Notify this mod that the content of the disk may have changed.
+ */
+ virtual void diskContentModified();
+
protected:
/**
@@ -41,6 +55,17 @@ protected:
**/
virtual bool doTestValid() const;
+ /**
+ * @brief Retrieve a file tree corresponding to the underlying disk content
+ * of this mod.
+ *
+ * The file tree should not be cached since it is already cached and updated when
+ * required.
+ *
+ * @return a file tree representing the content of this mod.
+ */
+ std::shared_ptr<const MOBase::IFileTree> contentFileTree() const;
+
ModInfoWithConflictInfo(
PluginContainer* pluginContainer,
const MOBase::IPluginGame* gamePlugin,
@@ -81,10 +106,19 @@ private:
bool hasHiddenFiles() const;
-private:
+protected:
// Current game plugin running in MO2:
- MOBase::IPluginGame const* m_GamePlugin;
+ MOBase::IPluginGame const * const m_GamePlugin;
+
+private:
+
+ // Mutex:
+ mutable std::mutex m_Mutex;
+
+ // File tree representing the content of the disk. A null pointer indicates
+ // that the content needs to be loaded from the disk:
+ mutable std::shared_ptr<const MOBase::IFileTree> m_FileTree = nullptr;
MOShared::DirectoryEntry **m_DirectoryStructure;
diff --git a/src/modlist.cpp b/src/modlist.cpp
index ea4aa2e3..e8c14434 100644
--- a/src/modlist.cpp
+++ b/src/modlist.cpp
@@ -849,7 +849,7 @@ void ModList::modInfoChanged(ModInfo::Ptr info)
}
int row = ModInfo::getIndex(info->name());
- info->testValid();
+ info->diskContentModified();
emit aboutToChangeData();
emit dataChanged(index(row, 0), index(row, columnCount()));
emit postDataChanged();
@@ -1076,7 +1076,7 @@ bool ModList::dropURLs(const QMimeData *mimeData, int row, const QModelIndex &pa
}
if (!modInfo->isValid()) {
- modInfo->testValid();
+ modInfo->diskContentModified();
}
return true;
diff --git a/src/modlist.h b/src/modlist.h
index d8980dec..4d456a9a 100644
--- a/src/modlist.h
+++ b/src/modlist.h
@@ -276,8 +276,6 @@ protected:
private:
- bool testValid(const QString &modDir);
-
QVariant getOverwriteData(int column, int role) const;
QString getFlagText(ModInfo::EFlag flag, ModInfo::Ptr modInfo) const;
diff --git a/src/organizercore.cpp b/src/organizercore.cpp
index feab76a7..74163d8d 100644
--- a/src/organizercore.cpp
+++ b/src/organizercore.cpp
@@ -1629,7 +1629,7 @@ void OrganizerCore::syncOverwrite()
qApp->activeWindow());
if (syncDialog.exec() == QDialog::Accepted) {
syncDialog.apply(QDir::fromNativeSeparators(m_Settings.paths().mods()));
- modInfo->testValid();
+ modInfo->diskContentModified();
refreshDirectoryStructure();
}
}