diff options
| author | Al <26797547+Al12rs@users.noreply.github.com> | 2020-05-20 13:05:02 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-05-20 13:05:02 +0200 |
| commit | b7110cba2dceb172bf6a903f1c5de5ff1c460f11 (patch) | |
| tree | ee3be3be522842c6ef42c14d48c822fa657333c9 /src | |
| parent | c214b67ae784537d696a53c8cae00676eefd3841 (diff) | |
| parent | c391c2b584a309f64f87dd5e00b0083279e6211c (diff) | |
Merge pull request #1066 from Holt59/new-filetree
Update for the new file tree implementation and minor fixes
Diffstat (limited to 'src')
| -rw-r--r-- | src/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | src/archivefiletree.cpp | 279 | ||||
| -rw-r--r-- | src/archivefiletree.h | 72 | ||||
| -rw-r--r-- | src/directoryrefresher.cpp | 13 | ||||
| -rw-r--r-- | src/installationmanager.cpp | 326 | ||||
| -rw-r--r-- | src/installationmanager.h | 93 | ||||
| -rw-r--r-- | src/modinfo.cpp | 27 | ||||
| -rw-r--r-- | src/modinfo.h | 53 | ||||
| -rw-r--r-- | src/modinfobackup.h | 53 | ||||
| -rw-r--r-- | src/modinfodialognexus.cpp | 2 | ||||
| -rw-r--r-- | src/modinfoforeign.h | 110 | ||||
| -rw-r--r-- | src/modinfooverwrite.h | 104 | ||||
| -rw-r--r-- | src/modinforegular.cpp | 5 | ||||
| -rw-r--r-- | src/modinforegular.h | 132 | ||||
| -rw-r--r-- | src/modinfoseparator.h | 86 | ||||
| -rw-r--r-- | src/modinfowithconflictinfo.cpp | 31 | ||||
| -rw-r--r-- | src/modinfowithconflictinfo.h | 29 | ||||
| -rw-r--r-- | src/pluginlist.cpp | 17 |
18 files changed, 818 insertions, 615 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 6e454fc1..99d31541 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -26,6 +26,7 @@ add_filter(NAME src/browser GROUPS add_filter(NAME src/core GROUPS categories + archivefiletree installationmanager instancemanager loadmechanism diff --git a/src/archivefiletree.cpp b/src/archivefiletree.cpp new file mode 100644 index 00000000..0b715f4f --- /dev/null +++ b/src/archivefiletree.cpp @@ -0,0 +1,279 @@ +/* +Copyright (C) MO2 Team. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +// For QObject::tr: +#include <QObject> + +#include "archivefiletree.h" + +#include "log.h" + +using namespace MOBase; + +/** + * We use custom file entries to store the index. + */ +class ArchiveFileEntry : public virtual FileTreeEntry { +public: + + /** + * @brief Create a new entry corresponding to a file. + * + * @param parent The tree containing this file. + * @param name The name of this file. + * @param index The index of the file in the archive. + * @param time The modification time of this file. + */ + ArchiveFileEntry(std::shared_ptr<const IFileTree> parent, QString name, int index, QDateTime time) : + FileTreeEntry(parent, name, time), m_Index(index) { + } + + /** + * @brief Create a new entry corresponding to a directory. + * + * @param parent The tree containing this directory. + * @param name The name of this directory. + * @param index The index of the directory in the archive, or -1. + */ + ArchiveFileEntry(std::shared_ptr<const IFileTree> parent, QString name, int index) : + FileTreeEntry(parent, name), m_Index(index) { + } + + virtual std::shared_ptr<FileTreeEntry> clone() const override { + return std::make_shared<ArchiveFileEntry>(nullptr, name(), m_Index); + } + + // No private since we are in an implementation file: + const int m_Index; +}; + + +/** + * + */ +class ArchiveFileTreeImpl: public virtual ArchiveFileTree, public virtual ArchiveFileEntry { +public: + + using File = std::tuple<QStringList, bool, int>; + +public: // Public for make_shared (but not accessible by other since not exposed in .h): + + ArchiveFileTreeImpl(std::shared_ptr<const IFileTree> parent, QString name, int index, std::vector<File> files) + : FileTreeEntry(parent, name), ArchiveFileEntry(parent, name, index), IFileTree(), m_Files(std::move(files)) { } + +public: // Override to avoid VS warnings: + + virtual std::shared_ptr<IFileTree> astree() override { + return IFileTree::astree(); + } + + virtual std::shared_ptr<const IFileTree> astree() const override { + return IFileTree::astree(); + } + +protected: + + virtual std::shared_ptr<FileTreeEntry> clone() const override { + return IFileTree::clone(); + } + +public: // Overrides: + + /** + * @override + */ + std::shared_ptr<FileTreeEntry> addFile(QString path, QDateTime time = QDateTime()) override { + // Cannot add file to an archive. + throw UnsupportedOperationException(QObject::tr("Cannot create file within an archive.")); + } + + /** + * + */ + static void mapToArchive(IFileTree const& tree, QString path, FileData* const* data) + { + if (path.length() > 0) { + // when using a long windows path (starting with \\?\) we apparently can have redundant + // . components in the path. This wasn't a problem with "regular" path names. + if (path == ".") { + path.clear(); + } + else { + path.append("\\"); + } + } + + for (auto const& entry : tree) { + if (entry->isDir()) { + const ArchiveFileTreeImpl& archiveEntry = dynamic_cast<const ArchiveFileTreeImpl&>(*entry); + QString tmp = path + archiveEntry.name(); + if (archiveEntry.m_Index != -1) { + data[archiveEntry.m_Index]->addOutputFileName(tmp); + } + mapToArchive(*archiveEntry.astree(), tmp, data); + } + else { + const ArchiveFileEntry& archiveFileEntry = dynamic_cast<const ArchiveFileEntry&>(*entry); + data[archiveFileEntry.m_Index]->addOutputFileName(path + archiveFileEntry.name()); + } + } + } + + /** + * + */ + void mapToArchive(Archive* archive) const override { + FileData* const* data; + size_t size; + archive->getFileList(data, size); + mapToArchive(*this, "", data); + } + +protected: + + /* + * Overriding this to create custom FileTreeEntry with index set to -1. No need to + * override makeFile() since we addFile is overriden. Note that this will not be + * used to create existing tree since we do this manually in doPopulate. + * + * @override + */ + virtual std::shared_ptr<IFileTree> makeDirectory( + std::shared_ptr<const IFileTree> parent, QString name) const override { + return std::make_shared<ArchiveFileTreeImpl>(parent, name, -1, std::vector<File>{}); + } + + virtual void doPopulate(std::shared_ptr<const IFileTree> parent, std::vector<std::shared_ptr<FileTreeEntry>>& entries) const override { + + // Sort by name: + std::sort(std::begin(m_Files), std::end(m_Files), + [](const auto& a, const auto& b) { + return std::get<0>(a)[0].compare(std::get<0>(b)[0], Qt::CaseInsensitive) < 0; }); + + // We know that the files are sorted: + QString currentName = ""; + int currentIndex = -1; + std::vector<File> currentFiles; + for (auto& p : m_Files) { + + // At the start or if we have reset, just retrieve the current name: + if (currentName == "") { + currentName = std::get<0>(p)[0]; + } + + // If the name is different, we need to create a directory from what we have + // accumulated: + if (currentName != std::get<0>(p)[0]) { + + // We may or may not have an index here, it depends on the type of archive (some archives list + // intermediate non-empty folders, some don't): + entries.push_back(std::make_shared<ArchiveFileTreeImpl>(parent, currentName, currentIndex, std::move(currentFiles))); + + currentFiles.clear(); // Back to a valid state. + + // Reset the index: + currentIndex = -1; + } + + // We can always override the current name: + currentName = std::get<0>(p)[0]; + + // If the current path contains only one components: + if (std::get<0>(p).size() == 1) { + + // If it is not a directory, then it is a file in directly under this tree: + if (!std::get<1>(p)) { + entries.push_back( + std::make_shared<ArchiveFileEntry>(parent, currentName, std::get<2>(p), QDateTime())); + currentName = ""; + } + else { + // Otherwize, it is the actual "file" corresponding to the directory we are listing, so we can retrieve + // the index here: + currentIndex = std::get<2>(p); + } + } + else { + currentFiles.push_back({ + QStringList(std::get<0>(p).begin() + 1, std::get<0>(p).end()), std::get<1>(p), std::get<2>(p) + }); + } + } + + if (currentName != "") { + entries.push_back(std::make_shared<ArchiveFileTreeImpl>(parent, currentName, currentIndex, std::move(currentFiles))); + } + } + + virtual std::shared_ptr<IFileTree> doClone() const override { + return std::make_shared<ArchiveFileTreeImpl>(nullptr, name(), m_Index, m_Files); + } + +private: + + mutable std::vector<File> m_Files; +}; + +std::shared_ptr<ArchiveFileTree> ArchiveFileTree::makeTree(Archive* archive) { + + FileData* const* data; + size_t size; + archive->getFileList(data, size); + + std::vector<ArchiveFileTreeImpl::File> files; + files.reserve(size); + + for (size_t i = 0; i < size; ++i) { + files.push_back(std::make_tuple(data[i]->getFileName().replace("\\", "/").split("/", Qt::SkipEmptyParts), data[i]->isDirectory(), (int) i)); + } + + auto tree = std::make_shared<ArchiveFileTreeImpl>(nullptr, "", -1, std::move(files)); + return tree; +} + +/** + * @brief Recursive function for the ArchiveFileTree::mapToArchive method. Need a template + * here because iterators from a vector of entries are not exactly the same as the iterators + * returned by a IFileTree. + * + */ +template <class It> +void mapToArchive(FileData* const* data, It begin, It end) { + for (auto it = begin; it != end; ++it) { + auto entry = *it; + auto* aentry = dynamic_cast<const ArchiveFileEntry*>(entry.get()); + + if (aentry->m_Index != -1) { + data[aentry->m_Index]->addOutputFileName(aentry->path()); + } + + if (entry->isDir()) { + auto tree = entry->astree(); + mapToArchive(data, tree->begin(), tree->end()); + } + } +} + +void ArchiveFileTree::mapToArchive(Archive* archive, std::vector<std::shared_ptr<const FileTreeEntry>> const& entries) { + FileData* const* data; + size_t size; + archive->getFileList(data, size); + + ::mapToArchive(data, entries.cbegin(), entries.cend()); +} diff --git a/src/archivefiletree.h b/src/archivefiletree.h new file mode 100644 index 00000000..0041acd6 --- /dev/null +++ b/src/archivefiletree.h @@ -0,0 +1,72 @@ +/* +Copyright (C) MO2 Team. All rights reserved. + +This file is part of Mod Organizer. + +Mod Organizer is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Mod Organizer is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef ARCHIVEFILENETRY_H +#define ARCHIVEFILENTRY_H + +#include "archive.h" +#include "ifiletree.h" + + +/** + * + */ +class ArchiveFileTree: public virtual MOBase::IFileTree { +public: + + /** + * @brief Create a new file tree representing the given archive. + * + * @param archive Archive to represent by the file tree. + * + * @return a file tree representing the given archive. + */ + static std::shared_ptr<ArchiveFileTree> makeTree(Archive* archive); + + /** + * @brief Update the given archive to reflect change in this tree. + * + * This method disables files that have been removed from the file + * tree and move the ones that have been moved. + * + * @param archive The archive to update. Must be the one used to + * create the tree. + */ + virtual void mapToArchive(Archive *archive) const = 0; + + /** + * @brief Update the given archive to prepare for the extraction + * of the given entries. + * + * This method "enables" files that correspond to the given entry. + * + * @param archive The archive to update. Must be the one used to + * create the tree. + * @param entries List of entries to mark for extraction. All the entries must + * come from a tree created with the given archive. + */ + static void mapToArchive(Archive* archive, std::vector<std::shared_ptr<const FileTreeEntry>> const& entries); + +protected: + + using IFileTree::IFileTree; + +}; + +#endif diff --git a/src/directoryrefresher.cpp b/src/directoryrefresher.cpp index 0369b1b0..383e6b33 100644 --- a/src/directoryrefresher.cpp +++ b/src/directoryrefresher.cpp @@ -216,9 +216,12 @@ void DirectoryRefresher::addModBSAToStructure( {
const IPluginGame *game = qApp->property("managed_game").value<IPluginGame*>();
- GamePlugins *gamePlugins = game->feature<GamePlugins>();
QStringList loadOrder = QStringList();
- gamePlugins->getLoadOrder(loadOrder);
+
+ GamePlugins* gamePlugins = game->feature<GamePlugins>();
+ if (gamePlugins) {
+ gamePlugins->getLoadOrder(loadOrder);
+ }
std::vector<std::wstring> lo;
for (auto&& s : loadOrder) {
@@ -364,9 +367,11 @@ struct ModThread if (Settings::instance().archiveParsing()) {
const IPluginGame *game = qApp->property("managed_game").value<IPluginGame*>();
- GamePlugins *gamePlugins = game->feature<GamePlugins>();
QStringList loadOrder = QStringList();
- gamePlugins->getLoadOrder(loadOrder);
+ GamePlugins* gamePlugins = game->feature<GamePlugins>();
+ if (gamePlugins) {
+ gamePlugins->getLoadOrder(loadOrder);
+ }
std::vector<std::wstring> lo;
for (auto&& s : loadOrder) {
diff --git a/src/installationmanager.cpp b/src/installationmanager.cpp index d62067c2..d4e6a444 100644 --- a/src/installationmanager.cpp +++ b/src/installationmanager.cpp @@ -17,6 +17,8 @@ You should have received a copy of the GNU General Public License along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. */ +#include <tuple> + #include "installationmanager.h" #include "utility.h" @@ -56,6 +58,8 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #include <boost/assign.hpp> #include <boost/scoped_ptr.hpp> +#include "archivefiletree.h" + using namespace MOBase; using namespace MOShared; @@ -121,172 +125,18 @@ void InstallationManager::queryPassword(QString *password) tr("Password"), QLineEdit::Password); } -void InstallationManager::mapToArchive(const DirectoryTree::Node *node, QString path, FileData * const *data) -{ - if (path.length() > 0) { - // when using a long windows path (starting with \\?\) we apparently can have redundant - // . components in the path. This wasn't a problem with "regular" path names. - if (path == ".") { - path.clear(); - } else { - path.append("\\"); - } - } - - for (DirectoryTree::const_leaf_iterator iter = node->leafsBegin(); iter != node->leafsEnd(); ++iter) { - data[iter->getIndex()]->addOutputFileName(path + iter->getName().toQString()); - } - - for (DirectoryTree::const_node_iterator iter = node->nodesBegin(); iter != node->nodesEnd(); ++iter) { - QString temp = path + (*iter)->getData().name.toQString(); - if ((*iter)->getData().index != -1) { - data[(*iter)->getData().index]->addOutputFileName(temp); - } - mapToArchive(*iter, temp, data); - } -} - - -void InstallationManager::mapToArchive(const DirectoryTree::Node *baseNode) -{ - FileData* const *data; - size_t size; - m_ArchiveHandler->getFileList(data, size); - - mapToArchive(baseNode, "", data); -} - -bool InstallationManager::unpackSingleFile(const QString &fileName) +bool InstallationManager::extractFiles(QDir extractPath) { - FileData* const *data; - size_t size; - m_ArchiveHandler->getFileList(data, size); - - QString baseName = QFileInfo(fileName).fileName(); - - bool available = false; - for (size_t i = 0; i < size; ++i) { - if (data[i]->getFileName().compare(fileName, Qt::CaseInsensitive) == 0) { - available = true; - data[i]->addOutputFileName(baseName); - m_TempFilesToDelete.insert(baseName); - } - } - - if (!available) { - return false; - } - m_InstallationProgress = new QProgressDialog(m_ParentWidget); - ON_BLOCK_EXIT([this] () { + ON_BLOCK_EXIT([this]() { m_InstallationProgress->hide(); m_InstallationProgress->deleteLater(); m_InstallationProgress = nullptr; m_Progress = 0; - }); + }); m_InstallationProgress->setWindowFlags( - m_InstallationProgress->windowFlags() & ~Qt::WindowContextHelpButtonHint); - - m_InstallationProgress->setWindowTitle(tr("Extracting files")); - m_InstallationProgress->setWindowModality(Qt::WindowModal); - m_InstallationProgress->setFixedSize(600, 100); - m_InstallationProgress->show(); - - QFuture<bool> future = QtConcurrent::run([&]() -> bool { - return m_ArchiveHandler->extract( - QDir::tempPath(), - new MethodCallback<InstallationManager, void, float>(this, &InstallationManager::updateProgress), - nullptr, - new MethodCallback<InstallationManager, void, QString const &>(this, &InstallationManager::report7ZipError) - ); - }); - do { - if (m_Progress != m_InstallationProgress->value()) - m_InstallationProgress->setValue(m_Progress); - QCoreApplication::processEvents(); - } while (!future.isFinished() || m_InstallationProgress->isVisible()); - bool res = future.result(); - - return res; -} - - -QString InstallationManager::extractFile(const QString &fileName) -{ - if (unpackSingleFile(fileName)) { - return QDir::tempPath() + "/" + QFileInfo(fileName).fileName(); - } else { - return QString(); - } -} - - -static QString canonicalize(const QString &name) -{ - QString result(name); - if ((result.startsWith('/')) || - (result.startsWith('\\'))) { - result.remove(0, 1); - } - result.replace('/', '\\'); - - return result; -} - - -QStringList InstallationManager::extractFiles(const QStringList &filesOrig, bool flatten) -{ - QStringList files; - - for (const QString &file : filesOrig) { - files.append(canonicalize(file)); - } - - QStringList result; - - FileData* const *data; - size_t size; - m_ArchiveHandler->getFileList(data, size); - - for (size_t i = 0; i < size; ++i) { - //FIXME Use qstring all the way through - if (files.contains(data[i]->getFileName(), Qt::CaseInsensitive)) { - std::wstring temp = data[i]->getFileName().toStdWString(); - wchar_t const * const origFile = temp.c_str(); - const wchar_t *targetFile = origFile; - //Note: I don't think 'flatten' is ever set to true. so this code - //might never be executed - if (flatten) { - targetFile = wcsrchr(origFile/*data[i]->getFileName()*/, '\\'); - if (targetFile == nullptr) { - targetFile = wcsrchr(origFile/*data[i]->getFileName()*/, '/'); - } - if (targetFile == nullptr) { - log::error("Failed to find backslash in {}", data[i]->getFileName()); - continue; - } else { - // skip the slash - ++targetFile; - } - } - data[i]->addOutputFileName(ToQString(targetFile)); - - result.append(QDir::tempPath().append("/").append(ToQString(targetFile))); - - m_TempFilesToDelete.insert(ToQString(targetFile)); - } - } - - m_InstallationProgress = new QProgressDialog(m_ParentWidget); - ON_BLOCK_EXIT([this] () { - m_InstallationProgress->hide(); - m_InstallationProgress->deleteLater(); - m_InstallationProgress = nullptr; - m_Progress = 0; - }); - m_InstallationProgress->setWindowFlags( - m_InstallationProgress->windowFlags() & (~Qt::WindowContextHelpButtonHint)); + m_InstallationProgress->windowFlags() & (~Qt::WindowContextHelpButtonHint)); m_InstallationProgress->setWindowTitle(tr("Extracting files")); m_InstallationProgress->setWindowModality(Qt::WindowModal); m_InstallationProgress->setFixedSize(600, 100); @@ -298,9 +148,9 @@ QStringList InstallationManager::extractFiles(const QStringList &filesOrig, bool QDir::tempPath(), new MethodCallback<InstallationManager, void, float>(this, &InstallationManager::updateProgress), nullptr, - new MethodCallback<InstallationManager, void, QString const &>(this, &InstallationManager::report7ZipError) + new MethodCallback<InstallationManager, void, QString const&>(this, &InstallationManager::report7ZipError) ); - }); + }); do { if (m_Progress != m_InstallationProgress->value()) m_InstallationProgress->setValue(m_Progress); @@ -310,8 +160,9 @@ QStringList InstallationManager::extractFiles(const QStringList &filesOrig, bool if (m_ArchiveHandler->getLastError() == Archive::ERROR_EXTRACT_CANCELLED) { if (!m_ErrorMessage.isEmpty()) { throw MyException(tr("Extraction failed: %1").arg(m_ErrorMessage)); - } else { - return QStringList(); + } + else { + return false; } } else { @@ -319,122 +170,53 @@ QStringList InstallationManager::extractFiles(const QStringList &filesOrig, bool } } - return result; + return true; } -IPluginInstaller::EInstallResult InstallationManager::installArchive(GuessedValue<QString> &modName, const QString &archiveName, const int &modId) -{ - // in earlier versions the modName was copied here and the copy passed to install. I don't know why I did this and it causes - // a problem if this is called by the bundle installer and the bundled installer adds additional names that then end up being used, - // because the caller will then not have the right name. - bool iniTweaks; - return install(archiveName, modName, iniTweaks, modId); -} -DirectoryTree *InstallationManager::createFilesTree() +QString InstallationManager::extractFile(std::shared_ptr<const FileTreeEntry> entry) { - FileData* const *data; - size_t size; - m_ArchiveHandler->getFileList(data, size); + QStringList result = this->extractFiles({ entry }); + return result.isEmpty() ? QString() : result[0]; +} - QScopedPointer<DirectoryTree> result(new DirectoryTree); - for (size_t i = 0; i < size; ++i) { - // the files are in a flat list where each file has a a full path relative to the archive root - // to create a tree, we have to iterate over each path component of each. This could be sped up by - // grouping the filenames first, but so far there doesn't seem to be an actual performance problem - DirectoryTree::Node *currentNode = result.data(); +QStringList InstallationManager::extractFiles(std::vector<std::shared_ptr<const FileTreeEntry>> const& entries) +{ + // Remove the directory since mapToArchive would add them: + std::vector<std::shared_ptr<const FileTreeEntry>> files; + std::copy_if(entries.begin(), entries.end(), std::back_inserter(files), + [](auto const& entry) { return entry->isFile(); }); - QString fileName = data[i]->getFileName(); - QStringList components = fileName.split("\\"); + // Update the archive: + ArchiveFileTree::mapToArchive(m_ArchiveHandler, files); - // iterate over all path-components of this filename (including the filename itself) - for (QStringList::iterator componentIter = components.begin(); componentIter != components.end(); ++componentIter) { - if (componentIter->size() == 0) { - // empty string indicates fileName is actually only a directory name and we have - // completely processed it already. - break; - } - - bool exists = false; - // test if this path is already in the tree - for (DirectoryTree::node_iterator nodeIter = currentNode->nodesBegin(); nodeIter != currentNode->nodesEnd(); ++nodeIter) { - if ((*nodeIter)->getData().name == *componentIter) { - currentNode = *nodeIter; - exists = true; - break; - } - } + // Retrieve the file path: + QStringList result; - if (!exists) { - if (componentIter + 1 == components.end()) { - // last path component. directory or file? - if (data[i]->isDirectory()) { - // this is a bit problematic. archives will often only list directories if they are empty, - // otherwise the dir only appears in the path of a file. In the UI however we allow the user - // to uncheck all files in a directory while keeping the dir checked. Those directories are - // currently not installed. - DirectoryTree::Node *newNode = new DirectoryTree::Node; - newNode->setData( - DirectoryTreeInformation(*componentIter, static_cast<int>(i))); - currentNode->addNode(newNode, false); - currentNode = newNode; - } else { - currentNode->addLeaf(FileTreeInformation(*componentIter, i)); - } - } else { - DirectoryTree::Node *newNode = new DirectoryTree::Node; - newNode->setData(DirectoryTreeInformation(*componentIter, -1)); - currentNode->addNode(newNode, false); - currentNode = newNode; - } - } - } + for (auto &entry : files) { + auto path = entry->path(); + result.append(QDir::tempPath().append("/").append(path)); + m_TempFilesToDelete.insert(path); } - return result.take(); -} - - -bool InstallationManager::isSimpleArchiveTopLayer(const DirectoryTree::Node *node, bool bainStyle) -{ - // see if there is at least one directory that makes sense on the top level - for (DirectoryTree::const_node_iterator iter = node->nodesBegin(); iter != node->nodesEnd(); ++iter) { - if ((bainStyle && InstallationTester::isTopLevelDirectoryBain((*iter)->getData().name)) || - (!bainStyle && InstallationTester::isTopLevelDirectory((*iter)->getData().name))) { - log::debug("{} on the top level", (*iter)->getData().name.toQString()); - return true; - } + if (!extractFiles(QDir::tempPath())) { + return QStringList(); } - // see if there is a file that makes sense on the top level - for (DirectoryTree::const_leaf_iterator iter = node->leafsBegin(); iter != node->leafsEnd(); ++iter) { - if (InstallationTester::isTopLevelSuffix(iter->getName())) { - return true; - } - } - return false; + return result; } -DirectoryTree::Node *InstallationManager::getSimpleArchiveBase(DirectoryTree *dataTree) +IPluginInstaller::EInstallResult InstallationManager::installArchive(GuessedValue<QString> &modName, const QString &archiveName, int modId) { - DirectoryTree::Node *currentNode = dataTree; - - while (true) { - if (isSimpleArchiveTopLayer(currentNode, false)) { - return currentNode; - } else if ((currentNode->numLeafs() == 0) && - (currentNode->numNodes() == 1)) { - currentNode = *currentNode->nodesBegin(); - } else { - log::debug("not a simple archive"); - return nullptr; - } - } + // in earlier versions the modName was copied here and the copy passed to install. I don't know why I did this and it causes + // a problem if this is called by the bundle installer and the bundled installer adds additional names that then end up being used, + // because the caller will then not have the right name. + bool iniTweaks; + return install(archiveName, modName, iniTweaks, modId); } - void InstallationManager::updateProgress(float percentage) { if (m_InstallationProgress != nullptr) { @@ -804,7 +586,8 @@ IPluginInstaller::EInstallResult InstallationManager::install(const QString &fil } ON_BLOCK_EXIT(std::bind(&InstallationManager::postInstallCleanup, this)); - QScopedPointer<DirectoryTree> filesTree(archiveOpen ? createFilesTree() : nullptr); + std::shared_ptr<IFileTree> filesTree = + archiveOpen ? ArchiveFileTree::makeTree(m_ArchiveHandler) : nullptr; IPluginInstaller::EInstallResult installResult = IPluginInstaller::RESULT_NOTATTEMPTED; std::sort(m_Installers.begin(), m_Installers.end(), [] (IPluginInstaller *LHS, IPluginInstaller *RHS) { @@ -831,11 +614,20 @@ IPluginInstaller::EInstallResult InstallationManager::install(const QString &fil IPluginInstallerSimple *installerSimple = dynamic_cast<IPluginInstallerSimple *>(installer); if ((installerSimple != nullptr) && (filesTree != nullptr) - && (installer->isArchiveSupported(*filesTree))) { + && (installer->isArchiveSupported(filesTree))) { installResult - = installerSimple->install(modName, *filesTree, version, modID); + = installerSimple->install(modName, filesTree, version, modID); if (installResult == IPluginInstaller::RESULT_SUCCESS) { - mapToArchive(filesTree.data()); + + // Note: Have to maintain a pointer to IFileTree because install() takes a + // reference. This could be an issue if ever a plugin creates a new tree that + // is not a ArchiveFileTree. + ArchiveFileTree* p = dynamic_cast<ArchiveFileTree*>(filesTree.get()); + if (p == nullptr) { + throw IncompatibilityException(tr("Invalid file tree returned by plugin.")); + } + p->mapToArchive(m_ArchiveHandler); + // the simple installer only prepares the installation, the rest // works the same for all installers installResult = doInstall(modName, gameName, modID, version, newestVersion, categoryID, fileCategoryID, repository); @@ -848,7 +640,7 @@ IPluginInstaller::EInstallResult InstallationManager::install(const QString &fil = dynamic_cast<IPluginInstallerCustom *>(installer); if ((installerCustom != nullptr) && (((filesTree != nullptr) - && installer->isArchiveSupported(*filesTree)) + && installer->isArchiveSupported(filesTree)) || ((filesTree == nullptr) && installerCustom->isArchiveSupported(fileName)))) { std::set<QString> installerExt @@ -880,9 +672,9 @@ IPluginInstaller::EInstallResult InstallationManager::install(const QString &fil case IPluginInstaller::RESULT_SUCCESS: case IPluginInstaller::RESULT_SUCCESSCANCEL: { if (filesTree != nullptr) { - DirectoryTree::node_iterator iniTweakNode = filesTree->nodeFind(DirectoryTreeInformation("INI Tweaks")); - hasIniTweaks = (iniTweakNode != filesTree->nodesEnd()) && - ((*iniTweakNode)->numLeafs() != 0); + auto iniTweakEntry = filesTree->find("INI Tweaks", FileTreeEntry::DIRECTORY); + hasIniTweaks = iniTweakEntry != nullptr + && !iniTweakEntry->astree()->empty(); } return IPluginInstaller::RESULT_SUCCESS; } break; diff --git a/src/installationmanager.h b/src/installationmanager.h index 199a0f82..008a0916 100644 --- a/src/installationmanager.h +++ b/src/installationmanager.h @@ -20,7 +20,7 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #ifndef INSTALLATIONMANAGER_H #define INSTALLATIONMANAGER_H - +#include <ifiletree.h> #include <iinstallationmanager.h> #include <iplugininstaller.h> #include <guessedvalue.h> @@ -107,42 +107,61 @@ public: * @brief register an installer-plugin * @param the installer to register */ - void registerInstaller(MOBase::IPluginInstaller *installer); - + void registerInstaller(MOBase::IPluginInstaller *installer); + /** * @return list of file extensions we can install */ QStringList getSupportedExtensions() const; /** - * @brief extract the specified file from the currently open archive to a temporary location - * @param (relative) name of the file within the archive - * @return the absolute name of the temporary file - * @note the call will fail with an exception if no archive is open (plugins deriving - * from IPluginInstallerSimple can rely on that, custom installers shouldn't) - * @note the temporary file is automatically cleaned up after the installation - * @note This call can be very slow if the archive is large and "solid" + * @brief Extract the specified file from the currently opened archive to a temporary location. + * + * This method cannot be used to extract directory. + * + * @param entry Entry corresponding to the file to extract. + * + * @return the absolute path to the temporary file. + * + * @note The call will fail with an exception if no archive is open (plugins deriving + * from IPluginInstallerSimple can rely on that, custom installers should not). + * @note The temporary file is automatically cleaned up after the installation. + * @note This call can be very slow if the archive is large and "solid". */ - virtual QString extractFile(const QString &fileName); + virtual QString extractFile(std::shared_ptr<const MOBase::FileTreeEntry> entry) override; /** - * @brief extract the specified files from the currently open archive to a temporary location - * @param (relative) names of files within the archive - * @return the absolute names of the temporary files - * @note the call will fail with an exception if no archive is open (plugins deriving - * from IPluginInstallerSimple can rely on that, custom installers shouldn't) - * @note the temporary file is automatically cleaned up after the installation - * @note This call can be very slow if the archive is large and "solid" + * @brief Extract the specified files from the currently opened archive to a temporary location. + * + * This method cannot be used to extract directory. + * + * @param entres Entries corresponding to the files to extract. + * + * @return the list of absolute paths to the temporary files. + * + * @note The call will fail with an exception if no archive is open (plugins deriving + * from IPluginInstallerSimple can rely on that, custom installers should not). + * @note The temporary file is automatically cleaned up after the installation. + * @note This call can be very slow if the archive is large and "solid". + * + * The flatten argument is not present here while it is present in the deprecated QStringList + * version for multiple reasons: 1) it was never used, 2) it is kind of fishy because there + * is no way to know if a file is going to be overriden, 3) it is quite easy to flatten a + * IFileTree and thus to given a list of entries flattened (this was not possible with the + * QStringList version since these were based on the name of the file inside the archive). */ - virtual QStringList extractFiles(const QStringList &files, bool flatten); + virtual QStringList extractFiles(std::vector<std::shared_ptr<const MOBase::FileTreeEntry>> const& entries) override; /** - * @brief installs an archive - * @param modName suggested name of the mod - * @param archiveFile path to the archive to install - * @return the installation result + * @brief Installs the given archive. + * + * @param modName Suggested name of the mod. + * @param archiveFile Path to the archive to install. + * @param modId ID of the mod, if available. + * + * @return the installation result. */ - virtual MOBase::IPluginInstaller::EInstallResult installArchive(MOBase::GuessedValue<QString> &modName, const QString &archiveName, const int &modId = 0); + virtual MOBase::IPluginInstaller::EInstallResult installArchive(MOBase::GuessedValue<QString> &modName, const QString &archiveName, int modId = 0) override; /** * @brief test if the specified mod name is free. If not, query the user how to proceed @@ -161,20 +180,9 @@ private: void updateProgressFile(const QString &fileName); void report7ZipError(const QString &errorMessage); - MOBase::DirectoryTree *createFilesTree(); - - // remap all files in the archive to the directory structure represented by baseNode - // files not present in baseNode are disabled - void mapToArchive(const MOBase::DirectoryTree::Node *baseNode); - - // recursive worker function for mapToArchive - void mapToArchive(const MOBase::DirectoryTree::Node *node, QString path, FileData * const *data); + // Recursive worker function for mapToArchive (takes raw reference for "speed"). bool unpackSingleFile(const QString &fileName); - - bool isSimpleArchiveTopLayer(const MOBase::DirectoryTree::Node *node, bool bainStyle); - MOBase::DirectoryTree::Node *getSimpleArchiveBase(MOBase::DirectoryTree *dataTree); - MOBase::IPluginInstaller::EInstallResult doInstall(MOBase::GuessedValue<QString> &modName, QString gameName, int modID, const QString &version, const QString &newestVersion, int categoryID, int fileCategoryID, const QString &repository); @@ -205,6 +213,19 @@ private: } }; + /** + * @brief Extract the files from the archived that are not disabled (that have + * output filenames associated with them) to the given path. + * + * @param extractPath Path (on the disk) were the extracted files should be put. + * + * This method is mainly a convenience method for the extractFiles() methods. + * + * @return true if the extraction was successful, false if the extraciton was + * cancelled. If an error occured, an exception is thrown. + */ + bool extractFiles(QDir extractPath); + private: bool m_IsRunning; diff --git a/src/modinfo.cpp b/src/modinfo.cpp index 085eaf80..7f888bdc 100644 --- a/src/modinfo.cpp +++ b/src/modinfo.cpp @@ -25,11 +25,9 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #include "modinfooverwrite.h" #include "modinfoseparator.h" -#include "installationtester.h" #include "categories.h" #include "modinfodialog.h" #include "overwriteinfodialog.h" -#include "filenamestring.h" #include "versioninfo.h" #include <iplugingame.h> @@ -475,7 +473,7 @@ bool ModInfo::removeCategory(const QString &categoryName) return true; } -QStringList ModInfo::categories() +QStringList ModInfo::categories() const { QStringList result; @@ -529,28 +527,7 @@ bool ModInfo::categorySet(int categoryID) const void ModInfo::testValid() { - m_Valid = false; - QDirIterator dirIter(absolutePath()); - while (dirIter.hasNext()) { - dirIter.next(); - if (dirIter.fileInfo().isDir()) { - if (InstallationTester::isTopLevelDirectory(dirIter.fileName())) { - m_Valid = true; - break; - } - } else { - if (InstallationTester::isTopLevelSuffix(dirIter.fileName())) { - m_Valid = true; - break; - } - } - } - - // NOTE: in Qt 4.7 it seems that QDirIterator leaves a file handle open if it is not iterated to the - // end - while (dirIter.hasNext()) { - dirIter.next(); - } + m_Valid = doTestValid(); } QUrl ModInfo::parseCustomURL() const diff --git a/src/modinfo.h b/src/modinfo.h index 34b1ecdf..2c108378 100644 --- a/src/modinfo.h +++ b/src/modinfo.h @@ -319,11 +319,23 @@ public: virtual void setNotes(const QString ¬es) = 0; /** - * @brief set/change the source game of this mod - * - * @param gameName the source game shortName - */ - virtual void setGameName(const QString &gameName) = 0; + * @brief set/change the source game of this mod + * + * @param gameName the source game shortName + */ + virtual void setGameName(const QString& gameName) = 0; + + /** + * @brief set the name of this mod + * + * set the name of this mod. This will also update the name of the + * directory that contains this mod + * + * @param name new name of the mod + * @return true on success, false if the new name can't be used (i.e. because the new + * directory name wouldn't be valid) + **/ + virtual bool setName(const QString& name) = 0; /** * @brief set/change the nexus mod id of this mod @@ -336,7 +348,7 @@ public: * @brief set/change the version of this mod * @param version new version of the mod */ - virtual void setVersion(const MOBase::VersionInfo &version); + virtual void setVersion(const MOBase::VersionInfo &version) override; /** * @brief Controls if mod should be highlighted based on plugin selection @@ -382,7 +394,7 @@ public: virtual void addCategory(const QString &categoryName) override; virtual bool removeCategory(const QString &categoryName) override; - virtual QStringList categories() override; + virtual QStringList categories() const override; /** * update the endorsement state for the mod. This only changes the @@ -645,12 +657,12 @@ public: /* *@return the color choosen by the user for the mod/separator */ - virtual QColor getColor() { return QColor(); } + virtual QColor getColor() const { return QColor(); } /* *@return true if the color has been set successfully. */ - virtual void setColor(QColor color) { } + virtual void setColor(QColor) { } /** * @brief adds the information that a file has been installed into this mod @@ -709,12 +721,12 @@ public: /** * @brief updates the mod to flag it as converted in order to ignore the alternate game warning */ - virtual void markConverted(bool converted) {} + virtual void markConverted(bool) {} /** * @brief updates the mod to flag it as valid in order to ignore the invalid game data flag */ - virtual void markValidated(bool validated) {} + virtual void markValidated(bool) {} /** * @brief reads meta information from disk @@ -729,32 +741,32 @@ public: /** * @return retrieve list of mods (as mod index) that are overwritten by this one. Updates may be delayed */ - virtual std::set<unsigned int> getModOverwrite() { return std::set<unsigned int>(); } + virtual std::set<unsigned int> getModOverwrite() const { return std::set<unsigned int>(); } /** * @return list of mods (as mod index) that overwrite this one. Updates may be delayed */ - virtual std::set<unsigned int> getModOverwritten() { return std::set<unsigned int>(); } + virtual std::set<unsigned int> getModOverwritten() const { return std::set<unsigned int>(); } /** * @return retrieve list of mods (as mod index) with archives that are overwritten by this one. Updates may be delayed */ - virtual std::set<unsigned int> getModArchiveOverwrite() { return std::set<unsigned int>(); } + virtual std::set<unsigned int> getModArchiveOverwrite() const { return std::set<unsigned int>(); } /** * @return list of mods (as mod index) with archives that overwrite this one. Updates may be delayed */ - virtual std::set<unsigned int> getModArchiveOverwritten() { return std::set<unsigned int>(); } + virtual std::set<unsigned int> getModArchiveOverwritten() const { return std::set<unsigned int>(); } /** * @return retrieve list of mods (as mod index) with archives that are overwritten by thos mod's loose files. Updates may be delayed */ - virtual std::set<unsigned int> getModArchiveLooseOverwrite() { return std::set<unsigned int>(); } + virtual std::set<unsigned int> getModArchiveLooseOverwrite() const { return std::set<unsigned int>(); } /** * @return list of mods (as mod index) with loose files that overwrite this one's archive files. Updates may be delayed */ - virtual std::set<unsigned int> getModArchiveLooseOverwritten() { return std::set<unsigned int>(); } + virtual std::set<unsigned int> getModArchiveLooseOverwritten() const { return std::set<unsigned int>(); } /** * @brief update conflict information @@ -804,6 +816,13 @@ 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, diff --git a/src/modinfobackup.h b/src/modinfobackup.h index 393c2e38..9eba545c 100644 --- a/src/modinfobackup.h +++ b/src/modinfobackup.h @@ -12,35 +12,32 @@ class ModInfoBackup : public ModInfoRegular public: - virtual bool updateAvailable() const { return false; } - virtual bool updateIgnored() const { return false; } - virtual bool downgradeAvailable() const { return false; } - virtual bool updateNXMInfo() { return false; } - virtual void setGameName(const QString&) {} - virtual void setNexusID(int) {} - virtual void endorse(bool) {} - virtual void parseNexusInfo() {} - virtual int getFixedPriority() const { return -1; } - virtual void ignoreUpdate(bool) {} - virtual bool canBeUpdated() const { return false; } - virtual QDateTime getExpires() const { return QDateTime(); } - virtual bool canBeEnabled() const { return false; } - virtual std::vector<QString> getIniTweaks() const { return std::vector<QString>(); } - virtual std::vector<EFlag> getFlags() const; - virtual QString getDescription() const; - virtual int getNexusFileStatus() const { return 0; } - virtual void setNexusFileStatus(int) {} - virtual QDateTime getLastNexusQuery() const { return QDateTime(); } - virtual void setLastNexusQuery(QDateTime) {} - virtual QDateTime getLastNexusUpdate() const { return QDateTime(); } - virtual void setLastNexusUpdate(QDateTime) {} - virtual QDateTime getNexusLastModified() const { return QDateTime(); } - virtual void setNexusLastModified(QDateTime) {} - virtual void getNexusFiles(QList<MOBase::ModRepositoryFileInfo*>::const_iterator&, - QList<MOBase::ModRepositoryFileInfo*>::const_iterator&) {} - virtual QString getNexusDescription() const { return QString(); } + virtual bool updateAvailable() const override { return false; } + virtual bool updateIgnored() const override { return false; } + virtual bool downgradeAvailable() const override { return false; } + virtual bool updateNXMInfo() override { return false; } + virtual void setGameName(const QString& gameName) override {} + virtual void setNexusID(int) override {} + virtual void endorse(bool) override {} + virtual int getFixedPriority() const override { return -1; } + virtual void ignoreUpdate(bool) override {} + virtual bool canBeUpdated() const override { return false; } + virtual QDateTime getExpires() const override { return QDateTime(); } + virtual bool canBeEnabled() const override { return false; } + virtual std::vector<QString> getIniTweaks() const override { return std::vector<QString>(); } + virtual std::vector<EFlag> getFlags() const override; + virtual QString getDescription() const override; + virtual int getNexusFileStatus() const override { return 0; } + virtual void setNexusFileStatus(int) override {} + virtual QDateTime getLastNexusQuery() const override { return QDateTime(); } + virtual void setLastNexusQuery(QDateTime) override {} + virtual QDateTime getLastNexusUpdate() const override { return QDateTime(); } + virtual void setLastNexusUpdate(QDateTime) override {} + virtual QDateTime getNexusLastModified() const override { return QDateTime(); } + virtual void setNexusLastModified(QDateTime) override {} + virtual QString getNexusDescription() const override { return QString(); } - virtual void addInstalledFile(int, int) {} + virtual void addInstalledFile(int, int) override {} private: diff --git a/src/modinfodialognexus.cpp b/src/modinfodialognexus.cpp index 59bfe930..8d99d230 100644 --- a/src/modinfodialognexus.cpp +++ b/src/modinfodialognexus.cpp @@ -324,7 +324,7 @@ void NexusTab::onSourceGameChanged() for (auto game : plugin().plugins<MOBase::IPluginGame>()) { if (game->gameName() == ui->sourceGame->currentText()) { - mod().setGameName(game->gameShortName()); + mod().setGameName(game->gameShortName()); mod().setLastNexusQuery(QDateTime::fromSecsSinceEpoch(0)); refreshData(mod().getNexusID()); return; diff --git a/src/modinfoforeign.h b/src/modinfoforeign.h index c5763d6b..da2c865b 100644 --- a/src/modinfoforeign.h +++ b/src/modinfoforeign.h @@ -1,9 +1,11 @@ #ifndef MODINFOFOREIGN_H #define MODINFOFOREIGN_H +#include <limits> + #include "modinfowithconflictinfo.h" -class ModInfoForeign : public ModInfoWithConflictInfo +class ModInfoForeign: public ModInfoWithConflictInfo { Q_OBJECT @@ -12,65 +14,65 @@ class ModInfoForeign : public ModInfoWithConflictInfo public: - virtual bool updateAvailable() const { return false; } - virtual bool updateIgnored() const { return false; } - virtual bool downgradeAvailable() const { return false; } - virtual bool updateNXMInfo() { return false; } - virtual void setCategory(int, bool) {} - virtual bool setName(const QString&) { return false; } - virtual void setComments(const QString&) {} - virtual void setNotes(const QString&) {} - virtual void setGameName(const QString&) {} - virtual void setNexusID(int) {} - virtual void setNewestVersion(const MOBase::VersionInfo&) {} - virtual void ignoreUpdate(bool) {} - virtual void setNexusDescription(const QString&) {} - virtual void setInstallationFile(const QString&) {} - virtual void addNexusCategory(int) {} - virtual void setIsEndorsed(bool) {} - virtual void setNeverEndorse() {} - virtual void setIsTracked(bool) {} - virtual bool remove() { return false; } - virtual void endorse(bool) {} - virtual void track(bool) {} - virtual void parseNexusInfo() {} - virtual bool isEmpty() const { return false; } - virtual QString name() const { return m_Name; } - virtual QString internalName() const { return m_InternalName; } - virtual QString comments() const { return ""; } - virtual QString notes() const { return ""; } - virtual QDateTime creationTime() const; - virtual QString absolutePath() const; - virtual MOBase::VersionInfo getNewestVersion() const { return QString(); } - virtual QString getInstallationFile() const { return ""; } - virtual QString getGameName() const { return ""; } - virtual int getNexusID() const { return -1; } - virtual QDateTime getExpires() const { return QDateTime(); } - virtual std::vector<QString> getIniTweaks() const { return std::vector<QString>(); } - virtual std::vector<ModInfo::EFlag> getFlags() const; - virtual int getHighlight() const; - virtual QString getDescription() const; - virtual int getNexusFileStatus() const { return 0; } - virtual void setNexusFileStatus(int) {} - virtual QDateTime getLastNexusUpdate() const { return QDateTime(); } - virtual void setLastNexusUpdate(QDateTime) {} - virtual QDateTime getLastNexusQuery() const { return QDateTime(); } - virtual void setLastNexusQuery(QDateTime) {} - virtual QDateTime getNexusLastModified() const { return QDateTime(); } - virtual void setNexusLastModified(QDateTime) {} - virtual QString getNexusDescription() const { return QString(); } - virtual int getFixedPriority() const { return INT_MIN; } - virtual QStringList archives(bool checkOnDisk = false) { return m_Archives; } - virtual QStringList stealFiles() const { return m_Archives + QStringList(m_ReferenceFile); } - virtual bool alwaysEnabled() const { return true; } - virtual void addInstalledFile(int, int) {} + virtual bool updateAvailable() const override { return false; } + virtual bool updateIgnored() const override { return false; } + virtual bool downgradeAvailable() const override { return false; } + virtual bool updateNXMInfo() override { return false; } + virtual void setCategory(int, bool) override {} + virtual bool setName(const QString&) override { return false; } + virtual void setComments(const QString&) override {} + virtual void setNotes(const QString&) override {} + virtual void setGameName(const QString& gameName) override {} + virtual void setNexusID(int) override {} + virtual void setNewestVersion(const MOBase::VersionInfo&) override {} + virtual void ignoreUpdate(bool) override {} + virtual void setNexusDescription(const QString&) override {} + virtual void setInstallationFile(const QString&) override {} + virtual void addNexusCategory(int) override {} + virtual void setIsEndorsed(bool) override {} + virtual void setNeverEndorse() override {} + virtual void setIsTracked(bool) override {} + virtual bool remove() override { return false; } + virtual void endorse(bool) override {} + virtual void track(bool) override {} + virtual bool isEmpty() const override { return false; } + virtual QString name() const override { return m_Name; } + virtual QString internalName() const override { return m_InternalName; } + virtual QString comments() const override { return ""; } + virtual QString notes() const override { return ""; } + virtual QDateTime creationTime() const override; + virtual QString absolutePath() const override; + virtual MOBase::VersionInfo getNewestVersion() const override { return QString(); } + virtual QString getInstallationFile() const override { return ""; } + virtual QString getGameName() const override { return ""; } + virtual int getNexusID() const override { return -1; } + virtual QDateTime getExpires() const override { return QDateTime(); } + virtual std::vector<QString> getIniTweaks() const override { return std::vector<QString>(); } + virtual std::vector<ModInfo::EFlag> getFlags() const override; + virtual int getHighlight() const override; + virtual QString getDescription() const override; + virtual int getNexusFileStatus() const override { return 0; } + virtual void setNexusFileStatus(int) override {} + virtual QDateTime getLastNexusUpdate() const override { return QDateTime(); } + virtual void setLastNexusUpdate(QDateTime) override {} + virtual QDateTime getLastNexusQuery() const override { return QDateTime(); } + virtual void setLastNexusQuery(QDateTime) override {} + virtual QDateTime getNexusLastModified() const override { return QDateTime(); } + virtual void setNexusLastModified(QDateTime) override {} + virtual QString getNexusDescription() const override { return QString(); } + virtual int getFixedPriority() const override { return std::numeric_limits<int>::min(); } + virtual QStringList archives(bool = false) override { return m_Archives; } + virtual QStringList stealFiles() const override { return m_Archives + QStringList(m_ReferenceFile); } + virtual bool alwaysEnabled() const override { return true; } + virtual void addInstalledFile(int, int) override {} ModInfo::EModType modType() const { return m_ModType; } protected: ModInfoForeign(const QString &modName, const QString &referenceFile, const QStringList &archives, ModInfo::EModType modType, - MOShared::DirectoryEntry **directoryStructure, PluginContainer *pluginContainer); + MOShared::DirectoryEntry **directoryStructure, PluginContainer *pluginContainer); + private: QString m_Name; diff --git a/src/modinfooverwrite.h b/src/modinfooverwrite.h index ecbdbe3d..0bcf6f27 100644 --- a/src/modinfooverwrite.h +++ b/src/modinfooverwrite.h @@ -1,6 +1,8 @@ #ifndef MODINFOOVERWRITE_H #define MODINFOOVERWRITE_H +#include <limits> + #include "modinfowithconflictinfo.h" #include <QDateTime> @@ -14,60 +16,58 @@ class ModInfoOverwrite : public ModInfoWithConflictInfo public: - virtual bool updateAvailable() const { return false; } - virtual bool updateIgnored() const { return false; } - virtual bool downgradeAvailable() const { return false; } - virtual bool updateNXMInfo() { return false; } - virtual void setCategory(int, bool) {} - virtual bool setName(const QString&) { return false; } - virtual void setComments(const QString&) {} - virtual void setNotes(const QString&) {} - virtual void setGameName(const QString&) {} - virtual void setNexusID(int) {} - virtual void setNewestVersion(const MOBase::VersionInfo&) {} - virtual void ignoreUpdate(bool) {} - virtual void setNexusDescription(const QString&) {} - virtual void setInstallationFile(const QString&) {} - virtual void addNexusCategory(int) {} - virtual void setIsEndorsed(bool) {} - virtual void setNeverEndorse() {} - virtual void setIsTracked(bool) {} - virtual bool remove() { return false; } - virtual void endorse(bool) {} - virtual void track(bool) {} - virtual void parseNexusInfo() {} - virtual bool alwaysEnabled() const { return true; } - virtual bool isEmpty() const; - virtual QString name() const { return "Overwrite"; } - virtual QString comments() const { return ""; } - virtual QString notes() const { return ""; } - virtual QDateTime creationTime() const { return QDateTime(); } - virtual QString absolutePath() const; - virtual MOBase::VersionInfo getNewestVersion() const { return QString(); } - virtual QString getInstallationFile() const { return ""; } - virtual int getFixedPriority() const { return INT_MAX; } - virtual QString getGameName() const { return ""; } - virtual int getNexusID() const { return -1; } - virtual QDateTime getExpires() const { return QDateTime(); } - virtual std::vector<QString> getIniTweaks() const { return std::vector<QString>(); } - virtual std::vector<ModInfo::EFlag> getFlags() const; - virtual std::vector<ModInfo::EConflictFlag> getConflictFlags() const; - virtual int getHighlight() const; - virtual QString getDescription() const; - virtual int getNexusFileStatus() const { return 0; } - virtual void setNexusFileStatus(int) {} - virtual QDateTime getLastNexusUpdate() const { return QDateTime(); } - virtual void setLastNexusUpdate(QDateTime) {} - virtual QDateTime getLastNexusQuery() const { return QDateTime(); } - virtual void setLastNexusQuery(QDateTime) {} - virtual QDateTime getNexusLastModified() const { return QDateTime(); } - virtual void setNexusLastModified(QDateTime) {} - virtual QString getNexusDescription() const { return QString(); } - virtual QStringList archives(bool checkOnDisk = false); - virtual void addInstalledFile(int, int) {} + virtual bool updateAvailable() const override { return false; } + virtual bool updateIgnored() const override { return false; } + virtual bool downgradeAvailable() const override { return false; } + virtual bool updateNXMInfo() override { return false; } + virtual void setCategory(int, bool) override {} + virtual bool setName(const QString&) override { return false; } + virtual void setComments(const QString&) override {} + virtual void setNotes(const QString&) override {} + virtual void setGameName(const QString& gameName) override {} + virtual void setNexusID(int) override {} + virtual void setNewestVersion(const MOBase::VersionInfo&) override {} + virtual void ignoreUpdate(bool) override {} + virtual void setNexusDescription(const QString&) override {} + virtual void setInstallationFile(const QString&) override {} + virtual void addNexusCategory(int) override {} + virtual void setIsEndorsed(bool) override {} + virtual void setNeverEndorse() override {} + virtual void setIsTracked(bool) override {} + virtual bool remove() override { return false; } + virtual void endorse(bool) override {} + virtual void track(bool) override {} + virtual bool alwaysEnabled() const override { return true; } + virtual bool isEmpty() const override; + virtual QString name() const override { return "Overwrite"; } + virtual QString comments() const override { return ""; } + virtual QString notes() const override { return ""; } + virtual QDateTime creationTime() const override { return QDateTime(); } + virtual QString absolutePath() const override; + virtual MOBase::VersionInfo getNewestVersion() const override { return QString(); } + virtual QString getInstallationFile() const override { return ""; } + virtual int getFixedPriority() const override { return std::numeric_limits<int>::max(); } + virtual QString getGameName() const override { return ""; } + virtual int getNexusID() const override { return -1; } + virtual QDateTime getExpires() const override { return QDateTime(); } + virtual std::vector<QString> getIniTweaks() const override { return std::vector<QString>(); } + virtual std::vector<ModInfo::EFlag> getFlags() const override; + virtual std::vector<ModInfo::EConflictFlag> getConflictFlags() const override; + virtual int getHighlight() const override; + virtual QString getDescription() const override; + virtual int getNexusFileStatus() const override { return 0; } + virtual void setNexusFileStatus(int) override {} + virtual QDateTime getLastNexusUpdate() const override { return QDateTime(); } + virtual void setLastNexusUpdate(QDateTime) override {} + virtual QDateTime getLastNexusQuery() const override { return QDateTime(); } + virtual void setLastNexusQuery(QDateTime) override {} + virtual QDateTime getNexusLastModified() const override { return QDateTime(); } + virtual void setNexusLastModified(QDateTime) override {} + virtual QString getNexusDescription() const override { return QString(); } + virtual QStringList archives(bool checkOnDisk = false) override; + virtual void addInstalledFile(int, int) override {} private: - ModInfoOverwrite(PluginContainer *pluginContainer, MOShared::DirectoryEntry **directoryStructure ); }; diff --git a/src/modinforegular.cpp b/src/modinforegular.cpp index 3cff914a..a1ef5701 100644 --- a/src/modinforegular.cpp +++ b/src/modinforegular.cpp @@ -29,6 +29,7 @@ ModInfoRegular::ModInfoRegular(PluginContainer *pluginContainer, const IPluginGa , m_Name(path.dirName()) , m_Path(path.absolutePath()) , m_Repository() + , m_GamePlugin(game) , m_GameName(game->gameShortName()) , m_IsAlternate(false) , m_Converted(false) @@ -467,7 +468,7 @@ void ModInfoRegular::setNotes(const QString ¬es) m_MetaInfoChanged = true; } -void ModInfoRegular::setGameName(const QString &gameName) +void ModInfoRegular::setGameName(const QString& gameName) { m_GameName = gameName; m_MetaInfoChanged = true; @@ -556,7 +557,7 @@ void ModInfoRegular::setColor(QColor color) m_MetaInfoChanged = true; } -QColor ModInfoRegular::getColor() +QColor ModInfoRegular::getColor() const { return m_Color; } diff --git a/src/modinforegular.h b/src/modinforegular.h index 705e66a8..75b24a6b 100644 --- a/src/modinforegular.h +++ b/src/modinforegular.h @@ -1,6 +1,8 @@ #ifndef MODINFOREGULAR_H #define MODINFOREGULAR_H +#include <limits> + #include "modinfowithconflictinfo.h" #include "nexusinterface.h" @@ -22,9 +24,9 @@ public: ~ModInfoRegular(); - virtual bool isRegular() const { return true; } + virtual bool isRegular() const override { return true; } - virtual bool isEmpty() const; + virtual bool isEmpty() const override; bool isAlternate() { return m_IsAlternate; } bool isConverted() { return m_Converted; } @@ -39,12 +41,12 @@ public: * * @return true if there is a newer version **/ - bool updateAvailable() const; + bool updateAvailable() const override; /** * @return true if the current update is being ignored */ - virtual bool updateIgnored() const { return m_IgnoredVersion.isValid() && m_IgnoredVersion == m_NewestVersion; } + virtual bool updateIgnored() const override { return m_IgnoredVersion.isValid() && m_IgnoredVersion == m_NewestVersion; } /** * @brief test if there is a newer version of the mod @@ -55,7 +57,7 @@ public: * * @return true if there is a newer version **/ - bool downgradeAvailable() const; + bool downgradeAvailable() const override; /** * @brief request an update of nexus description for this mod. @@ -65,7 +67,7 @@ public: * * @return returns true if information for this mod will be updated, false if there is no nexus mod id to use **/ - bool updateNXMInfo(); + bool updateNXMInfo() override; /** * @brief assign or unassign the specified category @@ -76,7 +78,7 @@ public: * @param active determines wheter the category is assigned or unassigned * @note this function does not test whether categoryID actually identifies a valid category **/ - void setCategory(int categoryID, bool active); + void setCategory(int categoryID, bool active) override; /** * @brief set the name of this mod @@ -88,33 +90,33 @@ public: * @return true on success, false if the new name can't be used (i.e. because the new * directory name wouldn't be valid) **/ - bool setName(const QString &name); + bool setName(const QString &name) override; /** * @brief changes the comments (manually set information displayed in the mod list) for this mod * @param comments new comments */ - void setComments(const QString &comments); + void setComments(const QString &comments) override; /** * @brief change the notes (manually set information) for this mod * @param notes new notes */ - void setNotes(const QString ¬es); + void setNotes(const QString ¬es) override; /** * @brief set/change the source game of this mod * * @param gameName the source game shortName */ - void setGameName(const QString &gameName); + virtual void setGameName(const QString& gameName) override; /** * @brief set/change the nexus mod id of this mod * * @param modID the nexus mod id **/ - void setNexusID(int modID); + void setNexusID(int modID) override; /** * @brief set the version of this mod @@ -124,7 +126,7 @@ public: * * @param version the new version to use **/ - void setVersion(const MOBase::VersionInfo &version); + void setVersion(const MOBase::VersionInfo &version) override; /** * @brief set the newest version of this mod on the nexus @@ -136,73 +138,73 @@ public: * @todo this function should be made obsolete. All queries for mod information should go through * this class so no public function for this change is required **/ - void setNewestVersion(const MOBase::VersionInfo &version); + void setNewestVersion(const MOBase::VersionInfo &version) override; /** * @brief changes/updates the nexus description text * @param description the current description text */ - virtual void setNexusDescription(const QString &description); + virtual void setNexusDescription(const QString &description) override; - virtual void setInstallationFile(const QString &fileName); + virtual void setInstallationFile(const QString &fileName) override; /** * @brief sets the category id from a nexus category id. Conversion to MO id happens internally * @param categoryID the nexus category id * @note if a mapping is not possible, the category is set to the default value */ - virtual void addNexusCategory(int categoryID); + virtual void addNexusCategory(int categoryID) override; /** * @brief sets the new primary category of the mod * @param categoryID the category to set */ - virtual void setPrimaryCategory(int categoryID) { m_PrimaryCategory = categoryID; m_MetaInfoChanged = true; } + virtual void setPrimaryCategory(int categoryID) override { m_PrimaryCategory = categoryID; m_MetaInfoChanged = true; } /** * @brief sets the download repository * @param repository */ - virtual void setRepository(const QString &repository) { m_Repository = repository; } + virtual void setRepository(const QString &repository) override { m_Repository = repository; } /** * update the endorsement state for the mod. This only changes the * buffered state, it does not sync with Nexus * @param endorsed the new endorsement state */ - virtual void setIsEndorsed(bool endorsed); + virtual void setIsEndorsed(bool endorsed) override; /** * set the mod to "i don't intend to endorse". The mod will not show as unendorsed but can still be endorsed */ - virtual void setNeverEndorse(); + virtual void setNeverEndorse() override; /** * update the tracked state for the mod. This only changes the * buffered state. It does not sync with Nexus * @param tracked the new tracked state */ - virtual void setIsTracked(bool tracked); + virtual void setIsTracked(bool tracked) override; /** * @brief delete the mod from the disc. This does not update the global ModInfo structure or indices * @return true if the mod was successfully removed **/ - bool remove(); + bool remove() override; /** * @brief endorse or un-endorse the mod * @param doEndorse if true, the mod is endorsed, if false, it's un-endorsed. * @note if doEndorse doesn't differ from the current value, nothing happens. */ - virtual void endorse(bool doEndorse); + virtual void endorse(bool doEndorse) override; /** * @brief track or untrack the mod. This will sync with nexus! * @param doTrack if true, the mod is tracked, if false, it's untracked. * @note if doTrack doesn't differ from the current value, nothing happens. */ - virtual void track(bool doTrack); + virtual void track(bool doTrack) override; /** * @brief updates the mod to flag it as converted in order to ignore the alternate game warning @@ -219,183 +221,183 @@ public: * * @return the mod name **/ - QString name() const { return m_Name; } + QString name() const override { return m_Name; } /** * @brief getter for the mod path * * @return the (absolute) path to the mod **/ - QString absolutePath() const; + QString absolutePath() const override; /** * @brief getter for the newest version number of this mod * * @return newest version of the mod **/ - MOBase::VersionInfo getNewestVersion() const { return m_NewestVersion; } + MOBase::VersionInfo getNewestVersion() const override { return m_NewestVersion; } /** * @brief ignore the newest version for updates */ - void ignoreUpdate(bool ignore); + void ignoreUpdate(bool ignore) override; /** * @brief getter for the installation file * * @return file used to install this mod from */ - virtual QString getInstallationFile() const { return m_InstallationFile; } + virtual QString getInstallationFile() const override { return m_InstallationFile; } /** * @brief getter for the source game repository * * @return the source game repository. should default to the active game. **/ - QString getGameName() const { return m_GameName; } + QString getGameName() const override { return m_GameName; } /** * @brief getter for the nexus mod id * * @return the nexus mod id. may be 0 if the mod id isn't known or doesn't exist **/ - int getNexusID() const { return m_NexusID; } + int getNexusID() const override { return m_NexusID; } /** * @return the fixed priority of mods of this type or INT_MIN if the priority of mods * needs to be user-modifiable */ - virtual int getFixedPriority() const { return INT_MIN; } + virtual int getFixedPriority() const override { return std::numeric_limits<int>::min(); } /** * @return true if the mod can be updated */ - virtual bool canBeUpdated() const; + virtual bool canBeUpdated() const override; /** * @return the update expiration date based on the last updated date from Nexus */ - virtual QDateTime getExpires() const; + virtual QDateTime getExpires() const override; /** * @return true if the mod can be enabled/disabled */ - virtual bool canBeEnabled() const { return true; } + virtual bool canBeEnabled() const override { return true; } /** * @return a list of flags for this mod */ - virtual std::vector<EFlag> getFlags() const; + virtual std::vector<EFlag> getFlags() const override; - virtual std::vector<EContent> getContents() const; + virtual std::vector<EContent> getContents() const override; /** * @return an indicator if and how this mod should be highlighted by the UI */ - virtual int getHighlight() const; + virtual int getHighlight() const override; /** * @return list of names of ini tweaks **/ - std::vector<QString> getIniTweaks() const; + std::vector<QString> getIniTweaks() const override; /** * @return a description about the mod, to be displayed in the ui */ - virtual QString getDescription() const; + virtual QString getDescription() const override; /** * @return the nexus file status (aka category ID) */ - virtual int getNexusFileStatus() const; + virtual int getNexusFileStatus() const override; /** * @brief sets the file status (category ID) from Nexus * @param status the status id of the installed file */ - virtual void setNexusFileStatus(int status); + virtual void setNexusFileStatus(int status) override; /** * @return comments for this mod */ - virtual QString comments() const; + virtual QString comments() const override; /** * @return manually set notes for this mod */ - virtual QString notes() const; + virtual QString notes() const override; /** * @return time this mod was created (file time of the directory) */ - virtual QDateTime creationTime() const; + virtual QDateTime creationTime() const override; /** * @return nexus description of the mod (html) */ - QString getNexusDescription() const; + QString getNexusDescription() const override; /** * @return repository from which the file was downloaded */ - virtual QString repository() const; + virtual QString repository() const override; /** * @return true if the file has been endorsed on nexus */ - virtual EEndorsedState endorsedState() const; + virtual EEndorsedState endorsedState() const override; /** * @return true if the file is being tracked on nexus */ - virtual ETrackedState trackedState() const; + virtual ETrackedState trackedState() const override; /** * @brief get the last time nexus was checked for file updates on this mod */ - virtual QDateTime getLastNexusUpdate() const; + virtual QDateTime getLastNexusUpdate() const override; /** * @brief set the last time nexus was checked for file updates on this mod */ - virtual void setLastNexusUpdate(QDateTime time); + virtual void setLastNexusUpdate(QDateTime time) override; /** * @return last time nexus was queried for infos on this mod */ - virtual QDateTime getLastNexusQuery() const; + virtual QDateTime getLastNexusQuery() const override; /** * @brief set the last time nexus was queried for info on this mod */ - virtual void setLastNexusQuery(QDateTime time); + virtual void setLastNexusQuery(QDateTime time) override; /** * @return last time the mod was updated on Nexus */ - virtual QDateTime getNexusLastModified() const; + virtual QDateTime getNexusLastModified() const override; /** * @brief set the last time the mod was updated on Nexus */ - virtual void setNexusLastModified(QDateTime time); + virtual void setNexusLastModified(QDateTime time) override; - virtual QStringList archives(bool checkOnDisk = false); + virtual QStringList archives(bool checkOnDisk = false) override; - virtual void setColor(QColor color); + virtual void setColor(QColor color) override; - virtual QColor getColor(); + virtual QColor getColor() const override; - virtual void addInstalledFile(int modId, int fileId); + virtual void addInstalledFile(int modId, int fileId) override; /** * @brief stores meta information back to disk */ - virtual void saveMeta(); + virtual void saveMeta() override; - void readMeta(); + void readMeta() override; virtual void setHasCustomURL(bool b) override; virtual bool hasCustomURL() const override; @@ -429,6 +431,12 @@ private: QString m_Repository; QString m_CustomURL; bool m_HasCustomURL; + + // Current game plugin running in MO2: + MOBase::IPluginGame const* m_GamePlugin; + + // Game name for the mod, can be different from the actual game running in MO2 + // e.g., for Skyrim / Skyrim SE. QString m_GameName; mutable QStringList m_Archives; diff --git a/src/modinfoseparator.h b/src/modinfoseparator.h index 4b1e5217..80734bcf 100644 --- a/src/modinfoseparator.h +++ b/src/modinfoseparator.h @@ -12,62 +12,44 @@ class ModInfoSeparator: public: - virtual bool updateAvailable() const { return false; } - virtual bool updateIgnored() const { return false; } - virtual bool downgradeAvailable() const { return false; } - virtual bool updateNXMInfo() { return false; } - virtual bool isValid() const { return true; } + virtual bool updateAvailable() const override { return false; } + virtual bool updateIgnored() const override { return false; } + virtual bool downgradeAvailable() const override { return false; } + virtual bool updateNXMInfo() override { return false; } + virtual bool isValid() const override { return true; } //TODO: Fix renaming method to avoid priority reset virtual bool setName(const QString& name); - virtual int getNexusID() const { return -1; } + virtual int getNexusID() const override { return -1; } + virtual void setGameName(const QString& gameName) override {} + virtual void setNexusID(int /*modID*/) override {} + virtual void endorse(bool /*doEndorse*/) override {} + virtual void ignoreUpdate(bool /*ignore*/) override {} + virtual bool canBeUpdated() const override { return false; } + virtual QDateTime getExpires() const override { return QDateTime(); } + virtual bool canBeEnabled() const override { return false; } + virtual std::vector<QString> getIniTweaks() const override { return std::vector<QString>(); } + virtual std::vector<EFlag> getFlags() const override; + virtual int getHighlight() const override; + virtual QString getDescription() const override; + virtual QString name() const override; + virtual QString getGameName() const override { return ""; } + virtual QString getInstallationFile() const override { return ""; } + virtual QString repository() const override { return ""; } + virtual int getNexusFileStatus() const override { return 0; } + virtual void setNexusFileStatus(int) override {} + virtual QDateTime getLastNexusUpdate() const override { return QDateTime(); } + virtual void setLastNexusUpdate(QDateTime) override {} + virtual QDateTime getLastNexusQuery() const override { return QDateTime(); } + virtual void setLastNexusQuery(QDateTime) override {} + virtual QDateTime getNexusLastModified() const override { return QDateTime(); } + virtual void setNexusLastModified(QDateTime) override {} + virtual QDateTime creationTime() const override { return QDateTime(); } + virtual QString getNexusDescription() const override { return QString(); } + virtual void addInstalledFile(int /*modId*/, int /*fileId*/) override { } - virtual void setGameName(const QString& /*gameName*/) {} - - virtual void setNexusID(int /*modID*/) {} - - virtual void endorse(bool /*doEndorse*/) {} - - virtual void parseNexusInfo() {} - - virtual void ignoreUpdate(bool /*ignore*/) {} - - virtual bool canBeUpdated() const { return false; } - virtual QDateTime getExpires() const { return QDateTime(); } - virtual bool canBeEnabled() const { return false; } - virtual std::vector<QString> getIniTweaks() const { return std::vector<QString>(); } - - virtual std::vector<EFlag> getFlags() const; - virtual int getHighlight() const; - - virtual QString getDescription() const; - virtual QString name() const; - virtual QString getGameName() const { return ""; } - virtual QString getInstallationFile() const { return ""; } - virtual QString getURL() const { return ""; } - virtual QString repository() const { return ""; } - virtual int getNexusFileStatus() const { return 0; } - virtual void setNexusFileStatus(int) {} - virtual QDateTime getLastNexusUpdate() const { return QDateTime(); } - virtual void setLastNexusUpdate(QDateTime) {} - virtual QDateTime getLastNexusQuery() const { return QDateTime(); } - virtual void setLastNexusQuery(QDateTime) {} - virtual QDateTime getNexusLastModified() const { return QDateTime(); } - virtual void setNexusLastModified(QDateTime) {} - virtual QDateTime creationTime() const { return QDateTime(); } - - virtual void getNexusFiles - ( - QList<MOBase::ModRepositoryFileInfo*>::const_iterator& /*unused*/, - QList<MOBase::ModRepositoryFileInfo*>::const_iterator& /*unused*/) - { - } - - virtual QString getNexusDescription() const { return QString(); } - - virtual void addInstalledFile(int /*modId*/, int /*fileId*/) - { - } +protected: + virtual bool doTestValid() const override { return true; } private: diff --git a/src/modinfowithconflictinfo.cpp b/src/modinfowithconflictinfo.cpp index 2b4fa11c..d0516d06 100644 --- a/src/modinfowithconflictinfo.cpp +++ b/src/modinfowithconflictinfo.cpp @@ -1,4 +1,5 @@ #include "modinfowithconflictinfo.h" +#include "installationtester.h" #include "utility.h" #include "shared/directoryentry.h" #include "shared/filesorigin.h" @@ -291,3 +292,33 @@ bool ModInfoWithConflictInfo::hasHiddenFiles() const return m_HasHiddenFiles; } + + +bool ModInfoWithConflictInfo::doTestValid() const { + + bool valid = false; + QDirIterator dirIter(absolutePath()); + while (dirIter.hasNext()) { + dirIter.next(); + if (dirIter.fileInfo().isDir()) { + if (InstallationTester::isTopLevelDirectory(dirIter.fileName())) { + valid = true; + break; + } + } + else { + if (InstallationTester::isTopLevelSuffix(dirIter.fileName())) { + valid = true; + break; + } + } + } + + // NOTE: in Qt 4.7 it seems that QDirIterator leaves a file handle open if it is not iterated to the + // end + while (dirIter.hasNext()) { + dirIter.next(); + } + + return valid; +} diff --git a/src/modinfowithconflictinfo.h b/src/modinfowithconflictinfo.h index 460a7f49..0bb7c422 100644 --- a/src/modinfowithconflictinfo.h +++ b/src/modinfowithconflictinfo.h @@ -12,27 +12,36 @@ public: ModInfoWithConflictInfo(PluginContainer *pluginContainer, MOShared::DirectoryEntry **directoryStructure); - std::vector<ModInfo::EConflictFlag> getConflictFlags() const; - virtual std::vector<ModInfo::EFlag> getFlags() const; + std::vector<ModInfo::EConflictFlag> getConflictFlags() const override; + virtual std::vector<ModInfo::EFlag> getFlags() const override; /** * @brief clear all caches held for this mod */ - virtual void clearCaches(); + virtual void clearCaches() override; - virtual std::set<unsigned int> getModOverwrite() { return m_OverwriteList; } + virtual std::set<unsigned int> getModOverwrite() const override { return m_OverwriteList; } - virtual std::set<unsigned int> getModOverwritten() { return m_OverwrittenList; } + virtual std::set<unsigned int> getModOverwritten() const override { return m_OverwrittenList; } - virtual std::set<unsigned int> getModArchiveOverwrite() { return m_ArchiveOverwriteList; } + virtual std::set<unsigned int> getModArchiveOverwrite() const override { return m_ArchiveOverwriteList; } - virtual std::set<unsigned int> getModArchiveOverwritten() { return m_ArchiveOverwrittenList; } + virtual std::set<unsigned int> getModArchiveOverwritten() const override { return m_ArchiveOverwrittenList; } - virtual std::set<unsigned int> getModArchiveLooseOverwrite() { return m_ArchiveLooseOverwriteList; } + virtual std::set<unsigned int> getModArchiveLooseOverwrite() const override { return m_ArchiveLooseOverwriteList; } - virtual std::set<unsigned int> getModArchiveLooseOverwritten() { return m_ArchiveLooseOverwrittenList; } + virtual std::set<unsigned int> getModArchiveLooseOverwritten() const override { return m_ArchiveLooseOverwrittenList; } - virtual void doConflictCheck() const; + virtual void doConflictCheck() const override; + +protected: + + /** + * @brief check if the content of this mod is valid. + * + * @return true if the content is valid, false otherwize. + **/ + virtual bool doTestValid() const; private: diff --git a/src/pluginlist.cpp b/src/pluginlist.cpp index 1f320982..c2667557 100644 --- a/src/pluginlist.cpp +++ b/src/pluginlist.cpp @@ -185,7 +185,8 @@ void PluginList::refresh(const QString &profileName ChangeBracket<PluginList> layoutChange(this);
QStringList primaryPlugins = m_GamePlugin->primaryPlugins();
- bool lightPluginsAreSupported = m_GamePlugin->feature<GamePlugins>()->lightPluginsAreSupported();
+ GamePlugins *gamePlugins = m_GamePlugin->feature<GamePlugins>();
+ const bool lightPluginsAreSupported = gamePlugins ? gamePlugins->lightPluginsAreSupported() : false;
m_CurrentProfile = profileName;
@@ -265,8 +266,9 @@ void PluginList::refresh(const QString &profileName // indices need to work. priority will be off however
updateIndices();
- GamePlugins *gamePlugins = m_GamePlugin->feature<GamePlugins>();
- gamePlugins->readPluginLists(this);
+ if (gamePlugins) {
+ gamePlugins->readPluginLists(this);
+ }
testMasters();
@@ -521,7 +523,9 @@ void PluginList::saveTo(const QString &lockedOrderFileName , bool hideUnchecked) const
{
GamePlugins *gamePlugins = m_GamePlugin->feature<GamePlugins>();
- gamePlugins->writePluginLists(this);
+ if (gamePlugins) {
+ gamePlugins->writePluginLists(this);
+ }
writeLockedOrder(lockedOrderFileName);
@@ -870,7 +874,10 @@ void PluginList::generatePluginIndexes() {
int numESLs = 0;
int numSkipped = 0;
- bool lightPluginsSupported = m_GamePlugin->feature<GamePlugins>()->lightPluginsAreSupported();
+
+ GamePlugins* gamePlugins = m_GamePlugin->feature<GamePlugins>();
+ const bool lightPluginsSupported = gamePlugins ? gamePlugins->lightPluginsAreSupported() : false;
+
for (int l = 0; l < m_ESPs.size(); ++l) {
int i = m_ESPsByPriority.at(l);
if (!m_ESPs[i].enabled) {
|
