diff options
| author | Thomas Tanner <trtanner@btinternet.com> | 2015-12-05 12:49:12 +0000 |
|---|---|---|
| committer | Thomas Tanner <trtanner@btinternet.com> | 2015-12-05 12:49:12 +0000 |
| commit | c2ed844eeb2d213a72c405eb47e077da00f084fe (patch) | |
| tree | 647441b712dbe79caacf385395b04fd8ee94b66c | |
| parent | c07e48075e86c855f147e084a50ee1c7f0c00e40 (diff) | |
| parent | 688e149c96c29d8249c9db416f5773cfc7baad6d (diff) | |
Merge remote-tracking branch 'remotes/TanninOne/master' into issue/356
Conflicts:
src/downloadmanager.cpp
src/mainwindow.cpp
src/modinfo.cpp
src/modinfo.h
src/selfupdater.cpp
src/shared/fallout3info.cpp
src/shared/fallout3info.h
src/shared/falloutnvinfo.cpp
src/shared/falloutnvinfo.h
src/shared/gameinfo.h
src/shared/oblivioninfo.cpp
src/shared/oblivioninfo.h
src/shared/skyriminfo.cpp
src/shared/skyriminfo.h
37 files changed, 1659 insertions, 1497 deletions
@@ -20,7 +20,7 @@ Here is a complete list: * https://github.com/TanninOne/modorganizer-lootcli
* https://github.com/TanninOne/modorganizer-helper
* https://github.com/TanninOne/modorganizer-tool_nmmimport
-* https://github.com/TanninOne/modorganizer-tool_pyniedit
+* https://github.com/TanninOne/modorganizer-tool_configurator
* https://github.com/TanninOne/modorganizer-tool_inieditor
* https://github.com/TanninOne/modorganizer-preview_base
* https://github.com/TanninOne/modorganizer-diagnose_basic
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 8a2964d4..3c786868 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -35,6 +35,11 @@ SET(organizer_SRCS modlist.cpp modinfodialog.cpp modinfo.cpp + modinfobackup.cpp + modinfoforeign.cpp + modinfooverwrite.cpp + modinforegular.cpp + modinfowithconflictinfo.cpp messagedialog.cpp mainwindow.cpp main.cpp @@ -124,6 +129,11 @@ SET(organizer_HDRS modlist.h modinfodialog.h modinfo.h + modinfobackup.h + modinfoforeign.h + modinfooverwrite.h + modinforegular.h + modinfowithconflictinfo.h messagedialog.h mainwindow.h loghighlighter.h @@ -270,16 +280,20 @@ SET(default_project_path "${CMAKE_SOURCE_DIR}/..") GET_FILENAME_COMPONENT(${default_project_path} ${default_project_path} REALPATH) SET(project_path "${default_project_path}" CACHE PATH "path to the other mo projects") -SET(lib_path "${project_path}/../install/libs") +SET(lib_path "${project_path}/../../install/libs") + + +MESSAGE(STATUS ${lib_path}) +MESSAGE(STATUS ${project_path}) INCLUDE_DIRECTORIES(${project_path}/uibase/src ${project_path}/bsatk/src ${project_path}/esptk/src ${project_path}/archive/src - ${project_path}/plugin/game_features/src) + ${project_path}/game_features/src) INCLUDE_DIRECTORIES(shared ${ZLIB_INCLUDE_DIRS}) LINK_DIRECTORIES(${lib_path} - ${project_path}/zlib/lib) + ${project_path}/../zlib/lib) ADD_DEFINITIONS(-D_UNICODE -DUNICODE -DNOMINMAX -D_CRT_SECURE_NO_WARNINGS) @@ -296,7 +310,7 @@ SET_TARGET_PROPERTIES(ModOrganizer PROPERTIES LINK_FLAGS_RELWITHDEBINFO "/LTCG /INCREMENTAL:NO /LARGEADDRESSAWARE /OPT:REF /OPT:ICF") -QT5_USE_MODULES(ModOrganizer Widgets Declarative Network WebEngineWidgets) +QT5_USE_MODULES(ModOrganizer Widgets Declarative Network WebKitWidgets) ############### diff --git a/src/SConscript b/src/SConscript index 8e0280ef..787561b8 100644 --- a/src/SConscript +++ b/src/SConscript @@ -111,7 +111,11 @@ env.AppendUnique(CPPDEFINES = [ 'QT_MESSAGELOGCONTEXT'
])
-env.AppendUnique(CPPFLAGS = [ '-wd4100', '-wd4127', '-wd4512', '-wd4189' ])
+# Boost produces very long names with msvc truncates. Doesn't seem to cause
+# problems.
+# Also note to remove the -wd4100 I hacked the boost headers (tagged_argument.hpp)
+# appropriately.
+env.AppendUnique(CPPFLAGS = [ '-wd4503' ])
env.AppendUnique(LINKFLAGS = [
'/SUBSYSTEM:WINDOWS',
diff --git a/src/downloadmanager.cpp b/src/downloadmanager.cpp index e95a315f..70caaf3e 100644 --- a/src/downloadmanager.cpp +++ b/src/downloadmanager.cpp @@ -39,6 +39,7 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #include <QInputDialog>
#include <QMessageBox>
#include <QCoreApplication>
+#include <QTextDocument>
#include <boost/bind.hpp>
#include <regex>
@@ -912,10 +913,10 @@ QString DownloadManager::getDownloadFileName(const QString &baseName) const QString DownloadManager::getFileNameFromNetworkReply(QNetworkReply *reply)
{
if (reply->hasRawHeader("Content-Disposition")) {
- std::tr1::regex exp("filename=\"(.*)\"");
+ std::regex exp("filename=\"(.*)\"");
- std::tr1::cmatch result;
- if (std::tr1::regex_search(reply->rawHeader("Content-Disposition").constData(), result, exp)) {
+ std::cmatch result;
+ if (std::regex_search(reply->rawHeader("Content-Disposition").constData(), result, exp)) {
return QString::fromUtf8(result.str(1).c_str());
}
}
@@ -1131,6 +1132,12 @@ void DownloadManager::nxmFilesAvailable(int, QVariant userData, QVariant resultD if (!info->m_FileInfo->version.isValid()) {
info->m_FileInfo->version = info->m_FileInfo->newestVersion;
}
+ //Nexus has HTMLd these so unhtml them if necessary
+ QTextDocument doc;
+ doc.setHtml(info->m_FileInfo->modName);
+ info->m_FileInfo->modName = doc.toPlainText();
+ doc.setHtml(info->m_FileInfo->name);
+ info->m_FileInfo->name = doc.toPlainText();
info->m_FileInfo->fileCategory = convertFileCategory(fileInfo["category_id"].toInt());
info->m_FileInfo->fileTime = matchDate(fileInfo["date"].toString());
info->m_FileInfo->fileID = fileInfo["id"].toInt();
diff --git a/src/installationmanager.cpp b/src/installationmanager.cpp index 4b3722b8..7b1f3f37 100644 --- a/src/installationmanager.cpp +++ b/src/installationmanager.cpp @@ -84,16 +84,16 @@ InstallationManager::InstallationManager() CreateArchiveType CreateArchiveFunc = resolveFunction<CreateArchiveType>(archiveLib, "CreateArchive");
- m_CurrentArchive = CreateArchiveFunc();
- if (!m_CurrentArchive->isValid()) {
- throw MyException(getErrorString(m_CurrentArchive->getLastError()));
+ m_ArchiveHandler = CreateArchiveFunc();
+ if (!m_ArchiveHandler->isValid()) {
+ throw MyException(getErrorString(m_ArchiveHandler->getLastError()));
}
}
InstallationManager::~InstallationManager()
{
- delete m_CurrentArchive;
+ delete m_ArchiveHandler;
}
void InstallationManager::setParentWidget(QWidget *widget)
@@ -103,35 +103,37 @@ void InstallationManager::setParentWidget(QWidget *widget) }
}
+void InstallationManager::setURL(QString const &url)
+{
+ m_URL = url;
+}
-void InstallationManager::queryPassword(LPSTR password)
+void InstallationManager::queryPassword(QString *password)
{
- QString result = QInputDialog::getText(nullptr, tr("Password required"), tr("Password"), QLineEdit::Password);
- strncpy(password, result.toLocal8Bit().constData(), MAX_PASSWORD_LENGTH);
+ *password = QInputDialog::getText(nullptr, tr("Password required"), tr("Password"), QLineEdit::Password);
}
-void InstallationManager::mapToArchive(const DirectoryTree::Node *node, std::wstring path, FileData * const *data)
+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 == L".") {
+ if (path == ".") {
path.clear();
} else {
- path.append(L"\\");
+ path.append("\\");
}
}
for (DirectoryTree::const_leaf_iterator iter = node->leafsBegin(); iter != node->leafsEnd(); ++iter) {
- std::wstring temp = path + iter->getName().toStdWString();
- data[iter->getIndex()]->addOutputFileName(temp.c_str());
+ data[iter->getIndex()]->addOutputFileName(path + iter->getName().toQString());
}
for (DirectoryTree::const_node_iterator iter = node->nodesBegin(); iter != node->nodesEnd(); ++iter) {
- std::wstring temp = path + (*iter)->getData().name.toStdWString();
+ QString temp = path + (*iter)->getData().name.toQString();
if ((*iter)->getData().index != -1) {
- data[(*iter)->getData().index]->addOutputFileName(temp.c_str());
+ data[(*iter)->getData().index]->addOutputFileName(temp);
}
mapToArchive(*iter, temp, data);
}
@@ -142,11 +144,9 @@ void InstallationManager::mapToArchive(const DirectoryTree::Node *baseNode) {
FileData* const *data;
size_t size;
- m_CurrentArchive->getFileList(data, size);
-
- std::wstring currentPath;
+ m_ArchiveHandler->getFileList(data, size);
- mapToArchive(baseNode, currentPath, data);
+ mapToArchive(baseNode, "", data);
}
@@ -154,15 +154,15 @@ bool InstallationManager::unpackSingleFile(const QString &fileName) {
FileData* const *data;
size_t size;
- m_CurrentArchive->getFileList(data, size);
+ m_ArchiveHandler->getFileList(data, size);
QString baseName = QFileInfo(fileName).fileName();
bool available = false;
for (size_t i = 0; i < size; ++i) {
- if (_wcsicmp(data[i]->getFileName(), ToWString(fileName).c_str()) == 0) {
+ if (data[i]->getFileName().compare(fileName, Qt::CaseInsensitive) == 0) {
available = true;
- data[i]->addOutputFileName(ToWString(baseName).c_str());
+ data[i]->addOutputFileName(baseName);
m_TempFilesToDelete.insert(baseName);
}
}
@@ -184,10 +184,10 @@ bool InstallationManager::unpackSingleFile(const QString &fileName) m_InstallationProgress->setWindowModality(Qt::WindowModal);
m_InstallationProgress->show();
- bool res = m_CurrentArchive->extract(ToWString(QDir::toNativeSeparators(QDir::tempPath())).c_str(),
+ bool res = m_ArchiveHandler->extract(QDir::tempPath(),
new MethodCallback<InstallationManager, void, float>(this, &InstallationManager::updateProgress),
- new MethodCallback<InstallationManager, void, LPCWSTR>(this, &InstallationManager::dummyProgressFile),
- new MethodCallback<InstallationManager, void, LPCWSTR>(this, &InstallationManager::report7ZipError));
+ nullptr,
+ new MethodCallback<InstallationManager, void, QString const &>(this, &InstallationManager::report7ZipError));
return res;
}
@@ -228,25 +228,30 @@ QStringList InstallationManager::extractFiles(const QStringList &filesOrig, bool FileData* const *data;
size_t size;
- m_CurrentArchive->getFileList(data, size);
+ m_ArchiveHandler->getFileList(data, size);
for (size_t i = 0; i < size; ++i) {
- if (files.contains(ToQString(data[i]->getFileName()), Qt::CaseInsensitive)) {
- const wchar_t *targetFile = data[i]->getFileName();
+ //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(data[i]->getFileName(), '\\');
+ targetFile = wcsrchr(origFile/*data[i]->getFileName()*/, '\\');
if (targetFile == nullptr) {
- targetFile = wcsrchr(data[i]->getFileName(), '/');
+ targetFile = wcsrchr(origFile/*data[i]->getFileName()*/, '/');
}
if (targetFile == nullptr) {
- qCritical("failed to find backslash in %ls", data[i]->getFileName());
+ qCritical() << "Failed to find backslash in " << data[i]->getFileName();
continue;
} else {
// skip the slash
++targetFile;
}
}
- data[i]->addOutputFileName(targetFile);
+ data[i]->addOutputFileName(ToQString(targetFile));
result.append(QDir::tempPath().append("/").append(ToQString(targetFile)));
@@ -267,11 +272,11 @@ QStringList InstallationManager::extractFiles(const QStringList &filesOrig, bool m_InstallationProgress->show();
// unpack only the files we need for the installer
- if (!m_CurrentArchive->extract(ToWString(QDir::toNativeSeparators(QDir::tempPath())).c_str(),
+ if (!m_ArchiveHandler->extract(QDir::tempPath(),
new MethodCallback<InstallationManager, void, float>(this, &InstallationManager::updateProgress),
- new MethodCallback<InstallationManager, void, LPCWSTR>(this, &InstallationManager::dummyProgressFile),
- new MethodCallback<InstallationManager, void, LPCWSTR>(this, &InstallationManager::report7ZipError))) {
- throw MyException(QString("extracting failed (%1)").arg(m_CurrentArchive->getLastError()));
+ nullptr,
+ new MethodCallback<InstallationManager, void, QString const &>(this, &InstallationManager::report7ZipError))) {
+ throw MyException(QString("extracting failed (%1)").arg(m_ArchiveHandler->getLastError()));
}
return result;
@@ -295,7 +300,7 @@ DirectoryTree *InstallationManager::createFilesTree() {
FileData* const *data;
size_t size;
- m_CurrentArchive->getFileList(data, size);
+ m_ArchiveHandler->getFileList(data, size);
QScopedPointer<DirectoryTree> result(new DirectoryTree);
@@ -305,7 +310,7 @@ DirectoryTree *InstallationManager::createFilesTree() // grouping the filenames first, but so far there doesn't seem to be an actual performance problem
DirectoryTree::Node *currentNode = result.data();
- QString fileName = ToQString(data[i]->getFileName());
+ QString fileName = data[i]->getFileName();
QStringList components = fileName.split("\\");
// iterate over all path-components of this filename (including the filename itself)
@@ -399,25 +404,25 @@ void InstallationManager::updateProgress(float percentage) if (m_InstallationProgress != nullptr) {
m_InstallationProgress->setValue(static_cast<int>(percentage * 100.0));
if (m_InstallationProgress->wasCanceled()) {
- m_CurrentArchive->cancel();
+ m_ArchiveHandler->cancel();
m_InstallationProgress->reset();
}
}
}
-void InstallationManager::updateProgressFile(LPCWSTR fileName)
+void InstallationManager::updateProgressFile(QString const &fileName)
{
if (m_InstallationProgress != nullptr) {
- m_InstallationProgress->setLabelText(QString::fromWCharArray(fileName));
+ m_InstallationProgress->setLabelText(fileName);
}
}
-void InstallationManager::report7ZipError(LPCWSTR errorMessage)
+void InstallationManager::report7ZipError(QString const &errorMessage)
{
- reportError(QString::fromWCharArray(errorMessage));
- m_CurrentArchive->cancel();
+ reportError(errorMessage);
+ m_ArchiveHandler->cancel();
}
@@ -553,14 +558,14 @@ bool InstallationManager::doInstall(GuessedValue<QString> &modName, int modID, m_InstallationProgress->windowFlags() & (~Qt::WindowContextHelpButtonHint));
m_InstallationProgress->setWindowModality(Qt::WindowModal);
m_InstallationProgress->show();
- if (!m_CurrentArchive->extract(ToWString("\\\\?\\" + targetDirectoryNative).c_str(),
+ if (!m_ArchiveHandler->extract(targetDirectory,
new MethodCallback<InstallationManager, void, float>(this, &InstallationManager::updateProgress),
- new MethodCallback<InstallationManager, void, LPCWSTR>(this, &InstallationManager::updateProgressFile),
- new MethodCallback<InstallationManager, void, LPCWSTR>(this, &InstallationManager::report7ZipError))) {
- if (m_CurrentArchive->getLastError() == Archive::ERROR_EXTRACT_CANCELLED) {
+ new MethodCallback<InstallationManager, void, QString const &>(this, &InstallationManager::updateProgressFile),
+ new MethodCallback<InstallationManager, void, QString const &>(this, &InstallationManager::report7ZipError))) {
+ if (m_ArchiveHandler->getLastError() == Archive::ERROR_EXTRACT_CANCELLED) {
return false;
} else {
- throw MyException(QString("extracting failed (%1)").arg(m_CurrentArchive->getLastError()));
+ throw MyException(QString("extracting failed (%1)").arg(m_ArchiveHandler->getLastError()));
}
}
@@ -584,6 +589,7 @@ bool InstallationManager::doInstall(GuessedValue<QString> &modName, int modID, }
settingsFile.setValue("installationFile", m_CurrentFile);
settingsFile.setValue("repository", repository);
+ settingsFile.setValue("url", m_URL);
if (!merge) {
// this does not clear the list we have in memory but the mod is going to have to be re-read anyway
@@ -599,13 +605,13 @@ bool InstallationManager::doInstall(GuessedValue<QString> &modName, int modID, bool InstallationManager::wasCancelled()
{
- return m_CurrentArchive->getLastError() == Archive::ERROR_EXTRACT_CANCELLED;
+ return m_ArchiveHandler->getLastError() == Archive::ERROR_EXTRACT_CANCELLED;
}
void InstallationManager::postInstallCleanup()
{
- m_CurrentArchive->close();
+ m_ArchiveHandler->close();
// directories we may want to remove. sorted from longest to shortest to ensure we remove subdirectories first.
auto longestFirst = [](const QString &LHS, const QString &RHS) -> bool {
@@ -691,13 +697,13 @@ bool InstallationManager::install(const QString &fileName, GuessedValue<QString> //If there's an archive already open, close it. This happens with the bundle
//installer when it uncompresses a split archive, then finds it has a real archive
//to deal with.
- m_CurrentArchive->close();
+ m_ArchiveHandler->close();
// open the archive and construct the directory tree the installers work on
- bool archiveOpen = m_CurrentArchive->open(ToWString(QDir::toNativeSeparators(fileName)).c_str(),
- new MethodCallback<InstallationManager, void, LPSTR>(this, &InstallationManager::queryPassword));
+ bool archiveOpen = m_ArchiveHandler->open(fileName,
+ new MethodCallback<InstallationManager, void, QString *>(this, &InstallationManager::queryPassword));
if (!archiveOpen) {
- qDebug("integrated archiver can't open %s. errorcode %d", qPrintable(fileName), m_CurrentArchive->getLastError());
+ qDebug("integrated archiver can't open %s. errorcode %d", qPrintable(fileName), m_ArchiveHandler->getLastError());
}
ON_BLOCK_EXIT(std::bind(&InstallationManager::postInstallCleanup, this));
diff --git a/src/installationmanager.h b/src/installationmanager.h index 111b41f5..e1ebb519 100644 --- a/src/installationmanager.h +++ b/src/installationmanager.h @@ -59,6 +59,8 @@ public: void setParentWidget(QWidget *widget);
+ void setURL(const QString &url);
+
/**
* @brief update the directory where mods are to be installed
* @param modsDirectory the mod directory
@@ -147,12 +149,10 @@ public: private:
- void queryPassword(LPSTR password);
+ void queryPassword(QString *password);
void updateProgress(float percentage);
- void updateProgressFile(LPCWSTR fileName);
- void report7ZipError(LPCWSTR errorMessage);
-
- void dummyProgressFile(LPCWSTR) {}
+ void updateProgressFile(const QString &fileName);
+ void report7ZipError(const QString &errorMessage);
MOBase::DirectoryTree *createFilesTree();
@@ -161,15 +161,13 @@ private: void mapToArchive(const MOBase::DirectoryTree::Node *baseNode);
// recursive worker function for mapToArchive
- void mapToArchive(const MOBase::DirectoryTree::Node *node, std::wstring path, FileData * const *data);
+ 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 testOverwrite(const QString &modsDirectory, MOBase::GuessedValue<QString> &modName, bool *merge = nullptr);
-
bool doInstall(MOBase::GuessedValue<QString> &modName,
int modID, const QString &version, const QString &newestVersion, int categoryID, const QString &repository);
@@ -205,13 +203,14 @@ private: std::vector<MOBase::IPluginInstaller*> m_Installers;
std::set<QString, CaseInsensitive> m_SupportedExtensions;
- Archive *m_CurrentArchive;
+ Archive *m_ArchiveHandler;
QString m_CurrentFile;
QProgressDialog *m_InstallationProgress { nullptr };
std::set<QString> m_TempFilesToDelete;
+ QString m_URL;
};
diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 1101f3fa..7dd5d71b 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -2552,6 +2552,16 @@ void MainWindow::visitOnNexus_clicked() }
}
+void MainWindow::visitWebPage_clicked()
+{
+ ModInfo::Ptr info = ModInfo::getByIndex(m_ContextRow);
+ if (info->getURL() != "") {
+ linkClicked(info->getURL());
+ } else {
+ MessageDialog::showMessage(tr("Web page for this mod is unknown"), this);
+ }
+}
+
void MainWindow::openExplorer_clicked()
{
ModInfo::Ptr modInfo = ModInfo::getByIndex(m_ContextRow);
@@ -3122,12 +3132,22 @@ void MainWindow::on_modList_customContextMenuRequested(const QPoint &pos) } break;
}
}
+
std::vector<ModInfo::EFlag> flags = info->getFlags();
if (std::find(flags.begin(), flags.end(), ModInfo::FLAG_INVALID) != flags.end()) {
menu->addAction(tr("Ignore missing data"), this, SLOT(ignoreMissingData_clicked()));
}
- menu->addAction(tr("Visit on Nexus"), this, SLOT(visitOnNexus_clicked()));
+ if (info->getNexusID() > 0) {
+ menu->addAction(tr("Visit on Nexus"), this, SLOT(visitOnNexus_clicked()));
+ }
+
+ //If a URL is specified which is not the game's URL, pop up 'visit web page'
+ if (info->getURL() != "" &&
+ !NexusInterface::instance()->isModURL(info->getNexusID(), info->getURL())) {
+ menu->addAction(tr("Visit web page"), this, SLOT(visitWebPage_clicked()));
+ }
+
menu->addAction(tr("Open in explorer"), this, SLOT(openExplorer_clicked()));
}
diff --git a/src/mainwindow.h b/src/mainwindow.h index b97a728e..0cdea807 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -357,6 +357,7 @@ private slots: void unendorse_clicked();
void ignoreMissingData_clicked();
void visitOnNexus_clicked();
+ void visitWebPage_clicked();
void openExplorer_clicked();
void information_clicked();
// savegame context menu
diff --git a/src/modinfo.cpp b/src/modinfo.cpp index 03ab9a95..a4a8110c 100644 --- a/src/modinfo.cpp +++ b/src/modinfo.cpp @@ -19,15 +19,18 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #include "modinfo.h" -#include "utility.h" +#include "modinfobackup.h" +#include "modinforegular.h" +#include "modinfoforeign.h" +#include "modinfooverwrite.h" + #include "installationtester.h" #include "categories.h" -#include "report.h" #include "modinfodialog.h" #include "overwriteinfodialog.h" #include "json.h" -#include "messagedialog.h" #include "filenamestring.h" +#include "versioninfo.h" #include <iplugingame.h> #include <versioninfo.h> @@ -35,12 +38,9 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #include <scriptextender.h> #include <QApplication> - #include <QDirIterator> #include <QMutexLocker> #include <QSettings> -#include <sstream> - using namespace MOBase; using namespace MOShared; @@ -397,773 +397,3 @@ void ModInfo::testValid() dirIter.next(); } } - - -ModInfoWithConflictInfo::ModInfoWithConflictInfo(DirectoryEntry **directoryStructure) - : m_DirectoryStructure(directoryStructure) {} - -void ModInfoWithConflictInfo::clearCaches() -{ - m_LastConflictCheck = QTime(); -} - -std::vector<ModInfo::EFlag> ModInfoWithConflictInfo::getFlags() const -{ - std::vector<ModInfo::EFlag> result; - switch (isConflicted()) { - case CONFLICT_MIXED: { - result.push_back(ModInfo::FLAG_CONFLICT_MIXED); - } break; - case CONFLICT_OVERWRITE: { - result.push_back(ModInfo::FLAG_CONFLICT_OVERWRITE); - } break; - case CONFLICT_OVERWRITTEN: { - result.push_back(ModInfo::FLAG_CONFLICT_OVERWRITTEN); - } break; - case CONFLICT_REDUNDANT: { - result.push_back(ModInfo::FLAG_CONFLICT_REDUNDANT); - } break; - default: { /* NOP */ } - } - return result; -} - - -void ModInfoWithConflictInfo::doConflictCheck() const -{ - m_OverwriteList.clear(); - m_OverwrittenList.clear(); - - bool providesAnything = false; - - int dataID = 0; - if ((*m_DirectoryStructure)->originExists(L"data")) { - dataID = (*m_DirectoryStructure)->getOriginByName(L"data").getID(); - } - - std::wstring name = ToWString(this->name()); - - m_CurrentConflictState = CONFLICT_NONE; - - if ((*m_DirectoryStructure)->originExists(name)) { - FilesOrigin &origin = (*m_DirectoryStructure)->getOriginByName(name); - std::vector<FileEntry::Ptr> files = origin.getFiles(); - // for all files in this origin - for (FileEntry::Ptr file : files) { - const std::vector<int> &alternatives = file->getAlternatives(); - if ((alternatives.size() == 0) || (alternatives[0] == dataID)) { - // no alternatives -> no conflict - providesAnything = true; - } else { - if (file->getOrigin() != origin.getID()) { - FilesOrigin &altOrigin = (*m_DirectoryStructure)->getOriginByID(file->getOrigin()); - unsigned int altIndex = ModInfo::getIndex(ToQString(altOrigin.getName())); - m_OverwrittenList.insert(altIndex); - } else { - providesAnything = true; - } - - // for all non-providing alternative origins - for (int altId : alternatives) { - if ((altId != dataID) && (altId != origin.getID())) { - FilesOrigin &altOrigin = (*m_DirectoryStructure)->getOriginByID(altId); - unsigned int altIndex = ModInfo::getIndex(ToQString(altOrigin.getName())); - if (origin.getPriority() > altOrigin.getPriority()) { - m_OverwriteList.insert(altIndex); - } else { - m_OverwrittenList.insert(altIndex); - } - } - } - } - } - m_LastConflictCheck = QTime::currentTime(); - - if (files.size() != 0) { - if (!providesAnything) - m_CurrentConflictState = CONFLICT_REDUNDANT; - else if (!m_OverwriteList.empty() && !m_OverwrittenList.empty()) - m_CurrentConflictState = CONFLICT_MIXED; - else if (!m_OverwriteList.empty()) - m_CurrentConflictState = CONFLICT_OVERWRITE; - else if (!m_OverwrittenList.empty()) - m_CurrentConflictState = CONFLICT_OVERWRITTEN; - } - } -} - -ModInfoWithConflictInfo::EConflictType ModInfoWithConflictInfo::isConflicted() const -{ - // this is costy so cache the result - QTime now = QTime::currentTime(); - if (m_LastConflictCheck.isNull() || (m_LastConflictCheck.secsTo(now) > 10)) { - doConflictCheck(); - } - - return m_CurrentConflictState; -} - - -bool ModInfoWithConflictInfo::isRedundant() const -{ - std::wstring name = ToWString(this->name()); - if ((*m_DirectoryStructure)->originExists(name)) { - FilesOrigin &origin = (*m_DirectoryStructure)->getOriginByName(name); - std::vector<FileEntry::Ptr> files = origin.getFiles(); - bool ignore = false; - for (auto iter = files.begin(); iter != files.end(); ++iter) { - if ((*iter)->getOrigin(ignore) == origin.getID()) { - return false; - } - } - return true; - } else { - return false; - } -} - - - -ModInfoRegular::ModInfoRegular(const QDir &path, DirectoryEntry **directoryStructure) - : ModInfoWithConflictInfo(directoryStructure) - , m_Name(path.dirName()) - , m_Path(path.absolutePath()) - , m_Repository() - , m_MetaInfoChanged(false) - , m_EndorsedState(ENDORSED_UNKNOWN) - , m_NexusBridge() -{ - testValid(); - m_CreationTime = QFileInfo(path.absolutePath()).created(); - // read out the meta-file for information - readMeta(); - - connect(&m_NexusBridge, SIGNAL(descriptionAvailable(int,QVariant,QVariant)) - , this, SLOT(nxmDescriptionAvailable(int,QVariant,QVariant))); - connect(&m_NexusBridge, SIGNAL(endorsementToggled(int,QVariant,QVariant)) - , this, SLOT(nxmEndorsementToggled(int,QVariant,QVariant))); - connect(&m_NexusBridge, SIGNAL(requestFailed(int,int,QVariant,QString)) - , this, SLOT(nxmRequestFailed(int,int,QVariant,QString))); -} - - -ModInfoRegular::~ModInfoRegular() -{ - try { - saveMeta(); - } catch (const std::exception &e) { - qCritical("failed to save meta information for \"%s\": %s", - m_Name.toUtf8().constData(), e.what()); - } -} - -bool ModInfoRegular::isEmpty() const -{ - QDirIterator iter(m_Path, QDir::NoDotAndDotDot | QDir::Files | QDir::Dirs); - if (!iter.hasNext()) return true; - iter.next(); - if ((iter.fileName() == "meta.ini") && !iter.hasNext()) return true; - return false; -} - - -void ModInfoRegular::readMeta() -{ - QSettings metaFile(m_Path + "/meta.ini", QSettings::IniFormat); - m_Notes = metaFile.value("notes", "").toString(); - m_NexusID = metaFile.value("modid", -1).toInt(); - m_Version.parse(metaFile.value("version", "").toString()); - m_NewestVersion = metaFile.value("newestVersion", "").toString(); - m_IgnoredVersion = metaFile.value("ignoredVersion", "").toString(); - m_InstallationFile = metaFile.value("installationFile", "").toString(); - m_NexusDescription = metaFile.value("nexusDescription", "").toString(); - m_Repository = metaFile.value("repository", "Nexus").toString(); - m_LastNexusQuery = QDateTime::fromString(metaFile.value("lastNexusQuery", "").toString(), Qt::ISODate); - if (metaFile.contains("endorsed")) { - if (metaFile.value("endorsed").canConvert<int>()) { - switch (metaFile.value("endorsed").toInt()) { - case ENDORSED_FALSE: m_EndorsedState = ENDORSED_FALSE; break; - case ENDORSED_TRUE: m_EndorsedState = ENDORSED_TRUE; break; - case ENDORSED_NEVER: m_EndorsedState = ENDORSED_NEVER; break; - default: m_EndorsedState = ENDORSED_UNKNOWN; break; - } - } else { - m_EndorsedState = metaFile.value("endorsed", false).toBool() ? ENDORSED_TRUE : ENDORSED_FALSE; - } - } - - QString categoriesString = metaFile.value("category", "").toString(); - - QStringList categories = categoriesString.split(',', QString::SkipEmptyParts); - for (QStringList::iterator iter = categories.begin(); iter != categories.end(); ++iter) { - bool ok = false; - int categoryID = iter->toInt(&ok); - if (categoryID < 0) { - // ignore invalid id - continue; - } - if (ok && (categoryID != 0) && (CategoryFactory::instance().categoryExists(categoryID))) { - m_Categories.insert(categoryID); - if (iter == categories.begin()) { - m_PrimaryCategory = categoryID; - } - } - } - - int numFiles = metaFile.beginReadArray("installedFiles"); - for (int i = 0; i < numFiles; ++i) { - metaFile.setArrayIndex(i); - m_InstalledFileIDs.insert(std::make_pair(metaFile.value("modid").toInt(), metaFile.value("fileid").toInt())); - } - metaFile.endArray(); - - m_MetaInfoChanged = false; -} - -void ModInfoRegular::saveMeta() -{ - // only write meta data if the mod directory exists - if (m_MetaInfoChanged && QFile::exists(absolutePath())) { - QSettings metaFile(absolutePath().append("/meta.ini"), QSettings::IniFormat); - if (metaFile.status() == QSettings::NoError) { - std::set<int> temp = m_Categories; - temp.erase(m_PrimaryCategory); - metaFile.setValue("category", QString("%1").arg(m_PrimaryCategory) + "," + SetJoin(temp, ",")); - metaFile.setValue("newestVersion", m_NewestVersion.canonicalString()); - metaFile.setValue("ignoredVersion", m_IgnoredVersion.canonicalString()); - metaFile.setValue("version", m_Version.canonicalString()); - metaFile.setValue("installationFile", m_InstallationFile); - metaFile.setValue("repository", m_Repository); - metaFile.setValue("modid", m_NexusID); - metaFile.setValue("notes", m_Notes); - metaFile.setValue("nexusDescription", m_NexusDescription); - metaFile.setValue("lastNexusQuery", m_LastNexusQuery.toString(Qt::ISODate)); - if (m_EndorsedState != ENDORSED_UNKNOWN) { - metaFile.setValue("endorsed", m_EndorsedState); - } - - metaFile.beginWriteArray("installedFiles"); - int idx = 0; - for (auto iter = m_InstalledFileIDs.begin(); iter != m_InstalledFileIDs.end(); ++iter) { - metaFile.setArrayIndex(idx++); - metaFile.setValue("modid", iter->first); - metaFile.setValue("fileid", iter->second); - } - metaFile.endArray(); - - metaFile.sync(); // sync needs to be called to ensure the file is created - - if (metaFile.status() == QSettings::NoError) { - m_MetaInfoChanged = false; - } else { - reportError(tr("failed to write %1/meta.ini: error %2").arg(absolutePath()).arg(metaFile.status())); - } - } else { - reportError(tr("failed to write %1/meta.ini: error %2").arg(absolutePath()).arg(metaFile.status())); - } - } -} - - -bool ModInfoRegular::updateAvailable() const -{ - if (m_IgnoredVersion.isValid() && (m_IgnoredVersion == m_NewestVersion)) { - return false; - } - return m_NewestVersion.isValid() && (m_Version < m_NewestVersion); -} - - -bool ModInfoRegular::downgradeAvailable() const -{ - if (m_IgnoredVersion.isValid() && (m_IgnoredVersion == m_NewestVersion)) { - return false; - } - return m_NewestVersion.isValid() && (m_NewestVersion < m_Version); -} - - -void ModInfoRegular::nxmDescriptionAvailable(int, QVariant, QVariant resultData) -{ - QVariantMap result = resultData.toMap(); - setNewestVersion(VersionInfo(result["version"].toString())); - setNexusDescription(result["description"].toString()); - - if ((m_EndorsedState != ENDORSED_NEVER) && (result.contains("voted_by_user"))) { - setEndorsedState(result["voted_by_user"].toBool() ? ENDORSED_TRUE : ENDORSED_FALSE); - } - m_LastNexusQuery = QDateTime::currentDateTime(); - //m_MetaInfoChanged = true; - saveMeta(); - emit modDetailsUpdated(true); -} - - -void ModInfoRegular::nxmEndorsementToggled(int, QVariant, QVariant resultData) -{ - m_EndorsedState = resultData.toBool() ? ENDORSED_TRUE : ENDORSED_FALSE; - m_MetaInfoChanged = true; - saveMeta(); - emit modDetailsUpdated(true); -} - - -void ModInfoRegular::nxmRequestFailed(int, int, QVariant userData, const QString &errorMessage) -{ - QString fullMessage = errorMessage; - if (userData.canConvert<int>() && (userData.toInt() == 1)) { - fullMessage += "\nNexus will reject endorsements within 15 Minutes of a failed attempt, the error message may be misleading."; - } - if (QApplication::activeWindow() != nullptr) { - MessageDialog::showMessage(fullMessage, QApplication::activeWindow()); - } - emit modDetailsUpdated(false); -} - - -bool ModInfoRegular::updateNXMInfo() -{ - if (m_NexusID > 0) { - m_NexusBridge.requestDescription(m_NexusID, QVariant()); - return true; - } - return false; -} - - -void ModInfoRegular::setCategory(int categoryID, bool active) -{ - m_MetaInfoChanged = true; - - if (active) { - m_Categories.insert(categoryID); - if (m_PrimaryCategory == -1) { - m_PrimaryCategory = categoryID; - } - } else { - std::set<int>::iterator iter = m_Categories.find(categoryID); - if (iter != m_Categories.end()) { - m_Categories.erase(iter); - } - if (categoryID == m_PrimaryCategory) { - if (m_Categories.size() == 0) { - m_PrimaryCategory = -1; - } else { - m_PrimaryCategory = *(m_Categories.begin()); - } - } - } -} - - -bool ModInfoRegular::setName(const QString &name) -{ - if (name.contains('/') || name.contains('\\')) { - return false; - } - - QString newPath = m_Path.mid(0).replace(m_Path.length() - m_Name.length(), m_Name.length(), name); - QDir modDir(m_Path.mid(0, m_Path.length() - m_Name.length())); - - if (m_Name.compare(name, Qt::CaseInsensitive) == 0) { - QString tempName = name; - tempName.append("_temp"); - while (modDir.exists(tempName)) { - tempName.append("_"); - } - if (!modDir.rename(m_Name, tempName)) { - return false; - } - if (!modDir.rename(tempName, name)) { - qCritical("rename to final name failed after successful rename to intermediate name"); - modDir.rename(tempName, m_Name); - return false; - } - } else { - if (!shellRename(modDir.absoluteFilePath(m_Name), modDir.absoluteFilePath(name))) { - qCritical("failed to rename mod %s (errorcode %d)", - qPrintable(name), ::GetLastError()); - return false; - } - } - - std::map<QString, unsigned int>::iterator nameIter = s_ModsByName.find(m_Name); - if (nameIter != s_ModsByName.end()) { - unsigned int index = nameIter->second; - s_ModsByName.erase(nameIter); - - m_Name = name; - m_Path = newPath; - - s_ModsByName[m_Name] = index; - - std::sort(s_Collection.begin(), s_Collection.end(), ByName); - updateIndices(); - } else { // otherwise mod isn't registered yet? - m_Name = name; - m_Path = newPath; - } - - return true; -} - -void ModInfoRegular::setNotes(const QString ¬es) -{ - m_Notes = notes; - m_MetaInfoChanged = true; -} - -void ModInfoRegular::setNexusID(int modID) -{ - m_NexusID = modID; - m_MetaInfoChanged = true; -} - -void ModInfoRegular::setVersion(const VersionInfo &version) -{ - m_Version = version; - m_MetaInfoChanged = true; -} - -void ModInfoRegular::setNewestVersion(const VersionInfo &version) -{ - if (version != m_NewestVersion) { - m_NewestVersion = version; - m_MetaInfoChanged = true; - } -} - -void ModInfoRegular::setNexusDescription(const QString &description) -{ - if (qHash(description) != qHash(m_NexusDescription)) { - m_NexusDescription = description; - m_MetaInfoChanged = true; - } -} - -void ModInfoRegular::setEndorsedState(EEndorsedState endorsedState) -{ - if (endorsedState != m_EndorsedState) { - m_EndorsedState = endorsedState; - m_MetaInfoChanged = true; - } -} - -void ModInfoRegular::setInstallationFile(const QString &fileName) -{ - m_InstallationFile = fileName; - m_MetaInfoChanged = true; -} - -void ModInfoRegular::addNexusCategory(int categoryID) -{ - m_Categories.insert(CategoryFactory::instance().resolveNexusID(categoryID)); -} - -void ModInfoRegular::setIsEndorsed(bool endorsed) -{ - if (m_EndorsedState != ENDORSED_NEVER) { - m_EndorsedState = endorsed ? ENDORSED_TRUE : ENDORSED_FALSE; - m_MetaInfoChanged = true; - } -} - - -void ModInfoRegular::setNeverEndorse() -{ - m_EndorsedState = ENDORSED_NEVER; - m_MetaInfoChanged = true; -} - - -bool ModInfoRegular::remove() -{ - m_MetaInfoChanged = false; - return shellDelete(QStringList(absolutePath()), true); -} - -void ModInfoRegular::endorse(bool doEndorse) -{ - if (doEndorse != (m_EndorsedState == ENDORSED_TRUE)) { - m_NexusBridge.requestToggleEndorsement(getNexusID(), doEndorse, QVariant(1)); - } -} - - -QString ModInfoRegular::absolutePath() const -{ - return m_Path; -} - -void ModInfoRegular::ignoreUpdate(bool ignore) -{ - if (ignore) { - m_IgnoredVersion = m_NewestVersion; - } else { - m_IgnoredVersion.clear(); - } - m_MetaInfoChanged = true; -} - - -std::vector<ModInfo::EFlag> ModInfoRegular::getFlags() const -{ - std::vector<ModInfo::EFlag> result = ModInfoWithConflictInfo::getFlags(); - if ((m_NexusID > 0) && (endorsedState() == ENDORSED_FALSE)) { - result.push_back(ModInfo::FLAG_NOTENDORSED); - } - if (!isValid()) { - result.push_back(ModInfo::FLAG_INVALID); - } - if (m_Notes.length() != 0) { - result.push_back(ModInfo::FLAG_NOTES); - } - return result; -} - - -std::vector<ModInfo::EContent> ModInfoRegular::getContents() const -{ - QTime now = QTime::currentTime(); - if (m_LastContentCheck.isNull() || (m_LastContentCheck.secsTo(now) > 60)) { - m_CachedContent.clear(); - QDir dir(absolutePath()); - if (dir.entryList(QStringList() << "*.esp" << "*.esm").size() > 0) { - m_CachedContent.push_back(CONTENT_PLUGIN); - } - if (dir.entryList(QStringList() << "*.bsa").size() > 0) { - m_CachedContent.push_back(CONTENT_BSA); - } - - ScriptExtender *extender = qApp->property("managed_game").value<IPluginGame const *>()->feature<ScriptExtender>(); - - if (extender != nullptr) { - QString sePluginPath = extender->name() + "/plugins"; - if (dir.exists(sePluginPath)) m_CachedContent.push_back(CONTENT_SKSE); - } - if (dir.exists("textures")) m_CachedContent.push_back(CONTENT_TEXTURE); - if (dir.exists("meshes")) m_CachedContent.push_back(CONTENT_MESH); - if (dir.exists("interface") - || dir.exists("menus")) m_CachedContent.push_back(CONTENT_INTERFACE); - if (dir.exists("music")) m_CachedContent.push_back(CONTENT_MUSIC); - if (dir.exists("sound")) m_CachedContent.push_back(CONTENT_SOUND); - if (dir.exists("scripts")) m_CachedContent.push_back(CONTENT_SCRIPT); - if (dir.exists("strings")) m_CachedContent.push_back(CONTENT_STRING); - if (dir.exists("SkyProc Patchers")) m_CachedContent.push_back(CONTENT_SKYPROC); - - m_LastContentCheck = QTime::currentTime(); - } - - return m_CachedContent; - -} - - -int ModInfoRegular::getHighlight() const -{ - return isValid() ? HIGHLIGHT_NONE: HIGHLIGHT_INVALID; -} - - -QString ModInfoRegular::getDescription() const -{ - if (!isValid()) { - return tr("%1 contains no esp/esm and no asset (textures, meshes, interface, ...) directory").arg(name()); - } else { - const std::set<int> &categories = getCategories(); - std::wostringstream categoryString; - categoryString << ToWString(tr("Categories: <br>")); - CategoryFactory &categoryFactory = CategoryFactory::instance(); - for (std::set<int>::const_iterator catIter = categories.begin(); - catIter != categories.end(); ++catIter) { - if (catIter != categories.begin()) { - categoryString << " , "; - } - categoryString << "<span style=\"white-space: nowrap;\"><i>" << ToWString(categoryFactory.getCategoryName(categoryFactory.getCategoryIndex(*catIter))) << "</font></span>"; - } - - return ToQString(categoryString.str()); - } -} - -QString ModInfoRegular::notes() const -{ - return m_Notes; -} - -QDateTime ModInfoRegular::creationTime() const -{ - return m_CreationTime; -} - -QString ModInfoRegular::getNexusDescription() const -{ - return m_NexusDescription; -} - -QString ModInfoRegular::repository() const -{ - return m_Repository; -} - -ModInfoRegular::EEndorsedState ModInfoRegular::endorsedState() const -{ - return m_EndorsedState; -} - -QDateTime ModInfoRegular::getLastNexusQuery() const -{ - return m_LastNexusQuery; -} - - -QStringList ModInfoRegular::archives() const -{ - QStringList result; - QDir dir(this->absolutePath()); - for (const QString &archive : dir.entryList(QStringList("*.bsa"))) { - result.append(this->absolutePath() + "/" + archive); - } - return result; -} - -void ModInfoRegular::addInstalledFile(int modId, int fileId) -{ - m_InstalledFileIDs.insert(std::make_pair(modId, fileId)); - m_MetaInfoChanged = true; -} - -std::vector<QString> ModInfoRegular::getIniTweaks() const -{ - QString metaFileName = absolutePath().append("/meta.ini"); - QSettings metaFile(metaFileName, QSettings::IniFormat); - - std::vector<QString> result; - - int numTweaks = metaFile.beginReadArray("INI Tweaks"); - - if (numTweaks != 0) { - qDebug("%d active ini tweaks in %s", - numTweaks, QDir::toNativeSeparators(metaFileName).toUtf8().constData()); - } - - for (int i = 0; i < numTweaks; ++i) { - metaFile.setArrayIndex(i); - QString filename = absolutePath().append("/INI Tweaks/").append(metaFile.value("name").toString()); - result.push_back(filename); - } - metaFile.endArray(); - return result; -} - -std::vector<ModInfo::EFlag> ModInfoBackup::getFlags() const -{ - std::vector<ModInfo::EFlag> result = ModInfoRegular::getFlags(); - result.insert(result.begin(), ModInfo::FLAG_BACKUP); - return result; -} - - -QString ModInfoBackup::getDescription() const -{ - return tr("This is the backup of a mod"); -} - - -ModInfoBackup::ModInfoBackup(const QDir &path, DirectoryEntry **directoryStructure) - : ModInfoRegular(path, directoryStructure) -{ -} - - -ModInfoOverwrite::ModInfoOverwrite() -{ - testValid(); -} - - -bool ModInfoOverwrite::isEmpty() const -{ - QDirIterator iter(absolutePath(), QDir::NoDotAndDotDot | QDir::Files | QDir::Dirs); - if (!iter.hasNext()) return true; - iter.next(); - if ((iter.fileName() == "meta.ini") && !iter.hasNext()) return true; - return false; -} - -QString ModInfoOverwrite::absolutePath() const -{ - return QDir::fromNativeSeparators(qApp->property("dataPath").toString() + "/" + QString::fromStdWString(AppConfig::overwritePath())); -} - -std::vector<ModInfo::EFlag> ModInfoOverwrite::getFlags() const -{ - std::vector<ModInfo::EFlag> result; - result.push_back(FLAG_OVERWRITE); - return result; -} - -int ModInfoOverwrite::getHighlight() const -{ - return (isValid() ? HIGHLIGHT_IMPORTANT : HIGHLIGHT_INVALID) | HIGHLIGHT_CENTER; -} - -QString ModInfoOverwrite::getDescription() const -{ - return tr("This pseudo mod contains files from the virtual data tree that got " - "modified (i.e. by the construction kit)"); -} - -QStringList ModInfoOverwrite::archives() const -{ - QStringList result; - QDir dir(this->absolutePath()); - for (const QString &archive : dir.entryList(QStringList("*.bsa"))) { - result.append(this->absolutePath() + "/" + archive); - } - return result; -} - -QString ModInfoForeign::name() const -{ - return m_Name; -} - -QDateTime ModInfoForeign::creationTime() const -{ - return m_CreationTime; -} - -QString ModInfoForeign::absolutePath() const -{ - //I ought to store this, it's used elsewhere - IPluginGame const *game = qApp->property("managed_game").value<IPluginGame const *>(); - return game->dataDirectory().absolutePath(); -} - -std::vector<ModInfo::EFlag> ModInfoForeign::getFlags() const -{ - std::vector<ModInfo::EFlag> result = ModInfoWithConflictInfo::getFlags(); - result.push_back(FLAG_FOREIGN); - return result; -} - -int ModInfoForeign::getHighlight() const -{ - return 0; -} - -QString ModInfoForeign::getDescription() const -{ - return tr("This pseudo mod represents content managed outside MO. It isn't modified by MO."); -} - -ModInfoForeign::ModInfoForeign(const QString &referenceFile, const QStringList &archives, - DirectoryEntry **directoryStructure) - : ModInfoWithConflictInfo(directoryStructure) - , m_ReferenceFile(referenceFile) - , m_Archives(archives) -{ - m_CreationTime = QFileInfo(referenceFile).created(); - m_Name = "Unmanaged: " + QFileInfo(m_ReferenceFile).baseName(); -} diff --git a/src/modinfo.h b/src/modinfo.h index f6484707..ae22ccd8 100644 --- a/src/modinfo.h +++ b/src/modinfo.h @@ -20,12 +20,11 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #ifndef MODINFO_H
#define MODINFO_H
-#include "nexusinterface.h"
-#include <versioninfo.h>
-#include <imodinterface.h>
+#include "imodinterface.h"
+#include "versioninfo.h"
//#include <directoryentry.h>
-#include <QDateTime>
+class QDateTime;
class QDir;
#include <QMutex>
#include <QSharedPointer>
@@ -563,6 +562,16 @@ public: */
virtual void doConflictCheck() const {}
+ /**
+ * @brief set the URL for a mod
+ */
+ virtual void setURL(QString const &) {}
+
+ /**
+ * @returns the URL for a mod
+ */
+ virtual QString getURL() const { return ""; }
+
signals:
/**
@@ -603,536 +612,4 @@ private: };
-class ModInfoWithConflictInfo : public ModInfo
-{
-
-public:
-
- ModInfoWithConflictInfo(MOShared::DirectoryEntry **directoryStructure);
-
- std::vector<ModInfo::EFlag> getFlags() const;
-
- /**
- * @brief clear all caches held for this mod
- */
- virtual void clearCaches();
-
- virtual std::set<unsigned int> getModOverwrite() { return m_OverwriteList; }
-
- virtual std::set<unsigned int> getModOverwritten() { return m_OverwrittenList; }
-
- virtual void doConflictCheck() const;
-
-private:
-
- enum EConflictType {
- CONFLICT_NONE,
- CONFLICT_OVERWRITE,
- CONFLICT_OVERWRITTEN,
- CONFLICT_MIXED,
- CONFLICT_REDUNDANT
- };
-
-private:
-
- /**
- * @return true if there is a conflict for files in this mod
- */
- EConflictType isConflicted() const;
-
- /**
- * @return true if this mod is completely replaced by others
- */
- bool isRedundant() const;
-
-private:
-
- MOShared::DirectoryEntry **m_DirectoryStructure;
-
- mutable EConflictType m_CurrentConflictState;
- mutable QTime m_LastConflictCheck;
-
- mutable std::set<unsigned int> m_OverwriteList; // indices of mods overritten by this mod
- mutable std::set<unsigned int> m_OverwrittenList; // indices of mods overwriting this mod
-
-};
-
-
-/**
- * @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
- *
- **/
-class ModInfoRegular : public ModInfoWithConflictInfo
-{
-
- Q_OBJECT
-
- friend class ModInfo;
-
-public:
-
- ~ModInfoRegular();
-
- virtual bool isRegular() const { return true; }
-
- virtual bool isEmpty() const;
-
- /**
- * @brief test if there is a newer version of the mod
- *
- * test if there is a newer version of the mod. This does NOT cause
- * information to be retrieved from the nexus, it will only test version information already
- * available locally. Use checkAllForUpdate() to update this version information
- *
- * @return true if there is a newer version
- **/
- bool updateAvailable() const;
-
- /**
- * @return true if the current update is being ignored
- */
- virtual bool updateIgnored() const { return m_IgnoredVersion == m_NewestVersion; }
-
- /**
- * @brief test if there is a newer version of the mod
- *
- * test if there is a newer version of the mod. This does NOT cause
- * information to be retrieved from the nexus, it will only test version information already
- * available locally. Use checkAllForUpdate() to update this version information
- *
- * @return true if there is a newer version
- **/
- bool downgradeAvailable() const;
-
- /**
- * @brief request an update of nexus description for this mod.
- *
- * This requests mod information from the nexus. This is an asynchronous request,
- * so there is no immediate effect of this call.
- *
- * @return returns true if information for this mod will be updated, false if there is no nexus mod id to use
- **/
- bool updateNXMInfo();
-
- /**
- * @brief assign or unassign the specified category
- *
- * Every mod can have an arbitrary number of categories assigned to it
- *
- * @param categoryID id of the category to set
- * @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);
-
- /**
- * @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)
- **/
- bool setName(const QString &name);
-
- /**
- * @brief change the notes (manually set information) for this mod
- * @param notes new notes
- */
- void setNotes(const QString ¬es);
-
- /**
- * @brief set/change the nexus mod id of this mod
- *
- * @param modID the nexus mod id
- **/
- void setNexusID(int modID);
-
- /**
- * @brief set the version of this mod
- *
- * this can be used to overwrite the version of a mod without actually
- * updating the mod
- *
- * @param version the new version to use
- **/
- void setVersion(const MOBase::VersionInfo &version);
-
- /**
- * @brief set the newest version of this mod on the nexus
- *
- * this can be used to overwrite the version of a mod without actually
- * updating the mod
- *
- * @param version the new version to use
- * @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);
-
- /**
- * @brief changes/updates the nexus description text
- * @param description the current description text
- */
- virtual void setNexusDescription(const QString &description);
-
- virtual void setInstallationFile(const QString &fileName);
-
- /**
- * @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);
-
- /**
- * @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; }
-
- /**
- * @brief sets the download repository
- * @param repository
- */
- virtual void setRepository(const QString &repository) { 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);
-
- /**
- * 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();
-
- /**
- * @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();
-
- /**
- * @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);
-
- /**
- * @brief getter for the mod name
- *
- * @return the mod name
- **/
- QString name() const { return m_Name; }
-
- /**
- * @brief getter for the mod path
- *
- * @return the (absolute) path to the mod
- **/
- QString absolutePath() const;
-
- /**
- * @brief getter for the newest version number of this mod
- *
- * @return newest version of the mod
- **/
- MOBase::VersionInfo getNewestVersion() const { return m_NewestVersion; }
-
- /**
- * @brief ignore the newest version for updates
- */
- void ignoreUpdate(bool ignore);
-
- /**
- * @brief getter for the installation file
- *
- * @return file used to install this mod from
- */
- virtual QString getInstallationFile() const { return m_InstallationFile; }
- /**
- * @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; }
-
- /**
- * @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; }
-
- /**
- * @return true if the mod can be updated
- */
- virtual bool canBeUpdated() const { return m_NexusID > 0; }
-
- /**
- * @return true if the mod can be enabled/disabled
- */
- virtual bool canBeEnabled() const { return true; }
-
- /**
- * @return a list of flags for this mod
- */
- virtual std::vector<EFlag> getFlags() const;
-
- virtual std::vector<EContent> getContents() const;
-
- /**
- * @return an indicator if and how this mod should be highlighted by the UI
- */
- virtual int getHighlight() const;
-
- /**
- * @return list of names of ini tweaks
- **/
- std::vector<QString> getIniTweaks() const;
-
- /**
- * @return a description about the mod, to be displayed in the ui
- */
- virtual QString getDescription() const;
-
- /**
- * @return manually set notes for this mod
- */
- virtual QString notes() const;
-
- /**
- * @return time this mod was created (file time of the directory)
- */
- virtual QDateTime creationTime() const;
-
- /**
- * @return nexus description of the mod (html)
- */
- QString getNexusDescription() const;
-
- /**
- * @return repository from which the file was downloaded
- */
- virtual QString repository() const;
-
- /**
- * @return true if the file has been endorsed on nexus
- */
- virtual EEndorsedState endorsedState() const;
-
- /**
- * @return last time nexus was queried for infos on this mod
- */
- virtual QDateTime getLastNexusQuery() const;
-
- virtual QStringList archives() const;
-
- virtual void addInstalledFile(int modId, int fileId);
-
- /**
- * @brief stores meta information back to disk
- */
- virtual void saveMeta();
-
- void readMeta();
-
-private:
-
- void setEndorsedState(EEndorsedState endorsedState);
-
-private slots:
-
- void nxmDescriptionAvailable(int modID, QVariant userData, QVariant resultData);
- void nxmEndorsementToggled(int, QVariant userData, QVariant resultData);
- void nxmRequestFailed(int modID, int fileID, QVariant userData, const QString &errorMessage);
-
-protected:
-
- ModInfoRegular(const QDir &path, MOShared::DirectoryEntry **directoryStructure);
-
-private:
-
- QString m_Name;
- QString m_Path;
- QString m_InstallationFile;
- QString m_Notes;
- QString m_NexusDescription;
- QString m_Repository;
-
- QDateTime m_CreationTime;
- QDateTime m_LastNexusQuery;
-
- int m_NexusID;
- std::set<std::pair<int, int>> m_InstalledFileIDs;
-
- bool m_MetaInfoChanged;
- MOBase::VersionInfo m_NewestVersion;
- MOBase::VersionInfo m_IgnoredVersion;
-
- EEndorsedState m_EndorsedState;
-
- NexusBridge m_NexusBridge;
-
- mutable std::vector<ModInfo::EContent> m_CachedContent;
- mutable QTime m_LastContentCheck;
-
-};
-
-
-class ModInfoBackup : public ModInfoRegular
-{
-
- friend class ModInfo;
-
-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 setNexusID(int) {}
- virtual void endorse(bool) {}
- virtual int getFixedPriority() const { return -1; }
- virtual void ignoreUpdate(bool) {}
- virtual bool canBeUpdated() const { return false; }
- 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 QDateTime getLastNexusQuery() const { return QDateTime(); }
- virtual void getNexusFiles(QList<MOBase::ModRepositoryFileInfo*>::const_iterator&,
- QList<MOBase::ModRepositoryFileInfo*>::const_iterator&) {}
- virtual QString getNexusDescription() const { return QString(); }
-
- virtual void addInstalledFile(int, int) {}
-
-private:
-
- ModInfoBackup(const QDir &path, MOShared::DirectoryEntry **directoryStructure);
-
-};
-
-
-class ModInfoOverwrite : public ModInfo
-{
-
- Q_OBJECT
-
- friend class ModInfo;
-
-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 setNotes(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 bool remove() { return false; }
- virtual void endorse(bool) {}
- virtual bool alwaysEnabled() const { return true; }
- virtual bool isEmpty() const;
- virtual QString name() const { return "Overwrite"; }
- virtual QString notes() const { return ""; }
- virtual QDateTime creationTime() const { return QDateTime(); }
- virtual QString absolutePath() const;
- virtual MOBase::VersionInfo getNewestVersion() const { return ""; }
- virtual QString getInstallationFile() const { return ""; }
- virtual int getFixedPriority() const { return INT_MAX; }
- virtual int getNexusID() const { return -1; }
- 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 QDateTime getLastNexusQuery() const { return QDateTime(); }
- virtual QString getNexusDescription() const { return QString(); }
- virtual QStringList archives() const;
- virtual void addInstalledFile(int, int) {}
-
-private:
-
- ModInfoOverwrite();
-
-};
-
-
-class ModInfoForeign : public ModInfoWithConflictInfo
-{
-
- Q_OBJECT
-
- friend class ModInfo;
-
-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 setNotes(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 bool remove() { return false; }
- virtual void endorse(bool) {}
- virtual bool isEmpty() const { return false; }
- virtual QString name() const;
- virtual QString internalName() const { return name(); }
- virtual QString notes() const { return ""; }
- virtual QDateTime creationTime() const;
- virtual QString absolutePath() const;
- virtual MOBase::VersionInfo getNewestVersion() const { return ""; }
- virtual QString getInstallationFile() const { return ""; }
- virtual int getNexusID() const { return -1; }
- 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 QDateTime getLastNexusQuery() const { return QDateTime(); }
- virtual QString getNexusDescription() const { return QString(); }
- virtual int getFixedPriority() const { return INT_MIN; }
- virtual QStringList archives() const { return m_Archives; }
- virtual QStringList stealFiles() const { return m_Archives + QStringList(m_ReferenceFile); }
- virtual bool alwaysEnabled() const { return true; }
- virtual void addInstalledFile(int, int) {}
-
-protected:
-
- ModInfoForeign(const QString &referenceFile, const QStringList &archives, MOShared::DirectoryEntry **directoryStructure);
-
-private:
-
- QString m_Name;
- QString m_ReferenceFile;
- QStringList m_Archives;
- QDateTime m_CreationTime;
- int m_Priority;
-
-};
-
#endif // MODINFO_H
diff --git a/src/modinfobackup.cpp b/src/modinfobackup.cpp new file mode 100644 index 00000000..a57b84fe --- /dev/null +++ b/src/modinfobackup.cpp @@ -0,0 +1,20 @@ +#include "modinfobackup.h" + +std::vector<ModInfo::EFlag> ModInfoBackup::getFlags() const +{ + std::vector<ModInfo::EFlag> result = ModInfoRegular::getFlags(); + result.insert(result.begin(), ModInfo::FLAG_BACKUP); + return result; +} + + +QString ModInfoBackup::getDescription() const +{ + return tr("This is the backup of a mod"); +} + + +ModInfoBackup::ModInfoBackup(const QDir &path, MOShared::DirectoryEntry **directoryStructure) + : ModInfoRegular(path, directoryStructure) +{ +} diff --git a/src/modinfobackup.h b/src/modinfobackup.h new file mode 100644 index 00000000..adbac783 --- /dev/null +++ b/src/modinfobackup.h @@ -0,0 +1,40 @@ +#ifndef MODINFOBACKUP_H +#define MODINFOBACKUP_H + +#include "modinforegular.h" + +class ModInfoBackup : public ModInfoRegular +{ + + friend class ModInfo; + +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 setNexusID(int) {} + virtual void endorse(bool) {} + virtual int getFixedPriority() const { return -1; } + virtual void ignoreUpdate(bool) {} + virtual bool canBeUpdated() const { return false; } + 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 QDateTime getLastNexusQuery() const { return QDateTime(); } + virtual void getNexusFiles(QList<MOBase::ModRepositoryFileInfo*>::const_iterator&, + QList<MOBase::ModRepositoryFileInfo*>::const_iterator&) {} + virtual QString getNexusDescription() const { return QString(); } + + virtual void addInstalledFile(int, int) {} + +private: + + ModInfoBackup(const QDir &path, MOShared::DirectoryEntry **directoryStructure); + +}; + + +#endif // MODINFOBACKUP_H diff --git a/src/modinfodialog.cpp b/src/modinfodialog.cpp index 687f641e..feaac2d4 100644 --- a/src/modinfodialog.cpp +++ b/src/modinfodialog.cpp @@ -21,6 +21,7 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #include "ui_modinfodialog.h"
#include "iplugingame.h"
+#include "nexusinterface.h"
#include "report.h"
#include "utility.h"
#include "messagedialog.h"
diff --git a/src/modinfoforeign.cpp b/src/modinfoforeign.cpp new file mode 100644 index 00000000..c0e769c9 --- /dev/null +++ b/src/modinfoforeign.cpp @@ -0,0 +1,50 @@ +#include "modinfoforeign.h" + +#include "gameinfo.h" +#include "utility.h" + +using namespace MOBase; +using namespace MOShared; + +QString ModInfoForeign::name() const +{ + return m_Name; +} + +QDateTime ModInfoForeign::creationTime() const +{ + return m_CreationTime; +} + +QString ModInfoForeign::absolutePath() const +{ + return QDir::fromNativeSeparators(ToQString(GameInfo::instance().getGameDirectory())) + "/data"; +} + +std::vector<ModInfo::EFlag> ModInfoForeign::getFlags() const +{ + std::vector<ModInfo::EFlag> result = ModInfoWithConflictInfo::getFlags(); + result.push_back(FLAG_FOREIGN); + + return result; +} + +int ModInfoForeign::getHighlight() const +{ + return 0; +} + +QString ModInfoForeign::getDescription() const +{ + return tr("This pseudo mod represents content managed outside MO. It isn't modified by MO."); +} + +ModInfoForeign::ModInfoForeign(const QString &referenceFile, const QStringList &archives, + DirectoryEntry **directoryStructure) + : ModInfoWithConflictInfo(directoryStructure) + , m_ReferenceFile(referenceFile) + , m_Archives(archives) +{ + m_CreationTime = QFileInfo(referenceFile).created(); + m_Name = "Unmanaged: " + QFileInfo(m_ReferenceFile).baseName(); +} diff --git a/src/modinfoforeign.h b/src/modinfoforeign.h new file mode 100644 index 00000000..b8ff2671 --- /dev/null +++ b/src/modinfoforeign.h @@ -0,0 +1,67 @@ +#ifndef MODINFOFOREIGN_H +#define MODINFOFOREIGN_H + +#include "modinfowithconflictinfo.h" + +class ModInfoForeign : public ModInfoWithConflictInfo +{ + + Q_OBJECT + + friend class ModInfo; + +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 setNotes(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 bool remove() { return false; } + virtual void endorse(bool) {} + virtual bool isEmpty() const { return false; } + virtual QString name() const; + virtual QString internalName() const { return name(); } + virtual QString notes() const { return ""; } + virtual QDateTime creationTime() const; + virtual QString absolutePath() const; + virtual MOBase::VersionInfo getNewestVersion() const { return ""; } + virtual QString getInstallationFile() const { return ""; } + virtual int getNexusID() const { return -1; } + 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 QDateTime getLastNexusQuery() const { return QDateTime(); } + virtual QString getNexusDescription() const { return QString(); } + virtual int getFixedPriority() const { return INT_MIN; } + virtual QStringList archives() const { return m_Archives; } + virtual QStringList stealFiles() const { return m_Archives + QStringList(m_ReferenceFile); } + virtual bool alwaysEnabled() const { return true; } + virtual void addInstalledFile(int, int) {} + +protected: + + ModInfoForeign(const QString &referenceFile, const QStringList &archives, MOShared::DirectoryEntry **directoryStructure); + +private: + + QString m_Name; + QString m_ReferenceFile; + QStringList m_Archives; + QDateTime m_CreationTime; + int m_Priority; + +}; + +#endif // MODINFOFOREIGN_H diff --git a/src/modinfooverwrite.cpp b/src/modinfooverwrite.cpp new file mode 100644 index 00000000..4380a255 --- /dev/null +++ b/src/modinfooverwrite.cpp @@ -0,0 +1,53 @@ +#include "modinfooverwrite.h" + +#include "appconfig.h" + +#include <QApplication> +#include <QDirIterator> + +ModInfoOverwrite::ModInfoOverwrite() +{ + testValid(); +} + +bool ModInfoOverwrite::isEmpty() const +{ + QDirIterator iter(absolutePath(), QDir::NoDotAndDotDot | QDir::Files | QDir::Dirs); + if (!iter.hasNext()) return true; + iter.next(); + if ((iter.fileName() == "meta.ini") && !iter.hasNext()) return true; + return false; +} + +QString ModInfoOverwrite::absolutePath() const +{ + return QDir::fromNativeSeparators(qApp->property("dataPath").toString() + "/" + QString::fromStdWString(AppConfig::overwritePath())); +} + +std::vector<ModInfo::EFlag> ModInfoOverwrite::getFlags() const +{ + std::vector<ModInfo::EFlag> result; + result.push_back(FLAG_OVERWRITE); + return result; +} + +int ModInfoOverwrite::getHighlight() const +{ + return (isValid() ? HIGHLIGHT_IMPORTANT : HIGHLIGHT_INVALID) | HIGHLIGHT_CENTER; +} + +QString ModInfoOverwrite::getDescription() const +{ + return tr("This pseudo mod contains files from the virtual data tree that got " + "modified (i.e. by the construction kit)"); +} + +QStringList ModInfoOverwrite::archives() const +{ + QStringList result; + QDir dir(this->absolutePath()); + for (const QString &archive : dir.entryList(QStringList("*.bsa"))) { + result.append(this->absolutePath() + "/" + archive); + } + return result; +} diff --git a/src/modinfooverwrite.h b/src/modinfooverwrite.h new file mode 100644 index 00000000..9184a90c --- /dev/null +++ b/src/modinfooverwrite.h @@ -0,0 +1,59 @@ +#ifndef MODINFOOVERWRITE_H +#define MODINFOOVERWRITE_H + +#include "modinfo.h" + +#include <QDateTime> + +class ModInfoOverwrite : public ModInfo +{ + + Q_OBJECT + + friend class ModInfo; + +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 setNotes(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 bool remove() { return false; } + virtual void endorse(bool) {} + virtual bool alwaysEnabled() const { return true; } + virtual bool isEmpty() const; + virtual QString name() const { return "Overwrite"; } + virtual QString notes() const { return ""; } + virtual QDateTime creationTime() const { return QDateTime(); } + virtual QString absolutePath() const; + virtual MOBase::VersionInfo getNewestVersion() const { return ""; } + virtual QString getInstallationFile() const { return ""; } + virtual int getFixedPriority() const { return INT_MAX; } + virtual int getNexusID() const { return -1; } + 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 QDateTime getLastNexusQuery() const { return QDateTime(); } + virtual QString getNexusDescription() const { return QString(); } + virtual QStringList archives() const; + virtual void addInstalledFile(int, int) {} + +private: + + ModInfoOverwrite(); + +}; + +#endif // MODINFOOVERWRITE_H diff --git a/src/modinforegular.cpp b/src/modinforegular.cpp new file mode 100644 index 00000000..b1f73a37 --- /dev/null +++ b/src/modinforegular.cpp @@ -0,0 +1,571 @@ +#include "modinforegular.h" + +#include "categories.h" +#include "iplugingame.h" +#include "messagedialog.h" +#include "report.h" +#include "scriptextender.h" + +#include <QApplication> +#include <QDirIterator> +#include <QSettings> + +#include <sstream> + +using namespace MOBase; +using namespace MOShared; + +namespace { + //Arguably this should be a class static or we should be using FileString rather + //than QString for the names. Or both. + static bool ByName(const ModInfo::Ptr &LHS, const ModInfo::Ptr &RHS) + { + return QString::compare(LHS->name(), RHS->name(), Qt::CaseInsensitive) < 0; + } +} + +ModInfoRegular::ModInfoRegular(const QDir &path, DirectoryEntry **directoryStructure) + : ModInfoWithConflictInfo(directoryStructure) + , m_Name(path.dirName()) + , m_Path(path.absolutePath()) + , m_Repository() + , m_MetaInfoChanged(false) + , m_EndorsedState(ENDORSED_UNKNOWN) + , m_NexusBridge() +{ + testValid(); + m_CreationTime = QFileInfo(path.absolutePath()).created(); + // read out the meta-file for information + readMeta(); + + connect(&m_NexusBridge, SIGNAL(descriptionAvailable(int,QVariant,QVariant)) + , this, SLOT(nxmDescriptionAvailable(int,QVariant,QVariant))); + connect(&m_NexusBridge, SIGNAL(endorsementToggled(int,QVariant,QVariant)) + , this, SLOT(nxmEndorsementToggled(int,QVariant,QVariant))); + connect(&m_NexusBridge, SIGNAL(requestFailed(int,int,QVariant,QString)) + , this, SLOT(nxmRequestFailed(int,int,QVariant,QString))); +} + + +ModInfoRegular::~ModInfoRegular() +{ + try { + saveMeta(); + } catch (const std::exception &e) { + qCritical("failed to save meta information for \"%s\": %s", + m_Name.toUtf8().constData(), e.what()); + } +} + +bool ModInfoRegular::isEmpty() const +{ + QDirIterator iter(m_Path, QDir::NoDotAndDotDot | QDir::Files | QDir::Dirs); + if (!iter.hasNext()) return true; + iter.next(); + if ((iter.fileName() == "meta.ini") && !iter.hasNext()) return true; + return false; +} + + +void ModInfoRegular::readMeta() +{ + QSettings metaFile(m_Path + "/meta.ini", QSettings::IniFormat); + m_Notes = metaFile.value("notes", "").toString(); + m_NexusID = metaFile.value("modid", -1).toInt(); + m_Version.parse(metaFile.value("version", "").toString()); + m_NewestVersion = metaFile.value("newestVersion", "").toString(); + m_IgnoredVersion = metaFile.value("ignoredVersion", "").toString(); + m_InstallationFile = metaFile.value("installationFile", "").toString(); + m_NexusDescription = metaFile.value("nexusDescription", "").toString(); + m_Repository = metaFile.value("repository", "Nexus").toString(); + m_URL = metaFile.value("url", "").toString(); + m_LastNexusQuery = QDateTime::fromString(metaFile.value("lastNexusQuery", "").toString(), Qt::ISODate); + if (metaFile.contains("endorsed")) { + if (metaFile.value("endorsed").canConvert<int>()) { + switch (metaFile.value("endorsed").toInt()) { + case ENDORSED_FALSE: m_EndorsedState = ENDORSED_FALSE; break; + case ENDORSED_TRUE: m_EndorsedState = ENDORSED_TRUE; break; + case ENDORSED_NEVER: m_EndorsedState = ENDORSED_NEVER; break; + default: m_EndorsedState = ENDORSED_UNKNOWN; break; + } + } else { + m_EndorsedState = metaFile.value("endorsed", false).toBool() ? ENDORSED_TRUE : ENDORSED_FALSE; + } + } + + QString categoriesString = metaFile.value("category", "").toString(); + + QStringList categories = categoriesString.split(',', QString::SkipEmptyParts); + for (QStringList::iterator iter = categories.begin(); iter != categories.end(); ++iter) { + bool ok = false; + int categoryID = iter->toInt(&ok); + if (categoryID < 0) { + // ignore invalid id + continue; + } + if (ok && (categoryID != 0) && (CategoryFactory::instance().categoryExists(categoryID))) { + m_Categories.insert(categoryID); + if (iter == categories.begin()) { + m_PrimaryCategory = categoryID; + } + } + } + + int numFiles = metaFile.beginReadArray("installedFiles"); + for (int i = 0; i < numFiles; ++i) { + metaFile.setArrayIndex(i); + m_InstalledFileIDs.insert(std::make_pair(metaFile.value("modid").toInt(), metaFile.value("fileid").toInt())); + } + metaFile.endArray(); + + m_MetaInfoChanged = false; +} + +void ModInfoRegular::saveMeta() +{ + // only write meta data if the mod directory exists + if (m_MetaInfoChanged && QFile::exists(absolutePath())) { + QSettings metaFile(absolutePath().append("/meta.ini"), QSettings::IniFormat); + if (metaFile.status() == QSettings::NoError) { + std::set<int> temp = m_Categories; + temp.erase(m_PrimaryCategory); + metaFile.setValue("category", QString("%1").arg(m_PrimaryCategory) + "," + SetJoin(temp, ",")); + metaFile.setValue("newestVersion", m_NewestVersion.canonicalString()); + metaFile.setValue("ignoredVersion", m_IgnoredVersion.canonicalString()); + metaFile.setValue("version", m_Version.canonicalString()); + metaFile.setValue("installationFile", m_InstallationFile); + metaFile.setValue("repository", m_Repository); + metaFile.setValue("modid", m_NexusID); + metaFile.setValue("notes", m_Notes); + metaFile.setValue("nexusDescription", m_NexusDescription); + metaFile.setValue("url", m_URL); + metaFile.setValue("lastNexusQuery", m_LastNexusQuery.toString(Qt::ISODate)); + if (m_EndorsedState != ENDORSED_UNKNOWN) { + metaFile.setValue("endorsed", m_EndorsedState); + } + + metaFile.beginWriteArray("installedFiles"); + int idx = 0; + for (auto iter = m_InstalledFileIDs.begin(); iter != m_InstalledFileIDs.end(); ++iter) { + metaFile.setArrayIndex(idx++); + metaFile.setValue("modid", iter->first); + metaFile.setValue("fileid", iter->second); + } + metaFile.endArray(); + + metaFile.sync(); // sync needs to be called to ensure the file is created + + if (metaFile.status() == QSettings::NoError) { + m_MetaInfoChanged = false; + } else { + reportError(tr("failed to write %1/meta.ini: error %2").arg(absolutePath()).arg(metaFile.status())); + } + } else { + reportError(tr("failed to write %1/meta.ini: error %2").arg(absolutePath()).arg(metaFile.status())); + } + } +} + + +bool ModInfoRegular::updateAvailable() const +{ + if (m_IgnoredVersion.isValid() && (m_IgnoredVersion == m_NewestVersion)) { + return false; + } + return m_NewestVersion.isValid() && (m_Version < m_NewestVersion); +} + + +bool ModInfoRegular::downgradeAvailable() const +{ + if (m_IgnoredVersion.isValid() && (m_IgnoredVersion == m_NewestVersion)) { + return false; + } + return m_NewestVersion.isValid() && (m_NewestVersion < m_Version); +} + + +void ModInfoRegular::nxmDescriptionAvailable(int, QVariant, QVariant resultData) +{ + QVariantMap result = resultData.toMap(); + setNewestVersion(VersionInfo(result["version"].toString())); + setNexusDescription(result["description"].toString()); + + if ((m_EndorsedState != ENDORSED_NEVER) && (result.contains("voted_by_user"))) { + setEndorsedState(result["voted_by_user"].toBool() ? ENDORSED_TRUE : ENDORSED_FALSE); + } + m_LastNexusQuery = QDateTime::currentDateTime(); + //m_MetaInfoChanged = true; + saveMeta(); + emit modDetailsUpdated(true); +} + + +void ModInfoRegular::nxmEndorsementToggled(int, QVariant, QVariant resultData) +{ + m_EndorsedState = resultData.toBool() ? ENDORSED_TRUE : ENDORSED_FALSE; + m_MetaInfoChanged = true; + saveMeta(); + emit modDetailsUpdated(true); +} + + +void ModInfoRegular::nxmRequestFailed(int, int, QVariant userData, const QString &errorMessage) +{ + QString fullMessage = errorMessage; + if (userData.canConvert<int>() && (userData.toInt() == 1)) { + fullMessage += "\nNexus will reject endorsements within 15 Minutes of a failed attempt, the error message may be misleading."; + } + if (QApplication::activeWindow() != nullptr) { + MessageDialog::showMessage(fullMessage, QApplication::activeWindow()); + } + emit modDetailsUpdated(false); +} + + +bool ModInfoRegular::updateNXMInfo() +{ + if (m_NexusID > 0) { + m_NexusBridge.requestDescription(m_NexusID, QVariant()); + return true; + } + return false; +} + + +void ModInfoRegular::setCategory(int categoryID, bool active) +{ + m_MetaInfoChanged = true; + + if (active) { + m_Categories.insert(categoryID); + if (m_PrimaryCategory == -1) { + m_PrimaryCategory = categoryID; + } + } else { + std::set<int>::iterator iter = m_Categories.find(categoryID); + if (iter != m_Categories.end()) { + m_Categories.erase(iter); + } + if (categoryID == m_PrimaryCategory) { + if (m_Categories.size() == 0) { + m_PrimaryCategory = -1; + } else { + m_PrimaryCategory = *(m_Categories.begin()); + } + } + } +} + + +bool ModInfoRegular::setName(const QString &name) +{ + if (name.contains('/') || name.contains('\\')) { + return false; + } + + QString newPath = m_Path.mid(0).replace(m_Path.length() - m_Name.length(), m_Name.length(), name); + QDir modDir(m_Path.mid(0, m_Path.length() - m_Name.length())); + + if (m_Name.compare(name, Qt::CaseInsensitive) == 0) { + QString tempName = name; + tempName.append("_temp"); + while (modDir.exists(tempName)) { + tempName.append("_"); + } + if (!modDir.rename(m_Name, tempName)) { + return false; + } + if (!modDir.rename(tempName, name)) { + qCritical("rename to final name failed after successful rename to intermediate name"); + modDir.rename(tempName, m_Name); + return false; + } + } else { + if (!shellRename(modDir.absoluteFilePath(m_Name), modDir.absoluteFilePath(name))) { + qCritical("failed to rename mod %s (errorcode %d)", + qPrintable(name), ::GetLastError()); + return false; + } + } + + std::map<QString, unsigned int>::iterator nameIter = s_ModsByName.find(m_Name); + if (nameIter != s_ModsByName.end()) { + unsigned int index = nameIter->second; + s_ModsByName.erase(nameIter); + + m_Name = name; + m_Path = newPath; + + s_ModsByName[m_Name] = index; + + std::sort(s_Collection.begin(), s_Collection.end(), ByName); + updateIndices(); + } else { // otherwise mod isn't registered yet? + m_Name = name; + m_Path = newPath; + } + + return true; +} + +void ModInfoRegular::setNotes(const QString ¬es) +{ + m_Notes = notes; + m_MetaInfoChanged = true; +} + +void ModInfoRegular::setNexusID(int modID) +{ + m_NexusID = modID; + m_MetaInfoChanged = true; +} + +void ModInfoRegular::setVersion(const VersionInfo &version) +{ + m_Version = version; + m_MetaInfoChanged = true; +} + +void ModInfoRegular::setNewestVersion(const VersionInfo &version) +{ + if (version != m_NewestVersion) { + m_NewestVersion = version; + m_MetaInfoChanged = true; + } +} + +void ModInfoRegular::setNexusDescription(const QString &description) +{ + if (qHash(description) != qHash(m_NexusDescription)) { + m_NexusDescription = description; + m_MetaInfoChanged = true; + } +} + +void ModInfoRegular::setEndorsedState(EEndorsedState endorsedState) +{ + if (endorsedState != m_EndorsedState) { + m_EndorsedState = endorsedState; + m_MetaInfoChanged = true; + } +} + +void ModInfoRegular::setInstallationFile(const QString &fileName) +{ + m_InstallationFile = fileName; + m_MetaInfoChanged = true; +} + +void ModInfoRegular::addNexusCategory(int categoryID) +{ + m_Categories.insert(CategoryFactory::instance().resolveNexusID(categoryID)); +} + +void ModInfoRegular::setIsEndorsed(bool endorsed) +{ + if (m_EndorsedState != ENDORSED_NEVER) { + m_EndorsedState = endorsed ? ENDORSED_TRUE : ENDORSED_FALSE; + m_MetaInfoChanged = true; + } +} + + +void ModInfoRegular::setNeverEndorse() +{ + m_EndorsedState = ENDORSED_NEVER; + m_MetaInfoChanged = true; +} + + +bool ModInfoRegular::remove() +{ + m_MetaInfoChanged = false; + return shellDelete(QStringList(absolutePath()), true); +} + +void ModInfoRegular::endorse(bool doEndorse) +{ + if (doEndorse != (m_EndorsedState == ENDORSED_TRUE)) { + m_NexusBridge.requestToggleEndorsement(getNexusID(), doEndorse, QVariant(1)); + } +} + + +QString ModInfoRegular::absolutePath() const +{ + return m_Path; +} + +void ModInfoRegular::ignoreUpdate(bool ignore) +{ + if (ignore) { + m_IgnoredVersion = m_NewestVersion; + } else { + m_IgnoredVersion.clear(); + } + m_MetaInfoChanged = true; +} + + +std::vector<ModInfo::EFlag> ModInfoRegular::getFlags() const +{ + std::vector<ModInfo::EFlag> result = ModInfoWithConflictInfo::getFlags(); + if ((m_NexusID > 0) && (endorsedState() == ENDORSED_FALSE)) { + result.push_back(ModInfo::FLAG_NOTENDORSED); + } + if (!isValid()) { + result.push_back(ModInfo::FLAG_INVALID); + } + if (m_Notes.length() != 0) { + result.push_back(ModInfo::FLAG_NOTES); + } + return result; +} + + +std::vector<ModInfo::EContent> ModInfoRegular::getContents() const +{ + QTime now = QTime::currentTime(); + if (m_LastContentCheck.isNull() || (m_LastContentCheck.secsTo(now) > 60)) { + m_CachedContent.clear(); + QDir dir(absolutePath()); + if (dir.entryList(QStringList() << "*.esp" << "*.esm").size() > 0) { + m_CachedContent.push_back(CONTENT_PLUGIN); + } + if (dir.entryList(QStringList() << "*.bsa").size() > 0) { + m_CachedContent.push_back(CONTENT_BSA); + } + + ScriptExtender *extender = qApp->property("managed_game").value<IPluginGame*>()->feature<ScriptExtender>(); + + if (extender != nullptr) { + QString sePluginPath = extender->name() + "/plugins"; + if (dir.exists(sePluginPath)) m_CachedContent.push_back(CONTENT_SKSE); + } + if (dir.exists("textures")) m_CachedContent.push_back(CONTENT_TEXTURE); + if (dir.exists("meshes")) m_CachedContent.push_back(CONTENT_MESH); + if (dir.exists("interface") + || dir.exists("menus")) m_CachedContent.push_back(CONTENT_INTERFACE); + if (dir.exists("music")) m_CachedContent.push_back(CONTENT_MUSIC); + if (dir.exists("sound")) m_CachedContent.push_back(CONTENT_SOUND); + if (dir.exists("scripts")) m_CachedContent.push_back(CONTENT_SCRIPT); + if (dir.exists("strings")) m_CachedContent.push_back(CONTENT_STRING); + if (dir.exists("SkyProc Patchers")) m_CachedContent.push_back(CONTENT_SKYPROC); + + m_LastContentCheck = QTime::currentTime(); + } + + return m_CachedContent; + +} + + +int ModInfoRegular::getHighlight() const +{ + return isValid() ? HIGHLIGHT_NONE: HIGHLIGHT_INVALID; +} + + +QString ModInfoRegular::getDescription() const +{ + if (!isValid()) { + return tr("%1 contains no esp/esm and no asset (textures, meshes, interface, ...) directory").arg(name()); + } else { + const std::set<int> &categories = getCategories(); + std::wostringstream categoryString; + categoryString << ToWString(tr("Categories: <br>")); + CategoryFactory &categoryFactory = CategoryFactory::instance(); + for (std::set<int>::const_iterator catIter = categories.begin(); + catIter != categories.end(); ++catIter) { + if (catIter != categories.begin()) { + categoryString << " , "; + } + categoryString << "<span style=\"white-space: nowrap;\"><i>" << ToWString(categoryFactory.getCategoryName(categoryFactory.getCategoryIndex(*catIter))) << "</font></span>"; + } + + return ToQString(categoryString.str()); + } +} + +QString ModInfoRegular::notes() const +{ + return m_Notes; +} + +QDateTime ModInfoRegular::creationTime() const +{ + return m_CreationTime; +} + +QString ModInfoRegular::getNexusDescription() const +{ + return m_NexusDescription; +} + +QString ModInfoRegular::repository() const +{ + return m_Repository; +} + +ModInfoRegular::EEndorsedState ModInfoRegular::endorsedState() const +{ + return m_EndorsedState; +} + +QDateTime ModInfoRegular::getLastNexusQuery() const +{ + return m_LastNexusQuery; +} + +void ModInfoRegular::setURL(QString const &url) +{ + m_URL = url; + m_MetaInfoChanged = true; +} + +QString ModInfoRegular::getURL() const +{ + return m_URL; +} + + + +QStringList ModInfoRegular::archives() const +{ + QStringList result; + QDir dir(this->absolutePath()); + for (const QString &archive : dir.entryList(QStringList("*.bsa"))) { + result.append(this->absolutePath() + "/" + archive); + } + return result; +} + +void ModInfoRegular::addInstalledFile(int modId, int fileId) +{ + m_InstalledFileIDs.insert(std::make_pair(modId, fileId)); + m_MetaInfoChanged = true; +} + +std::vector<QString> ModInfoRegular::getIniTweaks() const +{ + QString metaFileName = absolutePath().append("/meta.ini"); + QSettings metaFile(metaFileName, QSettings::IniFormat); + + std::vector<QString> result; + + int numTweaks = metaFile.beginReadArray("INI Tweaks"); + + if (numTweaks != 0) { + qDebug("%d active ini tweaks in %s", + numTweaks, QDir::toNativeSeparators(metaFileName).toUtf8().constData()); + } + + for (int i = 0; i < numTweaks; ++i) { + metaFile.setArrayIndex(i); + QString filename = absolutePath().append("/INI Tweaks/").append(metaFile.value("name").toString()); + result.push_back(filename); + } + metaFile.endArray(); + return result; +} diff --git a/src/modinforegular.h b/src/modinforegular.h new file mode 100644 index 00000000..a94d0363 --- /dev/null +++ b/src/modinforegular.h @@ -0,0 +1,349 @@ +#ifndef MODINFOREGULAR_H +#define MODINFOREGULAR_H + +#include "modinfowithconflictinfo.h" + +#include "nexusinterface.h" + +/** + * @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 + * + **/ +class ModInfoRegular : public ModInfoWithConflictInfo +{ + + Q_OBJECT + + friend class ModInfo; + +public: + + ~ModInfoRegular(); + + virtual bool isRegular() const { return true; } + + virtual bool isEmpty() const; + + /** + * @brief test if there is a newer version of the mod + * + * test if there is a newer version of the mod. This does NOT cause + * information to be retrieved from the nexus, it will only test version information already + * available locally. Use checkAllForUpdate() to update this version information + * + * @return true if there is a newer version + **/ + bool updateAvailable() const; + + /** + * @return true if the current update is being ignored + */ + virtual bool updateIgnored() const { return m_IgnoredVersion == m_NewestVersion; } + + /** + * @brief test if there is a newer version of the mod + * + * test if there is a newer version of the mod. This does NOT cause + * information to be retrieved from the nexus, it will only test version information already + * available locally. Use checkAllForUpdate() to update this version information + * + * @return true if there is a newer version + **/ + bool downgradeAvailable() const; + + /** + * @brief request an update of nexus description for this mod. + * + * This requests mod information from the nexus. This is an asynchronous request, + * so there is no immediate effect of this call. + * + * @return returns true if information for this mod will be updated, false if there is no nexus mod id to use + **/ + bool updateNXMInfo(); + + /** + * @brief assign or unassign the specified category + * + * Every mod can have an arbitrary number of categories assigned to it + * + * @param categoryID id of the category to set + * @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); + + /** + * @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) + **/ + bool setName(const QString &name); + + /** + * @brief change the notes (manually set information) for this mod + * @param notes new notes + */ + void setNotes(const QString ¬es); + + /** + * @brief set/change the nexus mod id of this mod + * + * @param modID the nexus mod id + **/ + void setNexusID(int modID); + + /** + * @brief set the version of this mod + * + * this can be used to overwrite the version of a mod without actually + * updating the mod + * + * @param version the new version to use + **/ + void setVersion(const MOBase::VersionInfo &version); + + /** + * @brief set the newest version of this mod on the nexus + * + * this can be used to overwrite the version of a mod without actually + * updating the mod + * + * @param version the new version to use + * @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); + + /** + * @brief changes/updates the nexus description text + * @param description the current description text + */ + virtual void setNexusDescription(const QString &description); + + virtual void setInstallationFile(const QString &fileName); + + /** + * @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); + + /** + * @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; } + + /** + * @brief sets the download repository + * @param repository + */ + virtual void setRepository(const QString &repository) { 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); + + /** + * 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(); + + /** + * @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(); + + /** + * @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); + + /** + * @brief getter for the mod name + * + * @return the mod name + **/ + QString name() const { return m_Name; } + + /** + * @brief getter for the mod path + * + * @return the (absolute) path to the mod + **/ + QString absolutePath() const; + + /** + * @brief getter for the newest version number of this mod + * + * @return newest version of the mod + **/ + MOBase::VersionInfo getNewestVersion() const { return m_NewestVersion; } + + /** + * @brief ignore the newest version for updates + */ + void ignoreUpdate(bool ignore); + + /** + * @brief getter for the installation file + * + * @return file used to install this mod from + */ + virtual QString getInstallationFile() const { return m_InstallationFile; } + /** + * @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; } + + /** + * @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; } + + /** + * @return true if the mod can be updated + */ + virtual bool canBeUpdated() const { return m_NexusID > 0; } + + /** + * @return true if the mod can be enabled/disabled + */ + virtual bool canBeEnabled() const { return true; } + + /** + * @return a list of flags for this mod + */ + virtual std::vector<EFlag> getFlags() const; + + virtual std::vector<EContent> getContents() const; + + /** + * @return an indicator if and how this mod should be highlighted by the UI + */ + virtual int getHighlight() const; + + /** + * @return list of names of ini tweaks + **/ + std::vector<QString> getIniTweaks() const; + + /** + * @return a description about the mod, to be displayed in the ui + */ + virtual QString getDescription() const; + + /** + * @return manually set notes for this mod + */ + virtual QString notes() const; + + /** + * @return time this mod was created (file time of the directory) + */ + virtual QDateTime creationTime() const; + + /** + * @return nexus description of the mod (html) + */ + QString getNexusDescription() const; + + /** + * @return repository from which the file was downloaded + */ + virtual QString repository() const; + + /** + * @return true if the file has been endorsed on nexus + */ + virtual EEndorsedState endorsedState() const; + + /** + * @return last time nexus was queried for infos on this mod + */ + virtual QDateTime getLastNexusQuery() const; + + virtual QStringList archives() const; + + virtual void addInstalledFile(int modId, int fileId); + + /** + * @brief stores meta information back to disk + */ + virtual void saveMeta(); + + void readMeta(); + + /** + * @brief set the URL for a mod + */ + virtual void setURL(QString const &); + + /** + * @returns the URL for a mod + */ + virtual QString getURL() const; + +private: + + void setEndorsedState(EEndorsedState endorsedState); + +private slots: + + void nxmDescriptionAvailable(int modID, QVariant userData, QVariant resultData); + void nxmEndorsementToggled(int, QVariant userData, QVariant resultData); + void nxmRequestFailed(int modID, int fileID, QVariant userData, const QString &errorMessage); + +protected: + + ModInfoRegular(const QDir &path, MOShared::DirectoryEntry **directoryStructure); + +private: + + QString m_Name; + QString m_Path; + QString m_InstallationFile; + QString m_Notes; + QString m_NexusDescription; + QString m_Repository; + QString m_URL; + + QDateTime m_CreationTime; + QDateTime m_LastNexusQuery; + + int m_NexusID; + std::set<std::pair<int, int>> m_InstalledFileIDs; + + bool m_MetaInfoChanged; + MOBase::VersionInfo m_NewestVersion; + MOBase::VersionInfo m_IgnoredVersion; + + EEndorsedState m_EndorsedState; + + NexusBridge m_NexusBridge; + + mutable std::vector<ModInfo::EContent> m_CachedContent; + mutable QTime m_LastContentCheck; + +}; + + +#endif // MODINFOREGULAR_H diff --git a/src/modinfowithconflictinfo.cpp b/src/modinfowithconflictinfo.cpp new file mode 100644 index 00000000..fbf2345f --- /dev/null +++ b/src/modinfowithconflictinfo.cpp @@ -0,0 +1,130 @@ +#include "modinfowithconflictinfo.h" + +#include "directoryentry.h" +#include "utility.h" + +using namespace MOBase; +using namespace MOShared; + +ModInfoWithConflictInfo::ModInfoWithConflictInfo(DirectoryEntry **directoryStructure) + : m_DirectoryStructure(directoryStructure) {} + +void ModInfoWithConflictInfo::clearCaches() +{ + m_LastConflictCheck = QTime(); +} + +std::vector<ModInfo::EFlag> ModInfoWithConflictInfo::getFlags() const +{ + std::vector<ModInfo::EFlag> result; + switch (isConflicted()) { + case CONFLICT_MIXED: { + result.push_back(ModInfo::FLAG_CONFLICT_MIXED); + } break; + case CONFLICT_OVERWRITE: { + result.push_back(ModInfo::FLAG_CONFLICT_OVERWRITE); + } break; + case CONFLICT_OVERWRITTEN: { + result.push_back(ModInfo::FLAG_CONFLICT_OVERWRITTEN); + } break; + case CONFLICT_REDUNDANT: { + result.push_back(ModInfo::FLAG_CONFLICT_REDUNDANT); + } break; + default: { /* NOP */ } + } + return result; +} + + +void ModInfoWithConflictInfo::doConflictCheck() const +{ + m_OverwriteList.clear(); + m_OverwrittenList.clear(); + + bool providesAnything = false; + + int dataID = 0; + if ((*m_DirectoryStructure)->originExists(L"data")) { + dataID = (*m_DirectoryStructure)->getOriginByName(L"data").getID(); + } + + std::wstring name = ToWString(this->name()); + + m_CurrentConflictState = CONFLICT_NONE; + + if ((*m_DirectoryStructure)->originExists(name)) { + FilesOrigin &origin = (*m_DirectoryStructure)->getOriginByName(name); + std::vector<FileEntry::Ptr> files = origin.getFiles(); + // for all files in this origin + for (FileEntry::Ptr file : files) { + const std::vector<int> &alternatives = file->getAlternatives(); + if ((alternatives.size() == 0) || (alternatives[0] == dataID)) { + // no alternatives -> no conflict + providesAnything = true; + } else { + if (file->getOrigin() != origin.getID()) { + FilesOrigin &altOrigin = (*m_DirectoryStructure)->getOriginByID(file->getOrigin()); + unsigned int altIndex = ModInfo::getIndex(ToQString(altOrigin.getName())); + m_OverwrittenList.insert(altIndex); + } else { + providesAnything = true; + } + + // for all non-providing alternative origins + for (int altId : alternatives) { + if ((altId != dataID) && (altId != origin.getID())) { + FilesOrigin &altOrigin = (*m_DirectoryStructure)->getOriginByID(altId); + unsigned int altIndex = ModInfo::getIndex(ToQString(altOrigin.getName())); + if (origin.getPriority() > altOrigin.getPriority()) { + m_OverwriteList.insert(altIndex); + } else { + m_OverwrittenList.insert(altIndex); + } + } + } + } + } + m_LastConflictCheck = QTime::currentTime(); + + if (files.size() != 0) { + if (!providesAnything) + m_CurrentConflictState = CONFLICT_REDUNDANT; + else if (!m_OverwriteList.empty() && !m_OverwrittenList.empty()) + m_CurrentConflictState = CONFLICT_MIXED; + else if (!m_OverwriteList.empty()) + m_CurrentConflictState = CONFLICT_OVERWRITE; + else if (!m_OverwrittenList.empty()) + m_CurrentConflictState = CONFLICT_OVERWRITTEN; + } + } +} + +ModInfoWithConflictInfo::EConflictType ModInfoWithConflictInfo::isConflicted() const +{ + // this is costy so cache the result + QTime now = QTime::currentTime(); + if (m_LastConflictCheck.isNull() || (m_LastConflictCheck.secsTo(now) > 10)) { + doConflictCheck(); + } + + return m_CurrentConflictState; +} + + +bool ModInfoWithConflictInfo::isRedundant() const +{ + std::wstring name = ToWString(this->name()); + if ((*m_DirectoryStructure)->originExists(name)) { + FilesOrigin &origin = (*m_DirectoryStructure)->getOriginByName(name); + std::vector<FileEntry::Ptr> files = origin.getFiles(); + bool ignore = false; + for (auto iter = files.begin(); iter != files.end(); ++iter) { + if ((*iter)->getOrigin(ignore) == origin.getID()) { + return false; + } + } + return true; + } else { + return false; + } +} diff --git a/src/modinfowithconflictinfo.h b/src/modinfowithconflictinfo.h new file mode 100644 index 00000000..be31f20f --- /dev/null +++ b/src/modinfowithconflictinfo.h @@ -0,0 +1,64 @@ +#ifndef MODINFOWITHCONFLICTINFO_H +#define MODINFOWITHCONFLICTINFO_H + +#include "modinfo.h" + +#include <QTime> + +class ModInfoWithConflictInfo : public ModInfo +{ + +public: + + ModInfoWithConflictInfo(MOShared::DirectoryEntry **directoryStructure); + + std::vector<ModInfo::EFlag> getFlags() const; + + /** + * @brief clear all caches held for this mod + */ + virtual void clearCaches(); + + virtual std::set<unsigned int> getModOverwrite() { return m_OverwriteList; } + + virtual std::set<unsigned int> getModOverwritten() { return m_OverwrittenList; } + + virtual void doConflictCheck() const; + +private: + + enum EConflictType { + CONFLICT_NONE, + CONFLICT_OVERWRITE, + CONFLICT_OVERWRITTEN, + CONFLICT_MIXED, + CONFLICT_REDUNDANT + }; + +private: + + /** + * @return true if there is a conflict for files in this mod + */ + EConflictType isConflicted() const; + + /** + * @return true if this mod is completely replaced by others + */ + bool isRedundant() const; + +private: + + MOShared::DirectoryEntry **m_DirectoryStructure; + + mutable EConflictType m_CurrentConflictState; + mutable QTime m_LastConflictCheck; + + mutable std::set<unsigned int> m_OverwriteList; // indices of mods overritten by this mod + mutable std::set<unsigned int> m_OverwrittenList; // indices of mods overwriting this mod + +}; + + + +#endif // MODINFOWITHCONFLICTINFO_H diff --git a/src/nexusinterface.cpp b/src/nexusinterface.cpp index aadfdc1e..9bed19b3 100644 --- a/src/nexusinterface.cpp +++ b/src/nexusinterface.cpp @@ -192,12 +192,13 @@ void NexusInterface::loginCompleted() void NexusInterface::interpretNexusFileName(const QString &fileName, QString &modName, int &modID, bool query)
{
- static std::tr1::regex exp("^([a-zA-Z0-9_\\- ]*?)([-_ ][VvRr]?[0-9_]+)?-([1-9][0-9]+).*");
- static std::tr1::regex simpleexp("^([a-zA-Z0-9_]+)");
+ //Look for something along the lines of modulename-Vn-m + any old rubbish.
+ static std::regex exp("^([a-zA-Z0-9_'\"\\- ]*?)([-_ ][VvRr]?[0-9_]+)?-([1-9][0-9]+).*");
+ static std::regex simpleexp("^([a-zA-Z0-9_]+)");
QByteArray fileNameUTF8 = fileName.toUtf8();
- std::tr1::cmatch result;
- if (std::tr1::regex_search(fileNameUTF8.constData(), result, exp)) {
+ std::cmatch result;
+ if (std::regex_search(fileNameUTF8.constData(), result, exp)) {
modName = QString::fromUtf8(result[1].str().c_str());
modName = modName.replace('_', ' ').trimmed();
@@ -227,7 +228,7 @@ void NexusInterface::interpretNexusFileName(const QString &fileName, QString &mo modID = strtol(candidate.c_str(), nullptr, 10);
}
qDebug("mod id guessed: %s -> %d", qPrintable(fileName), modID);
- } else if (std::tr1::regex_search(fileNameUTF8.constData(), result, simpleexp)) {
+ } else if (std::regex_search(fileNameUTF8.constData(), result, simpleexp)) {
qDebug("simple expression matched, using name only");
modName = QString::fromUtf8(result[1].str().c_str());
modName = modName.replace('_', ' ').trimmed();
@@ -244,7 +245,7 @@ bool NexusInterface::isURLGameRelated(const QUrl &url) const {
QString const name(url.toString());
return name.startsWith(getGameURL() + "/") ||
- name.startsWith("http://" + m_Game->getGameShortName().toLower() + ".nexusmods.com/mods/");
+ name.startsWith(getOldModsURL() + "/");
}
QString NexusInterface::getGameURL() const
@@ -252,11 +253,27 @@ QString NexusInterface::getGameURL() const return "http://www.nexusmods.com/" + m_Game->getGameShortName().toLower();
}
+QString NexusInterface::getOldModsURL() const
+{
+ return "http://" + m_Game->getGameShortName().toLower() + ".nexusmods.com/mods";
+}
+
+
QString NexusInterface::getModURL(int modID) const
{
return QString("%1/mods/%2").arg(getGameURL()).arg(modID);
}
+bool NexusInterface::isModURL(int modID, QString const &url) const
+{
+ if (url == getModURL(modID)) {
+ return true;
+ }
+ //Try the alternate (old style) mod name
+ QString alt = QString("%1/%2").arg(getOldModsURL()).arg(modID);
+ return alt == url;
+}
+
int NexusInterface::requestDescription(int modID, QObject *receiver, QVariant userData,
const QString &subModule, MOBase::IPluginGame const *game)
{
diff --git a/src/nexusinterface.h b/src/nexusinterface.h index 3fa8f564..c9a81134 100644 --- a/src/nexusinterface.h +++ b/src/nexusinterface.h @@ -345,6 +345,14 @@ public: */
QString getModURL(int modID) const;
+ /**
+ * @brief Checks if the specified URL might correspond to a nexus mod
+ * @param modID
+ * @param url
+ * @return
+ */
+ bool isModURL(int modID, QString const &url) const;
+
signals:
void requestNXMDownload(const QString &url);
@@ -412,6 +420,7 @@ private: void nextRequest();
void requestFinished(std::list<NXMRequestInfo>::iterator iter);
bool requiresLogin(const NXMRequestInfo &info);
+ QString getOldModsURL() const;
private:
diff --git a/src/organizer.pro b/src/organizer.pro index f472bd80..0cdb4400 100644 --- a/src/organizer.pro +++ b/src/organizer.pro @@ -90,7 +90,12 @@ SOURCES += \ organizerproxy.cpp \
viewmarkingscrollbar.cpp \
plugincontainer.cpp \
- organizercore.cpp
+ organizercore.cpp \
+ modinfowithconflictinfo.cpp \
+ modinforegular.cpp \
+ modinfobackup.cpp \
+ modinfooverwrite.cpp \
+ modinfoforeign.cpp
HEADERS += \
@@ -165,7 +170,12 @@ HEADERS += \ viewmarkingscrollbar.h \
plugincontainer.h \
organizercore.h \
- iuserinterface.h
+ iuserinterface.h \
+ modinfowithconflictinfo.h \
+ modinforegular.h \
+ modinfobackup.h \
+ modinfooverwrite.h \
+ modinfoforeign.h
FORMS += \
transfersavesdialog.ui \
diff --git a/src/selfupdater.cpp b/src/selfupdater.cpp index 8fb204d8..11478fbc 100644 --- a/src/selfupdater.cpp +++ b/src/selfupdater.cpp @@ -72,9 +72,9 @@ SelfUpdater::SelfUpdater(NexusInterface *nexusInterface) CreateArchiveType CreateArchiveFunc = resolveFunction<CreateArchiveType>(archiveLib, "CreateArchive");
- m_CurrentArchive = CreateArchiveFunc();
- if (!m_CurrentArchive->isValid()) {
- throw MyException(InstallationManager::getErrorString(m_CurrentArchive->getLastError()));
+ m_ArchiveHandler = CreateArchiveFunc();
+ if (!m_ArchiveHandler->isValid()) {
+ throw MyException(InstallationManager::getErrorString(m_ArchiveHandler->getLastError()));
}
connect(m_Progress, SIGNAL(canceled()), this, SLOT(downloadCancel()));
@@ -89,7 +89,7 @@ SelfUpdater::SelfUpdater(NexusInterface *nexusInterface) SelfUpdater::~SelfUpdater()
{
- delete m_CurrentArchive;
+ delete m_ArchiveHandler;
}
void SelfUpdater::setUserInterface(QWidget *widget)
@@ -249,26 +249,25 @@ void SelfUpdater::installUpdate() QDir().mkdir(backupPath);
// rename files that are currently open so we can unpack the update
- if (!m_CurrentArchive->open(ToWString(QDir::toNativeSeparators(m_UpdateFile.fileName())).c_str(),
- new MethodCallback<SelfUpdater, void, LPSTR>(this, &SelfUpdater::queryPassword))) {
+ if (!m_ArchiveHandler->open(m_UpdateFile.fileName(), nullptr)) {
throw MyException(tr("failed to open archive \"%1\": %2")
.arg(m_UpdateFile.fileName())
- .arg(InstallationManager::getErrorString(m_CurrentArchive->getLastError())));
+ .arg(InstallationManager::getErrorString(m_ArchiveHandler->getLastError())));
}
// move all files contained in the archive out of the way,
// otherwise we can't overwrite everything
FileData* const *data;
size_t size;
- m_CurrentArchive->getFileList(data, size);
+ m_ArchiveHandler->getFileList(data, size);
for (size_t i = 0; i < size; ++i) {
- QString outputName = ToQString(data[i]->getFileName());
+ QString outputName = data[i]->getFileName();
if (outputName.startsWith("ModOrganizer\\", Qt::CaseInsensitive)) {
outputName = outputName.mid(13);
- data[i]->addOutputFileName(ToWString(outputName).c_str());
+ data[i]->addOutputFileName(outputName);
} else if (outputName != "ModOrganizer") {
- data[i]->addOutputFileName(ToWString(outputName).c_str());
+ data[i]->addOutputFileName(outputName);
}
QFileInfo file(mopath + "/" + outputName);
if (file.exists() && file.isFile()) {
@@ -281,14 +280,12 @@ void SelfUpdater::installUpdate() }
// now unpack the archive into the mo directory
- if (!m_CurrentArchive->extract(QDir::toNativeSeparators(mopath).toStdWString().c_str(),
- new MethodCallback<SelfUpdater, void, float>(this, &SelfUpdater::updateProgress),
- new MethodCallback<SelfUpdater, void, LPCWSTR>(this, &SelfUpdater::updateProgressFile),
- new MethodCallback<SelfUpdater, void, LPCWSTR>(this, &SelfUpdater::report7ZipError))) {
+ if (!m_ArchiveHandler->extract(mopath, nullptr, nullptr,
+ new MethodCallback<SelfUpdater, void, QString const &>(this, &SelfUpdater::report7ZipError))) {
throw std::runtime_error("extracting failed");
}
- m_CurrentArchive->close();
+ m_ArchiveHandler->close();
m_UpdateFile.remove();
@@ -303,24 +300,9 @@ void SelfUpdater::installUpdate() emit restart();
}
-void SelfUpdater::queryPassword(LPSTR)
+void SelfUpdater::report7ZipError(QString const &errorMessage)
{
- // nop
-}
-
-void SelfUpdater::updateProgress(float)
-{
- // nop
-}
-
-void SelfUpdater::updateProgressFile(LPCWSTR)
-{
- // nop
-}
-
-void SelfUpdater::report7ZipError(LPCWSTR errorMessage)
-{
- QMessageBox::critical(m_Parent, tr("Error"), ToQString(errorMessage));
+ QMessageBox::critical(m_Parent, tr("Error"), errorMessage);
}
diff --git a/src/selfupdater.h b/src/selfupdater.h index 4fdc3d7d..446778fb 100644 --- a/src/selfupdater.h +++ b/src/selfupdater.h @@ -67,7 +67,7 @@ public: * @param parent parent widget
* @todo passing the nexus interface is unneccessary
**/
- SelfUpdater(NexusInterface *nexusInterface);
+ explicit SelfUpdater(NexusInterface *nexusInterface);
virtual ~SelfUpdater();
@@ -120,10 +120,7 @@ private: void download(const QString &downloadLink, const QString &fileName);
void installUpdate();
- void queryPassword(LPSTR password);
- void updateProgress(float percentage);
- void updateProgressFile(LPCWSTR fileName);
- void report7ZipError(LPCWSTR errorMessage);
+ void report7ZipError(const QString &errorMessage);
QString retrieveNews(const QString &description);
void showProgress();
void closeProgress();
@@ -148,7 +145,7 @@ private: bool m_Canceled;
int m_Attempts;
- Archive *m_CurrentArchive;
+ Archive *m_ArchiveHandler;
MOBase::IPluginGame const *m_NexusDownload;
};
diff --git a/src/shared/SConscript b/src/shared/SConscript index 69a95289..24ca5b19 100644 --- a/src/shared/SConscript +++ b/src/shared/SConscript @@ -1,8 +1,6 @@ -Import('qt_env')
+Import('env')
-env = qt_env.Clone()
-
-env.EnableQtModules('Core', 'Gui')
+env = env.Clone()
env.AppendUnique(CPPDEFINES = [
'UNICODE',
@@ -21,5 +19,5 @@ env.AppendUnique(CPPPATH = [ # Not sure if renaming this helps much as it's static
env.StaticLibrary('mo_shared', env.Glob('*.cpp'))
-res = env['QT_USED_MODULES']
-Return('res')
+#res = env['QT_USED_MODULES']
+#Return('res')
diff --git a/src/shared/fallout3info.cpp b/src/shared/fallout3info.cpp index 043a25dc..008a046c 100644 --- a/src/shared/fallout3info.cpp +++ b/src/shared/fallout3info.cpp @@ -63,22 +63,22 @@ std::wstring Fallout3Info::getRegPathStatic() }
-std::vector<std::wstring> Fallout3Info::getSavegameAttachmentExtensions()
+std::vector<std::wstring> Fallout3Info::getSavegameAttachmentExtensions() const
{
return std::vector<std::wstring>();
}
-std::vector<std::wstring> Fallout3Info::getIniFileNames()
+std::vector<std::wstring> Fallout3Info::getIniFileNames() const
{
return boost::assign::list_of(L"fallout.ini")(L"falloutprefs.ini");
}
-std::wstring Fallout3Info::getReferenceDataFile()
+std::wstring Fallout3Info::getReferenceDataFile() const
{
return L"Fallout - Meshes.bsa";
}
-bool Fallout3Info::rerouteToProfile(const wchar_t *fileName, const wchar_t*)
+bool Fallout3Info::rerouteToProfile(const wchar_t *fileName, const wchar_t*) const
{
static LPCWSTR profileFiles[] = { L"fallout.ini", L"falloutprefs.ini", L"plugins.txt", nullptr };
diff --git a/src/shared/fallout3info.h b/src/shared/fallout3info.h index 489ac038..21356924 100644 --- a/src/shared/fallout3info.h +++ b/src/shared/fallout3info.h @@ -20,7 +20,6 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #ifndef FALLOUT3INFO_H
#define FALLOUT3INFO_H
-
#include "gameinfo.h"
namespace MOShared {
@@ -36,22 +35,18 @@ public: virtual ~Fallout3Info() {}
static std::wstring getRegPathStatic();
- virtual std::wstring getRegPath() { return getRegPathStatic(); }
+ virtual std::wstring getRegPath() const { return getRegPathStatic(); }
- virtual std::vector<std::wstring> getSavegameAttachmentExtensions();
+ virtual std::vector<std::wstring> getSavegameAttachmentExtensions() const;
// file name of this games ini (no path)
- virtual std::vector<std::wstring> getIniFileNames();
-
- virtual std::wstring getReferenceDataFile();
+ virtual std::vector<std::wstring> getIniFileNames() const;
- virtual bool rerouteToProfile(const wchar_t *fileName, const wchar_t *fullPath);
+ virtual std::wstring getReferenceDataFile() const;
- // get a list of executables (game binary and known-to-work 3rd party tools). All of these are relative to
- // the game directory
- //virtual std::vector<ExecutableInfo> getExecutables();
+ virtual bool rerouteToProfile(const wchar_t *fileName, const wchar_t *fullPath) const;
- virtual std::wstring archiveListKey() { return L"SArchiveList"; }
+ virtual std::wstring archiveListKey() const { return L"SArchiveList"; }
private:
diff --git a/src/shared/falloutnvinfo.cpp b/src/shared/falloutnvinfo.cpp index 88985ad6..80d2fba5 100644 --- a/src/shared/falloutnvinfo.cpp +++ b/src/shared/falloutnvinfo.cpp @@ -63,22 +63,22 @@ std::wstring FalloutNVInfo::getRegPathStatic() }
}
-std::vector<std::wstring> FalloutNVInfo::getSavegameAttachmentExtensions()
+std::vector<std::wstring> FalloutNVInfo::getSavegameAttachmentExtensions() const
{
return std::vector<std::wstring>();
}
-std::vector<std::wstring> FalloutNVInfo::getIniFileNames()
+std::vector<std::wstring> FalloutNVInfo::getIniFileNames() const
{
return boost::assign::list_of(L"fallout.ini")(L"falloutprefs.ini");
}
-std::wstring FalloutNVInfo::getReferenceDataFile()
+std::wstring FalloutNVInfo::getReferenceDataFile() const
{
return L"Fallout - Meshes.bsa";
}
-bool FalloutNVInfo::rerouteToProfile(const wchar_t *fileName, const wchar_t*)
+bool FalloutNVInfo::rerouteToProfile(const wchar_t *fileName, const wchar_t*) const
{
static LPCWSTR profileFiles[] = { L"fallout.ini", L"falloutprefs.ini", L"plugins.txt", nullptr };
diff --git a/src/shared/falloutnvinfo.h b/src/shared/falloutnvinfo.h index a0bc5bd4..4bffff3f 100644 --- a/src/shared/falloutnvinfo.h +++ b/src/shared/falloutnvinfo.h @@ -36,22 +36,18 @@ public: virtual ~FalloutNVInfo() {}
static std::wstring getRegPathStatic();
- virtual std::wstring getRegPath() { return getRegPathStatic(); }
+ virtual std::wstring getRegPath() const { return getRegPathStatic(); }
- virtual std::vector<std::wstring> getSavegameAttachmentExtensions();
+ virtual std::vector<std::wstring> getSavegameAttachmentExtensions() const;
// file name of this games ini (no path)
- virtual std::vector<std::wstring> getIniFileNames();
+ virtual std::vector<std::wstring> getIniFileNames() const;
- virtual std::wstring getReferenceDataFile();
+ virtual std::wstring getReferenceDataFile() const;
- virtual bool rerouteToProfile(const wchar_t *fileName, const wchar_t *fullPath);
+ virtual bool rerouteToProfile(const wchar_t *fileName, const wchar_t *fullPath) const;
- // get a list of executables (game binary and known-to-work 3rd party tools). All of these are relative to
- // the game directory
- //virtual std::vector<ExecutableInfo> getExecutables();
-
- virtual std::wstring archiveListKey() { return L"SArchiveList"; }
+ virtual std::wstring archiveListKey() const { return L"SArchiveList"; }
private:
diff --git a/src/shared/gameinfo.cpp b/src/shared/gameinfo.cpp index 2890e9cc..e77b9d17 100644 --- a/src/shared/gameinfo.cpp +++ b/src/shared/gameinfo.cpp @@ -86,7 +86,6 @@ void GameInfo::identifyMyGamesDirectory(const std::wstring &file) }
}
-
bool GameInfo::identifyGame(const std::wstring &searchPath)
{
if (OblivionInfo::identifyGame(searchPath)) {
diff --git a/src/shared/gameinfo.h b/src/shared/gameinfo.h index 9e6a35ef..a5c615cf 100644 --- a/src/shared/gameinfo.h +++ b/src/shared/gameinfo.h @@ -47,7 +47,7 @@ public: //**Used only in savegame which needs refactoring a lot.
// get a list of file extensions for additional files belonging to a save game
- virtual std::vector<std::wstring> getSavegameAttachmentExtensions() = 0;
+ virtual std::vector<std::wstring> getSavegameAttachmentExtensions() const = 0;
//**USED ONLY IN HOOKDLL
virtual std::wstring getGameDirectory() const;
@@ -58,17 +58,17 @@ public: static bool init(const std::wstring &moDirectory, const std::wstring &gamePath = L"");
//**USED ONLY IN HOOKDLL
- virtual std::wstring getRegPath() = 0;
+ virtual std::wstring getRegPath() const = 0;
//**USED ONLY IN HOOKDLL
// file name of this games ini file(s)
- virtual std::vector<std::wstring> getIniFileNames() = 0;
+ virtual std::vector<std::wstring> getIniFileNames() const = 0;
//**USED ONLY IN HOOKDLL
- virtual std::wstring getReferenceDataFile() = 0;
+ virtual std::wstring getReferenceDataFile() const = 0;
//**USED ONLY IN HOOKDLL
- virtual bool rerouteToProfile(const wchar_t *fileName, const wchar_t *fullPath) = 0;
+ virtual bool rerouteToProfile(const wchar_t *fileName, const wchar_t *fullPath) const = 0;
protected:
@@ -78,6 +78,8 @@ protected: const std::wstring &getMyGamesDirectory() const { return m_MyGamesDirectory; }
void identifyMyGamesDirectory(const std::wstring &file);
+ bool isValidModURL(int modID, const std::wstring &url, const std::wstring &alt) const;
+
private:
static bool identifyGame(const std::wstring &searchPath);
diff --git a/src/shared/oblivioninfo.cpp b/src/shared/oblivioninfo.cpp index a3dc3986..8f1f1843 100644 --- a/src/shared/oblivioninfo.cpp +++ b/src/shared/oblivioninfo.cpp @@ -66,18 +66,18 @@ std::wstring OblivionInfo::getRegPathStatic() -std::vector<std::wstring> OblivionInfo::getSavegameAttachmentExtensions()
+std::vector<std::wstring> OblivionInfo::getSavegameAttachmentExtensions() const
{
return boost::assign::list_of(L"obse");
}
-std::vector<std::wstring> OblivionInfo::getIniFileNames()
+std::vector<std::wstring> OblivionInfo::getIniFileNames() const
{
return boost::assign::list_of(L"oblivion.ini")(L"oblivionprefs.ini");
}
-bool OblivionInfo::rerouteToProfile(const wchar_t *fileName, const wchar_t*)
+bool OblivionInfo::rerouteToProfile(const wchar_t *fileName, const wchar_t*) const
{
static LPCWSTR profileFiles[] = { L"oblivion.ini", L"oblivionprefs.ini", L"plugins.txt", nullptr };
@@ -89,7 +89,7 @@ bool OblivionInfo::rerouteToProfile(const wchar_t *fileName, const wchar_t*) return false;
}
-std::wstring OblivionInfo::getReferenceDataFile()
+std::wstring OblivionInfo::getReferenceDataFile() const
{
return L"Oblivion - Meshes.bsa";
}
diff --git a/src/shared/oblivioninfo.h b/src/shared/oblivioninfo.h index 1e48b742..fc949f4b 100644 --- a/src/shared/oblivioninfo.h +++ b/src/shared/oblivioninfo.h @@ -34,22 +34,18 @@ public: virtual ~OblivionInfo() {}
static std::wstring getRegPathStatic();
- virtual std::wstring getRegPath() { return getRegPathStatic(); }
+ virtual std::wstring getRegPath() const { return getRegPathStatic(); }
- virtual std::vector<std::wstring> getSavegameAttachmentExtensions();
+ virtual std::vector<std::wstring> getSavegameAttachmentExtensions() const;
// file name of this games ini (no path)
- virtual std::vector<std::wstring> getIniFileNames();
+ virtual std::vector<std::wstring> getIniFileNames() const;
- virtual std::wstring getReferenceDataFile();
+ virtual std::wstring getReferenceDataFile() const;
- virtual bool rerouteToProfile(const wchar_t *fileName, const wchar_t *fullPath);
+ virtual bool rerouteToProfile(const wchar_t *fileName, const wchar_t *fullPath) const;
- // get a list of executables (game binary and known-to-work 3rd party tools). All of these are relative to
- // the game directory
- //virtual std::vector<ExecutableInfo> getExecutables();
-
- virtual std::wstring archiveListKey() { return L"SArchiveList"; }
+ virtual std::wstring archiveListKey() const { return L"SArchiveList"; }
private:
diff --git a/src/shared/skyriminfo.cpp b/src/shared/skyriminfo.cpp index 869ac47d..d255e60f 100644 --- a/src/shared/skyriminfo.cpp +++ b/src/shared/skyriminfo.cpp @@ -73,22 +73,22 @@ std::wstring SkyrimInfo::getRegPathStatic() }
}
-std::vector<std::wstring> SkyrimInfo::getSavegameAttachmentExtensions()
+std::vector<std::wstring> SkyrimInfo::getSavegameAttachmentExtensions() const
{
return boost::assign::list_of(L"skse");
}
-std::vector<std::wstring> SkyrimInfo::getIniFileNames()
+std::vector<std::wstring> SkyrimInfo::getIniFileNames() const
{
return boost::assign::list_of(L"skyrim.ini")(L"skyrimprefs.ini");
}
-std::wstring SkyrimInfo::getReferenceDataFile()
+std::wstring SkyrimInfo::getReferenceDataFile() const
{
return L"Skyrim - Meshes.bsa";
}
-bool SkyrimInfo::rerouteToProfile(const wchar_t *fileName, const wchar_t *fullPath)
+bool SkyrimInfo::rerouteToProfile(const wchar_t *fileName, const wchar_t *fullPath) const
{
static LPCWSTR profileFiles[] = { L"skyrim.ini", L"skyrimprefs.ini", L"loadorder.txt", nullptr };
@@ -106,5 +106,4 @@ bool SkyrimInfo::rerouteToProfile(const wchar_t *fileName, const wchar_t *fullPa return false;
}
-
} // namespace MOShared
diff --git a/src/shared/skyriminfo.h b/src/shared/skyriminfo.h index ce2510f1..ac979d20 100644 --- a/src/shared/skyriminfo.h +++ b/src/shared/skyriminfo.h @@ -36,16 +36,16 @@ public: virtual ~SkyrimInfo() {}
static std::wstring getRegPathStatic();
- virtual std::wstring getRegPath() { return getRegPathStatic(); }
+ virtual std::wstring getRegPath() const { return getRegPathStatic(); }
- virtual std::vector<std::wstring> getSavegameAttachmentExtensions();
+ virtual std::vector<std::wstring> getSavegameAttachmentExtensions() const;
// file name of this games ini (no path)
- virtual std::vector<std::wstring> getIniFileNames();
+ virtual std::vector<std::wstring> getIniFileNames() const;
- virtual std::wstring getReferenceDataFile();
+ virtual std::wstring getReferenceDataFile() const;
- virtual bool rerouteToProfile(const wchar_t *fileName, const wchar_t *fullPath);
+ virtual bool rerouteToProfile(const wchar_t *fileName, const wchar_t *fullPath) const;
private:
|
