mirror of
https://github.com/ModOrganizer2/modorganizer.git
synced 2026-07-27 13:58:24 -07:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e2b799bd6b | ||
|
|
185eb8e5ef | ||
|
|
63efd21a6a | ||
|
|
ed67ac2113 | ||
|
|
9a33dc1480 | ||
|
|
1b0c437788 | ||
|
|
5e530becc2 | ||
|
|
d9835cc4ae | ||
|
|
18ea79c2d0 | ||
|
|
37a6989ba8 | ||
|
|
830b63c4e2 | ||
|
|
662772c2fc | ||
|
|
027edcf688 | ||
|
|
ff51aa10c2 | ||
|
|
cbc9d00584 | ||
|
|
e15f768a15 | ||
|
|
e63eba2ca1 | ||
|
|
20008e17b7 | ||
|
|
c24200bc04 | ||
|
|
25a9290cd5 | ||
|
|
efe657c23e | ||
|
|
571347d2de | ||
|
|
346bc630f8 | ||
|
|
013890f644 | ||
|
|
3559364473 | ||
|
|
92cdf41243 | ||
|
|
789e95ca58 | ||
|
|
9b9a1f435e | ||
|
|
7f82ffa664 | ||
|
|
68a1afed49 | ||
|
|
7b1ece5f28 | ||
|
|
2306e006dc | ||
|
|
f6cd53e932 | ||
|
|
5335188e63 | ||
|
|
dac716bb86 | ||
|
|
c486220d20 | ||
|
|
0af33ccddf | ||
|
|
413c045383 | ||
|
|
1266e13921 | ||
|
|
f4af3264f0 | ||
|
|
f61236e4cf | ||
|
|
d7e6fd1dd6 | ||
|
|
9d9dbd9f7e | ||
|
|
93763a9364 | ||
|
|
a94977988b | ||
|
|
c501b5cca0 | ||
|
|
c87d97de8c | ||
|
|
4914fd172d | ||
|
|
02fe0d3384 | ||
|
|
e76891b926 | ||
|
|
b53be165fd | ||
|
|
849d00521a | ||
|
|
deb3c5ca21 | ||
|
|
25448ef076 | ||
|
|
40919c1520 | ||
|
|
79c451bb17 | ||
|
|
87292ca30f | ||
|
|
c0b55690bc | ||
|
|
f1384cdfa7 | ||
|
|
c9658e1a65 | ||
|
|
9431597e66 | ||
|
|
4566b51093 | ||
|
|
2212ad6f1c | ||
|
|
6142872620 | ||
|
|
4cae1397e7 | ||
|
|
7fbfc12118 | ||
|
|
4eaa0d16bb | ||
|
|
a219d03444 | ||
|
|
ad01e1d608 | ||
|
|
aaa1523db9 | ||
|
|
effd05df06 | ||
|
|
545b7b4eb7 | ||
|
|
71830a65d4 | ||
|
|
bde2e5fca1 | ||
|
|
15bbfdfa6f | ||
|
|
a85a6e635e | ||
|
|
9abb3ca162 | ||
|
|
5588b8b756 | ||
|
|
d48392c89f | ||
|
|
21d61e617b | ||
|
|
a48a20f13f | ||
|
|
2e09e633bd | ||
|
|
1189b8cc33 | ||
|
|
17f1cf0aab | ||
|
|
78cd0110d3 | ||
|
|
2c57899cf6 | ||
|
|
3dbfba91e1 | ||
|
|
2c53f9d934 | ||
|
|
6323a348da | ||
|
|
73842ee245 | ||
|
|
122744454c | ||
|
|
5de173ba1a | ||
|
|
eb26120332 | ||
|
|
6056202ead | ||
|
|
c1d90b131b | ||
|
|
63a66c8754 | ||
|
|
ab95f78689 | ||
|
|
9e66799abf | ||
|
|
dce6507dad | ||
|
|
42d2344f0b | ||
|
|
18e49b71b5 | ||
|
|
fcb29afe83 | ||
|
|
cf52aa335a | ||
|
|
9c35443780 | ||
|
|
9c6c01df56 | ||
|
|
b83807e4d5 | ||
|
|
2d50b17243 | ||
|
|
5a1d4e8783 | ||
|
|
478aeeb28c | ||
|
|
07fc9d3546 | ||
|
|
15ab8d5c5e | ||
|
|
192f14b001 | ||
|
|
3ccceb19e1 | ||
|
|
2d9a2a0432 | ||
|
|
ac650ae078 | ||
|
|
1a91174757 | ||
|
|
e2ec6632ec | ||
|
|
b1a3bdd6e8 | ||
|
|
22a004be2e | ||
|
|
a3cb400152 | ||
|
|
3e29d31231 | ||
|
|
edf48bca6f | ||
|
|
33e11e2056 | ||
|
|
67fb7e56d3 | ||
|
|
979206228d | ||
|
|
ba162804cd | ||
|
|
c6751b690a | ||
|
|
138154aca0 | ||
|
|
c576f1ff40 | ||
|
|
c4636d891f | ||
|
|
8ea8444dc8 |
@@ -0,0 +1,16 @@
|
||||
root = true
|
||||
|
||||
[*.cpp]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
insert_final_newline = true
|
||||
|
||||
[*.h]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
insert_final_newline = true
|
||||
|
||||
[*.ui]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
insert_final_newline = true
|
||||
@@ -20,7 +20,7 @@ Through the work of a few people of the community MO2 has come quite far, now it
|
||||
## Reporting Issues:
|
||||
Issues should be reported to the GitHub page or on the open discord server: [ModOrganizerDevs](https://discord.gg/vD2ZbfX). Here is also where dev builds are tested, bugs are reported and investigated, suggestions are discussed and a lot more.
|
||||
|
||||
Credits to Tannin, LePresidente, Silarn, erasmux, AL12 and many others for the development.
|
||||
Credits to Tannin, LePresidente, Silarn, erasmux, AL12, LostDragonist, AnyOldName3 and many others for the development.
|
||||
|
||||
## Download Location
|
||||
|
||||
@@ -49,6 +49,7 @@ Here is a complete list:
|
||||
* https://github.com/Modorganizer2/modorganizer-check_fnis
|
||||
* https://github.com/Modorganizer2/modorganizer-diagnose_basic
|
||||
* https://github.com/Modorganizer2/modorganizer-esptk
|
||||
* https://github.com/ModOrganizer2/modorganizer-fnistool
|
||||
* https://github.com/Modorganizer2/modorganizer-helper
|
||||
* https://github.com/Modorganizer2/modorganizer-game_fallout3
|
||||
* https://github.com/Modorganizer2/modorganizer-game_fallout4
|
||||
@@ -60,6 +61,7 @@ Here is a complete list:
|
||||
* https://github.com/Modorganizer2/modorganizer-game_oblivion
|
||||
* https://github.com/Modorganizer2/modorganizer-game_skyrim
|
||||
* https://github.com/Modorganizer2/modorganizer-game_skyrimSE
|
||||
* https://github.com/ModOrganizer2/modorganizer-game_skyrimVR
|
||||
* https://github.com/Modorganizer2/modorganizer-game_ttw
|
||||
* https://github.com/Modorganizer2/modorganizer-installer_bain
|
||||
* https://github.com/Modorganizer2/modorganizer-installer_bundle
|
||||
|
||||
+7
-1
@@ -37,6 +37,7 @@ SET(organizer_SRCS
|
||||
modinfoforeign.cpp
|
||||
modinfooverwrite.cpp
|
||||
modinforegular.cpp
|
||||
modinfoseparator.cpp
|
||||
modinfowithconflictinfo.cpp
|
||||
messagedialog.cpp
|
||||
mainwindow.cpp
|
||||
@@ -90,6 +91,7 @@ SET(organizer_SRCS
|
||||
usvfsconnector.cpp
|
||||
eventfilter.cpp
|
||||
moshortcut.cpp
|
||||
listdialog.cpp
|
||||
|
||||
shared/windows_error.cpp
|
||||
shared/error_report.cpp
|
||||
@@ -128,6 +130,7 @@ SET(organizer_HDRS
|
||||
modinfoforeign.h
|
||||
modinfooverwrite.h
|
||||
modinforegular.h
|
||||
modinfoseparator.h
|
||||
modinfowithconflictinfo.h
|
||||
messagedialog.h
|
||||
mainwindow.h
|
||||
@@ -183,6 +186,7 @@ SET(organizer_HDRS
|
||||
eventfilter.h
|
||||
descriptionpage.h
|
||||
moshortcut.h
|
||||
listdialog.h
|
||||
|
||||
shared/windows_error.h
|
||||
shared/error_report.h
|
||||
@@ -223,6 +227,7 @@ SET(organizer_UIS
|
||||
previewdialog.ui
|
||||
browserdialog.ui
|
||||
aboutdialog.ui
|
||||
listdialog.ui
|
||||
)
|
||||
|
||||
SET(organizer_QRCS
|
||||
@@ -288,7 +293,8 @@ INCLUDE_DIRECTORIES(${project_path}/uibase/src
|
||||
${project_path}/esptk/src
|
||||
${project_path}/archive/src
|
||||
${project_path}/../usvfs/include
|
||||
${project_path}/game_gamebryo/src
|
||||
${project_path}/game_gamebryo/src/gamebryo
|
||||
${project_path}/game_gamebryo/src/creation
|
||||
${project_path}/game_features/src
|
||||
${project_path}/githubpp/src
|
||||
${LZ4_ROOT}/include)
|
||||
|
||||
+4
-2
@@ -47,8 +47,10 @@ public:
|
||||
static const int CATEGORY_SPECIAL_NOCATEGORY = 10003;
|
||||
static const int CATEGORY_SPECIAL_CONFLICT = 10004;
|
||||
static const int CATEGORY_SPECIAL_NOTENDORSED = 10005;
|
||||
static const int CATEGORY_SPECIAL_MANAGED = 10006;
|
||||
static const int CATEGORY_SPECIAL_UNMANAGED = 10007;
|
||||
static const int CATEGORY_SPECIAL_BACKUP = 10006;
|
||||
static const int CATEGORY_SPECIAL_MANAGED = 10007;
|
||||
static const int CATEGORY_SPECIAL_UNMANAGED = 10008;
|
||||
|
||||
|
||||
public:
|
||||
|
||||
|
||||
+928
-917
File diff suppressed because it is too large
Load Diff
+227
-224
@@ -1,224 +1,227 @@
|
||||
/*
|
||||
Copyright (C) 2012 Sebastian Herbord. 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 INSTALLATIONMANAGER_H
|
||||
#define INSTALLATIONMANAGER_H
|
||||
|
||||
|
||||
#include <iinstallationmanager.h>
|
||||
#include <iplugininstaller.h>
|
||||
#include <guessedvalue.h>
|
||||
|
||||
#include <QObject>
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <Windows.h>
|
||||
#include <archive.h>
|
||||
#include <QProgressDialog>
|
||||
#include <set>
|
||||
#include <errorcodes.h>
|
||||
|
||||
|
||||
/**
|
||||
* @brief manages the installation of mod archives
|
||||
* This currently supports two special kind of archives:
|
||||
* - "simple" archives: properly packaged archives without options, so they can be extracted to the (virtual) data directory directly
|
||||
* - "complex" bain archives: archives with options for the bain system.
|
||||
* All other archives are managed through the manual "InstallDialog"
|
||||
* @todo this may be a good place to support plugins
|
||||
**/
|
||||
class InstallationManager : public QObject, public MOBase::IInstallationManager
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief constructor
|
||||
*
|
||||
* @param parent parent object.
|
||||
**/
|
||||
explicit InstallationManager();
|
||||
|
||||
virtual ~InstallationManager();
|
||||
|
||||
void setParentWidget(QWidget *widget);
|
||||
|
||||
void setURL(const QString &url);
|
||||
|
||||
/**
|
||||
* @brief update the directory where mods are to be installed
|
||||
* @param modsDirectory the mod directory
|
||||
* @note this is called a lot, probably redundantly
|
||||
*/
|
||||
void setModsDirectory(const QString &modsDirectory) { m_ModsDirectory = modsDirectory; }
|
||||
|
||||
/**
|
||||
* @brief update the directory where downloads are stored
|
||||
* @param downloadDirectory the download directory
|
||||
*/
|
||||
void setDownloadDirectory(const QString &downloadDirectory) { m_DownloadsDirectory = downloadDirectory; }
|
||||
|
||||
/**
|
||||
* @brief install a mod from an archive
|
||||
*
|
||||
* @param fileName absolute file name of the archive to install
|
||||
* @param modName suggested name of the mod. If this is empty (the default), a name will be guessed based on the filename. The user will always have a chance to rename the mod
|
||||
* @return true if the archive was installed, false if installation failed or was refused
|
||||
* @exception std::exception an exception may be thrown if the archive can't be opened (maybe the format is invalid or the file is damaged)
|
||||
**/
|
||||
bool install(const QString &fileName, MOBase::GuessedValue<QString> &modName, bool &hasIniTweaks);
|
||||
|
||||
/**
|
||||
* @return true if the installation was canceled
|
||||
**/
|
||||
bool wasCancelled();
|
||||
|
||||
/**
|
||||
* @brief retrieve a string describing the specified error code
|
||||
*
|
||||
* @param errorCode an error code as returned by the archiving function
|
||||
* @return the error string
|
||||
* @todo This function doesn't belong here, it is only public because the SelfUpdater class also uses "Archive" to get to the package.txt file
|
||||
**/
|
||||
static QString getErrorString(Archive::Error errorCode);
|
||||
|
||||
/**
|
||||
* @brief register an installer-plugin
|
||||
* @param the installer to register
|
||||
*/
|
||||
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"
|
||||
*/
|
||||
virtual QString extractFile(const QString &fileName);
|
||||
|
||||
/**
|
||||
* @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"
|
||||
*/
|
||||
virtual QStringList extractFiles(const QStringList &files, bool flatten);
|
||||
|
||||
/**
|
||||
* @brief installs an archive
|
||||
* @param modName suggested name of the mod
|
||||
* @param archiveFile path to the archive to install
|
||||
* @return the installation result
|
||||
*/
|
||||
virtual MOBase::IPluginInstaller::EInstallResult installArchive(MOBase::GuessedValue<QString> &modName, const QString &archiveName);
|
||||
|
||||
/**
|
||||
* @brief test if the specified mod name is free. If not, query the user how to proceed
|
||||
* @param modName current possible names for the mod
|
||||
* @param merge if this value is not null, the value will be set to whether the use chose to merge or replace
|
||||
* @return true if we can proceed with the installation, false if the user canceled or in case of an unrecoverable error
|
||||
*/
|
||||
virtual bool testOverwrite(MOBase::GuessedValue<QString> &modName, bool *merge = nullptr) const;
|
||||
|
||||
private:
|
||||
|
||||
void queryPassword(QString *password);
|
||||
void updateProgress(float percentage);
|
||||
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);
|
||||
bool unpackSingleFile(const QString &fileName);
|
||||
|
||||
|
||||
bool isSimpleArchiveTopLayer(const MOBase::DirectoryTree::Node *node, bool bainStyle);
|
||||
MOBase::DirectoryTree::Node *getSimpleArchiveBase(MOBase::DirectoryTree *dataTree);
|
||||
|
||||
bool doInstall(MOBase::GuessedValue<QString> &modName, QString gameName,
|
||||
int modID, const QString &version, const QString &newestVersion, int categoryID, const QString &repository);
|
||||
|
||||
QString generateBackupName(const QString &directoryName) const;
|
||||
|
||||
bool ensureValidModName(MOBase::GuessedValue<QString> &name) const;
|
||||
|
||||
void postInstallCleanup();
|
||||
|
||||
signals:
|
||||
|
||||
void progressUpdate(float percentage);
|
||||
void progressUpdate(QString const fileName);
|
||||
|
||||
private:
|
||||
|
||||
struct ByPriority {
|
||||
bool operator()(MOBase::IPluginInstaller *LHS, MOBase::IPluginInstaller *RHS) const
|
||||
{
|
||||
return LHS->priority() > RHS->priority();
|
||||
}
|
||||
};
|
||||
|
||||
struct CaseInsensitive {
|
||||
bool operator() (const QString &LHS, const QString &RHS) const
|
||||
{
|
||||
return QString::compare(LHS, RHS, Qt::CaseInsensitive) < 0;
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
QWidget *m_ParentWidget;
|
||||
|
||||
QString m_ModsDirectory;
|
||||
QString m_DownloadsDirectory;
|
||||
|
||||
std::vector<MOBase::IPluginInstaller*> m_Installers;
|
||||
std::set<QString, CaseInsensitive> m_SupportedExtensions;
|
||||
|
||||
Archive *m_ArchiveHandler;
|
||||
QString m_CurrentFile;
|
||||
|
||||
QProgressDialog *m_InstallationProgress { nullptr };
|
||||
int m_Progress;
|
||||
QString m_ProgressFile;
|
||||
|
||||
std::set<QString> m_TempFilesToDelete;
|
||||
|
||||
QString m_URL;
|
||||
};
|
||||
|
||||
|
||||
#endif // INSTALLATIONMANAGER_H
|
||||
/*
|
||||
Copyright (C) 2012 Sebastian Herbord. 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 INSTALLATIONMANAGER_H
|
||||
#define INSTALLATIONMANAGER_H
|
||||
|
||||
|
||||
#include <iinstallationmanager.h>
|
||||
#include <iplugininstaller.h>
|
||||
#include <guessedvalue.h>
|
||||
|
||||
#include <QObject>
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <Windows.h>
|
||||
#include <archive.h>
|
||||
#include <QProgressDialog>
|
||||
#include <set>
|
||||
#include <errorcodes.h>
|
||||
|
||||
|
||||
/**
|
||||
* @brief manages the installation of mod archives
|
||||
* This currently supports two special kind of archives:
|
||||
* - "simple" archives: properly packaged archives without options, so they can be extracted to the (virtual) data directory directly
|
||||
* - "complex" bain archives: archives with options for the bain system.
|
||||
* All other archives are managed through the manual "InstallDialog"
|
||||
* @todo this may be a good place to support plugins
|
||||
**/
|
||||
class InstallationManager : public QObject, public MOBase::IInstallationManager
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief constructor
|
||||
*
|
||||
* @param parent parent object.
|
||||
**/
|
||||
explicit InstallationManager();
|
||||
|
||||
virtual ~InstallationManager();
|
||||
|
||||
void setParentWidget(QWidget *widget);
|
||||
|
||||
void setURL(const QString &url);
|
||||
|
||||
/**
|
||||
* @brief update the directory where mods are to be installed
|
||||
* @param modsDirectory the mod directory
|
||||
* @note this is called a lot, probably redundantly
|
||||
*/
|
||||
void setModsDirectory(const QString &modsDirectory) { m_ModsDirectory = modsDirectory; }
|
||||
|
||||
/**
|
||||
* @brief update the directory where downloads are stored
|
||||
* @param downloadDirectory the download directory
|
||||
*/
|
||||
void setDownloadDirectory(const QString &downloadDirectory) { m_DownloadsDirectory = downloadDirectory; }
|
||||
|
||||
/**
|
||||
* @brief install a mod from an archive
|
||||
*
|
||||
* @param fileName absolute file name of the archive to install
|
||||
* @param modName suggested name of the mod. If this is empty (the default), a name will be guessed based on the filename. The user will always have a chance to rename the mod
|
||||
* @return true if the archive was installed, false if installation failed or was refused
|
||||
* @exception std::exception an exception may be thrown if the archive can't be opened (maybe the format is invalid or the file is damaged)
|
||||
**/
|
||||
bool install(const QString &fileName, MOBase::GuessedValue<QString> &modName, bool &hasIniTweaks, int modID = 0);
|
||||
|
||||
/**
|
||||
* @return true if the installation was canceled
|
||||
**/
|
||||
bool wasCancelled();
|
||||
|
||||
/**
|
||||
* @brief retrieve a string describing the specified error code
|
||||
*
|
||||
* @param errorCode an error code as returned by the archiving function
|
||||
* @return the error string
|
||||
* @todo This function doesn't belong here, it is only public because the SelfUpdater class also uses "Archive" to get to the package.txt file
|
||||
**/
|
||||
static QString getErrorString(Archive::Error errorCode);
|
||||
|
||||
/**
|
||||
* @brief register an installer-plugin
|
||||
* @param the installer to register
|
||||
*/
|
||||
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"
|
||||
*/
|
||||
virtual QString extractFile(const QString &fileName);
|
||||
|
||||
/**
|
||||
* @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"
|
||||
*/
|
||||
virtual QStringList extractFiles(const QStringList &files, bool flatten);
|
||||
|
||||
/**
|
||||
* @brief installs an archive
|
||||
* @param modName suggested name of the mod
|
||||
* @param archiveFile path to the archive to install
|
||||
* @return the installation result
|
||||
*/
|
||||
virtual MOBase::IPluginInstaller::EInstallResult installArchive(MOBase::GuessedValue<QString> &modName, const QString &archiveName, const int &modId = 0);
|
||||
|
||||
/**
|
||||
* @brief test if the specified mod name is free. If not, query the user how to proceed
|
||||
* @param modName current possible names for the mod
|
||||
* @param merge if this value is not null, the value will be set to whether the use chose to merge or replace
|
||||
* @return true if we can proceed with the installation, false if the user canceled or in case of an unrecoverable error
|
||||
*/
|
||||
virtual bool testOverwrite(MOBase::GuessedValue<QString> &modName, bool *merge = nullptr) const;
|
||||
|
||||
QString generateBackupName(const QString &directoryName) const;
|
||||
|
||||
private:
|
||||
|
||||
void queryPassword(QString *password);
|
||||
void updateProgress(float percentage);
|
||||
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);
|
||||
bool unpackSingleFile(const QString &fileName);
|
||||
|
||||
|
||||
bool isSimpleArchiveTopLayer(const MOBase::DirectoryTree::Node *node, bool bainStyle);
|
||||
MOBase::DirectoryTree::Node *getSimpleArchiveBase(MOBase::DirectoryTree *dataTree);
|
||||
|
||||
bool doInstall(MOBase::GuessedValue<QString> &modName, QString gameName,
|
||||
int modID, const QString &version, const QString &newestVersion, int categoryID, const QString &repository);
|
||||
|
||||
//QString generateBackupName(const QString &directoryName) const;
|
||||
|
||||
bool ensureValidModName(MOBase::GuessedValue<QString> &name) const;
|
||||
|
||||
void postInstallCleanup();
|
||||
|
||||
signals:
|
||||
|
||||
void progressUpdate(float percentage);
|
||||
void progressUpdate(QString const fileName);
|
||||
|
||||
private:
|
||||
|
||||
struct ByPriority {
|
||||
bool operator()(MOBase::IPluginInstaller *LHS, MOBase::IPluginInstaller *RHS) const
|
||||
{
|
||||
return LHS->priority() > RHS->priority();
|
||||
}
|
||||
};
|
||||
|
||||
struct CaseInsensitive {
|
||||
bool operator() (const QString &LHS, const QString &RHS) const
|
||||
{
|
||||
return QString::compare(LHS, RHS, Qt::CaseInsensitive) < 0;
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
QWidget *m_ParentWidget;
|
||||
|
||||
QString m_ModsDirectory;
|
||||
QString m_DownloadsDirectory;
|
||||
|
||||
std::vector<MOBase::IPluginInstaller*> m_Installers;
|
||||
std::set<QString, CaseInsensitive> m_SupportedExtensions;
|
||||
|
||||
Archive *m_ArchiveHandler;
|
||||
QString m_CurrentFile;
|
||||
QString m_ErrorMessage;
|
||||
|
||||
QProgressDialog *m_InstallationProgress { nullptr };
|
||||
int m_Progress;
|
||||
QString m_ProgressFile;
|
||||
|
||||
std::set<QString> m_TempFilesToDelete;
|
||||
|
||||
QString m_URL;
|
||||
};
|
||||
|
||||
|
||||
#endif // INSTALLATIONMANAGER_H
|
||||
|
||||
@@ -66,6 +66,7 @@ void InstanceManager::clearCurrentInstance()
|
||||
{
|
||||
setCurrentInstance("");
|
||||
m_Reset = true;
|
||||
m_overrideInstance = false;
|
||||
}
|
||||
|
||||
void InstanceManager::setCurrentInstance(const QString &name)
|
||||
@@ -136,12 +137,13 @@ QString InstanceManager::queryInstanceName(const QStringList &instanceList) cons
|
||||
QInputDialog dialog;
|
||||
|
||||
dialog.setWindowTitle(QObject::tr("Enter a Name for the new Instance"));
|
||||
dialog.setLabelText(QObject::tr("Enter a new name or select one from the suggested list:"));
|
||||
dialog.setLabelText(QObject::tr("Enter a new name or select one from the suggested list: \n"
|
||||
"(This is just the name of the Instance, not the game selection)"));
|
||||
// would be neat if we could take the names from the game plugins but
|
||||
// the required initialization order requires the ini file to be
|
||||
// available *before* we load plugins
|
||||
dialog.setComboBoxItems({ "NewName", "Fallout 4", "SkyrimSE", "Skyrim", "Fallout 3",
|
||||
"Fallout NV", "FO4VR", "Oblivion" });
|
||||
dialog.setComboBoxItems({ "NewName", "Fallout 4", "SkyrimSE", "Skyrim", "SkyrimVR", "Fallout 3",
|
||||
"Fallout NV", "TTW", "FO4VR", "Oblivion", "Morrowind" });
|
||||
dialog.setComboBoxEditable(true);
|
||||
|
||||
if (dialog.exec() == QDialog::Rejected) {
|
||||
@@ -324,4 +326,4 @@ QString InstanceManager::sanitizeInstanceName(const QString &name) const
|
||||
return sanitizeInstanceName(new_name);
|
||||
}
|
||||
return new_name;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
#include <ipluginmodpage.h>
|
||||
#include <delayedfilewriter.h>
|
||||
|
||||
#include <QMenu>
|
||||
|
||||
class QSettings;
|
||||
|
||||
class IUserInterface
|
||||
@@ -16,7 +18,8 @@ public:
|
||||
|
||||
virtual void storeSettings(QSettings &settings) = 0;
|
||||
|
||||
virtual void registerPluginTool(MOBase::IPluginTool *tool) = 0;
|
||||
virtual void registerPluginTool(MOBase::IPluginTool *tool, QString name = QString(), QMenu *menu = nullptr) = 0;
|
||||
virtual void registerPluginTools(std::vector<MOBase::IPluginTool *> toolPlugins) = 0;
|
||||
virtual void registerModPage(MOBase::IPluginModPage *modPage) = 0;
|
||||
|
||||
virtual void installTranslator(const QString &name) = 0;
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
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/>.
|
||||
*/
|
||||
|
||||
#include "listdialog.h"
|
||||
#include "ui_listdialog.h"
|
||||
|
||||
ListDialog::ListDialog(QWidget *parent)
|
||||
: QDialog(parent)
|
||||
, ui(new Ui::ListDialog)
|
||||
, m_Choices()
|
||||
{
|
||||
ui->setupUi(this);
|
||||
ui->filterEdit->setFocus();
|
||||
}
|
||||
|
||||
ListDialog::~ListDialog()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void ListDialog::setChoices(QStringList choices)
|
||||
{
|
||||
m_Choices = choices;
|
||||
ui->choiceList->clear();
|
||||
ui->choiceList->addItems(m_Choices);
|
||||
}
|
||||
|
||||
QString ListDialog::getChoice() const
|
||||
{
|
||||
if (ui->choiceList->selectedItems().length()) {
|
||||
return ui->choiceList->currentItem()->text();
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
void ListDialog::on_filterEdit_textChanged(QString filter)
|
||||
{
|
||||
QStringList newChoices;
|
||||
for (auto choice : m_Choices) {
|
||||
if (choice.contains(filter, Qt::CaseInsensitive)){
|
||||
newChoices << choice;
|
||||
}
|
||||
}
|
||||
ui->choiceList->clear();
|
||||
ui->choiceList->addItems(newChoices);
|
||||
|
||||
if (newChoices.length() == 1) {
|
||||
QListWidgetItem *item = ui->choiceList->item(0);
|
||||
ui->choiceList->setItemSelected(item, true);
|
||||
ui->choiceList->setCurrentItem(item);
|
||||
}
|
||||
|
||||
if (!filter.isEmpty()) {
|
||||
ui->choiceList->setStyleSheet("QListWidget { border: 2px ridge #f00; }");
|
||||
} else {
|
||||
ui->choiceList->setStyleSheet("");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
#ifndef LISTDIALOG_H
|
||||
#define LISTDIALOG_H
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
namespace Ui {
|
||||
class ListDialog;
|
||||
}
|
||||
|
||||
class ListDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ListDialog(QWidget *parent = nullptr);
|
||||
~ListDialog();
|
||||
|
||||
void setChoices(QStringList choices);
|
||||
QString getChoice() const;
|
||||
|
||||
public slots:
|
||||
void on_filterEdit_textChanged(QString filter);
|
||||
|
||||
private:
|
||||
Ui::ListDialog *ui;
|
||||
QStringList m_Choices;
|
||||
};
|
||||
|
||||
#endif // LISTDIALOG_H
|
||||
@@ -0,0 +1,103 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>ListDialog</class>
|
||||
<widget class="QDialog" name="ListDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>260</width>
|
||||
<height>380</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Select an item...</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QListWidget" name="choiceList">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>240</width>
|
||||
<height>280</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="verticalScrollMode">
|
||||
<enum>QAbstractItemView::ScrollPerPixel</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="MOBase::LineEditClear" name="filterEdit">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="placeholderText">
|
||||
<string>Filter</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="layoutDirection">
|
||||
<enum>Qt::LeftToRight</enum>
|
||||
</property>
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>MOBase::LineEditClear</class>
|
||||
<extends>QLineEdit</extends>
|
||||
<header>lineeditclear.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>ListDialog</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>248</x>
|
||||
<y>254</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>ListDialog</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>316</x>
|
||||
<y>260</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
||||
+3
-2
@@ -322,7 +322,7 @@ MOBase::IPluginGame *determineCurrentGame(QString const &moPath, QSettings &sett
|
||||
|
||||
//The following code would try to determine the right game to mange but it would usually find the wrong one
|
||||
//so it was commented out.
|
||||
/*
|
||||
/*
|
||||
//OK, we are in a new setup or existing info is useless.
|
||||
//See if MO has been installed inside a game directory
|
||||
for (IPluginGame * const game : plugins.plugins<IPluginGame>()) {
|
||||
@@ -383,7 +383,7 @@ MOBase::IPluginGame *determineCurrentGame(QString const &moPath, QSettings &sett
|
||||
}
|
||||
}
|
||||
reportError(QObject::tr("No game identified in \"%1\". The directory is required to contain "
|
||||
"the game binary and its launcher.").arg(gamePath));
|
||||
"the game binary.").arg(gamePath));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -715,5 +715,6 @@ int main(int argc, char *argv[])
|
||||
return result;
|
||||
}
|
||||
argc = 1;
|
||||
moshortcut = MOShortcut("");
|
||||
} while (true);
|
||||
}
|
||||
|
||||
+683
-100
File diff suppressed because it is too large
Load Diff
+27
-2
@@ -132,7 +132,8 @@ public:
|
||||
|
||||
void saveArchiveList();
|
||||
|
||||
void registerPluginTool(MOBase::IPluginTool *tool);
|
||||
void registerPluginTool(MOBase::IPluginTool *tool, QString name = QString(), QMenu *menu = nullptr);
|
||||
void registerPluginTools(std::vector<MOBase::IPluginTool *> toolPlugins);
|
||||
void registerModPage(MOBase::IPluginModPage *modPage);
|
||||
|
||||
void addPrimaryCategoryCandidates(QMenu *primaryCategoryMenu, ModInfo::Ptr info);
|
||||
@@ -210,7 +211,7 @@ private:
|
||||
|
||||
void startSteam();
|
||||
|
||||
void updateTo(QTreeWidgetItem *subTree, const std::wstring &directorySoFar, const MOShared::DirectoryEntry &directoryEntry, bool conflictsOnly);
|
||||
void updateTo(QTreeWidgetItem *subTree, const std::wstring &directorySoFar, const MOShared::DirectoryEntry &directoryEntry, bool conflictsOnly, QIcon *fileIcon, QIcon *folderIcon);
|
||||
bool refreshProfiles(bool selectProfile = true);
|
||||
void refreshExecutablesList();
|
||||
void installMod(QString fileName = "");
|
||||
@@ -278,6 +279,8 @@ private:
|
||||
QString queryRestore(const QString &filePath);
|
||||
|
||||
QMenu *modListContextMenu();
|
||||
void addModSendToContextMenu(QMenu *menu);
|
||||
void addPluginSendToContextMenu(QMenu *menu);
|
||||
|
||||
QMenu *openFolderMenu();
|
||||
|
||||
@@ -294,6 +297,9 @@ private:
|
||||
|
||||
bool registerWidgetState(const QString &name, QHeaderView *view, const char *oldSettingName = nullptr);
|
||||
|
||||
void sendSelectedModsToPriority(int newPriority);
|
||||
void sendSelectedPluginsToPriority(int newPriority);
|
||||
|
||||
private:
|
||||
|
||||
static const char *PATTERN_BACKUP_GLOB;
|
||||
@@ -404,9 +410,13 @@ private slots:
|
||||
// modlist context menu
|
||||
void installMod_clicked();
|
||||
void createEmptyMod_clicked();
|
||||
void createSeparator_clicked();
|
||||
void restoreBackup_clicked();
|
||||
void renameMod_clicked();
|
||||
void removeMod_clicked();
|
||||
void setColor_clicked();
|
||||
void resetColor_clicked();
|
||||
void backupMod_clicked();
|
||||
void reinstallMod_clicked();
|
||||
void endorse_clicked();
|
||||
void dontendorse_clicked();
|
||||
@@ -416,9 +426,15 @@ private slots:
|
||||
void visitOnNexus_clicked();
|
||||
void visitWebPage_clicked();
|
||||
void openExplorer_clicked();
|
||||
void openOriginExplorer_clicked();
|
||||
void openOriginInformation_clicked();
|
||||
void information_clicked();
|
||||
void enableSelectedMods_clicked();
|
||||
void disableSelectedMods_clicked();
|
||||
void sendSelectedModsToTop_clicked();
|
||||
void sendSelectedModsToBottom_clicked();
|
||||
void sendSelectedModsToPriority_clicked();
|
||||
void sendSelectedModsToSeparator_clicked();
|
||||
// savegame context menu
|
||||
void deleteSavegame_clicked();
|
||||
void fixMods_clicked(SaveGameInfo::MissingAssets const &missingAssets);
|
||||
@@ -433,6 +449,9 @@ private slots:
|
||||
// pluginlist context menu
|
||||
void enableSelectedPlugins_clicked();
|
||||
void disableSelectedPlugins_clicked();
|
||||
void sendSelectedPluginsToTop_clicked();
|
||||
void sendSelectedPluginsToBottom_clicked();
|
||||
void sendSelectedPluginsToPriority_clicked();
|
||||
|
||||
void linkToolbar();
|
||||
void linkDesktop();
|
||||
@@ -510,6 +529,7 @@ private slots:
|
||||
void openDownloadsFolder();
|
||||
void openModsFolder();
|
||||
void openProfileFolder();
|
||||
void openIniFolder();
|
||||
void openGameFolder();
|
||||
void openMyGamesFolder();
|
||||
void startExeAction();
|
||||
@@ -561,6 +581,9 @@ private slots:
|
||||
void modlistSelectionsChanged(const QItemSelection ¤t);
|
||||
void esplistSelectionsChanged(const QItemSelection ¤t);
|
||||
|
||||
void search_activated();
|
||||
void searchClear_activated();
|
||||
|
||||
private slots: // ui slots
|
||||
// actions
|
||||
void on_actionAdd_Profile_triggered();
|
||||
@@ -575,12 +598,14 @@ private slots: // ui slots
|
||||
void on_bsaList_customContextMenuRequested(const QPoint &pos);
|
||||
void on_clearFiltersButton_clicked();
|
||||
void on_btnRefreshData_clicked();
|
||||
void on_btnRefreshDownloads_clicked();
|
||||
void on_categoriesList_customContextMenuRequested(const QPoint &pos);
|
||||
void on_conflictsCheckBox_toggled(bool checked);
|
||||
void on_dataTree_customContextMenuRequested(const QPoint &pos);
|
||||
void on_executablesListBox_currentIndexChanged(int index);
|
||||
void on_modList_customContextMenuRequested(const QPoint &pos);
|
||||
void on_modList_doubleClicked(const QModelIndex &index);
|
||||
void on_listOptionsBtn_pressed();
|
||||
void on_espList_doubleClicked(const QModelIndex &index);
|
||||
void on_profileBox_currentIndexChanged(int index);
|
||||
void on_savegameList_customContextMenuRequested(const QPoint &pos);
|
||||
|
||||
+42
-14
@@ -65,13 +65,13 @@
|
||||
<widget class="QTreeWidget" name="categoriesList">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>100</width>
|
||||
<width>120</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>161</width>
|
||||
<width>214</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
@@ -84,6 +84,9 @@
|
||||
<property name="indentation">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="uniformRowHeights">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<attribute name="headerVisible">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
@@ -432,6 +435,9 @@ p, li { white-space: pre-wrap; }
|
||||
<property name="indentation">
|
||||
<number>20</number>
|
||||
</property>
|
||||
<property name="uniformRowHeights">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="itemsExpandable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
@@ -825,9 +831,6 @@ p, li { white-space: pre-wrap; }
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_7">
|
||||
<item>
|
||||
<widget class="QPushButton" name="bossButton">
|
||||
<property name="visible">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Sort</string>
|
||||
</property>
|
||||
@@ -1042,7 +1045,7 @@ p, li { white-space: pre-wrap; }
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="MOBase::SortableTreeWidget" name="bsaList">
|
||||
<widget class="QTreeWidget" name="bsaList">
|
||||
<property name="contextMenuPolicy">
|
||||
<enum>Qt::CustomContextMenu</enum>
|
||||
</property>
|
||||
@@ -1058,21 +1061,26 @@ p, li { white-space: pre-wrap; }
|
||||
<property name="showDropIndicator" stdset="0">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="dragEnabled" stdset="0">
|
||||
<property name="dragEnabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="dragDropOverwriteMode" stdset="0">
|
||||
<property name="dragDropOverwriteMode">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="indentation" stdset="0">
|
||||
<property name="indentation">
|
||||
<number>20</number>
|
||||
</property>
|
||||
<property name="itemsExpandable" stdset="0">
|
||||
<property name="itemsExpandable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="columnCount" stdset="0">
|
||||
<property name="columnCount">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string notr="true">Archives</string>
|
||||
</property>
|
||||
</column>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
@@ -1121,6 +1129,9 @@ p, li { white-space: pre-wrap; }
|
||||
<property name="whatsThis">
|
||||
<string>This is an overview of your data directory as visible to the game (and tools). </string>
|
||||
</property>
|
||||
<property name="uniformRowHeights">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="animated">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
@@ -1186,7 +1197,7 @@ p, li { white-space: pre-wrap; }
|
||||
<html><head><meta name="qrichtext" content="1" /><style type="text/css">
|
||||
p, li { white-space: pre-wrap; }
|
||||
</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;">
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">This is a list of all savegames for this game. Hover over a list entry to get detailed information about the save including a list of esps/esms that were used at the time this save was created but aren't active now.</span></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">This is a list of all save games for this game. Hover over a list entry to get detailed information about the save including a list of esps/esms that were used at the time this save was created but aren't active now.</span></p>
|
||||
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:8pt;"></p>
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">If you click &quot;Fix Mods...&quot; in the context menu, MO will try to activate all mods and esps to fix those missing esps. It will not disable anything!</span></p></body></html></string>
|
||||
</property>
|
||||
@@ -1217,6 +1228,20 @@ p, li { white-space: pre-wrap; }
|
||||
<property name="bottomMargin">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnRefreshDownloads">
|
||||
<property name="toolTip">
|
||||
<string>Refresh downloads view</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Refresh</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="resources.qrc">
|
||||
<normaloff>:/MO/gui/resources/view-refresh.png</normaloff>:/MO/gui/resources/view-refresh.png</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="downloadLayout">
|
||||
<item>
|
||||
@@ -1243,7 +1268,7 @@ p, li { white-space: pre-wrap; }
|
||||
<enum>Qt::ScrollBarAlwaysOn</enum>
|
||||
</property>
|
||||
<property name="horizontalScrollBarPolicy">
|
||||
<enum>Qt::ScrollBarAsNeeded</enum>
|
||||
<enum>Qt::ScrollBarAsNeeded</enum>
|
||||
</property>
|
||||
<property name="dragEnabled">
|
||||
<bool>true</bool>
|
||||
@@ -1278,7 +1303,7 @@ p, li { white-space: pre-wrap; }
|
||||
<attribute name="headerDefaultSectionSize">
|
||||
<number>50</number>
|
||||
</attribute>
|
||||
<attribute name="headerMinimumSectionSize">
|
||||
<attribute name="headerMinimumSectionSize">
|
||||
<number>15</number>
|
||||
</attribute>
|
||||
<attribute name="headerStretchLastSection">
|
||||
@@ -1336,6 +1361,9 @@ p, li { white-space: pre-wrap; }
|
||||
<property name="selectionMode">
|
||||
<enum>QAbstractItemView::NoSelection</enum>
|
||||
</property>
|
||||
<property name="uniformRowHeights">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="itemsExpandable">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
|
||||
+9
-2
@@ -23,6 +23,7 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
|
||||
#include "modinforegular.h"
|
||||
#include "modinfoforeign.h"
|
||||
#include "modinfooverwrite.h"
|
||||
#include "modinfoseparator.h"
|
||||
|
||||
#include "installationtester.h"
|
||||
#include "categories.h"
|
||||
@@ -64,11 +65,14 @@ bool ModInfo::ByName(const ModInfo::Ptr &LHS, const ModInfo::Ptr &RHS)
|
||||
ModInfo::Ptr ModInfo::createFrom(PluginContainer *pluginContainer, const MOBase::IPluginGame *game, const QDir &dir, DirectoryEntry **directoryStructure)
|
||||
{
|
||||
QMutexLocker locker(&s_Mutex);
|
||||
// int id = s_NextID++;
|
||||
// int id = s_NextID++;
|
||||
static QRegExp backupExp(".*backup[0-9]*");
|
||||
static QRegExp separatorExp(".*_separator");
|
||||
ModInfo::Ptr result;
|
||||
if (backupExp.exactMatch(dir.dirName())) {
|
||||
result = ModInfo::Ptr(new ModInfoBackup(pluginContainer, game, dir, directoryStructure));
|
||||
} else if(separatorExp.exactMatch(dir.dirName())){
|
||||
result = Ptr(new ModInfoSeparator(pluginContainer, game, dir, directoryStructure));
|
||||
} else {
|
||||
result = ModInfo::Ptr(new ModInfoRegular(pluginContainer, game, dir, directoryStructure));
|
||||
}
|
||||
@@ -100,9 +104,12 @@ QString ModInfo::getContentTypeName(int contentType)
|
||||
case CONTENT_SOUND: return tr("Sound Effects");
|
||||
case CONTENT_SCRIPT: return tr("Scripts");
|
||||
case CONTENT_SKSE: return tr("Script Extender");
|
||||
case CONTENT_SKSEFILES: return tr("Script Extender Files");
|
||||
case CONTENT_SKYPROC: return tr("SkyProc Tools");
|
||||
case CONTENT_MCM: return tr("MCM Data");
|
||||
case CONTENT_INI: return tr("INI files");
|
||||
case CONTENT_MODGROUP: return tr("ModGroup files");
|
||||
|
||||
default: throw MyException(tr("invalid content type %1").arg(contentType));
|
||||
}
|
||||
}
|
||||
@@ -415,4 +422,4 @@ void ModInfo::testValid()
|
||||
while (dirIter.hasNext()) {
|
||||
dirIter.next();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+35
-4
@@ -31,6 +31,7 @@ class QDir;
|
||||
#include <QSharedPointer>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QColor>
|
||||
|
||||
#include <boost/function.hpp>
|
||||
|
||||
@@ -43,7 +44,7 @@ namespace MOShared { class DirectoryEntry; }
|
||||
|
||||
/**
|
||||
* @brief Represents meta information about a single mod.
|
||||
*
|
||||
*
|
||||
* Represents meta information about a single mod. The class interface is used
|
||||
* to manage the mod collection
|
||||
*
|
||||
@@ -62,6 +63,7 @@ public:
|
||||
enum EFlag {
|
||||
FLAG_INVALID,
|
||||
FLAG_BACKUP,
|
||||
FLAG_SEPARATOR,
|
||||
FLAG_OVERWRITE,
|
||||
FLAG_FOREIGN,
|
||||
FLAG_NOTENDORSED,
|
||||
@@ -83,12 +85,15 @@ public:
|
||||
CONTENT_SOUND,
|
||||
CONTENT_SCRIPT,
|
||||
CONTENT_SKSE,
|
||||
CONTENT_SKSEFILES,
|
||||
CONTENT_SKYPROC,
|
||||
CONTENT_MCM,
|
||||
CONTENT_INI
|
||||
CONTENT_INI,
|
||||
CONTENT_MODGROUP
|
||||
|
||||
};
|
||||
|
||||
static const int NUM_CONTENT_TYPES = CONTENT_INI + 1;
|
||||
static const int NUM_CONTENT_TYPES = CONTENT_MODGROUP + 1;
|
||||
|
||||
enum EHighlight {
|
||||
HIGHLIGHT_NONE = 0,
|
||||
@@ -263,6 +268,12 @@ public:
|
||||
**/
|
||||
virtual void setCategory(int categoryID, bool active) = 0;
|
||||
|
||||
/**
|
||||
* @brief changes the comments (manually set information displayed in the mod list) for this mod
|
||||
* @param comments new comments
|
||||
*/
|
||||
virtual void setComments(const QString &comments) = 0;
|
||||
|
||||
/**
|
||||
* @brief change the notes (manually set information) for this mod
|
||||
* @param notes new notes
|
||||
@@ -490,6 +501,11 @@ public:
|
||||
*/
|
||||
virtual QString getDescription() const = 0;
|
||||
|
||||
/**
|
||||
* @return comments for this mod
|
||||
*/
|
||||
virtual QString comments() const = 0;
|
||||
|
||||
/**
|
||||
* @return notes for this mod
|
||||
*/
|
||||
@@ -520,6 +536,16 @@ public:
|
||||
*/
|
||||
virtual QStringList archives() const = 0;
|
||||
|
||||
/*
|
||||
*@return the color choosen by the user for the mod/separator
|
||||
*/
|
||||
virtual QColor getColor() { return QColor(); }
|
||||
|
||||
/*
|
||||
*@return true if the color has been set successfully.
|
||||
*/
|
||||
virtual void setColor(QColor color) { }
|
||||
|
||||
/**
|
||||
* @brief adds the information that a file has been installed into this mod
|
||||
* @param modId id of the mod installed
|
||||
@@ -557,7 +583,7 @@ public:
|
||||
/**
|
||||
* @return true if this mod is considered "valid", that is: it contains data used by the game
|
||||
**/
|
||||
bool isValid() const { return m_Valid; }
|
||||
virtual bool isValid() const { return m_Valid; }
|
||||
|
||||
/**
|
||||
* @return true if the file has been endorsed on nexus
|
||||
@@ -574,6 +600,11 @@ public:
|
||||
*/
|
||||
virtual void markConverted(bool converted) {}
|
||||
|
||||
/**
|
||||
* @brief updates the mod to flag it as valid in order to ignore the invalid game data flag
|
||||
*/
|
||||
virtual void markValidated(bool validated) {}
|
||||
|
||||
/**
|
||||
* @brief reads meta information from disk
|
||||
*/
|
||||
|
||||
+19
-2
@@ -112,6 +112,7 @@ ModInfoDialog::ModInfoDialog(ModInfo::Ptr modInfo, const DirectoryEntry *directo
|
||||
}
|
||||
ui->sourceGameEdit->setCurrentIndex(ui->sourceGameEdit->findData(gameName));
|
||||
|
||||
ui->commentsEdit->setText(modInfo->comments());
|
||||
ui->notesEdit->setText(modInfo->notes());
|
||||
|
||||
ui->descriptionView->setPage(new DescriptionPage);
|
||||
@@ -134,7 +135,22 @@ ModInfoDialog::ModInfoDialog(ModInfo::Ptr modInfo, const DirectoryEntry *directo
|
||||
|
||||
refreshLists();
|
||||
|
||||
if (unmanaged) {
|
||||
if (modInfo->hasFlag(ModInfo::FLAG_SEPARATOR))
|
||||
{
|
||||
ui->tabWidget->setTabEnabled(TAB_TEXTFILES, false);
|
||||
ui->tabWidget->setTabEnabled(TAB_INIFILES, false);
|
||||
ui->tabWidget->setTabEnabled(TAB_IMAGES, false);
|
||||
ui->tabWidget->setTabEnabled(TAB_ESPS, false);
|
||||
ui->tabWidget->setTabEnabled(TAB_CONFLICTS, false);
|
||||
//ui->tabWidget->setTabEnabled(TAB_CATEGORIES, false);
|
||||
addCategories(CategoryFactory::instance(), modInfo->getCategories(), ui->categoriesTree->invisibleRootItem(), 0);
|
||||
refreshPrimaryCategoriesBox();
|
||||
ui->tabWidget->setTabEnabled(TAB_NEXUS, false);
|
||||
//ui->tabWidget->setTabEnabled(TAB_NOTES, false);
|
||||
ui->tabWidget->setTabEnabled(TAB_FILETREE, false);
|
||||
}
|
||||
else if (unmanaged)
|
||||
{
|
||||
ui->tabWidget->setTabEnabled(TAB_INIFILES, false);
|
||||
ui->tabWidget->setTabEnabled(TAB_CATEGORIES, false);
|
||||
ui->tabWidget->setTabEnabled(TAB_NEXUS, false);
|
||||
@@ -174,6 +190,7 @@ ModInfoDialog::ModInfoDialog(ModInfo::Ptr modInfo, const DirectoryEntry *directo
|
||||
|
||||
ModInfoDialog::~ModInfoDialog()
|
||||
{
|
||||
m_ModInfo->setComments(ui->commentsEdit->text());
|
||||
m_ModInfo->setNotes(ui->notesEdit->toPlainText());
|
||||
saveCategories(ui->categoriesTree->invisibleRootItem());
|
||||
saveIniTweaks(); // ini tweaks are written to the ini file directly. This is the only information not managed by ModInfo
|
||||
@@ -1080,7 +1097,7 @@ void ModInfoDialog::openFile(const QModelIndex &index)
|
||||
QString fileName = m_FileSystemModel->filePath(index);
|
||||
|
||||
HINSTANCE res = ::ShellExecuteW(nullptr, L"open", ToWString(fileName).c_str(), nullptr, nullptr, SW_SHOW);
|
||||
if ((int)res <= 32) {
|
||||
if ((unsigned long long)res <= 32) {
|
||||
qCritical("failed to invoke %s: %d", fileName.toUtf8().constData(), res);
|
||||
}
|
||||
}
|
||||
|
||||
+44
-9
@@ -20,7 +20,7 @@
|
||||
<enum>QTabWidget::Rounded</enum>
|
||||
</property>
|
||||
<property name="currentIndex">
|
||||
<number>8</number>
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="movable">
|
||||
<bool>true</bool>
|
||||
@@ -238,8 +238,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>98</width>
|
||||
<height>28</height>
|
||||
<width>746</width>
|
||||
<height>126</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
@@ -677,12 +677,12 @@ p, li { white-space: pre-wrap; }
|
||||
<widget class="QLineEdit" name="versionEdit">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>50</width>
|
||||
<width>150</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maxLength">
|
||||
<number>10</number>
|
||||
<number>32</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@@ -723,8 +723,20 @@ p, li { white-space: pre-wrap; }
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QWebEngineView" name="descriptionView">
|
||||
<property name="url">
|
||||
<widget class="QWebEngineView" name="descriptionView" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="MinimumExpanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>200</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="url" stdset="0">
|
||||
<url>
|
||||
<string>about:blank</string>
|
||||
</url>
|
||||
@@ -770,7 +782,30 @@ p, li { white-space: pre-wrap; }
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_10">
|
||||
<item>
|
||||
<widget class="QTextEdit" name="notesEdit"/>
|
||||
<widget class="QLineEdit" name="commentsEdit">
|
||||
<property name="toolTip">
|
||||
<string>Enter comments about the mod here. These are displayed in the notes column of the mod list.</string>
|
||||
</property>
|
||||
<property name="whatsThis">
|
||||
<string>Enter comments about the mod here. These are displayed in the notes column of the mod list.</string>
|
||||
</property>
|
||||
<property name="placeholderText">
|
||||
<string>Enter comments about the mod here. These are displayed in the notes column of the mod list.</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QTextEdit" name="notesEdit">
|
||||
<property name="toolTip">
|
||||
<string>Enter notes about the mod here. These can be viewed in the mod list by hovering over the notes column or the flags column.</string>
|
||||
</property>
|
||||
<property name="whatsThis">
|
||||
<string>Enter notes about the mod here. These can be viewed in the mod list by hovering over the notes column or the flags column.</string>
|
||||
</property>
|
||||
<property name="placeholderText">
|
||||
<string>Enter notes about the mod here. These can be viewed in the mod list by hovering over the notes column or the flags column.</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
@@ -795,7 +830,7 @@ p, li { white-space: pre-wrap; }
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_4">
|
||||
<spacer name="horizontalSpacer_5">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
|
||||
@@ -18,6 +18,7 @@ public:
|
||||
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(QString) {}
|
||||
virtual void setNexusID(int) {}
|
||||
@@ -33,6 +34,7 @@ public:
|
||||
virtual bool isEmpty() const { return false; }
|
||||
virtual QString name() const;
|
||||
virtual QString internalName() const { return name(); }
|
||||
virtual QString comments() const { return ""; }
|
||||
virtual QString notes() const { return ""; }
|
||||
virtual QDateTime creationTime() const;
|
||||
virtual QString absolutePath() const;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user