From 21296a64594729a59360131270beaadf61cbced0 Mon Sep 17 00:00:00 2001 From: Mikaël Capelle Date: Sat, 30 May 2020 14:59:38 +0200 Subject: Allow creation of file using addFile() in ArchiveFileTree. --- src/archivefiletree.cpp | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/src/archivefiletree.cpp b/src/archivefiletree.cpp index 6ba06924..37d80537 100644 --- a/src/archivefiletree.cpp +++ b/src/archivefiletree.cpp @@ -83,14 +83,6 @@ protected: public: // Overrides: - /** - * @override - */ - std::shared_ptr addFile(QString path) override { - // Cannot add file to an archive. - throw UnsupportedOperationException(QObject::tr("Cannot create file within an archive.")); - } - /** * */ @@ -118,7 +110,9 @@ public: // Overrides: } else { const ArchiveFileEntry& archiveFileEntry = dynamic_cast(*entry); - data[archiveFileEntry.m_Index]->addOutputFileName(path + archiveFileEntry.name()); + if (archiveFileEntry.m_Index != -1) { + data[archiveFileEntry.m_Index]->addOutputFileName(path + archiveFileEntry.name()); + } } } } @@ -135,18 +129,20 @@ public: // Overrides: 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. + /** + * Overriding makeDirectory and makeFile to create file tree or file entry with index -1. * - * @override */ virtual std::shared_ptr makeDirectory( std::shared_ptr parent, QString name) const override { return std::make_shared(parent, name, -1, std::vector{}); } + virtual std::shared_ptr makeFile( + std::shared_ptr parent, QString name) const override { + return std::make_shared(parent, name, -1); + } + virtual bool doPopulate(std::shared_ptr parent, std::vector>& entries) const override { // Sort by name: -- cgit v1.3.1 From 3f768ae53a580dbb41e8940bbf8b79336ead309c Mon Sep 17 00:00:00 2001 From: Mikaël Capelle Date: Sat, 30 May 2020 15:00:10 +0200 Subject: Implement createFile() for the installation manager. --- src/installationmanager.cpp | 91 +++++++++++++++++++++++++++++++++++++++++++-- src/installationmanager.h | 25 ++++++++++++- 2 files changed, 112 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/installationmanager.cpp b/src/installationmanager.cpp index 62a97591..b5efc5f6 100644 --- a/src/installationmanager.cpp +++ b/src/installationmanager.cpp @@ -207,6 +207,60 @@ QStringList InstallationManager::extractFiles(std::vector entry) +{ + // Use QTemporaryFile to create the temporary file with the given template: + QTemporaryFile tempFile(QDir::cleanPath(QDir::tempPath() + QDir::separator() + "mo2-install")); + + // Turn-off autoRemove otherwise the file is deleted when destructor is called: + tempFile.setAutoRemove(false); + + // Open/Close the file so that installer can use it properly: + if (!tempFile.open()) { + return QString(); + } + tempFile.close(); + + // fileName() returns the full path since we provide a full path in the constructor: + const QString absPath = tempFile.fileName(); + + m_CreatedFiles[entry] = absPath; + m_TempFilesToDelete.insert(QDir::temp().relativeFilePath(absPath)); + + // Returns the path with native separators: + return QDir::toNativeSeparators(absPath); +} + +void InstallationManager::cleanCreatedFiles(std::shared_ptr fileTree) +{ + // We simply have to check if all the entries have fileTree as a parent: + for (auto it = std::begin(m_CreatedFiles); it != std::end(m_CreatedFiles); ) { + + // Find the parent - Could this be in FileTreeEntry? + bool found = false; + { + auto parent = it->first->parent(); + while (parent && !found) { + if (parent == fileTree) { + found = true; + } + else { + parent = parent->parent(); + } + } + } + + // If the parent was not found, we remove the entry, otherwize we move to the next one: + if (!found) { + it = m_CreatedFiles.erase(it); + } + else { + ++it; + } + } +} + + IPluginInstaller::EInstallResult InstallationManager::installArchive(GuessedValue &modName, const QString &archiveName, 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 @@ -368,6 +422,7 @@ IPluginInstaller::EInstallResult InstallationManager::doInstall(GuessedValuecancel(); @@ -410,6 +465,24 @@ IPluginInstaller::EInstallResult InstallationManager::doInstall(GuessedValuepath()); + log::debug("Moving {} to {}.", p.second, destPath); + + // We need to remove the path if it exists: + if (QFile::exists(destPath)) { + QFile::remove(destPath); + } + + QDir dir = QFileInfo(destPath).absoluteDir(); + if (!dir.exists()) { + dir.mkpath("."); + } + + QFile::copy(p.second, destPath); + } + QSettings settingsFile(targetDirectory + "/meta.ini", QSettings::IniFormat); // overwrite settings only if they are actually are available or haven't been set before @@ -467,6 +540,10 @@ bool InstallationManager::isRunning() void InstallationManager::postInstallCleanup() { + // Clear the list of created files: + m_CreatedFiles.clear(); + + // Close the archive: m_ArchiveHandler->close(); // directories we may want to remove. sorted from longest to shortest to ensure we remove subdirectories first. @@ -618,15 +695,23 @@ IPluginInstaller::EInstallResult InstallationManager::install(const QString &fil = installerSimple->install(modName, filesTree, version, modID); if (installResult == IPluginInstaller::RESULT_SUCCESS) { - // 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. + // Downcast to an actual ArchiveFileTree and map to the archive. Test if + // the tree is still an ArchiveFileTree, otherwize it means the installer + // did some bad stuff. ArchiveFileTree* p = dynamic_cast(filesTree.get()); if (p == nullptr) { throw IncompatibilityException(tr("Invalid file tree returned by plugin.")); } + + // Detach the file tree (this ensure the parent is null and call to path() + // stops at this root): + p->detach(); + p->mapToArchive(m_ArchiveHandler); + // Clean the created files: + cleanCreatedFiles(filesTree); + // 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); diff --git a/src/installationmanager.h b/src/installationmanager.h index 008a0916..9eec4abc 100644 --- a/src/installationmanager.h +++ b/src/installationmanager.h @@ -31,6 +31,7 @@ along with Mod Organizer. If not, see . #include #include #include +#include #include @@ -152,6 +153,19 @@ public: */ virtual QStringList extractFiles(std::vector> const& entries) override; + /** + * @brief Create a new file on the disk corresponding to the given entry. + * + * This method can be used by installer that needs to create files that are not in the original + * archive. At the end of the installation, if there are entries in the final tree that were used + * to create files, the corresponding files will be moved to the mod folder. + * + * @param entry The entry for which a temporary file should be created. + * + * @return the path to the created file. + */ + virtual QString createFile(std::shared_ptr entry) override; + /** * @brief Installs the given archive. * @@ -186,7 +200,13 @@ private: MOBase::IPluginInstaller::EInstallResult doInstall(MOBase::GuessedValue &modName, QString gameName, int modID, const QString &version, const QString &newestVersion, int categoryID, int fileCategoryID, const QString &repository); - //QString generateBackupName(const QString &directoryName) const; + /** + * @brief Clean the list of created files by removing all entries that are not + * in the given tree. + * + * @param tree The parent tree. Usually the tree returned by the installer. + */ + void cleanCreatedFiles(std::shared_ptr fileTree); bool ensureValidModName(MOBase::GuessedValue &name) const; @@ -242,6 +262,9 @@ private: QString m_CurrentFile; QString m_ErrorMessage; + // List of creates files: + std::map, QString> m_CreatedFiles; + QProgressDialog *m_InstallationProgress { nullptr }; int m_Progress; QString m_ProgressFile; -- cgit v1.3.1 From e9595ec91a91c00b1fda58305796591b510efdbf Mon Sep 17 00:00:00 2001 From: Mikaël Capelle Date: Sat, 30 May 2020 17:49:46 +0200 Subject: Fix comment in installation manager. --- src/installationmanager.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/installationmanager.h b/src/installationmanager.h index 9eec4abc..bdc9eafc 100644 --- a/src/installationmanager.h +++ b/src/installationmanager.h @@ -262,7 +262,8 @@ private: QString m_CurrentFile; QString m_ErrorMessage; - // List of creates files: + // Map from entries in the tree that is used by the installer and absolute + // paths to temporary files: std::map, QString> m_CreatedFiles; QProgressDialog *m_InstallationProgress { nullptr }; -- cgit v1.3.1 From 1dc98e3af2f1c2296d4691c578e70d0ddeb810a1 Mon Sep 17 00:00:00 2001 From: Mikaël Capelle Date: Sat, 30 May 2020 21:32:04 +0200 Subject: Small update to installation manager following uibase changes. --- src/installationmanager.cpp | 10 +++------- src/installationmanager.h | 8 ++++---- 2 files changed, 7 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/installationmanager.cpp b/src/installationmanager.cpp index b5efc5f6..66fd2e97 100644 --- a/src/installationmanager.cpp +++ b/src/installationmanager.cpp @@ -527,12 +527,12 @@ IPluginInstaller::EInstallResult InstallationManager::doInstall(GuessedValuegetLastError() == Archive::ERROR_EXTRACT_CANCELLED; } -bool InstallationManager::isRunning() +bool InstallationManager::isRunning() const { return m_IsRunning; } @@ -828,9 +828,5 @@ void InstallationManager::registerInstaller(IPluginInstaller *installer) QStringList InstallationManager::getSupportedExtensions() const { - QStringList result; - foreach (const QString &extension, m_SupportedExtensions) { - result.append(extension); - } - return result; + return QStringList(std::begin(m_SupportedExtensions), std::end(m_SupportedExtensions)); } diff --git a/src/installationmanager.h b/src/installationmanager.h index bdc9eafc..cb355641 100644 --- a/src/installationmanager.h +++ b/src/installationmanager.h @@ -88,12 +88,12 @@ public: /** * @return true if the installation was canceled **/ - bool wasCancelled(); + bool wasCancelled() const; /** * @return true if an installation is currently in progress **/ - bool isRunning(); + bool isRunning() const; /** * @brief retrieve a string describing the specified error code @@ -111,9 +111,9 @@ public: void registerInstaller(MOBase::IPluginInstaller *installer); /** - * @return list of file extensions we can install + * @return the extensions of archives supported by this installation manager. */ - QStringList getSupportedExtensions() const; + QStringList getSupportedExtensions() const override; /** * @brief Extract the specified file from the currently opened archive to a temporary location. -- cgit v1.3.1 From 0b3e3ab59085701e85881571126a95b1880c20fb Mon Sep 17 00:00:00 2001 From: Mikaël Capelle Date: Sat, 30 May 2020 21:44:40 +0200 Subject: Set the parent widget properly in installation manager. --- src/installationmanager.cpp | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/installationmanager.cpp b/src/installationmanager.cpp index 66fd2e97..6159115b 100644 --- a/src/installationmanager.cpp +++ b/src/installationmanager.cpp @@ -108,6 +108,7 @@ InstallationManager::~InstallationManager() void InstallationManager::setParentWidget(QWidget *widget) { + m_ParentWidget = widget; for (IPluginInstaller *installer : m_Installers) { installer->setParentWidget(widget); } -- cgit v1.3.1 From 926267faa059082865fc3a1d62d3090645267e37 Mon Sep 17 00:00:00 2001 From: Mikaël Capelle Date: Sun, 31 May 2020 00:31:29 +0200 Subject: Fix issue with progress dialog disapearing too soon during installation. --- src/installationmanager.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/installationmanager.cpp b/src/installationmanager.cpp index 6159115b..79f5ee91 100644 --- a/src/installationmanager.cpp +++ b/src/installationmanager.cpp @@ -130,6 +130,7 @@ bool InstallationManager::extractFiles(QDir extractPath) { m_InstallationProgress = new QProgressDialog(m_ParentWidget); ON_BLOCK_EXIT([this]() { + m_InstallationProgress->cancel(); m_InstallationProgress->hide(); m_InstallationProgress->deleteLater(); m_InstallationProgress = nullptr; @@ -140,6 +141,7 @@ bool InstallationManager::extractFiles(QDir extractPath) m_InstallationProgress->setWindowTitle(tr("Extracting files")); m_InstallationProgress->setWindowModality(Qt::WindowModal); m_InstallationProgress->setFixedSize(600, 100); + m_InstallationProgress->setAutoReset(false); m_InstallationProgress->show(); // unpack only the files we need for the installer @@ -155,7 +157,7 @@ bool InstallationManager::extractFiles(QDir extractPath) if (m_Progress != m_InstallationProgress->value()) m_InstallationProgress->setValue(m_Progress); QCoreApplication::processEvents(); - } while (!future.isFinished() || m_InstallationProgress->isVisible()); + } while (!future.isFinished()); if (!future.result()) { if (m_ArchiveHandler->getLastError() == Archive::ERROR_EXTRACT_CANCELLED) { if (!m_ErrorMessage.isEmpty()) { @@ -434,6 +436,13 @@ IPluginInstaller::EInstallResult InstallationManager::doInstall(GuessedValuesetAutoReset(false); + m_InstallationProgress->setWindowFlags( m_InstallationProgress->windowFlags() & (~Qt::WindowContextHelpButtonHint)); m_InstallationProgress->setWindowModality(Qt::WindowModal); -- cgit v1.3.1