summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/CMakeLists.txt16
-rw-r--r--src/SConscript18
-rw-r--r--src/bbcode.cpp4
-rw-r--r--src/browserdialog.cpp6
-rw-r--r--src/browserview.h4
-rw-r--r--src/categories.cpp4
-rw-r--r--src/directoryrefresher.cpp9
-rw-r--r--src/downloadmanager.cpp28
-rw-r--r--src/downloadmanager.h6
-rw-r--r--src/executableslist.cpp10
-rw-r--r--src/executableslist.h7
-rw-r--r--src/gameinfoimpl.h39
-rw-r--r--src/helper.h2
-rw-r--r--src/installationmanager.cpp124
-rw-r--r--src/installationmanager.h17
-rw-r--r--src/loadmechanism.cpp21
-rw-r--r--src/loadmechanism.h2
-rw-r--r--src/main.cpp206
-rw-r--r--src/mainwindow.cpp114
-rw-r--r--src/mainwindow.h5
-rw-r--r--src/modinfo.cpp815
-rw-r--r--src/modinfo.h568
-rw-r--r--src/modinfobackup.cpp20
-rw-r--r--src/modinfobackup.h40
-rw-r--r--src/modinfodialog.cpp14
-rw-r--r--src/modinfoforeign.cpp54
-rw-r--r--src/modinfoforeign.h67
-rw-r--r--src/modinfooverwrite.cpp53
-rw-r--r--src/modinfooverwrite.h59
-rw-r--r--src/modinforegular.cpp571
-rw-r--r--src/modinforegular.h349
-rw-r--r--src/modinfowithconflictinfo.cpp130
-rw-r--r--src/modinfowithconflictinfo.h64
-rw-r--r--src/modlist.cpp5
-rw-r--r--src/nexusinterface.cpp133
-rw-r--r--src/nexusinterface.h164
-rw-r--r--src/nxmaccessmanager.cpp31
-rw-r--r--src/nxmaccessmanager.h3
-rw-r--r--src/organizer.pro26
-rw-r--r--src/organizercore.cpp72
-rw-r--r--src/organizercore.h13
-rw-r--r--src/organizerproxy.cpp23
-rw-r--r--src/organizerproxy.h11
-rw-r--r--src/pluginlist.cpp12
-rw-r--r--src/pluginlist.h12
-rw-r--r--src/profile.cpp38
-rw-r--r--src/profile.h24
-rw-r--r--src/profilesdialog.cpp12
-rw-r--r--src/profilesdialog.h4
-rw-r--r--src/savegame.cpp81
-rw-r--r--src/savegame.h20
-rw-r--r--src/savegamegamebryo.cpp389
-rw-r--r--src/savegamegamebyro.h43
-rw-r--r--src/selfupdater.cpp92
-rw-r--r--src/selfupdater.h14
-rw-r--r--src/settings.cpp16
-rw-r--r--src/settings.h14
-rw-r--r--src/settingsdialog.cpp14
-rw-r--r--src/shared/SConscript10
-rw-r--r--src/shared/fallout3info.cpp45
-rw-r--r--src/shared/fallout3info.h31
-rw-r--r--src/shared/fallout4info.cpp11
-rw-r--r--src/shared/fallout4info.h11
-rw-r--r--src/shared/falloutnvinfo.cpp51
-rw-r--r--src/shared/falloutnvinfo.h63
-rw-r--r--src/shared/gameinfo.cpp42
-rw-r--r--src/shared/gameinfo.h69
-rw-r--r--src/shared/oblivioninfo.cpp68
-rw-r--r--src/shared/oblivioninfo.h63
-rw-r--r--src/shared/skyriminfo.cpp68
-rw-r--r--src/shared/skyriminfo.h29
-rw-r--r--src/shared/stackdata.cpp5
-rw-r--r--src/spawn.cpp7
-rw-r--r--src/syncoverwritedialog.cpp3
-rw-r--r--src/transfersavesdialog.cpp12
-rw-r--r--src/transfersavesdialog.h10
76 files changed, 2449 insertions, 2861 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 313f7506..c55f9efe 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
@@ -61,7 +66,6 @@ SET(organizer_SRCS
moapplication.cpp
profileinputdialog.cpp
icondelegate.cpp
- gameinfoimpl.cpp
csvbuilder.cpp
savetextasdialog.cpp
qtgroupingproxy.cpp
@@ -127,6 +131,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
@@ -152,7 +161,6 @@ SET(organizer_HDRS
moapplication.h
profileinputdialog.h
icondelegate.h
- gameinfoimpl.h
csvbuilder.h
savetextasdialog.h
qtgroupingproxy.h
@@ -284,8 +292,12 @@ INCLUDE_DIRECTORIES(${project_path}/uibase/src
${project_path}/esptk/src
${project_path}/archive/src
${project_path}/../usvfs/usvfs
+ ${project_path}/game_gamebryo/src
${project_path}/game_features/src)
+MESSAGE(STATUS ${project_path}/gameGamebryo/src)
+
+
INCLUDE_DIRECTORIES(shared ${ZLIB_INCLUDE_DIRS})
LINK_DIRECTORIES(${lib_path}
${project_path}/../zlib/lib)
diff --git a/src/SConscript b/src/SConscript
index f09db093..6de7cb62 100644
--- a/src/SConscript
+++ b/src/SConscript
@@ -67,7 +67,6 @@ env.Uic(env.Glob('*.ui'))
env.RequireLibraries('uibase', 'shared', 'bsatk', 'esptk')
-
env.AppendUnique(LIBS = [
'shell32',
'user32',
@@ -96,6 +95,12 @@ env['CPPPATH'] += [
'${BOOSTPATH}',
]
+#########################FUDGE###############################
+env['CPPPATH'] += [
+ '../plugins/gameGamebryo',
+ ]
+#############################################################
+
env.AppendUnique(CPPDEFINES = [
'_UNICODE',
'_CRT_SECURE_NO_WARNINGS',
@@ -105,7 +110,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',
@@ -114,8 +123,9 @@ env.AppendUnique(LINKFLAGS = [
# modeltest is optional and it doesn't compile anyway...
cpp_files = [
- x for x in Glob('*.cpp')
- if x.name != 'modeltest.cpp' and x.name != 'aboutdialog.cpp'
+ x for x in env.Glob('*.cpp', source = True)
+ if x.name != 'modeltest.cpp' and x.name != 'aboutdialog.cpp' and \
+ not x.name.startswith('moc_') # I think this is a strange bug
]
about_env = env.Clone()
diff --git a/src/bbcode.cpp b/src/bbcode.cpp
index 0f9170d4..56369538 100644
--- a/src/bbcode.cpp
+++ b/src/bbcode.cpp
@@ -21,8 +21,6 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#include <QRegExp>
#include <map>
-#include <algorithm>
-#include <boost/assign.hpp>
namespace BBCode {
@@ -80,7 +78,7 @@ public:
if (tagName == "color") {
QString color = tagIter->second.first.cap(1);
QString content = tagIter->second.first.cap(2);
- if (color.at(0) == "#") {
+ if (color.at(0) == '#') {
return temp.replace(tagIter->second.first, QString("<font style=\"color: %1;\">%2</font>").arg(color, content));
} else {
auto colIter = m_ColorMap.find(color.toLower());
diff --git a/src/browserdialog.cpp b/src/browserdialog.cpp
index c382c112..e5f0f21d 100644
--- a/src/browserdialog.cpp
+++ b/src/browserdialog.cpp
@@ -18,18 +18,16 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
*/
#include "browserdialog.h"
+
#include "ui_browserdialog.h"
#include "browserview.h"
-
#include "messagedialog.h"
#include "report.h"
#include "persistentcookiejar.h"
-#include "json.h"
-
#include <utility.h>
-#include <gameinfo.h>
#include "settings.h"
+
#include <QNetworkCookieJar>
#include <QNetworkCookie>
#include <QMenu>
diff --git a/src/browserview.h b/src/browserview.h
index f8b132b8..6a89752a 100644
--- a/src/browserview.h
+++ b/src/browserview.h
@@ -21,9 +21,11 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#define NEXUSVIEW_H
+class QEvent;
+class QUrl;
+class QWidget;
#include <QWebView>
#include <QWebPage>
-#include <QTabWidget>
/**
* @brief web view used to display a nexus page
diff --git a/src/categories.cpp b/src/categories.cpp
index f096a902..7539d3fd 100644
--- a/src/categories.cpp
+++ b/src/categories.cpp
@@ -18,9 +18,10 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
*/
#include "categories.h"
+
#include <utility.h>
#include <report.h>
-#include <gameinfo.h>
+
#include <QObject>
#include <QFile>
#include <QDir>
@@ -29,7 +30,6 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
using namespace MOBase;
-using namespace MOShared;
CategoryFactory* CategoryFactory::s_Instance = nullptr;
diff --git a/src/directoryrefresher.cpp b/src/directoryrefresher.cpp
index c253f384..f50a717e 100644
--- a/src/directoryrefresher.cpp
+++ b/src/directoryrefresher.cpp
@@ -18,10 +18,13 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
*/
#include "directoryrefresher.h"
+
+#include "iplugingame.h"
#include "utility.h"
#include "report.h"
#include "modinfo.h"
-#include <gameinfo.h>
+
+#include <QApplication>
#include <QDir>
#include <QString>
@@ -141,7 +144,9 @@ void DirectoryRefresher::refresh()
m_DirectoryStructure = new DirectoryEntry(L"data", nullptr, 0);
- std::wstring dataDirectory = GameInfo::instance().getGameDirectory() + L"\\data";
+ IPluginGame const *game = qApp->property("managed_game").value<IPluginGame const *>();
+
+ std::wstring dataDirectory = QDir::toNativeSeparators(game->dataDirectory().absolutePath()).toStdWString();
m_DirectoryStructure->addFromOrigin(L"data", dataDirectory, 0);
// TODO what was the point of having the priority in this tuple? the list is already sorted by priority
diff --git a/src/downloadmanager.cpp b/src/downloadmanager.cpp
index bc78cdc6..cbc1ba45 100644
--- a/src/downloadmanager.cpp
+++ b/src/downloadmanager.cpp
@@ -18,18 +18,19 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
*/
#include "downloadmanager.h"
+
#include "nxmurl.h"
#include "nexusinterface.h"
#include "nxmaccessmanager.h"
-#include <gameinfo.h>
+#include "iplugingame.h"
#include <nxmurl.h>
#include <taskprogressmanager.h>
#include "utility.h"
-#include "json.h"
#include "selectiondialog.h"
#include "bbcode.h"
#include <utility.h>
#include <report.h>
+
#include <QTimer>
#include <QFileInfo>
#include <QRegExp>
@@ -37,6 +38,8 @@ 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>
@@ -447,7 +450,7 @@ void DownloadManager::addNXMDownload(const QString &url)
{
NXMUrl nxmInfo(url);
- QString managedGame = ToQString(MOShared::GameInfo::instance().getGameShortName());
+ QString managedGame = m_ManagedGame->getGameShortName();
qDebug("add nxm download: %s", qPrintable(url));
if (nxmInfo.game().compare(managedGame, Qt::CaseInsensitive) != 0) {
qDebug("download requested for wrong game (game: %s, url: %s)", qPrintable(managedGame), qPrintable(nxmInfo.game()));
@@ -909,10 +912,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());
}
}
@@ -1128,6 +1131,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();
@@ -1235,13 +1244,14 @@ int DownloadManager::startDownloadURLs(const QStringList &urls)
return m_ActiveDownloads.size() - 1;
}
+/* This doesn't appear to be used by anything
int DownloadManager::startDownloadNexusFile(int modID, int fileID)
{
int newID = m_ActiveDownloads.size();
addNXMDownload(QString("nxm://%1/mods/%2/files/%3").arg(ToQString(MOShared::GameInfo::instance().getGameName())).arg(modID).arg(fileID));
return newID;
}
-
+*/
QString DownloadManager::downloadPath(int id)
{
return getFilePath(id);
@@ -1461,3 +1471,7 @@ void DownloadManager::directoryChanged(const QString&)
refreshList();
}
+void DownloadManager::managedGameChanged(MOBase::IPluginGame const *managedGame)
+{
+ m_ManagedGame = managedGame;
+}
diff --git a/src/downloadmanager.h b/src/downloadmanager.h
index 57bd592d..54db4648 100644
--- a/src/downloadmanager.h
+++ b/src/downloadmanager.h
@@ -35,6 +35,7 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#include <QFileSystemWatcher>
#include <QSettings>
+namespace MOBase { class IPluginGame; }
class NexusInterface;
@@ -328,7 +329,9 @@ public:
virtual int startDownloadURLs(const QStringList &urls);
+ /* This doesn't appear to be used anywhere
virtual int startDownloadNexusFile(int modID, int fileID);
+ */
virtual QString downloadPath(int id);
/**
@@ -414,6 +417,8 @@ public slots:
void nxmRequestFailed(int modID, int fileID, QVariant userData, int requestID, const QString &errorString);
+ void managedGameChanged(MOBase::IPluginGame const *gamePlugin);
+
private slots:
void downloadProgress(qint64 bytesReceived, qint64 bytesTotal);
@@ -501,6 +506,7 @@ private:
QRegExp m_DateExpression;
+ MOBase::IPluginGame const *m_ManagedGame;
};
diff --git a/src/executableslist.cpp b/src/executableslist.cpp
index 12e3d7aa..a4511ade 100644
--- a/src/executableslist.cpp
+++ b/src/executableslist.cpp
@@ -18,16 +18,18 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
*/
#include "executableslist.h"
-#include <gameinfo.h>
+
+#include "iplugingame.h"
+#include "utility.h"
+
#include <QFileInfo>
#include <QDir>
#include <QDebug>
-#include "utility.h"
+
#include <algorithm>
using namespace MOBase;
-using namespace MOShared;
ExecutablesList::ExecutablesList()
@@ -38,7 +40,7 @@ ExecutablesList::~ExecutablesList()
{
}
-void ExecutablesList::init(IPluginGame *game)
+void ExecutablesList::init(IPluginGame const *game)
{
Q_ASSERT(game != nullptr);
m_Executables.clear();
diff --git a/src/executableslist.h b/src/executableslist.h
index b4054bcc..3d5ba0ed 100644
--- a/src/executableslist.h
+++ b/src/executableslist.h
@@ -20,13 +20,14 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#ifndef EXECUTABLESLIST_H
#define EXECUTABLESLIST_H
+#include "executableinfo.h"
#include <vector>
+
#include <QFileInfo>
#include <QMetaType>
-#include <gameinfo.h>
-#include <iplugingame.h>
+namespace MOBase { class IPluginGame; }
/*!
* @brief Information about an executable
@@ -78,7 +79,7 @@ public:
/**
* @brief initialise the list with the executables preconfigured for this game
**/
- void init(MOBase::IPluginGame *game);
+ void init(MOBase::IPluginGame const *game);
/**
* @brief find an executable by its name
diff --git a/src/gameinfoimpl.h b/src/gameinfoimpl.h
deleted file mode 100644
index 3ed7be6b..00000000
--- a/src/gameinfoimpl.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
-Copyright (C) 2012 Sebastian Herbord. All rights reserved.
-
-This file is part of Mod Organizer.
-
-Mod Organizer is free software: you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
-
-Mod Organizer is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifndef GAMEINFOIMPL_H
-#define GAMEINFOIMPL_H
-
-
-#include <igameinfo.h>
-#include <QString>
-
-
-class GameInfoImpl : public MOBase::IGameInfo
-{
-public:
- GameInfoImpl();
-
- virtual Type type() const;
- virtual QString path() const;
- virtual QString binaryName() const;
-
-};
-
-#endif // GAMEINFOIMPL_H
diff --git a/src/helper.h b/src/helper.h
index 36f10db1..410e2527 100644
--- a/src/helper.h
+++ b/src/helper.h
@@ -21,7 +21,7 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#define HELPER_H
-#include <QString>
+#include <string>
/**
diff --git a/src/installationmanager.cpp b/src/installationmanager.cpp
index 1e06965d..739948cd 100644
--- a/src/installationmanager.cpp
+++ b/src/installationmanager.cpp
@@ -18,6 +18,7 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
*/
#include "installationmanager.h"
+
#include "utility.h"
#include "report.h"
#include "categories.h"
@@ -32,9 +33,9 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#include "modinfo.h"
#include <scopeguard.h>
#include <installationtester.h>
-#include <gameinfo.h>
#include <utility.h>
#include <scopeguard.h>
+
#include <QFileInfo>
#include <QLibrary>
#include <QInputDialog>
@@ -42,11 +43,14 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#include <QDir>
#include <QMessageBox>
#include <QSettings>
-#include <Shellapi.h>
#include <QPushButton>
#include <QApplication>
#include <QDateTime>
#include <QDirIterator>
+#include <QDebug>
+
+#include <Shellapi.h>
+
#include <boost/assign.hpp>
#include <boost/scoped_ptr.hpp>
@@ -81,16 +85,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)
@@ -100,35 +104,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);
}
@@ -139,11 +145,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);
}
@@ -151,15 +155,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);
}
}
@@ -181,10 +185,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;
}
@@ -225,25 +229,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)));
@@ -264,11 +273,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;
@@ -292,7 +301,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);
@@ -302,7 +311,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)
@@ -396,25 +405,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();
}
@@ -550,14 +559,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()));
}
}
@@ -581,6 +590,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
@@ -596,13 +606,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 {
@@ -688,16 +698,16 @@ 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: %s (%d)",
qPrintable(fileName),
- qPrintable(getErrorString(m_CurrentArchive->getLastError())),
- m_CurrentArchive->getLastError());
+ qPrintable(getErrorString(m_ArchiveHandler->getLastError())),
+ 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/loadmechanism.cpp b/src/loadmechanism.cpp
index 4f9f8b1b..8ca8464e 100644
--- a/src/loadmechanism.cpp
+++ b/src/loadmechanism.cpp
@@ -56,7 +56,7 @@ void LoadMechanism::writeHintFile(const QDir &targetDirectory)
}
-void LoadMechanism::removeHintFile(QDir &targetDirectory)
+void LoadMechanism::removeHintFile(QDir targetDirectory)
{
targetDirectory.remove("mo_path.txt");
}
@@ -64,7 +64,8 @@ void LoadMechanism::removeHintFile(QDir &targetDirectory)
bool LoadMechanism::isDirectLoadingSupported()
{
- IPluginGame *game = qApp->property("managed_game").value<IPluginGame*>();
+ //FIXME: Seriously? isn't there a 'do i need steam' thing?
+ IPluginGame const *game = qApp->property("managed_game").value<IPluginGame const *>();
if (game->gameName().compare("oblivion", Qt::CaseInsensitive) == 0) {
// oblivion can be loaded directly if it's not the steam variant
return !game->gameDirectory().exists("steam_api.dll");
@@ -76,13 +77,11 @@ bool LoadMechanism::isDirectLoadingSupported()
bool LoadMechanism::isScriptExtenderSupported()
{
- IPluginGame *game = qApp->property("managed_game").value<IPluginGame*>();
+ IPluginGame const *game = qApp->property("managed_game").value<IPluginGame const *>();
ScriptExtender *extender = game->feature<ScriptExtender>();
// test if there even is an extender for the managed game and if so whether it's installed
- return (extender != nullptr)
- && (game->gameDirectory().exists(extender->name() + "_loader.exe")
- || game->gameDirectory().exists(extender->name() + "_steam_loader.dll"));
+ return extender != nullptr && extender->isInstalled();
}
bool LoadMechanism::isProxyDLLSupported()
@@ -92,7 +91,7 @@ bool LoadMechanism::isProxyDLLSupported()
// plus: the proxy dll hasn't been working for at least the whole 1.12.x versions of MO and
// noone reported it so why maintain an unused feature?
return false;
-/* IPluginGame *game = qApp->property("managed_game").value<IPluginGame*>();
+/* IPluginGame const *game = qApp->property("managed_game").value<IPluginGame const *>();
return game->gameDirectory().exists(QString::fromStdWString(AppConfig::proxyDLLTarget()));*/
}
@@ -124,7 +123,7 @@ bool LoadMechanism::hashIdentical(const QString &fileNameLHS, const QString &fil
void LoadMechanism::deactivateScriptExtender()
{
try {
- IPluginGame *game = qApp->property("managed_game").value<IPluginGame*>();
+ IPluginGame const *game = qApp->property("managed_game").value<IPluginGame const *>();
ScriptExtender *extender = game->feature<ScriptExtender>();
if (extender == nullptr) {
throw MyException(QObject::tr("game doesn't support a script extender"));
@@ -154,7 +153,7 @@ void LoadMechanism::deactivateScriptExtender()
void LoadMechanism::deactivateProxyDLL()
{
try {
- IPluginGame *game = qApp->property("managed_game").value<IPluginGame*>();
+ IPluginGame const *game = qApp->property("managed_game").value<IPluginGame const *>();
QString targetPath = game->gameDirectory().absoluteFilePath(QString::fromStdWString(AppConfig::proxyDLLTarget()));
@@ -183,7 +182,7 @@ void LoadMechanism::deactivateProxyDLL()
void LoadMechanism::activateScriptExtender()
{
try {
- IPluginGame *game = qApp->property("managed_game").value<IPluginGame*>();
+ IPluginGame const *game = qApp->property("managed_game").value<IPluginGame const *>();
ScriptExtender *extender = game->feature<ScriptExtender>();
if (extender == nullptr) {
throw MyException(QObject::tr("game doesn't support a script extender"));
@@ -226,7 +225,7 @@ void LoadMechanism::activateScriptExtender()
void LoadMechanism::activateProxyDLL()
{
try {
- IPluginGame *game = qApp->property("managed_game").value<IPluginGame*>();
+ IPluginGame const *game = qApp->property("managed_game").value<IPluginGame const *>();
QString targetPath = game->gameDirectory().absoluteFilePath(QString::fromStdWString(AppConfig::proxyDLLTarget()));
diff --git a/src/loadmechanism.h b/src/loadmechanism.h
index 43a8dd6c..c04473ab 100644
--- a/src/loadmechanism.h
+++ b/src/loadmechanism.h
@@ -91,7 +91,7 @@ private:
void writeHintFile(const QDir &targetDirectory);
// remove the hint file if it exists. does nothing if the file doesn't exist
- void removeHintFile(QDir &targetDirectory);
+ void removeHintFile(QDir targetDirectory);
// compare the two files by md5-hash, returns true if they are identical
bool hashIdentical(const QString &fileNameLHS, const QString &fileNameRHS);
diff --git a/src/main.cpp b/src/main.cpp
index 7061a6e3..0258910c 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -26,21 +26,16 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <DbgHelp.h>
-#include <cstdarg>
+
#include <inject.h>
#include <appconfig.h>
#include <utility.h>
#include <scopeguard.h>
-#include <stdexcept>
#include "mainwindow.h"
#include <report.h>
#include "modlist.h"
#include "profile.h"
#include "gameinfo.h"
-#include "fallout3info.h"
-#include "falloutnvinfo.h"
-#include "oblivioninfo.h"
-#include "skyriminfo.h"
#include "spawn.h"
#include "executableslist.h"
#include "singleinstance.h"
@@ -51,11 +46,9 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#include "moapplication.h"
#include "tutorialmanager.h"
#include "nxmaccessmanager.h"
-#include <iostream>
-#include <ShellAPI.h>
#include <eh.h>
#include <windows_error.h>
-#include <boost/scoped_array.hpp>
+
#include <QApplication>
#include <QPushButton>
#include <QListWidget>
@@ -77,6 +70,14 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#include <QLibraryInfo>
#include <QSslSocket>
+#include <boost/scoped_array.hpp>
+
+#include <ShellAPI.h>
+
+#include <cstdarg>
+#include <iostream>
+#include <stdexcept>
+
#pragma comment(linker, "/manifestDependency:\"name='dlls' processorArchitecture='x86' version='1.0.0.0' type='win32' \"")
@@ -86,7 +87,8 @@ using namespace MOShared;
bool createAndMakeWritable(const std::wstring &subPath)
{
- QString fullPath = qApp->property("dataPath").toString() + "/" + QString::fromStdWString(subPath);
+ QString const dataPath = qApp->property("dataPath").toString();
+ QString fullPath = dataPath + "/" + QString::fromStdWString(subPath);
if (!QDir(fullPath).exists()) {
QDir().mkdir(fullPath);
@@ -100,7 +102,7 @@ bool createAndMakeWritable(const std::wstring &subPath)
"will be made writable for the current user account). You will be asked to run "
"\"helper.exe\" with administrative rights."),
QMessageBox::Yes | QMessageBox::Cancel) == QMessageBox::Yes) {
- if (!Helper::init(GameInfo::instance().getOrganizerDirectory())) {
+ if (!Helper::init(dataPath.toStdWString())) {
return false;
}
} else {
@@ -316,6 +318,124 @@ QString determineProfile(QStringList &arguments, const QSettings &settings)
return selectedProfileName;
}
+MOBase::IPluginGame *selectGame(QSettings &settings, QDir const &gamePath, MOBase::IPluginGame *game)
+{
+ settings.setValue("gameName", game->gameName());
+ //Sadly, hookdll needs gamePath in order to run. So following code block is
+ //commented out
+ /*if (gamePath == game->gameDirectory()) {
+ settings.remove("gamePath");
+ } else*/ {
+ QString gameDir = gamePath.absolutePath();
+ game->setGamePath(gameDir);
+ settings.setValue("gamePath", QDir::toNativeSeparators(gameDir).toUtf8().constData());
+ }
+ return game; //Woot
+}
+
+
+MOBase::IPluginGame *determineCurrentGame(QString const &moPath, QSettings &settings, PluginContainer const &plugins)
+{
+ //Determine what game we are running where. Be very paranoid in case the
+ //user has done something odd.
+ //If the game name has been set up, use that.
+ QString gameName = settings.value("gameName", "").toString();
+ if (!gameName.isEmpty()) {
+ MOBase::IPluginGame *game = plugins.managedGame(gameName);
+ if (game == nullptr) {
+ reportError(QObject::tr("Plugin to handle %1 no longer installed").arg(gameName));
+ return nullptr;
+ }
+ QString gamePath = QString::fromUtf8(settings.value("gamePath", "").toByteArray());
+ if (gamePath == "") {
+ gamePath = game->gameDirectory().absolutePath();
+ }
+ QDir gameDir(gamePath);
+ if (game->looksValid(gameDir)) {
+ return selectGame(settings, gameDir, game);
+ }
+ }
+
+ //gameName wasn't set, or otherwise can't be found. Try looking through all
+ //the plugins using the gamePath
+ QString gamePath = QString::fromUtf8(settings.value("gamePath", "").toByteArray());
+ if (!gamePath.isEmpty()) {
+ QDir gameDir(gamePath);
+ //Look to see if one of the installed games binary file exists in the current
+ //game directory.
+ for (IPluginGame * const game : plugins.plugins<IPluginGame>()) {
+ if (game->looksValid(gameDir)) {
+ return selectGame(settings, gameDir, game);
+ }
+ }
+ }
+
+ //OK, we are in a new setup or existing info is useless.
+ //See if MO has been installed inside a game directory
+ for (IPluginGame * const game : plugins.plugins<IPluginGame>()) {
+ if (game->isInstalled() && moPath.startsWith(game->gameDirectory().absolutePath())) {
+ //Found it.
+ return selectGame(settings, game->gameDirectory(), game);
+ }
+ }
+
+ //Try walking up the directory tree to see if MO has been installed inside a game
+ {
+ QDir gameDir(moPath);
+ do {
+ //Look to see if one of the installed games binary file exists in the current
+ //directory.
+ for (IPluginGame * const game : plugins.plugins<IPluginGame>()) {
+ if (game->looksValid(gameDir)) {
+ return selectGame(settings, gameDir, game);
+ }
+ }
+ //OK, chop off the last directory and try again
+ } while (gameDir.cdUp());
+ }
+
+ //Then try a selection dialogue.
+ if (!gamePath.isEmpty() || !gameName.isEmpty()) {
+ reportError(QObject::tr("Could not use configuration settings for game \"%1\", path \"%2\".").
+ arg(gameName).arg(gamePath));
+ }
+
+ SelectionDialog selection(QObject::tr("Please select the game to manage"), nullptr, QSize(32, 32));
+
+ for (IPluginGame *game : plugins.plugins<IPluginGame>()) {
+ if (game->isInstalled()) {
+ QString path = game->gameDirectory().absolutePath();
+ selection.addChoice(game->gameIcon(), game->gameName(), path, QVariant::fromValue(game));
+ }
+ }
+
+ selection.addChoice(QString("Browse..."), QString(), QVariant::fromValue(static_cast<IPluginGame *>(nullptr)));
+
+ while (selection.exec() != QDialog::Rejected) {
+ IPluginGame * game = selection.getChoiceData().value<IPluginGame *>();
+ if (game != nullptr) {
+ return selectGame(settings, game->gameDirectory(), game);
+ }
+
+ gamePath = QFileDialog::getExistingDirectory(
+ nullptr, QObject::tr("Please select the game to manage"), QString(),
+ QFileDialog::ShowDirsOnly);
+
+ if (!gamePath.isEmpty()) {
+ QDir gameDir(gamePath);
+ for (IPluginGame * const game : plugins.plugins<IPluginGame>()) {
+ if (game->looksValid(gameDir)) {
+ return selectGame(settings, gameDir, game);
+ }
+ }
+ reportError(QObject::tr("No game identified in \"%1\". The directory is required to contain "
+ "the game binary and its launcher.").arg(gamePath));
+ }
+ }
+
+ return nullptr;
+}
+
int main(int argc, char *argv[])
{
MOApplication application(argc, argv);
@@ -328,7 +448,7 @@ int main(int argc, char *argv[])
instanceID = instanceFile.readAll().trimmed();
}
- QString dataPath =
+ QString const dataPath =
instanceID.isEmpty() ? application.applicationDirPath()
: QDir::fromNativeSeparators(
QStandardPaths::writableLocation(QStandardPaths::DataLocation)
@@ -360,7 +480,7 @@ int main(int argc, char *argv[])
QSplashScreen splash(pixmap);
try {
- if (!bootstrap()) { // requires gameinfo to be initialised!
+ if (!bootstrap()) {
return -1;
}
@@ -429,63 +549,19 @@ int main(int argc, char *argv[])
PluginContainer pluginContainer(&organizer);
pluginContainer.loadPlugins();
- QString gamePath = QString::fromUtf8(settings.value("gamePath", "").toByteArray());
- bool done = false;
- while (!done) {
- if (!GameInfo::init(ToWString(application.applicationDirPath()), ToWString(dataPath), ToWString(QDir::toNativeSeparators(gamePath)))) {
- if (!gamePath.isEmpty()) {
- reportError(QObject::tr("No game identified in \"%1\". The directory is required to contain "
- "the game binary and its launcher.").arg(gamePath));
- }
- SelectionDialog selection(QObject::tr("Please select the game to manage"), nullptr, QSize(32, 32));
-
- for (const IPluginGame * const game : pluginContainer.plugins<IPluginGame>()) {
- if (game->isInstalled()) {
- QString path = game->gameDirectory().absolutePath();
- selection.addChoice(game->gameIcon(), game->gameName(), path, path);
- }
- }
-
- selection.addChoice(QString("Browse..."), QString(), QString());
-
- if (selection.exec() == QDialog::Rejected) {
- gamePath = "";
- done = true;
- } else {
- gamePath = QDir::cleanPath(selection.getChoiceData().toString());
- if (gamePath.isEmpty()) {
- gamePath = QFileDialog::getExistingDirectory(
- nullptr, QObject::tr("Please select the game to manage"), QString(),
- QFileDialog::ShowDirsOnly);
- qDebug() << "manually selected path " << gamePath;
- }
- }
- } else {
- done = true;
- gamePath = ToQString(GameInfo::instance().getGameDirectory());
- }
+ MOBase::IPluginGame *game = determineCurrentGame(application.applicationDirPath(), settings, pluginContainer);
+ if (game == nullptr) {
+ return 1;
}
- if (gamePath.isEmpty()) {
- // game not found and user canceled
- return -1;
- } else if (gamePath.length() != 0) {
- // user selected a folder and game was initialised with it
- qDebug("game path: %s", qPrintable(gamePath));
- settings.setValue("gamePath", gamePath.toUtf8().constData());
- }
+ organizer.setManagedGame(game);
- organizer.setManagedGame(ToQString(GameInfo::instance().getGameName()), gamePath);
+ //*sigh just for making it work
+ GameInfo::init(application.applicationDirPath().toStdWString(), game->gameDirectory().absolutePath().toStdWString());
organizer.createDefaultProfile();
- if (pluginContainer.managedGame(ToQString(GameInfo::instance().getGameName())) == nullptr) {
- reportError(QObject::tr("Plugin to handle %1 not installed").arg(ToQString(GameInfo::instance().getGameName())));
- return 1;
- }
-
- IPluginGame *game = organizer.managedGame();
-
+ //See the pragma - we apparently don't use this so not sure why we check it
if (!settings.contains("game_edition")) {
QStringList editions = game->gameVariants();
if (editions.size() > 1) {
@@ -504,7 +580,7 @@ int main(int argc, char *argv[])
game->setGameVariant(settings.value("game_edition").toString());
#pragma message("edition isn't used?")
- qDebug("managing game at %s", qPrintable(QDir::toNativeSeparators(gamePath)));
+ qDebug("managing game at %s", qPrintable(QDir::toNativeSeparators(game->gameDirectory().absolutePath())));
organizer.updateExecutablesList(settings);
diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp
index a3a5bf38..edcfe223 100644
--- a/src/mainwindow.cpp
+++ b/src/mainwindow.cpp
@@ -19,6 +19,7 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#include "mainwindow.h"
#include "ui_mainwindow.h"
+
#include "spawn.h"
#include "report.h"
#include "modlist.h"
@@ -52,17 +53,18 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#include "credentialsdialog.h"
#include "selectiondialog.h"
#include "csvbuilder.h"
-#include "gameinfoimpl.h"
#include "savetextasdialog.h"
#include "problemsdialog.h"
#include "previewdialog.h"
#include "browserdialog.h"
#include "aboutdialog.h"
#include "safewritefile.h"
-#include "organizerproxy.h"
+//?
+//#include "isavegame.h"
+//#include "savegameinfo.h"
+//?
#include "nxmaccessmanager.h"
#include <archive.h>
-#include <gameinfo.h>
#include <appconfig.h>
#include <utility.h>
#include <ipluginproxy.h>
@@ -71,15 +73,12 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#include <questionboxmemory.h>
#include <taskprogressmanager.h>
#include <util.h>
-#include <map>
-#include <ctime>
-#include <wchar.h>
-#include <utility.h>
+#include <scopeguard.h>
+
#include <QTime>
#include <QInputDialog>
#include <QSettings>
#include <QWhatsThis>
-#include <sstream>
#include <QProcess>
#include <QMenu>
#include <QBuffer>
@@ -101,10 +100,6 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#include <QtPlugin>
#include <QIdentityProxyModel>
#include <QClipboard>
-#include <Psapi.h>
-#include <shlobj.h>
-#include <ShellAPI.h>
-#include <TlHelp32.h>
#include <QNetworkInterface>
#include <QNetworkProxy>
#include <QJsonDocument>
@@ -119,7 +114,7 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#endif
#include <QCoreApplication>
#include <QProgressDialog>
-#include <scopeguard.h>
+
#ifndef Q_MOC_RUN
#include <boost/thread.hpp>
#include <boost/algorithm/string.hpp>
@@ -127,8 +122,19 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#include <boost/foreach.hpp>
#include <boost/assign.hpp>
#endif
+
+#include <Psapi.h>
+#include <shlobj.h>
+#include <ShellAPI.h>
+#include <TlHelp32.h>
+
+#include <sstream>
#include <regex>
#include <functional>
+#include <map>
+#include <ctime>
+#include <wchar.h>
+#include <utility.h>
#ifdef TEST_MODELS
#include "modeltest.h"
@@ -154,7 +160,6 @@ MainWindow::MainWindow(const QString &exeName
, m_ModListGroupingProxy(nullptr)
, m_ModListSortProxy(nullptr)
, m_OldExecutableIndex(-1)
- , m_GamePath(ToQString(GameInfo::instance().getGameDirectory()))
, m_CategoryFactory(CategoryFactory::instance())
, m_ContextItem(nullptr)
, m_ContextAction(nullptr)
@@ -352,7 +357,7 @@ MainWindow::~MainWindow()
void MainWindow::updateWindowTitle(const QString &accountName, bool premium)
{
QString title = QString("%1 Mod Organizer v%2").arg(
- ToQString(GameInfo::instance().getGameName()),
+ m_OrganizerCore.managedGame()->gameName(),
m_OrganizerCore.getVersion().displayString());
if (!accountName.isEmpty()) {
@@ -818,7 +823,8 @@ void MainWindow::setBrowserGeometry(const QByteArray &geometry)
SaveGameGamebryo *MainWindow::getSaveGame(const QString &name)
{
- return new SaveGameGamebryo(this, name);
+ IPluginGame const *game = m_OrganizerCore.managedGame();
+ return new SaveGameGamebryo(this, name, game);
}
@@ -1023,9 +1029,9 @@ void MainWindow::on_profileBox_currentIndexChanged(int index)
if (ui->profileBox->currentIndex() == 0) {
ui->profileBox->setCurrentIndex(previousIndex);
- ProfilesDialog(ui->profileBox->currentText(), this).exec();
+ ProfilesDialog(ui->profileBox->currentText(), m_OrganizerCore.managedGame(), this).exec();
while (!refreshProfiles()) {
- ProfilesDialog(ui->profileBox->currentText(), this).exec();
+ ProfilesDialog(ui->profileBox->currentText(), m_OrganizerCore.managedGame(), this).exec();
}
} else {
activateSelectedProfile();
@@ -1250,9 +1256,11 @@ QDir MainWindow::currentSavesDir() const
savesDir.setPath(m_OrganizerCore.currentProfile()->absolutePath() + "/saves");
} else {
wchar_t path[MAX_PATH];
- ::GetPrivateProfileStringW(L"General", L"SLocalSavePath", L"Saves",
- path, MAX_PATH,
- (ToWString(m_OrganizerCore.currentProfile()->absolutePath()) + L"\\" + GameInfo::instance().getIniFileNames().at(0)).c_str());
+ ::GetPrivateProfileStringW(
+ L"General", L"SLocalSavePath", L"Saves",
+ path, MAX_PATH,
+ ToWString(m_OrganizerCore.currentProfile()->absolutePath() + "/" +
+ m_OrganizerCore.managedGame()->getIniFiles()[0]).c_str());
savesDir.setPath(m_OrganizerCore.managedGame()->documentsDirectory().absoluteFilePath(QString::fromWCharArray(path)));
}
@@ -1646,16 +1654,18 @@ void MainWindow::on_actionInstallMod_triggered()
void MainWindow::on_actionAdd_Profile_triggered()
{
- bool repeat = true;
- while (repeat) {
- ProfilesDialog profilesDialog(m_GamePath, this);
+ for (;;) {
+ //Note: Calling this with an invalid profile name. Not quite sure why
+ ProfilesDialog profilesDialog(m_OrganizerCore.managedGame()->gameDirectory().absolutePath(),
+ m_OrganizerCore.managedGame(),
+ this);
// workaround: need to disable monitoring of the saves directory, otherwise the active
// profile directory is locked
stopMonitorSaves();
profilesDialog.exec();
refreshSaveList(); // since the save list may now be outdated we have to refresh it completely
if (refreshProfiles() && !profilesDialog.failed()) {
- repeat = false;
+ break;
}
}
// addProfile();
@@ -2353,12 +2363,22 @@ void MainWindow::visitOnNexus_clicked()
{
int modID = m_OrganizerCore.modList()->data(m_OrganizerCore.modList()->index(m_ContextRow, 0), Qt::UserRole).toInt();
if (modID > 0) {
- nexusLinkActivated(QString("%1/mods/%2").arg(ToQString(GameInfo::instance().getNexusPage(false))).arg(modID));
+ nexusLinkActivated(NexusInterface::instance()->getModURL(modID));
} else {
MessageDialog::showMessage(tr("Nexus ID for this Mod is unknown"), this);
}
}
+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);
@@ -2905,12 +2925,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()));
}
@@ -2973,7 +3003,7 @@ void MainWindow::deleteSavegame_clicked()
foreach (const QModelIndex &idx, selectedIndexes) {
QString name = idx.data().toString();
- SaveGame *save = new SaveGame(this, idx.data(Qt::UserRole).toString());
+ SaveGame *save = new SaveGame(this, idx.data(Qt::UserRole).toString(), m_OrganizerCore.managedGame());
if (count < 10) {
savesMsgLabel += "<li>" + QFileInfo(name).completeBaseName() + "</li>";
@@ -3029,9 +3059,9 @@ void MainWindow::fixMods_clicked()
// search in data
{
- QDir dataDir(m_GamePath + "/data");
+ QDir dataDir(m_OrganizerCore.managedGame()->dataDirectory());
QStringList esps = dataDir.entryList(espFilter);
- foreach (const QString &esp, esps) {
+ for (const QString &esp : esps) {
std::map<QString, std::vector<QString> >::iterator iter = missingPlugins.find(esp);
if (iter != missingPlugins.end()) {
iter->second.push_back("<data>");
@@ -3045,7 +3075,7 @@ void MainWindow::fixMods_clicked()
ModInfo::Ptr modInfo = ModInfo::getByIndex(modIndex);
QStringList esps = QDir(modInfo->absolutePath()).entryList(espFilter);
- foreach (const QString &esp, esps) {
+ for (const QString &esp : esps) {
std::map<QString, std::vector<QString> >::iterator iter = missingPlugins.find(esp);
if (iter != missingPlugins.end()) {
iter->second.push_back(modInfo->name());
@@ -3057,7 +3087,7 @@ void MainWindow::fixMods_clicked()
{
QDir overwriteDir(qApp->property("dataPath").toString() + "/" + QString::fromStdWString(AppConfig::overwritePath()));
QStringList esps = overwriteDir.entryList(espFilter);
- foreach (const QString &esp, esps) {
+ for (const QString &esp : esps) {
std::map<QString, std::vector<QString> >::iterator iter = missingPlugins.find(esp);
if (iter != missingPlugins.end()) {
iter->second.push_back("<overwrite>");
@@ -3221,7 +3251,9 @@ void MainWindow::on_actionSettings_triggered()
void MainWindow::on_actionNexus_triggered()
{
- ::ShellExecuteW(nullptr, L"open", GameInfo::instance().getNexusPage(false).c_str(), nullptr, nullptr, SW_SHOWNORMAL);
+ ::ShellExecuteW(nullptr, L"open",
+ NexusInterface::instance()->getGameURL().toStdWString().c_str(),
+ nullptr, nullptr, SW_SHOWNORMAL);
}
@@ -3615,9 +3647,11 @@ void MainWindow::on_actionUpdate_triggered()
void MainWindow::on_actionEndorseMO_triggered()
{
if (QMessageBox::question(this, tr("Endorse Mod Organizer"),
- tr("Do you want to endorse Mod Organizer on %1 now?").arg(ToQString(GameInfo::instance().getNexusPage())),
+ tr("Do you want to endorse Mod Organizer on %1 now?").arg(
+ NexusInterface::instance()->getGameURL()),
QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {
- NexusInterface::instance()->requestToggleEndorsement(GameInfo::instance().getNexusModID(), true, this, QVariant(), QString());
+ NexusInterface::instance()->requestToggleEndorsement(
+ m_OrganizerCore.managedGame()->getNexusModOrganizerID(), true, this, QVariant(), QString());
}
}
@@ -3680,7 +3714,7 @@ void MainWindow::nxmUpdatesAvailable(const std::vector<int> &modIDs, QVariant us
QVariantList resultList = resultData.toList();
for (auto iter = resultList.begin(); iter != resultList.end(); ++iter) {
QVariantMap result = iter->toMap();
- if (result["id"].toInt() == GameInfo::instance().getNexusModID()) {
+ if (result["id"].toInt() == m_OrganizerCore.managedGame()->getNexusModOrganizerID()) {
if (!result["voted_by_user"].toBool()) {
ui->actionEndorseMO->setVisible(true);
}
@@ -4170,8 +4204,8 @@ void MainWindow::on_bossButton_clicked()
parameters << "--unattended"
<< "--stdout"
<< "--noreport"
- << "--game" << ToQString(GameInfo::instance().getGameShortName())
- << "--gamePath" << QString("\"%1\"").arg(ToQString(GameInfo::instance().getGameDirectory()))
+ << "--game" << m_OrganizerCore.managedGame()->getGameShortName()
+ << "--gamePath" << QString("\"%1\"").arg(m_OrganizerCore.managedGame()->gameDirectory().absolutePath())
<< "--out" << outPath;
if (m_DidUpdateMasterList) {
@@ -4303,12 +4337,12 @@ void MainWindow::on_bossButton_clicked()
// if the game specifies load order by file time, our own load order file needs to be removed because it's outdated.
// refreshESPList will then use the file time as the load order.
- if (GameInfo::instance().getLoadOrderMechanism() == GameInfo::TYPE_FILETIME) {
+ if (m_OrganizerCore.managedGame()->getLoadOrderMechanism() == IPluginGame::LoadOrderMechanism::FileTime) {
qDebug("removing loadorder.txt");
QFile::remove(m_OrganizerCore.currentProfile()->getLoadOrderFileName());
}
m_OrganizerCore.refreshESPList();
- if (GameInfo::instance().getLoadOrderMechanism() == GameInfo::TYPE_FILETIME) {
+ if (m_OrganizerCore.managedGame()->getLoadOrderMechanism() == IPluginGame::LoadOrderMechanism::FileTime) {
// the load order should have been retrieved from file time, now save it to our own format
m_OrganizerCore.savePluginList();
}
diff --git a/src/mainwindow.h b/src/mainwindow.h
index 44f46f4b..489f9145 100644
--- a/src/mainwindow.h
+++ b/src/mainwindow.h
@@ -280,15 +280,11 @@ private:
int m_OldExecutableIndex;
- QString m_GamePath;
-
int m_ContextRow;
QPersistentModelIndex m_ContextIdx;
QTreeWidgetItem *m_ContextItem;
QAction *m_ContextAction;
- //int m_SelectedSaveGame;
-
CategoryFactory &m_CategoryFactory;
int m_ModsToUpdate;
@@ -352,6 +348,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 e0d888e6..8bc767c5 100644
--- a/src/modinfo.cpp
+++ b/src/modinfo.cpp
@@ -19,29 +19,27 @@ 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 <gameinfo.h>
#include <iplugingame.h>
#include <versioninfo.h>
#include <appconfig.h>
#include <scriptextender.h>
#include <QApplication>
-
#include <QDirIterator>
#include <QMutexLocker>
#include <QSettings>
-#include <sstream>
-
using namespace MOBase;
using namespace MOShared;
@@ -203,7 +201,10 @@ unsigned int ModInfo::findMod(const boost::function<bool (ModInfo::Ptr)> &filter
}
-void ModInfo::updateFromDisc(const QString &modDirectory, DirectoryEntry **directoryStructure, bool displayForeign)
+void ModInfo::updateFromDisc(const QString &modDirectory,
+ DirectoryEntry **directoryStructure,
+ bool displayForeign,
+ MOBase::IPluginGame const *game)
{
QMutexLocker lock(&s_Mutex);
s_Collection.clear();
@@ -219,19 +220,25 @@ void ModInfo::updateFromDisc(const QString &modDirectory, DirectoryEntry **direc
}
{ // list plugins in the data directory and make a foreign-managed mod out of each
- std::vector<std::wstring> dlcPlugins = GameInfo::instance().getDLCPlugins();
- QDir dataDir(QDir::fromNativeSeparators(ToQString(GameInfo::instance().getGameDirectory())) + "/data");
- foreach (const QFileInfo &file, dataDir.entryInfoList(QStringList() << "*.esp" << "*.esm")) {
- if ((file.baseName() != "Update") // hide update
- && (file.baseName() != ToQString(GameInfo::instance().getGameName())) // hide the game esp
+ QStringList dlcPlugins = game->getDLCPlugins();
+ QStringList mainPlugins = game->getPrimaryPlugins();
+ QDir dataDir(game->dataDirectory());
+ for (const QString &file : dataDir.entryList({ "*.esp", "*.esm" })) {
+ if (std::find_if(mainPlugins.begin(), mainPlugins.end(),
+ [&file](QString const &p) {
+ return p.compare(file, Qt::CaseInsensitive) == 0; }) == mainPlugins.end()
&& (displayForeign // show non-dlc bundles only if the user wants them
- || std::find(dlcPlugins.begin(), dlcPlugins.end(), ToWString(file.fileName())) != dlcPlugins.end())) {
+ || std::find_if(dlcPlugins.begin(), dlcPlugins.end(),
+ [&file](QString const &p) {
+ return p.compare(file, Qt::CaseInsensitive) == 0; }) != dlcPlugins.end())) {
+
+ QFileInfo f(file); //Just so I can get a basename...
QStringList archives;
- foreach (const QString archiveName, dataDir.entryList(QStringList() << file.baseName() + "*.bsa")) {
+ for (const QString &archiveName : dataDir.entryList({ f.baseName() + "*.bsa" })) {
archives.append(dataDir.absoluteFilePath(archiveName));
}
- createFromPlugin(file.fileName(), archives, directoryStructure);
+ createFromPlugin(file, archives, directoryStructure);
}
}
}
@@ -281,7 +288,10 @@ int ModInfo::checkAllForUpdate(QObject *receiver)
int result = 0;
std::vector<int> modIDs;
- modIDs.push_back(GameInfo::instance().getNexusModID());
+ //I ought to store this, it's used elsewhere
+ IPluginGame const *game = qApp->property("managed_game").value<IPluginGame const *>();
+
+ modIDs.push_back(game->getNexusModOrganizerID());
for (const ModInfo::Ptr &mod : s_Collection) {
if (mod->canBeUpdated()) {
@@ -386,772 +396,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 &notes)
-{
- 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;
-}
-
-
-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
-{
- 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/modinfo.h b/src/modinfo.h
index da97b09b..ae22ccd8 100644
--- a/src/modinfo.h
+++ b/src/modinfo.h
@@ -20,22 +20,25 @@ 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 <QString>
+class QDateTime;
+class QDir;
#include <QMutex>
-#include <QIcon>
-#include <QDir>
#include <QSharedPointer>
-#include <QDateTime>
+#include <QString>
+#include <QStringList>
+
+#include <boost/function.hpp>
+
#include <map>
#include <set>
#include <vector>
-#include <directoryentry.h>
-using MOBase::ModRepositoryFileInfo;
+namespace MOBase { class IPluginGame; }
+namespace MOShared { class DirectoryEntry; }
/**
* @brief Represents meta information about a single mod.
@@ -103,7 +106,10 @@ public:
/**
* @brief read the mod directory and Mod ModInfo objects for all subdirectories
**/
- static void updateFromDisc(const QString &modDirectory, MOShared::DirectoryEntry **directoryStructure, bool displayForeign);
+ static void updateFromDisc(const QString &modDirectory,
+ MOShared::DirectoryEntry **directoryStructure,
+ bool displayForeign,
+ MOBase::IPluginGame const *game);
static void clear() { s_Collection.clear(); s_ModsByName.clear(); s_ModsByModID.clear(); }
@@ -556,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:
/**
@@ -596,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 &notes);
-
- /**
- * @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 35da228b..feaac2d4 100644
--- a/src/modinfodialog.cpp
+++ b/src/modinfodialog.cpp
@@ -20,6 +20,8 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#include "modinfodialog.h"
#include "ui_modinfodialog.h"
+#include "iplugingame.h"
+#include "nexusinterface.h"
#include "report.h"
#include "utility.h"
#include "messagedialog.h"
@@ -27,7 +29,6 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#include "questionboxmemory.h"
#include "settings.h"
#include "categories.h"
-#include <gameinfo.h>
#include <QDir>
#include <QDirIterator>
@@ -36,9 +37,11 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#include <QMessageBox>
#include <QMenu>
#include <QFileSystemModel>
+#include <QInputDialog>
+
#include <Shlwapi.h>
+
#include <sstream>
-#include <QInputDialog>
using namespace MOBase;
@@ -688,7 +691,9 @@ void ModInfoDialog::on_visitNexusLabel_linkActivated(const QString &link)
void ModInfoDialog::linkClicked(const QUrl &url)
{
- if (url.toString().startsWith(ToQString(GameInfo::instance().getNexusPage(false)))) {
+ //Ideally we'd ask the mod for the game and the web service then pass the game
+ //and URL to the web service
+ if (NexusInterface::instance()->isURLGameRelated(url)) {
this->close();
emit nexusLinkActivated(url.toString());
} else {
@@ -832,12 +837,11 @@ void ModInfoDialog::activateNexusTab()
QLineEdit *modIDEdit = findChild<QLineEdit*>("modIDEdit");
int modID = modIDEdit->text().toInt();
if (modID != 0) {
- QString nexusLink = QString("%1/downloads/file.php?id=%2").arg(ToQString(GameInfo::instance().getNexusPage(false))).arg(modID);
+ QString nexusLink = NexusInterface::instance()->getModURL(modID);
QLabel *visitNexusLabel = findChild<QLabel*>("visitNexusLabel");
visitNexusLabel->setText(tr("<a href=\"%1\">Visit on Nexus</a>").arg(nexusLink));
visitNexusLabel->setToolTip(nexusLink);
-
if (m_ModInfo->getNexusDescription().isEmpty() ||
QDateTime::currentDateTime() > m_ModInfo->getLastNexusQuery().addDays(1)) {
refreshNexusData(modID);
diff --git a/src/modinfoforeign.cpp b/src/modinfoforeign.cpp
new file mode 100644
index 00000000..4dbe034b
--- /dev/null
+++ b/src/modinfoforeign.cpp
@@ -0,0 +1,54 @@
+#include "modinfoforeign.h"
+
+#include "iplugingame.h"
+#include "utility.h"
+
+#include <QApplication>
+
+using namespace MOBase;
+using namespace MOShared;
+
+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/modinfoforeign.h b/src/modinfoforeign.h
new file mode 100644
index 00000000..b35c099b
--- /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 QString(); }
+ 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..b6cdfb43
--- /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 QString(); }
+ 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 &notes)
+{
+ 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 &notes);
+
+ /**
+ * @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/modlist.cpp b/src/modlist.cpp
index 197250a3..9d7f32c8 100644
--- a/src/modlist.cpp
+++ b/src/modlist.cpp
@@ -24,15 +24,14 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#include "qtgroupingproxy.h"
#include "viewmarkingscrollbar.h"
#include "modlistsortproxy.h"
-#include <gameinfo.h>
#include <appconfig.h>
#include <utility.h>
#include <report.h>
+
#include <QFileInfo>
#include <QDir>
#include <QDirIterator>
#include <QMimeData>
-#include <stdexcept>
#include <QStandardItemModel>
#include <QMessageBox>
#include <QStringList>
@@ -44,7 +43,9 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#include <QAbstractItemView>
#include <QSortFilterProxyModel>
#include <QApplication>
+
#include <sstream>
+#include <stdexcept>
#include <algorithm>
diff --git a/src/nexusinterface.cpp b/src/nexusinterface.cpp
index 38660176..79749523 100644
--- a/src/nexusinterface.cpp
+++ b/src/nexusinterface.cpp
@@ -18,14 +18,18 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
*/
#include "nexusinterface.h"
+
+#include "iplugingame.h"
#include "nxmaccessmanager.h"
#include "json.h"
#include "selectiondialog.h"
-#include <QApplication>
#include <utility.h>
-#include <regex>
#include <util.h>
+#include <QApplication>
+
+#include <regex>
+
using namespace MOBase;
using namespace MOShared;
@@ -33,34 +37,33 @@ using namespace MOShared;
NexusBridge::NexusBridge(const QString &subModule)
: m_Interface(NexusInterface::instance())
- , m_Url() // lazy initialized
, m_SubModule(subModule)
{
}
void NexusBridge::requestDescription(int modID, QVariant userData)
{
- m_RequestIDs.insert(m_Interface->requestDescription(modID, this, userData, m_SubModule, url()));
+ m_RequestIDs.insert(m_Interface->requestDescription(modID, this, userData, m_SubModule));
}
void NexusBridge::requestFiles(int modID, QVariant userData)
{
- m_RequestIDs.insert(m_Interface->requestFiles(modID, this, userData, m_SubModule, url()));
+ m_RequestIDs.insert(m_Interface->requestFiles(modID, this, userData, m_SubModule));
}
void NexusBridge::requestFileInfo(int modID, int fileID, QVariant userData)
{
- m_RequestIDs.insert(m_Interface->requestFileInfo(modID, fileID, this, userData, m_SubModule, url()));
+ m_RequestIDs.insert(m_Interface->requestFileInfo(modID, fileID, this, userData, m_SubModule));
}
void NexusBridge::requestDownloadURL(int modID, int fileID, QVariant userData)
{
- m_RequestIDs.insert(m_Interface->requestDownloadURL(modID, fileID, this, userData, m_SubModule, url()));
+ m_RequestIDs.insert(m_Interface->requestDownloadURL(modID, fileID, this, userData, m_SubModule));
}
void NexusBridge::requestToggleEndorsement(int modID, bool endorse, QVariant userData)
{
- m_RequestIDs.insert(m_Interface->requestToggleEndorsement(modID, endorse, this, userData, m_SubModule, url()));
+ m_RequestIDs.insert(m_Interface->requestToggleEndorsement(modID, endorse, this, userData, m_SubModule));
}
void NexusBridge::nxmDescriptionAvailable(int modID, QVariant userData, QVariant resultData, int requestID)
@@ -136,13 +139,6 @@ void NexusBridge::nxmRequestFailed(int modID, int fileID, QVariant userData, int
}
}
-QString NexusBridge::url() {
- if (m_Url.isEmpty()) {
- m_Url = MOBase::ToQString(MOShared::GameInfo::instance().getNexusInfoUrl());
- }
- return m_Url;
-}
-
QAtomicInt NexusInterface::NXMRequestInfo::s_NextID(0);
@@ -196,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();
@@ -217,8 +214,8 @@ void NexusInterface::interpretNexusFileName(const QString &fileName, QString &mo
QString r3Highlight(fileName);
r3Highlight.insert(result.position(3) + result.length(3), "* ").insert(result.position(3), " *");
- selection.addChoice(candidate.c_str(), r3Highlight, strtol(candidate.c_str(), nullptr, 10));
- selection.addChoice(candidate2.c_str() + offset, r2Highlight, abs(strtol(candidate2.c_str() + offset, nullptr, 10)));
+ selection.addChoice(candidate.c_str(), r3Highlight, static_cast<int>(strtol(candidate.c_str(), nullptr, 10)));
+ selection.addChoice(candidate2.c_str() + offset, r2Highlight, static_cast<int>(abs(strtol(candidate2.c_str() + offset, nullptr, 10))));
if (selection.exec() == QDialog::Accepted) {
modID = selection.getChoiceData().toInt();
} else {
@@ -231,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,12 +241,43 @@ void NexusInterface::interpretNexusFileName(const QString &fileName, QString &mo
}
}
+bool NexusInterface::isURLGameRelated(const QUrl &url) const
+{
+ QString const name(url.toString());
+ return name.startsWith(getGameURL() + "/") ||
+ name.startsWith(getOldModsURL() + "/");
+}
+
+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, const QString &url, int nexusGameId)
+ const QString &subModule, MOBase::IPluginGame const *game)
{
- NXMRequestInfo requestInfo(modID, NXMRequestInfo::TYPE_DESCRIPTION, userData, subModule, url,
- nexusGameId == -1 ? GameInfo::instance().getNexusGameID() : nexusGameId);
+ NXMRequestInfo requestInfo(modID, NXMRequestInfo::TYPE_DESCRIPTION, userData, subModule, game);
m_RequestQueue.enqueue(requestInfo);
connect(this, SIGNAL(nxmDescriptionAvailable(int,QVariant,QVariant,int)),
@@ -264,9 +292,9 @@ int NexusInterface::requestDescription(int modID, QObject *receiver, QVariant us
int NexusInterface::requestUpdates(const std::vector<int> &modIDs, QObject *receiver, QVariant userData,
- const QString &subModule, const QString &url)
+ const QString &subModule, MOBase::IPluginGame const *game)
{
- NXMRequestInfo requestInfo(modIDs, NXMRequestInfo::TYPE_GETUPDATES, userData, subModule, url, GameInfo::instance().getNexusGameID());
+ NXMRequestInfo requestInfo(modIDs, NXMRequestInfo::TYPE_GETUPDATES, userData, subModule, game);
m_RequestQueue.enqueue(requestInfo);
connect(this, SIGNAL(nxmUpdatesAvailable(std::vector<int>,QVariant,QVariant,int)),
@@ -300,9 +328,9 @@ void NexusInterface::fakeFiles()
int NexusInterface::requestFiles(int modID, QObject *receiver, QVariant userData,
- const QString &subModule, const QString &url)
+ const QString &subModule, MOBase::IPluginGame const *game)
{
- NXMRequestInfo requestInfo(modID, NXMRequestInfo::TYPE_FILES, userData, subModule, url, GameInfo::instance().getNexusGameID());
+ NXMRequestInfo requestInfo(modID, NXMRequestInfo::TYPE_FILES, userData, subModule, game);
m_RequestQueue.enqueue(requestInfo);
connect(this, SIGNAL(nxmFilesAvailable(int,QVariant,QVariant,int)),
receiver, SLOT(nxmFilesAvailable(int,QVariant,QVariant,int)), Qt::UniqueConnection);
@@ -320,9 +348,9 @@ int NexusInterface::requestFiles(int modID, QObject *receiver, QVariant userData
int NexusInterface::requestFileInfo(int modID, int fileID, QObject *receiver, QVariant userData, const QString &subModule,
- const QString &url)
+ MOBase::IPluginGame const *game)
{
- NXMRequestInfo requestInfo(modID, fileID, NXMRequestInfo::TYPE_FILEINFO, userData, subModule, url, GameInfo::instance().getNexusGameID());
+ NXMRequestInfo requestInfo(modID, fileID, NXMRequestInfo::TYPE_FILEINFO, userData, subModule, game);
m_RequestQueue.enqueue(requestInfo);
connect(this, SIGNAL(nxmFileInfoAvailable(int,int,QVariant,QVariant,int)),
@@ -337,9 +365,9 @@ int NexusInterface::requestFileInfo(int modID, int fileID, QObject *receiver, QV
int NexusInterface::requestDownloadURL(int modID, int fileID, QObject *receiver, QVariant userData,
- const QString &subModule, const QString &url)
+ const QString &subModule, MOBase::IPluginGame const *game)
{
- NXMRequestInfo requestInfo(modID, fileID, NXMRequestInfo::TYPE_DOWNLOADURL, userData, subModule, url, GameInfo::instance().getNexusGameID());
+ NXMRequestInfo requestInfo(modID, fileID, NXMRequestInfo::TYPE_DOWNLOADURL, userData, subModule, game);
m_RequestQueue.enqueue(requestInfo);
connect(this, SIGNAL(nxmDownloadURLsAvailable(int,int,QVariant,QVariant,int)),
@@ -354,9 +382,9 @@ int NexusInterface::requestDownloadURL(int modID, int fileID, QObject *receiver,
int NexusInterface::requestToggleEndorsement(int modID, bool endorse, QObject *receiver, QVariant userData,
- const QString &subModule, const QString &url)
+ const QString &subModule, MOBase::IPluginGame const *game)
{
- NXMRequestInfo requestInfo(modID, NXMRequestInfo::TYPE_TOGGLEENDORSEMENT, userData, subModule, url, GameInfo::instance().getNexusGameID());
+ NXMRequestInfo requestInfo(modID, NXMRequestInfo::TYPE_TOGGLEENDORSEMENT, userData, subModule, game);
requestInfo.m_Endorse = endorse;
m_RequestQueue.enqueue(requestInfo);
@@ -559,13 +587,24 @@ void NexusInterface::requestTimeout()
}
}
+void NexusInterface::managedGameChanged(IPluginGame const *game)
+{
+ m_Game = game;
+}
+
+namespace {
+ QString get_management_url(MOBase::IPluginGame const *game)
+ {
+ return "http://nmm.nexusmods.com/" + game->getGameShortName().toLower();
+ }
+}
NexusInterface::NXMRequestInfo::NXMRequestInfo(int modID
, NexusInterface::NXMRequestInfo::Type type
, QVariant userData
, const QString &subModule
- , const QString &url
- , int nexusGameId)
+ , MOBase::IPluginGame const *game
+ )
: m_ModID(modID)
, m_FileID(0)
, m_Reply(nullptr)
@@ -574,9 +613,9 @@ NexusInterface::NXMRequestInfo::NXMRequestInfo(int modID
, m_Timeout(nullptr)
, m_Reroute(false)
, m_ID(s_NextID.fetchAndAddAcquire(1))
- , m_URL(url)
+ , m_URL(get_management_url(game))
, m_SubModule(subModule)
- , m_NexusGameID(nexusGameId)
+ , m_NexusGameID(game->getNexusGameID())
, m_Endorse(false)
{}
@@ -584,8 +623,8 @@ NexusInterface::NXMRequestInfo::NXMRequestInfo(std::vector<int> modIDList
, NexusInterface::NXMRequestInfo::Type type
, QVariant userData
, const QString &subModule
- , const QString &url
- , int nexusGameId)
+ , MOBase::IPluginGame const *game
+ )
: m_ModID(-1)
, m_ModIDList(modIDList)
, m_FileID(0)
@@ -595,9 +634,9 @@ NexusInterface::NXMRequestInfo::NXMRequestInfo(std::vector<int> modIDList
, m_Timeout(nullptr)
, m_Reroute(false)
, m_ID(s_NextID.fetchAndAddAcquire(1))
- , m_URL(url)
+ , m_URL(get_management_url(game))
, m_SubModule(subModule)
- , m_NexusGameID(nexusGameId)
+ , m_NexusGameID(game->getNexusGameID())
, m_Endorse(false)
{}
@@ -606,8 +645,8 @@ NexusInterface::NXMRequestInfo::NXMRequestInfo(int modID
, NexusInterface::NXMRequestInfo::Type type
, QVariant userData
, const QString &subModule
- , const QString &url
- , int nexusGameId)
+ , MOBase::IPluginGame const *game
+ )
: m_ModID(modID)
, m_FileID(fileID)
, m_Reply(nullptr)
@@ -616,8 +655,8 @@ NexusInterface::NXMRequestInfo::NXMRequestInfo(int modID
, m_Timeout(nullptr)
, m_Reroute(false)
, m_ID(s_NextID.fetchAndAddAcquire(1))
- , m_URL(url)
+ , m_URL(get_management_url(game))
, m_SubModule(subModule)
- , m_NexusGameID(nexusGameId)
+ , m_NexusGameID(game->getNexusGameID())
, m_Endorse(false)
{}
diff --git a/src/nexusinterface.h b/src/nexusinterface.h
index c0ee50cd..c9a81134 100644
--- a/src/nexusinterface.h
+++ b/src/nexusinterface.h
@@ -20,20 +20,20 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#ifndef NEXUSINTERFACE_H
#define NEXUSINTERFACE_H
-
-
#include <utility.h>
-#include <gameinfo.h>
#include <versioninfo.h>
#include <imodrepositorybridge.h>
+
#include <QNetworkReply>
#include <QNetworkDiskCache>
#include <QQueue>
#include <QVariant>
#include <QTimer>
+
#include <list>
#include <set>
+namespace MOBase { class IPluginGame; }
class NexusInterface;
class NXMAccessManager;
@@ -108,12 +108,7 @@ public slots:
private:
- QString url();
-
-private:
-
NexusInterface *m_Interface;
- QString m_Url;
QString m_SubModule;
std::set<int> m_RequestIDs;
@@ -150,26 +145,64 @@ public:
/**
* @brief request description for a mod
*
+ * @param modID id of the mod caller is interested in (assumed to be for the current game)
+ * @param receiver the object to receive the result asynchronously via a signal (nxmDescriptionAvailable)
+ * @param userData user data to be returned with the result
+ * @return int an id to identify the request
+ **/
+ int requestDescription(int modID, QObject *receiver, QVariant userData, const QString &subModule)
+ {
+ return requestDescription(modID, receiver, userData, subModule, m_Game);
+ }
+
+ /**
+ * @brief request description for a mod
+ *
* @param modID id of the mod caller is interested in
* @param receiver the object to receive the result asynchronously via a signal (nxmDescriptionAvailable)
* @param userData user data to be returned with the result
- * @param url the url to request from
+ * @param game Game with which the mod is associated
* @return int an id to identify the request
**/
int requestDescription(int modID, QObject *receiver, QVariant userData, const QString &subModule,
- const QString &url = MOBase::ToQString(MOShared::GameInfo::instance().getNexusInfoUrl()),
- int nexusGameId = -1);
+ MOBase::IPluginGame const *game);
+
+ /**
+ * @brief request nexus descriptions for multiple mods at once
+ * @param modIDs a list of ids of mods the caller is interested in (assumed to be for the current game)
+ * @param receiver the object to receive the result asynchronously via a signal (nxmDescriptionAvailable)
+ * @param userData user data to be returned with the result
+ * @return int an id to identify the request
+ */
+ int requestUpdates(const std::vector<int> &modIDs, QObject *receiver, QVariant userData, const QString &subModule)
+ {
+ return requestUpdates(modIDs, receiver, userData, subModule, m_Game);
+ }
/**
* @brief request nexus descriptions for multiple mods at once
* @param modIDs a list of ids of mods the caller is interested in
* @param receiver the object to receive the result asynchronously via a signal (nxmDescriptionAvailable)
* @param userData user data to be returned with the result
- * @param url the url to request from
+ * @param game the game with which the mods are associated
* @return int an id to identify the request
*/
int requestUpdates(const std::vector<int> &modIDs, QObject *receiver, QVariant userData, const QString &subModule,
- const QString &url = MOBase::ToQString(MOShared::GameInfo::instance().getNexusInfoUrl()));
+ MOBase::IPluginGame const *game);
+
+ /**
+ * @brief request a list of the files belonging to a mod
+ *
+ * @param modID id of the mod caller is interested in (assumed to be for the current game)
+ * @param receiver the object to receive the result asynchronously via a signal (nxmFilesAvailable)
+ * @param userData user data to be returned with the result
+ * @return int an id to identify the request
+ **/
+ int requestFiles(int modID, QObject *receiver, QVariant userData, const QString &subModule)
+ {
+ return requestFiles(modID, receiver, userData, subModule, m_Game);
+ }
+
/**
* @brief request a list of the files belonging to a mod
@@ -177,24 +210,52 @@ public:
* @param modID id of the mod caller is interested in
* @param receiver the object to receive the result asynchronously via a signal (nxmFilesAvailable)
* @param userData user data to be returned with the result
- * @param url the url to request from
+ * @param game the game with which the mods are associated
* @return int an id to identify the request
**/
int requestFiles(int modID, QObject *receiver, QVariant userData, const QString &subModule,
- const QString &url = MOBase::ToQString(MOShared::GameInfo::instance().getNexusInfoUrl()));
+ MOBase::IPluginGame const *game);
/**
* @brief request info about a single file of a mod
*
- * @param modID id of the mod caller is interested in
+ * @param modID id of the mod caller is interested in (assumed to be for the current game)
* @param fileID id of the file the caller is interested in
* @param receiver the object to receive the result asynchronously via a signal (nxmFilesAvailable)
* @param userData user data to be returned with the result
- * @param url the url to request from
+ * @return int an id to identify the request
+ **/
+ int requestFileInfo(int modID, int fileID, QObject *receiver, QVariant userData, const QString &subModule)
+ {
+ return requestFileInfo(modID, fileID, receiver, userData, subModule, m_Game);
+ }
+
+ /**
+ * @brief request info about a single file of a mod
+ *
+ * @param modID id of the mod caller is interested in (assumed to be for the current game)
+ * @param fileID id of the file the caller is interested in
+ * @param receiver the object to receive the result asynchronously via a signal (nxmFilesAvailable)
+ * @param userData user data to be returned with the result
+ * @param game the game with which the mods are associated
* @return int an id to identify the request
**/
int requestFileInfo(int modID, int fileID, QObject *receiver, QVariant userData, const QString &subModule,
- const QString &url = MOBase::ToQString(MOShared::GameInfo::instance().getNexusInfoUrl()));
+ MOBase::IPluginGame const *game);
+
+ /**
+ * @brief request the download url of a file
+ *
+ * @param modID id of the mod caller is interested in (assumed to be for the current game)
+ * @param fileID id of the file the caller is interested in
+ * @param receiver the object to receive the result asynchronously via a signal (nxmFilesAvailable)
+ * @param userData user data to be returned with the result
+ * @return int an id to identify the request
+ **/
+ int requestDownloadURL(int modID, int fileID, QObject *receiver, QVariant userData, const QString &subModule)
+ {
+ return requestDownloadURL(modID, fileID, receiver, userData, subModule, m_Game);
+ }
/**
* @brief request the download url of a file
@@ -203,11 +264,23 @@ public:
* @param fileID id of the file the caller is interested in
* @param receiver the object to receive the result asynchronously via a signal (nxmFilesAvailable)
* @param userData user data to be returned with the result
- * @param url the url to request from
+ * @param game the game with which the mods are associated
* @return int an id to identify the request
**/
- int requestDownloadURL(int modID, int fileID, QObject *receiver, QVariant userData, const QString &subModule,
- const QString &url = MOBase::ToQString(MOShared::GameInfo::instance().getNexusInfoUrl()));
+ int requestDownloadURL(int modID, int fileID, QObject *receiver, QVariant userData, const QString &subModule, MOBase::IPluginGame const *game);
+
+ /**
+ * @brief toggle endorsement state of the mod
+ * @param modID id of the mod (assumed to be for the current game)
+ * @param endorse true if the mod should be endorsed, false for un-endorse
+ * @param receiver the object to receive the result asynchronously via a signal (nxmFilesAvailable)
+ * @param userData user data to be returned with the result
+ * @return int an id to identify the request
+ */
+ int requestToggleEndorsement(int modID, bool endorse, QObject *receiver, QVariant userData, const QString &subModule)
+ {
+ return requestToggleEndorsement(modID, endorse, receiver, userData, subModule, m_Game);
+ }
/**
* @brief toggle endorsement state of the mod
@@ -215,11 +288,11 @@ public:
* @param endorse true if the mod should be endorsed, false for un-endorse
* @param receiver the object to receive the result asynchronously via a signal (nxmFilesAvailable)
* @param userData user data to be returned with the result
- * @param url the url to request from
+ * @param game the game with which the mods are associated
* @return int an id to identify the request
*/
int requestToggleEndorsement(int modID, bool endorse, QObject *receiver, QVariant userData, const QString &subModule,
- const QString &url = MOBase::ToQString(MOShared::GameInfo::instance().getNexusInfoUrl()));
+ MOBase::IPluginGame const *game);
/**
* @param directory the directory to store cache files
@@ -247,6 +320,39 @@ public:
*/
static void interpretNexusFileName(const QString &fileName, QString &modName, int &modID, bool query);
+ /**
+ * @brief get the currently managed game
+ */
+ MOBase::IPluginGame const *managedGame() const;
+
+ /**
+ * @brief see if the passed URL is related to the current game
+ *
+ * Arguably, this should optionally take a gameplugin pointer
+ */
+ bool isURLGameRelated(QUrl const &url) const;
+
+ /**
+ * @brief Get the nexus page for the current game
+ *
+ * Arguably, this should optionally take a gameplugin pointer
+ */
+ QString getGameURL() const;
+
+ /**
+ * @brief Get the URL for the mod web page
+ * @param modID
+ */
+ 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);
@@ -261,6 +367,9 @@ signals:
void nxmEndorsementToggled(int modID, QVariant userData, QVariant resultData, int requestID);
void nxmRequestFailed(int modID, int fileID, QVariant userData, int requestID, const QString &errorString);
+public slots:
+ void managedGameChanged(MOBase::IPluginGame const *game);
+
private slots:
void requestFinished();
@@ -295,9 +404,9 @@ private:
int m_ID;
int m_Endorse;
- NXMRequestInfo(int modID, Type type, QVariant userData, const QString &subModule, const QString &url, int nexusGameId);
- NXMRequestInfo(std::vector<int> modIDList, Type type, QVariant userData, const QString &subModule, const QString &url, int nexusGameId);
- NXMRequestInfo(int modID, int fileID, Type type, QVariant userData, const QString &subModule, const QString &url, int nexusGameId);
+ NXMRequestInfo(int modID, Type type, QVariant userData, const QString &subModule, MOBase::IPluginGame const *game);
+ NXMRequestInfo(std::vector<int> modIDList, Type type, QVariant userData, const QString &subModule, MOBase::IPluginGame const *game);
+ NXMRequestInfo(int modID, int fileID, Type type, QVariant userData, const QString &subModule, MOBase::IPluginGame const *game);
private:
static QAtomicInt s_NextID;
@@ -311,6 +420,7 @@ private:
void nextRequest();
void requestFinished(std::list<NXMRequestInfo>::iterator iter);
bool requiresLogin(const NXMRequestInfo &info);
+ QString getOldModsURL() const;
private:
@@ -324,6 +434,8 @@ private:
MOBase::VersionInfo m_MOVersion;
QString m_NMMVersion;
+ MOBase::IPluginGame const *m_Game;
+
};
#endif // NEXUSINTERFACE_H
diff --git a/src/nxmaccessmanager.cpp b/src/nxmaccessmanager.cpp
index e6479a7e..cdf50fd8 100644
--- a/src/nxmaccessmanager.cpp
+++ b/src/nxmaccessmanager.cpp
@@ -18,6 +18,8 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
*/
#include "nxmaccessmanager.h"
+
+#include "iplugingame.h"
#include "nxmurl.h"
#include "report.h"
#include "utility.h"
@@ -25,7 +27,6 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#include "persistentcookiejar.h"
#include "settings.h"
#include <gameinfo.h>
-#include <json.h>
#include <QMessageBox>
#include <QPushButton>
#include <QNetworkProxy>
@@ -39,10 +40,11 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#include <QJsonDocument>
#include <QJsonArray>
-
using namespace MOBase;
-using namespace MOShared;
+namespace {
+ QString const Nexus_Management_URL("http://nmm.nexusmods.com");
+}
// unfortunately Nexus doesn't seem to document these states, all I know is all these listed
// are considered premium (27 should be lifetime premium)
@@ -101,8 +103,7 @@ QNetworkReply *NXMAccessManager::createRequest(
void NXMAccessManager::showCookies() const
{
- QUrl url(ToQString(GameInfo::instance().getNexusPage()) + "/");
-
+ QUrl url(Nexus_Management_URL + "/");
for (const QNetworkCookie &cookie : cookieJar()->cookiesForUrl(url)) {
qDebug("%s - %s (expires: %s)",
cookie.name().constData(), cookie.value().constData(),
@@ -115,7 +116,7 @@ void NXMAccessManager::startLoginCheck()
{
if (hasLoginCookies()) {
qDebug("validating login cookies");
- QNetworkRequest request(ToQString(GameInfo::instance().getNexusPage()) + "/Sessions/?Validate");
+ QNetworkRequest request(Nexus_Management_URL + "/Sessions/?Validate");
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
request.setRawHeader("User-Agent", userAgent().toUtf8());
@@ -132,9 +133,8 @@ void NXMAccessManager::startLoginCheck()
void NXMAccessManager::retrieveCredentials()
{
qDebug("retrieving credentials");
- QNetworkRequest request(ToQString(GameInfo::instance().getNexusPage())
- + QString("/Core/Libs/Flamework/Entities/User?GetCredentials&game_id=%1"
- ).arg(GameInfo::instance().getNexusGameID()));
+
+ QNetworkRequest request(Nexus_Management_URL + "/Core/Libs/Flamework/Entities/User?GetCredentials");
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
request.setRawHeader("User-Agent", userAgent().toUtf8());
@@ -229,8 +229,9 @@ QString NXMAccessManager::userAgent(const QString &subModule) const
void NXMAccessManager::pageLogin()
{
qDebug("logging %s in on Nexus", qPrintable(m_Username));
- QString requestString = (ToQString(GameInfo::instance().getNexusPage()) + "/Sessions/?Login&uri=%1")
- .arg(QString(QUrl::toPercentEncoding(ToQString(GameInfo::instance().getNexusPage()))));
+
+ QString requestString = (Nexus_Management_URL + "/Sessions/?Login&uri=%1")
+ .arg(QString(QUrl::toPercentEncoding(Nexus_Management_URL)));
QNetworkRequest request(requestString);
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
@@ -294,15 +295,14 @@ void NXMAccessManager::loginError(QNetworkReply::NetworkError)
bool NXMAccessManager::hasLoginCookies() const
{
- bool sidCookie = false;
- QUrl url(ToQString(GameInfo::instance().getNexusPage()) + "/");
+ QUrl url(Nexus_Management_URL + "/");
QList<QNetworkCookie> cookies = cookieJar()->cookiesForUrl(url);
for (const QNetworkCookie &cookie : cookies) {
if (cookie.name() == "sid") {
- sidCookie = true;
+ return true;
}
}
- return sidCookie;
+ return false;
}
@@ -343,4 +343,3 @@ void NXMAccessManager::loginChecked()
m_LoginReply->deleteLater();
m_LoginReply = nullptr;
}
-
diff --git a/src/nxmaccessmanager.h b/src/nxmaccessmanager.h
index a03dbe36..82bd2bd5 100644
--- a/src/nxmaccessmanager.h
+++ b/src/nxmaccessmanager.h
@@ -27,6 +27,7 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#include <QProgressDialog>
#include <set>
+namespace MOBase { class IPluginGame; }
/**
* @brief access manager extended to handle nxm links
@@ -84,8 +85,6 @@ private slots:
void loginError(QNetworkReply::NetworkError errorCode);
void loginTimeout();
-public slots:
-
protected:
virtual QNetworkReply *createRequest(
diff --git a/src/organizer.pro b/src/organizer.pro
index 261e3c1c..1284aa40 100644
--- a/src/organizer.pro
+++ b/src/organizer.pro
@@ -70,7 +70,6 @@ SOURCES += \
moapplication.cpp \
profileinputdialog.cpp \
icondelegate.cpp \
- gameinfoimpl.cpp \
csvbuilder.cpp \
savetextasdialog.cpp \
qtgroupingproxy.cpp \
@@ -91,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 += \
@@ -145,7 +149,6 @@ HEADERS += \
moapplication.h \
profileinputdialog.h \
icondelegate.h \
- gameinfoimpl.h \
csvbuilder.h \
savetextasdialog.h \
qtgroupingproxy.h \
@@ -167,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 \
@@ -234,6 +242,10 @@ INCLUDEPATH += "E:/Visual Leak Detector/include"
LIBS += -L"E:/Visual Leak Detector/lib/Win32"
#DEFINES += LEAK_CHECK_WITH_VLD
+#########################FUDGE###############################
+INCLUDEPATH += ../plugins/gameGamebryo
+#############################################################
+
# custom leak detection
#LIBS += -lDbgHelp
@@ -355,10 +367,10 @@ CONFIG(debug, debug|release) {
}
OTHER_FILES += \
- SConscript
+ SConscript \
+ CMakeLists.txt
DISTFILES += \
tutorials/tutorial_primer_main.js \
tutorials/Tooltip.qml \
- tutorials/TooltipArea.qml \
- SConscript
+ tutorials/TooltipArea.qml
diff --git a/src/organizercore.cpp b/src/organizercore.cpp
index 89cdd4e6..fdc11c2a 100644
--- a/src/organizercore.cpp
+++ b/src/organizercore.cpp
@@ -1,6 +1,7 @@
#include "organizercore.h"
+
+#include "iplugingame.h"
#include "mainwindow.h"
-#include "gameinfoimpl.h"
#include "messagedialog.h"
#include "logbuffer.h"
#include "credentialsdialog.h"
@@ -20,11 +21,14 @@
#include <appconfig.h>
#include <report.h>
#include <questionboxmemory.h>
+
#include <QNetworkInterface>
#include <QMessageBox>
#include <QDialogButtonBox>
#include <QApplication>
+
#include <Psapi.h>
+
#include <functional>
@@ -119,8 +123,7 @@ QStringList toStringList(InputIterator current, InputIterator end)
OrganizerCore::OrganizerCore(const QSettings &initSettings)
- : m_GameInfo(new GameInfoImpl())
- , m_UserInterface(nullptr)
+ : m_UserInterface(nullptr)
, m_PluginContainer(nullptr)
, m_GameName()
, m_CurrentProfile(nullptr)
@@ -160,7 +163,11 @@ OrganizerCore::OrganizerCore(const QSettings &initSettings)
connect(NexusInterface::instance()->getAccessManager(), SIGNAL(loginSuccessful(bool)), this, SLOT(loginSuccessful(bool)));
connect(NexusInterface::instance()->getAccessManager(), SIGNAL(loginFailed(QString)), this, SLOT(loginFailed(QString)));
- connect(this, SIGNAL(managedGameChanged(MOBase::IPluginGame*)), &m_Settings, SLOT(managedGameChanged(MOBase::IPluginGame*)));
+ //This seems awfully imperative
+ connect(this, SIGNAL(managedGameChanged(MOBase::IPluginGame const *)), &m_Settings, SLOT(managedGameChanged(MOBase::IPluginGame const *)));
+ connect(this, SIGNAL(managedGameChanged(MOBase::IPluginGame const *)), &m_DownloadManager, SLOT(managedGameChanged(MOBase::IPluginGame const *)));
+ connect(this, SIGNAL(managedGameChanged(MOBase::IPluginGame const *)), &m_PluginList, SLOT(managedGameChanged(MOBase::IPluginGame const *)));
+ connect(this, SIGNAL(managedGameChanged(MOBase::IPluginGame const *)), NexusInterface::instance(), SLOT(managedGameChanged(MOBase::IPluginGame const *)));
connect(&m_PluginList, &PluginList::writePluginsList, &m_PluginListsWriter, &DelayedFileWriterBase::write);
@@ -187,7 +194,6 @@ OrganizerCore::~OrganizerCore()
m_ModList.setProfile(nullptr);
NexusInterface::instance()->cleanup();
- delete m_GameInfo;
delete m_DirectoryStructure;
}
@@ -325,7 +331,7 @@ void OrganizerCore::updateExecutablesList(QSettings &settings)
return;
}
- m_ExecutablesList.init(m_PluginContainer->managedGame(ToQString(GameInfo::instance().getGameName())));
+ m_ExecutablesList.init(managedGame());
qDebug("setting up configured executables");
@@ -353,7 +359,7 @@ void OrganizerCore::updateExecutablesList(QSettings &settings)
settings.endArray();
// TODO this has nothing to do with executables list move to an appropriate function!
- ModInfo::updateFromDisc(m_Settings.getModDirectory(), &m_DirectoryStructure, m_Settings.displayForeign());
+ ModInfo::updateFromDisc(m_Settings.getModDirectory(), &m_DirectoryStructure, m_Settings.displayForeign(), managedGame());
}
void OrganizerCore::setUserInterface(IUserInterface *userInterface, QWidget *widget)
@@ -396,6 +402,14 @@ void OrganizerCore::connectPlugins(PluginContainer *container)
m_GamePlugin = m_PluginContainer->managedGame(m_GameName);
emit managedGameChanged(m_GamePlugin);
}
+ //Do this the hard way
+ for (const IPluginGame * const game : container->plugins<IPluginGame>()) {
+ QString n = game->getGameShortName();
+ if (game->getGameShortName() == "Skyrim") {
+ m_Updater.setNexusDownload(game);
+ break;
+ }
+ }
}
void OrganizerCore::disconnectPlugins()
@@ -411,15 +425,12 @@ void OrganizerCore::disconnectPlugins()
m_PluginContainer = nullptr;
}
-void OrganizerCore::setManagedGame(const QString &gameName, const QString &gamePath)
+void OrganizerCore::setManagedGame(MOBase::IPluginGame const *game)
{
- m_GameName = gameName;
- if (m_PluginContainer != nullptr) {
- m_GamePlugin = m_PluginContainer->managedGame(m_GameName);
- m_GamePlugin->setGamePath(gamePath);
- qApp->setProperty("managed_game", QVariant::fromValue(m_GamePlugin));
- emit managedGameChanged(m_GamePlugin);
- }
+ m_GameName = game->gameName();
+ m_GamePlugin = game;
+ qApp->setProperty("managed_game", QVariant::fromValue(m_GamePlugin));
+ emit managedGameChanged(m_GamePlugin);
}
Settings &OrganizerCore::settings()
@@ -563,11 +574,6 @@ void OrganizerCore::setCurrentProfile(const QString &profileName)
refreshDirectoryStructure();
}
-MOBase::IGameInfo &OrganizerCore::gameInfo() const
-{
- return *m_GameInfo;
-}
-
MOBase::IModRepositoryBridge *OrganizerCore::createNexusBridge() const
{
return new NexusBridge();
@@ -601,14 +607,10 @@ MOBase::VersionInfo OrganizerCore::appVersion() const
return m_Updater.getVersion();
}
-MOBase::IModInterface *OrganizerCore::getMod(const QString &name)
+MOBase::IModInterface *OrganizerCore::getMod(const QString &name) const
{
unsigned int index = ModInfo::getIndex(name);
- if (index == UINT_MAX) {
- return nullptr;
- } else {
- return ModInfo::getByIndex(index).data();
- }
+ return index == UINT_MAX ? nullptr : ModInfo::getByIndex(index).data();
}
MOBase::IModInterface *OrganizerCore::createMod(GuessedValue<QString> &name)
@@ -938,12 +940,12 @@ void OrganizerCore::spawnBinary(const QFileInfo &binary, const QString &argument
refreshDirectoryStructure();
// need to remove our stored load order because it may be outdated if a foreign tool changed the
// file time. After removing that file, refreshESPList will use the file time as the order
- if (GameInfo::instance().getLoadOrderMechanism() == GameInfo::TYPE_FILETIME) {
+ if (managedGame()->getLoadOrderMechanism() == IPluginGame::LoadOrderMechanism::FileTime) {
qDebug("removing loadorder.txt");
QFile::remove(m_CurrentProfile->getLoadOrderFileName());
}
refreshESPList();
- if (GameInfo::instance().getLoadOrderMechanism() == GameInfo::TYPE_FILETIME) {
+ if (managedGame()->getLoadOrderMechanism() == IPluginGame::LoadOrderMechanism::FileTime) {
// the load order should have been retrieved from file time, now save it to our own format
savePluginList();
}
@@ -969,7 +971,11 @@ HANDLE OrganizerCore::spawnBinaryDirect(const QFileInfo &binary, const QString &
::SetEnvironmentVariableW(L"SteamAPPId", ToWString(m_Settings.getSteamAppID()).c_str());
}
- if ((GameInfo::instance().requiresSteam())
+
+ //This could possibly be extracted somewhere else but it's probably for when
+ //we have more than one provider of game registration.
+ if ((QFileInfo(managedGame()->gameDirectory().absoluteFilePath("steam_api.dll")).exists()
+ || QFileInfo(managedGame()->gameDirectory().absoluteFilePath("steam_api64.dll")).exists())
&& (m_Settings.getLoadMechanism() == LoadMechanism::LOAD_MODORGANIZER)) {
if (!testForSteam()) {
QWidget *window = qApp->activeWindow();
@@ -1026,7 +1032,7 @@ HANDLE OrganizerCore::startApplication(const QString &executable, const QStringL
binary = QFileInfo(executable);
if (binary.isRelative()) {
// relative path, should be relative to game directory
- binary = QFileInfo(QDir::fromNativeSeparators(ToQString(GameInfo::instance().getGameDirectory())) + "/" + executable);
+ binary = QFileInfo(managedGame()->gameDirectory().absoluteFilePath(executable));
}
if (cwd.length() == 0) {
currentDirectory = binary.absolutePath();
@@ -1142,7 +1148,7 @@ void OrganizerCore::refreshModList(bool saveChanges)
if (saveChanges) {
m_CurrentProfile->modlistWriter().writeImmediately(true);
}
- ModInfo::updateFromDisc(m_Settings.getModDirectory(), &m_DirectoryStructure, m_Settings.displayForeign());
+ ModInfo::updateFromDisc(m_Settings.getModDirectory(), &m_DirectoryStructure, m_Settings.displayForeign(), managedGame());
m_CurrentProfile->refreshModStatus();
@@ -1317,7 +1323,7 @@ PluginListSortProxy *OrganizerCore::createPluginListProxyModel()
return result;
}
-IPluginGame *OrganizerCore::managedGame() const
+IPluginGame const *OrganizerCore::managedGame() const
{
return m_GamePlugin;
}
@@ -1378,7 +1384,7 @@ void OrganizerCore::directory_refreshed()
void OrganizerCore::profileRefresh()
{
// have to refresh mods twice (again in refreshModList), otherwise the refresh isn't complete. Not sure why
- ModInfo::updateFromDisc(m_Settings.getModDirectory(), &m_DirectoryStructure, m_Settings.displayForeign());
+ ModInfo::updateFromDisc(m_Settings.getModDirectory(), &m_DirectoryStructure, m_Settings.displayForeign(), managedGame());
m_CurrentProfile->refreshModStatus();
refreshModList();
diff --git a/src/organizercore.h b/src/organizercore.h
index 74814461..86994f6d 100644
--- a/src/organizercore.h
+++ b/src/organizercore.h
@@ -74,7 +74,7 @@ public:
void connectPlugins(PluginContainer *container);
void disconnectPlugins();
- void setManagedGame(const QString &gameName, const QString &gamePath);
+ void setManagedGame(const MOBase::IPluginGame *game);
void updateExecutablesList(QSettings &settings);
@@ -100,7 +100,7 @@ public:
ModListSortProxy *createModListProxyModel();
PluginListSortProxy *createPluginListProxyModel();
- MOBase::IPluginGame *managedGame() const;
+ MOBase::IPluginGame const *managedGame() const;
bool isArchivesInit() const { return m_ArchivesInit; }
@@ -129,13 +129,12 @@ public:
void prepareVFS();
public:
- MOBase::IGameInfo &gameInfo() const;
MOBase::IModRepositoryBridge *createNexusBridge() const;
QString profileName() const;
QString profilePath() const;
QString downloadsPath() const;
MOBase::VersionInfo appVersion() const;
- MOBase::IModInterface *getMod(const QString &name);
+ MOBase::IModInterface *getMod(const QString &name) const;
MOBase::IModInterface *createMod(MOBase::GuessedValue<QString> &name);
bool removeMod(MOBase::IModInterface *mod);
void modDataChanged(MOBase::IModInterface *mod);
@@ -200,7 +199,7 @@ signals:
*/
void modInstalled(const QString &modName);
- void managedGameChanged(MOBase::IPluginGame *gamePlugin);
+ void managedGameChanged(MOBase::IPluginGame const *gamePlugin);
private:
@@ -236,12 +235,10 @@ private:
private:
- MOBase::IGameInfo *m_GameInfo;
-
IUserInterface *m_UserInterface;
PluginContainer *m_PluginContainer;
QString m_GameName;
- MOBase::IPluginGame *m_GamePlugin;
+ MOBase::IPluginGame const *m_GamePlugin;
Profile *m_CurrentProfile;
diff --git a/src/organizerproxy.cpp b/src/organizerproxy.cpp
index 665b15d1..79ff50e5 100644
--- a/src/organizerproxy.cpp
+++ b/src/organizerproxy.cpp
@@ -1,7 +1,8 @@
#include "organizerproxy.h"
-#include <gameinfo.h>
+
#include <appconfig.h>
+#include <QApplication>
using namespace MOBase;
using namespace MOShared;
@@ -13,11 +14,6 @@ OrganizerProxy::OrganizerProxy(OrganizerCore *organizer, const QString &pluginNa
{
}
-IGameInfo &OrganizerProxy::gameInfo() const
-{
- return m_Proxied->gameInfo();
-}
-
IModRepositoryBridge *OrganizerProxy::createNexusBridge() const
{
return new NexusBridge(m_PluginName);
@@ -40,7 +36,7 @@ QString OrganizerProxy::downloadsPath() const
QString OrganizerProxy::overwritePath() const
{
- return QDir::fromNativeSeparators(ToQString(GameInfo::instance().getOrganizerDirectory()))
+ return QDir::fromNativeSeparators(qApp->property("dataPath").toString())
+ "/"
+ ToQString(AppConfig::overwritePath());
}
@@ -50,7 +46,7 @@ VersionInfo OrganizerProxy::appVersion() const
return m_Proxied->appVersion();
}
-IModInterface *OrganizerProxy::getMod(const QString &name)
+IModInterface *OrganizerProxy::getMod(const QString &name) const
{
return m_Proxied->getMod(name);
}
@@ -160,17 +156,22 @@ MOBase::IProfile *OrganizerProxy::profile()
return m_Proxied->currentProfile();
}
-MOBase::IDownloadManager *OrganizerProxy::downloadManager()
+MOBase::IDownloadManager *OrganizerProxy::downloadManager() const
{
return m_Proxied->downloadManager();
}
-MOBase::IPluginList *OrganizerProxy::pluginList()
+MOBase::IPluginList *OrganizerProxy::pluginList() const
{
return m_Proxied->pluginList();
}
-MOBase::IModList *OrganizerProxy::modList()
+MOBase::IModList *OrganizerProxy::modList() const
{
return m_Proxied->modList();
}
+
+MOBase::IPluginGame const *OrganizerProxy::managedGame() const
+{
+ return m_Proxied->managedGame();
+}
diff --git a/src/organizerproxy.h b/src/organizerproxy.h
index 029abcaf..02507dd7 100644
--- a/src/organizerproxy.h
+++ b/src/organizerproxy.h
@@ -12,14 +12,13 @@ public:
OrganizerProxy(OrganizerCore *organizer, const QString &pluginName);
- virtual MOBase::IGameInfo &gameInfo() const;
virtual MOBase::IModRepositoryBridge *createNexusBridge() const;
virtual QString profileName() const;
virtual QString profilePath() const;
virtual QString downloadsPath() const;
virtual QString overwritePath() const;
virtual MOBase::VersionInfo appVersion() const;
- virtual MOBase::IModInterface *getMod(const QString &name);
+ virtual MOBase::IModInterface *getMod(const QString &name) const;
virtual MOBase::IModInterface *createMod(MOBase::GuessedValue<QString> &name);
virtual bool removeMod(MOBase::IModInterface *mod);
virtual void modDataChanged(MOBase::IModInterface *mod);
@@ -36,9 +35,9 @@ public:
virtual QList<FileInfo> findFileInfos(const QString &path, const std::function<bool(const FileInfo&)> &filter) const;
virtual MOBase::IProfile *profile();
- virtual MOBase::IDownloadManager *downloadManager();
- virtual MOBase::IPluginList *pluginList();
- virtual MOBase::IModList *modList();
+ virtual MOBase::IDownloadManager *downloadManager() const;
+ virtual MOBase::IPluginList *pluginList() const;
+ virtual MOBase::IModList *modList() const;
virtual HANDLE startApplication(const QString &executable, const QStringList &args = QStringList(), const QString &cwd = "", const QString &profile = "");
virtual bool waitForApplication(HANDLE handle, LPDWORD exitCode = nullptr) const;
virtual void refreshModList(bool saveChanges);
@@ -47,6 +46,8 @@ public:
virtual bool onFinishedRun(const std::function<void (const QString&, unsigned int)> &func);
virtual bool onModInstalled(const std::function<void (const QString&)> &func);
+ virtual MOBase::IPluginGame const *managedGame() const;
+
private:
OrganizerCore *m_Proxied;
diff --git a/src/pluginlist.cpp b/src/pluginlist.cpp
index e7d493a7..7a609374 100644
--- a/src/pluginlist.cpp
+++ b/src/pluginlist.cpp
@@ -24,7 +24,6 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#include "scopeguard.h"
#include "modinfo.h"
#include <utility.h>
-#include <gameinfo.h>
#include <iplugingame.h>
#include <espfile.h>
#include <report.h>
@@ -128,7 +127,7 @@ void PluginList::refresh(const QString &profileName
m_ESPsByPriority.clear();
m_ESPs.clear();
- QStringList primaryPlugins = qApp->property("managed_game").value<IPluginGame*>()->getPrimaryPlugins();
+ QStringList primaryPlugins = m_GamePlugin->getPrimaryPlugins();
m_CurrentProfile = profileName;
@@ -313,7 +312,7 @@ bool PluginList::readLoadOrder(const QString &fileName)
int priority = 0;
- QStringList primaryPlugins = qApp->property("managed_game").value<IPluginGame*>()->getPrimaryPlugins();
+ QStringList primaryPlugins = m_GamePlugin->getPrimaryPlugins();
for (const QString &plugin : primaryPlugins) {
if (availableESPs.find(plugin) != availableESPs.end()) {
m_ESPLoadOrder[plugin] = priority++;
@@ -504,7 +503,7 @@ void PluginList::saveTo(const QString &pluginFileName
bool PluginList::saveLoadOrder(DirectoryEntry &directoryStructure)
{
- if (GameInfo::instance().getLoadOrderMechanism() != GameInfo::TYPE_FILETIME) {
+ if (m_GamePlugin->getLoadOrderMechanism() != IPluginGame::LoadOrderMechanism::FileTime) {
// nothing to do
return true;
}
@@ -1210,3 +1209,8 @@ PluginList::ESPInfo::ESPInfo(const QString &name, bool enabled,
m_IsDummy = false;
}
}
+
+void PluginList::managedGameChanged(IPluginGame const *gamePlugin)
+{
+ m_GamePlugin = gamePlugin;
+}
diff --git a/src/pluginlist.h b/src/pluginlist.h
index f8972f05..9fe6eeac 100644
--- a/src/pluginlist.h
+++ b/src/pluginlist.h
@@ -22,16 +22,20 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#include <directoryentry.h>
#include <ipluginlist.h>
+namespace MOBase { class IPluginGame; }
+
#include <QString>
#include <QListWidget>
#include <QTimer>
#include <QTemporaryFile>
+
#pragma warning(push)
#pragma warning(disable: 4100)
#ifndef Q_MOC_RUN
#include <boost/signals2.hpp>
#include <boost/ptr_container/ptr_vector.hpp>
#endif
+
#include <vector>
#include <map>
@@ -253,6 +257,12 @@ public slots:
**/
void disableAll();
+ /**
+ * @brief The currently managed game has changed
+ * @param gamePlugin
+ */
+ void managedGameChanged(MOBase::IPluginGame const *gamePlugin);
+
signals:
/**
@@ -337,6 +347,8 @@ private:
QTemporaryFile m_TempFile;
+ MOBase::IPluginGame const *m_GamePlugin;
+
};
#pragma warning(pop)
diff --git a/src/profile.cpp b/src/profile.cpp
index 0b9fa06f..24f094f3 100644
--- a/src/profile.cpp
+++ b/src/profile.cpp
@@ -18,7 +18,7 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
*/
#include "profile.h"
-#include "gameinfo.h"
+
#include "windows_error.h"
#include "modinfo.h"
#include "safewritefile.h"
@@ -30,26 +30,22 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#include <report.h>
#include <bsainvalidation.h>
#include <dataarchives.h>
+
#include <QMessageBox>
#include <QApplication>
#include <QSettings>
#include <QTemporaryFile>
+
#include <functional>
+#include <stdexcept>
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <shlobj.h>
-#include <stdexcept>
using namespace MOBase;
using namespace MOShared;
-
-Profile::Profile()
- : m_ModListWriter(std::bind(&Profile::writeModlistNow, this))
-{
-}
-
void Profile::touchFile(QString fileName)
{
QFile modList(m_Directory.filePath(fileName));
@@ -58,7 +54,7 @@ void Profile::touchFile(QString fileName)
}
}
-Profile::Profile(const QString &name, IPluginGame *gamePlugin, bool useDefaultSettings)
+Profile::Profile(const QString &name, IPluginGame const *gamePlugin, bool useDefaultSettings)
: m_ModListWriter(std::bind(&Profile::writeModlistNow, this))
, m_GamePlugin(gamePlugin)
{
@@ -99,8 +95,9 @@ Profile::Profile(const QString &name, IPluginGame *gamePlugin, bool useDefaultSe
}
-Profile::Profile(const QDir &directory, IPluginGame *gamePlugin)
+Profile::Profile(const QDir &directory, IPluginGame const *gamePlugin)
: m_Directory(directory)
+ , m_GamePlugin(gamePlugin)
, m_ModListWriter(std::bind(&Profile::writeModlistNow, this))
{
assert(gamePlugin != nullptr);
@@ -125,6 +122,8 @@ Profile::Profile(const QDir &directory, IPluginGame *gamePlugin)
Profile::Profile(const Profile &reference)
: m_Directory(reference.m_Directory)
, m_ModListWriter(std::bind(&Profile::writeModlistNow, this))
+ , m_GamePlugin(reference.m_GamePlugin)
+
{
refreshModStatus();
}
@@ -486,7 +485,7 @@ void Profile::setModPriority(unsigned int index, int &newPriority)
m_ModListWriter.write();
}
-Profile *Profile::createPtrFrom(const QString &name, const Profile &reference, MOBase::IPluginGame *gamePlugin)
+Profile *Profile::createPtrFrom(const QString &name, const Profile &reference, MOBase::IPluginGame const *gamePlugin)
{
QString profileDirectory = qApp->property("dataPath").toString() + "/" + QString::fromStdWString(AppConfig::profilesPath()) + "/" + name;
reference.copyFilesTo(profileDirectory);
@@ -568,10 +567,8 @@ void Profile::mergeTweaks(ModInfo::Ptr modInfo, const QString &tweakedIni) const
bool Profile::invalidationActive(bool *supported) const
{
- IPluginGame *gamePlugin = qApp->property("managed_game").value<IPluginGame*>();
-
- BSAInvalidation *invalidation = gamePlugin->feature<BSAInvalidation>();
- DataArchives *dataArchives = gamePlugin->feature<DataArchives>();
+ BSAInvalidation *invalidation = m_GamePlugin->feature<BSAInvalidation>();
+ DataArchives *dataArchives = m_GamePlugin->feature<DataArchives>();
if ((invalidation != nullptr) && (dataArchives != nullptr)) {
if (supported != nullptr) {
@@ -595,9 +592,7 @@ bool Profile::invalidationActive(bool *supported) const
void Profile::deactivateInvalidation()
{
- IPluginGame *gamePlugin = qApp->property("managed_game").value<IPluginGame*>();
-
- BSAInvalidation *invalidation = gamePlugin->feature<BSAInvalidation>();
+ BSAInvalidation *invalidation = m_GamePlugin->feature<BSAInvalidation>();
if (invalidation != nullptr) {
invalidation->deactivate(this);
@@ -607,9 +602,7 @@ void Profile::deactivateInvalidation()
void Profile::activateInvalidation()
{
- IPluginGame *gamePlugin = qApp->property("managed_game").value<IPluginGame*>();
-
- BSAInvalidation *invalidation = gamePlugin->feature<BSAInvalidation>();
+ BSAInvalidation *invalidation = m_GamePlugin->feature<BSAInvalidation>();
if (invalidation != nullptr) {
invalidation->activate(this);
@@ -683,8 +676,7 @@ QString Profile::getDeleterFileName() const
QString Profile::getIniFileName() const
{
- std::wstring primaryIniFile = *(GameInfo::instance().getIniFileNames().begin());
- return m_Directory.absoluteFilePath(ToQString(primaryIniFile));
+ return m_Directory.absoluteFilePath(m_GamePlugin->getIniFiles()[0]);
}
QString Profile::getProfileTweaks() const
diff --git a/src/profile.h b/src/profile.h
index 249ef618..5d5a3bc5 100644
--- a/src/profile.h
+++ b/src/profile.h
@@ -24,17 +24,16 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#include "modinfo.h"
#include <iprofile.h>
#include <delayedfilewriter.h>
+
#include <QString>
#include <QDir>
-#include <QMetaType>
#include <QSettings>
+
#include <vector>
#include <tuple>
-namespace MOBase {
- class IPluginGame;
-}
+namespace MOBase { class IPluginGame; }
/**
* @brief represents a profile
@@ -51,12 +50,6 @@ public:
public:
/**
- * @brief default constructor
- * @todo This constructor initialised nothing, the resulting object is not usable
- **/
- Profile();
-
- /**
* @brief constructor
*
* This constructor is used to create a new profile so it is to be assumed a profile
@@ -64,7 +57,8 @@ public:
* @param name name of the new profile
* @param filter save game filter. Defaults to &lt;no filter&gt;.
**/
- Profile(const QString &name, MOBase::IPluginGame *gamePlugin, bool useDefaultSettings);
+ Profile(const QString &name, MOBase::IPluginGame const *gamePlugin, bool useDefaultSettings);
+
/**
* @brief constructor
*
@@ -73,7 +67,7 @@ public:
* invoking this should always produce a working profile
* @param directory directory to read the profile from
**/
- Profile(const QDir &directory, MOBase::IPluginGame *gamePlugin);
+ Profile(const QDir &directory, MOBase::IPluginGame const *gamePlugin);
Profile(const Profile &reference);
@@ -88,7 +82,7 @@ public:
* @param name of the new profile
* @param reference profile to copy from
**/
- static Profile *createPtrFrom(const QString &name, const Profile &reference, MOBase::IPluginGame *gamePlugin);
+ static Profile *createPtrFrom(const QString &name, const Profile &reference, MOBase::IPluginGame const *gamePlugin);
MOBase::DelayedFileWriter &modlistWriter() { return m_ModListWriter; }
@@ -308,7 +302,7 @@ private:
QDir m_Directory;
- MOBase::IPluginGame *m_GamePlugin;
+ MOBase::IPluginGame const * const m_GamePlugin;
mutable QByteArray m_LastModlistHash;
std::vector<ModStatus> m_ModStatus;
@@ -319,7 +313,5 @@ private:
};
-Q_DECLARE_METATYPE(Profile)
-
#endif // PROFILE_H
diff --git a/src/profilesdialog.cpp b/src/profilesdialog.cpp
index 58be5448..b21aee53 100644
--- a/src/profilesdialog.cpp
+++ b/src/profilesdialog.cpp
@@ -42,10 +42,11 @@ using namespace MOShared;
Q_DECLARE_METATYPE(Profile::Ptr)
-ProfilesDialog::ProfilesDialog(const QString &profileName, QWidget *parent)
+ProfilesDialog::ProfilesDialog(const QString &profileName, MOBase::IPluginGame const *game, QWidget *parent)
: TutorableDialog("Profiles", parent)
, ui(new Ui::ProfilesDialog)
, m_FailState(false)
+ , m_Game(game)
{
ui->setupUi(this);
@@ -65,7 +66,6 @@ ProfilesDialog::ProfilesDialog(const QString &profileName, QWidget *parent)
QCheckBox *invalidationBox = findChild<QCheckBox*>("invalidationBox");
- IPluginGame *game = qApp->property("managed_game").value<IPluginGame*>();
BSAInvalidation *invalidation = game->feature<BSAInvalidation>();
if (invalidation == nullptr) {
@@ -104,7 +104,7 @@ QListWidgetItem *ProfilesDialog::addItem(const QString &name)
QDir profileDir(name);
QListWidgetItem *newItem = new QListWidgetItem(profileDir.dirName(), m_ProfilesList);
try {
- newItem->setData(Qt::UserRole, QVariant::fromValue(Profile::Ptr(new Profile(profileDir, qApp->property("managed_game").value<IPluginGame*>()))));
+ newItem->setData(Qt::UserRole, QVariant::fromValue(Profile::Ptr(new Profile(profileDir, m_Game))));
m_FailState = false;
} catch (const std::exception& e) {
reportError(tr("failed to create profile: %1").arg(e.what()));
@@ -117,7 +117,7 @@ void ProfilesDialog::createProfile(const QString &name, bool useDefaultSettings)
try {
QListWidget *profilesList = findChild<QListWidget*>("profilesList");
QListWidgetItem *newItem = new QListWidgetItem(name, profilesList);
- newItem->setData(Qt::UserRole, QVariant::fromValue(Profile::Ptr(new Profile(name, qApp->property("managed_game").value<IPluginGame*>(), useDefaultSettings))));
+ newItem->setData(Qt::UserRole, QVariant::fromValue(Profile::Ptr(new Profile(name, m_Game, useDefaultSettings))));
profilesList->addItem(newItem);
m_FailState = false;
} catch (const std::exception&) {
@@ -131,7 +131,7 @@ void ProfilesDialog::createProfile(const QString &name, const Profile &reference
try {
QListWidget *profilesList = findChild<QListWidget*>("profilesList");
QListWidgetItem *newItem = new QListWidgetItem(name, profilesList);
- newItem->setData(Qt::UserRole, QVariant::fromValue(Profile::Ptr(Profile::createPtrFrom(name, reference, qApp->property("managed_game").value<IPluginGame*>()))));
+ newItem->setData(Qt::UserRole, QVariant::fromValue(Profile::Ptr(Profile::createPtrFrom(name, reference, m_Game))));
profilesList->addItem(newItem);
m_FailState = false;
} catch (const std::exception&) {
@@ -324,6 +324,6 @@ void ProfilesDialog::on_localSavesBox_stateChanged(int state)
void ProfilesDialog::on_transferButton_clicked()
{
const Profile::Ptr currentProfile = m_ProfilesList->currentItem()->data(Qt::UserRole).value<Profile::Ptr>();
- TransferSavesDialog transferDialog(*currentProfile, qApp->property("managed_game").value<IPluginGame*>(), this);
+ TransferSavesDialog transferDialog(*currentProfile, m_Game, this);
transferDialog.exec();
}
diff --git a/src/profilesdialog.h b/src/profilesdialog.h
index 6dd0c1d4..26476883 100644
--- a/src/profilesdialog.h
+++ b/src/profilesdialog.h
@@ -50,7 +50,7 @@ public:
* @param parent parent widget
* @todo the game path could be retrieved from GameInfo just as easily
**/
- explicit ProfilesDialog(const QString &profileName, QWidget *parent = 0);
+ explicit ProfilesDialog(const QString &profileName, MOBase::IPluginGame const *game, QWidget *parent = 0);
~ProfilesDialog();
/**
@@ -93,7 +93,7 @@ private:
Ui::ProfilesDialog *ui;
QListWidget *m_ProfilesList;
bool m_FailState;
-
+ MOBase::IPluginGame const *m_Game;
};
#endif // PROFILESDIALOG_H
diff --git a/src/savegame.cpp b/src/savegame.cpp
index 1cdabb2d..2b125575 100644
--- a/src/savegame.cpp
+++ b/src/savegame.cpp
@@ -18,50 +18,28 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
*/
#include "savegame.h"
-#include <QFile>
-#include <QBuffer>
-#include <set>
-#include <QFileInfo>
-#include <QDateTime>
-#include <utility.h>
-#include <limits>
-#include "gameinfo.h"
-
-
-SaveGame::SaveGame(QObject *parent)
- : QObject(parent), m_FileName(), m_PCName(), m_PCLevel(0), m_PCLocation(), m_SaveNumber(0), m_Screenshot()
-{
-}
+#include "iplugingame.h"
+#include "scriptextender.h"
+#include "utility.h"
-SaveGame::SaveGame(QObject *parent, const QString &filename)
- : QObject(parent), m_FileName(filename), m_PCName(), m_PCLevel(0), m_PCLocation(), m_SaveNumber(0), m_Screenshot()
-{
-}
-
+#include <QApplication>
+#include <QDateTime>
+#include <QFile>
+#include <QFileInfo>
-SaveGame::SaveGame(const SaveGame& reference)
- : m_FileName(reference.m_FileName), m_PCName(reference.m_PCName), m_PCLevel(reference.m_PCLevel),
- m_PCLocation(reference.m_PCLocation), m_SaveNumber(reference.m_SaveNumber),
- m_Screenshot(reference.m_Screenshot)
-{
-}
+#include <limits>
+#include <set>
+using namespace MOBase;
-SaveGame& SaveGame::operator=(const SaveGame &reference)
+SaveGame::SaveGame(QObject *parent, const QString &filename, const MOBase::IPluginGame *game)
+ : QObject(parent)
+ , m_FileName(filename)
+ , m_Game(game)
{
- if (&reference != this) {
- m_FileName = reference.m_FileName;
- m_PCName = reference.m_PCName;
- m_PCLevel = reference.m_PCLevel;
- m_PCLocation = reference.m_PCLocation;
- m_SaveNumber = reference.m_SaveNumber;
- m_Screenshot = reference.m_Screenshot;
- }
- return *this;
}
-
SaveGame::~SaveGame()
{
}
@@ -69,11 +47,14 @@ SaveGame::~SaveGame()
QStringList SaveGame::attachedFiles() const
{
QStringList result;
- foreach (const std::wstring &ext, MOShared::GameInfo::instance().getSavegameAttachmentExtensions()) {
- QFileInfo fi(fileName());
- fi.setFile(fi.canonicalPath() + "/" + fi.completeBaseName() + "." + MOBase::ToQString(ext));
- if (fi.exists()) {
- result.append(fi.filePath());
+ ScriptExtender const *extender = m_Game->feature<ScriptExtender>();
+ if (extender != nullptr) {
+ for (QString const &ext : extender->saveGameAttachmentExtensions()) {
+ QFileInfo fi(fileName());
+ fi.setFile(fi.canonicalPath() + "/" + fi.completeBaseName() + "." + ext);
+ if (fi.exists()) {
+ result.append(fi.filePath());
+ }
}
}
@@ -86,21 +67,3 @@ QStringList SaveGame::saveFiles() const
result.append(fileName());
return result;
}
-
-
-void SaveGame::setCreationTime(const QString &fileName)
-{
- QFileInfo creationTime(fileName);
- QDateTime modified = creationTime.lastModified();
- memset(&m_CreationTime, 0, sizeof(SYSTEMTIME));
-
- m_CreationTime.wDay = static_cast<WORD>(modified.date().day());
- m_CreationTime.wDayOfWeek = static_cast<WORD>(modified.date().dayOfWeek());
- m_CreationTime.wMonth = static_cast<WORD>(modified.date().month());
- m_CreationTime.wYear =static_cast<WORD>( modified.date().year());
-
- m_CreationTime.wHour = static_cast<WORD>(modified.time().hour());
- m_CreationTime.wMinute = static_cast<WORD>(modified.time().minute());
- m_CreationTime.wSecond = static_cast<WORD>(modified.time().second());
- m_CreationTime.wMilliseconds = static_cast<WORD>(modified.time().msec());
-}
diff --git a/src/savegame.h b/src/savegame.h
index 1fd2f7ab..d1bf4691 100644
--- a/src/savegame.h
+++ b/src/savegame.h
@@ -31,6 +31,7 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
+namespace MOBase { class IPluginGame; }
/**
* @brief represents a single save game
@@ -42,22 +43,13 @@ Q_OBJECT
public:
/**
- * @brief construct an empty object
- **/
- SaveGame(QObject *parent = 0);
-
- /**
* @brief construct a save game and immediately read out information from the file
*
* @param filename absolute path of the save game file
**/
- SaveGame(QObject *parent, const QString &filename);
-
- SaveGame(const SaveGame& reference);
-
- SaveGame& operator=(const SaveGame &reference);
+ SaveGame(QObject *parent, const QString &filename, MOBase::IPluginGame const *game);
- ~SaveGame();
+ virtual ~SaveGame();
/**
* @brief read out information from a savegame
@@ -111,10 +103,6 @@ public:
**/
const QImage &screenshot() const { return m_Screenshot; }
-private:
-
- void setCreationTime(const QString &fileName);
-
protected:
QString m_FileName;
@@ -125,6 +113,8 @@ protected:
SYSTEMTIME m_CreationTime;
QImage m_Screenshot;
+private:
+ MOBase::IPluginGame const * const m_Game;
};
diff --git a/src/savegamegamebryo.cpp b/src/savegamegamebryo.cpp
index 2cece4e5..7aa6cdfc 100644
--- a/src/savegamegamebryo.cpp
+++ b/src/savegamegamebryo.cpp
@@ -18,374 +18,47 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
*/
#include "savegamegamebyro.h"
-#include "gameinfo.h"
-#include <QFile>
-#include <QBuffer>
-#include <set>
-#include <QFileInfo>
-#include <QDateTime>
+#include "isavegame.h"
+#include "savegameinfo.h"
+#include "iplugingame.h"
+#include <gamebryosavegame.h>
#include <limits>
+#include <set>
-
-using namespace MOShared;
-
-
-template <typename T>
-static void FileRead(QFile &file, T &value)
-{
- int read = file.read(reinterpret_cast<char*>(&value), sizeof(T));
- if (read != sizeof(T)) {
- throw std::runtime_error("unexpected end of file");
- }
-}
-
-
-template <typename T>
-static void FileSkip(QFile &file, int count = 1)
-{
- char ignore[sizeof(T)];
- for (int i = 0; i < count; ++i) {
- if (file.read(ignore, sizeof(T)) != sizeof(T)) {
- throw std::runtime_error("unexpected end of file");
- }
- }
-}
-
-
-static QString ReadBString(QFile &file)
-{
- char buffer[256];
- file.read(buffer, 1); // size including zero termination
- unsigned char size = buffer[0];
- file.read(buffer, size);
- return QString::fromLatin1(buffer, size);
-}
-
-
-static QString ReadFOSString(QFile &file, bool delimiter)
-{
- union {
- char lengthBuffer[2];
- unsigned short length;
- };
-
- file.read(lengthBuffer, 2);
- if (delimiter) {
- FileSkip<char>(file); // 0x7c
- }
- char *buffer = new char[length];
- file.read(buffer, length);
-
- QString result = QString::fromLatin1(buffer, length);
- delete [] buffer;
-
- return result;
-}
-
-
-SaveGameGamebryo::SaveGameGamebryo(QObject *parent)
- : SaveGame(parent), m_Plugins()
-{
-}
-
-
-SaveGameGamebryo::SaveGameGamebryo(QObject *parent, const QString &fileName)
- : SaveGame(parent, fileName), m_Plugins()
-{
- readFile(fileName);
-}
-
-
-SaveGameGamebryo::SaveGameGamebryo(const SaveGameGamebryo& reference)
- : SaveGame(reference), m_Plugins(reference.m_Plugins)
-{
-}
-
-
-SaveGameGamebryo& SaveGameGamebryo::operator=(const SaveGameGamebryo &reference)
-{
- if (&reference != this) {
- SaveGame::operator =(reference);
- m_Plugins = reference.m_Plugins;
- }
- return *this;
-}
-
-
-SaveGameGamebryo::~SaveGameGamebryo()
-{
-}
-
-
-void SaveGameGamebryo::readSkyrimFile(QFile &saveFile)
-{
- char fileID[14];
-
- saveFile.read(fileID, 13);
- fileID[13] = '\0';
- if (strncmp(fileID, "TESV_SAVEGAME", 13) != 0) {
- throw std::runtime_error(QObject::tr("wrong file format").toUtf8().constData());
- }
-
- FileSkip<unsigned long>(saveFile); // header size
- FileSkip<unsigned long>(saveFile); // header version, -> 8
- FileRead(saveFile, m_SaveNumber);
-
- m_PCName = ReadFOSString(saveFile, false);
-
- unsigned long temp;
- FileRead(saveFile, temp); // player level
- m_PCLevel = static_cast<unsigned short>(temp);
-
- m_PCLocation = ReadFOSString(saveFile, false);
- ReadFOSString(saveFile, false); // playtime as ascii hhh.mm.ss
- ReadFOSString(saveFile, false); // race name (i.e. BretonRace)
-
-
- FileSkip<unsigned short>(saveFile); // ???
- FileSkip<float>(saveFile, 2); // ???
- FileSkip<unsigned char>(saveFile, 8); // filetime
-
-// FileSkip<unsigned char>(saveFile, 18); // ??? 18 bytes of data. not completely random, maybe a time stamp? maybe
-
- unsigned long width, height;
- FileRead(saveFile, width); // 320
- FileRead(saveFile, height); // 192
-
- QScopedArrayPointer<unsigned char> buffer(new unsigned char[width * height * 3]);
- saveFile.read(reinterpret_cast<char*>(buffer.data()), width * height * 3);
- // why do I have to copy here? without the copy, the buffer seems to get deleted after the
- // temporary vanishes, but Qts implicit sharing should handle that?
- m_Screenshot = QImage(buffer.data(), width, height, QImage::Format_RGB888).copy();
-
- FileSkip<unsigned char>(saveFile); // form version
- FileSkip<unsigned long>(saveFile); // plugin info size
-
- unsigned char pluginCount;
- FileRead(saveFile, pluginCount);
-
- for (int i = 0; i < pluginCount; ++i) {
- m_Plugins.push_back(ReadFOSString(saveFile, false));
- }
-}
-
-void SaveGameGamebryo::readFO4File(QFile &saveFile)
-{
- char fileID[13];
-
- saveFile.read(fileID, 12);
- fileID[12] = '\0';
- if (strncmp(fileID, "FO4_SAVEGAME", 12) != 0) {
- throw std::runtime_error(QObject::tr("wrong file format").toUtf8().constData());
- }
-
- FileSkip<unsigned long>(saveFile); // header size
- FileSkip<unsigned long>(saveFile); // header version, -> 11
- FileRead(saveFile, m_SaveNumber);
-
- m_PCName = ReadFOSString(saveFile, false);
-
- unsigned long temp;
- FileRead(saveFile, temp); // player level
- m_PCLevel = static_cast<unsigned short>(temp);
-
- m_PCLocation = ReadFOSString(saveFile, false);
- ReadFOSString(saveFile, false); // playtime as ascii hhh.mm.ss
- ReadFOSString(saveFile, false); // race name (HumanRace)
-
-
- FileSkip<unsigned short>(saveFile); // ???
- FileSkip<float>(saveFile, 2); // ???
- FileSkip<unsigned char>(saveFile, 8); // filetime
-
-// FileSkip<unsigned char>(saveFile, 18); // ??? 18 bytes of data. not completely random, maybe a time stamp? maybe
-
- unsigned long width, height;
- FileRead(saveFile, width); // 640
- FileRead(saveFile, height); // 384
-
- QScopedArrayPointer<unsigned char> buffer(new unsigned char[width * height * 4]);
- saveFile.read(reinterpret_cast<char*>(buffer.data()), width * height * 4);
- // 640x384 is a bit large
- m_Screenshot = QImage(buffer.data(), width, height, QImage::Format_RGBA8888).scaledToWidth(320);
-
- FileSkip<unsigned char>(saveFile); // form version (?)
- ReadFOSString(saveFile, false); // game version
- FileSkip<unsigned long>(saveFile); // plugin info size (?)
-
- unsigned char pluginCount;
- FileRead(saveFile, pluginCount);
-
- for (int i = 0; i < pluginCount; ++i) {
- m_Plugins.push_back(ReadFOSString(saveFile, false));
- }
-}
-
-
-void SaveGameGamebryo::readESSFile(QFile &saveFile)
-{
- char fileID[13];
- unsigned char versionMinor;
- unsigned long headerVersion, saveHeaderSize;
-// *** format is different for fallout!
- saveFile.read(fileID, 12);
- fileID[12] = '\0';
- FileSkip<unsigned char>(saveFile); FileRead(saveFile, versionMinor);
- FileSkip<SYSTEMTIME>(saveFile); // modified time
- FileRead(saveFile, headerVersion); FileRead(saveFile, saveHeaderSize);
-
- if (strncmp(fileID, "TES4SAVEGAME", 12) != 0) {
- throw std::runtime_error(QObject::tr("wrong file format").toUtf8().constData());
- }
-
- FileRead(saveFile, m_SaveNumber);
-
- m_PCName = ReadBString(saveFile);
-
- FileRead(saveFile, m_PCLevel);
- m_PCLocation = ReadBString(saveFile);
- FileSkip<float>(saveFile); // game days
- FileSkip<unsigned long>(saveFile); // game ticks
- FileRead(saveFile, m_CreationTime);
-
- unsigned long size;
- FileRead(saveFile, size); // screenshot size
-
- unsigned long width, height;
- FileRead(saveFile, width); FileRead(saveFile, height);
- QScopedArrayPointer<unsigned char> buffer(new unsigned char[width * height * 3]);
- saveFile.read(reinterpret_cast<char*>(buffer.data()), width * height * 3);
- // why do I have to copy here? without the copy, the buffer seems to get deleted after the
- // temporary vanishes, but Qts implicit sharing should handle that?
- m_Screenshot = QImage(buffer.data(), width, height, QImage::Format_RGB888).copy();
-
- unsigned char pluginCount;
- FileRead(saveFile, pluginCount);
-
- for (int i = 0; i < pluginCount; ++i) {
- QString name = ReadBString(saveFile);
- m_Plugins.push_back(name);
- }
-}
+using namespace MOBase;
-void SaveGameGamebryo::readFOSFile(QFile &saveFile, bool newVegas)
+SaveGameGamebryo::SaveGameGamebryo(QObject *parent, const QString &fileName, IPluginGame const *game)
+ : SaveGame(parent, fileName, game)
+ , m_Plugins()
{
- char fileID[13];
- saveFile.read(fileID, 12);
- // the signature is only 11 characters, the 12th is random?
- fileID[11] = '\0';
-
- if (strncmp(fileID, "FO3SAVEGAME", 11) != 0) {
- throw std::runtime_error(QObject::tr("wrong file format").toUtf8().constData());
- }
-
- char ignore = 0x00;
- while (ignore != 0x7c) {
- FileRead<char>(saveFile, ignore); // unknown
- }
- if (newVegas) {
- ignore = 0x00;
- // in new vegas there is another block of uninteresting (?) information
- FileSkip<char>(saveFile); // 0x7c
- while (ignore != 0x7c) {
- FileRead<char>(saveFile, ignore); // unknown
- }
- }
-
- unsigned long width, height;
- FileRead(saveFile, width);
- FileSkip<char>(saveFile); // 0x7c
- FileRead(saveFile, height);
- FileSkip<char>(saveFile); // 0x7c
-
- FileRead(saveFile, m_SaveNumber);
- FileSkip<char>(saveFile); // 0x7c
-
- m_PCName = ReadFOSString(saveFile, true);
- FileSkip<char>(saveFile); // 0x7c
-
- ReadFOSString(saveFile, true);
- FileSkip<char>(saveFile); // 0x7c
+ SaveGameInfo const *info = game->feature<SaveGameInfo>();
+ if (info != nullptr) {
+ ISaveGame const *save = info->getSaveGameInfo(fileName);
+ m_Save = save;
- long Level;
- FileRead(saveFile, Level);
- m_PCLevel = Level;
- FileSkip<char>(saveFile); // 0x7c
+ //Kludgery
+ GamebryoSaveGame const *s = dynamic_cast<GamebryoSaveGame const *>(save);
+ m_PCName = s->getPCName();
+ m_PCLevel = s->getPCLevel();
+ m_PCLocation = s->getPCLocation();
+ m_SaveNumber = s->getSaveNumber();
- m_PCLocation = ReadFOSString(saveFile, true);
- FileSkip<char>(saveFile); // 0x7c
+ QDateTime modified = s->getCreationTime();
+ memset(&m_CreationTime, 0, sizeof(SYSTEMTIME));
- ReadFOSString(saveFile, true); // playtime
+ m_CreationTime.wDay = static_cast<WORD>(modified.date().day());
+ m_CreationTime.wDayOfWeek = static_cast<WORD>(modified.date().dayOfWeek());
+ m_CreationTime.wMonth = static_cast<WORD>(modified.date().month());
+ m_CreationTime.wYear =static_cast<WORD>( modified.date().year());
- FileSkip<char>(saveFile);
+ m_CreationTime.wHour = static_cast<WORD>(modified.time().hour());
+ m_CreationTime.wMinute = static_cast<WORD>(modified.time().minute());
+ m_CreationTime.wSecond = static_cast<WORD>(modified.time().second());
+ m_CreationTime.wMilliseconds = static_cast<WORD>(modified.time().msec());
- QScopedArrayPointer<unsigned char> buffer(new unsigned char[width * height * 3]);
- saveFile.read(reinterpret_cast<char*>(buffer.data()), width * height * 3);
- // why do I have to copy here? without the copy, the buffer seems to get deleted after the
- // temporary vanishes, but Qts implicit sharing should handle that?
- m_Screenshot = QImage(buffer.data(), width, height, QImage::Format_RGB888).scaledToWidth(256);
+ m_Screenshot = s->getScreenshot();
- FileSkip<char>(saveFile, 5); // unknown
-
- unsigned char pluginCount = 0;
- FileRead(saveFile, pluginCount);
- FileSkip<char>(saveFile); // 0x7c
-
- for (int i = 0; i < pluginCount; ++i) {
- QString name = ReadFOSString(saveFile, true);
- m_Plugins.push_back(name);
- FileSkip<char>(saveFile); // 0x7c
+ m_Plugins = s->getPlugins();
}
}
-
-
-void SaveGameGamebryo::setCreationTime(const QString &fileName)
-{
- QFileInfo creationTime(fileName);
- QDateTime modified = creationTime.lastModified();
- memset(&m_CreationTime, 0, sizeof(SYSTEMTIME));
-
- m_CreationTime.wDay = static_cast<WORD>(modified.date().day());
- m_CreationTime.wDayOfWeek = static_cast<WORD>(modified.date().dayOfWeek());
- m_CreationTime.wMonth = static_cast<WORD>(modified.date().month());
- m_CreationTime.wYear =static_cast<WORD>( modified.date().year());
-
- m_CreationTime.wHour = static_cast<WORD>(modified.time().hour());
- m_CreationTime.wMinute = static_cast<WORD>(modified.time().minute());
- m_CreationTime.wSecond = static_cast<WORD>(modified.time().second());
- m_CreationTime.wMilliseconds = static_cast<WORD>(modified.time().msec());
-}
-
-
-void SaveGameGamebryo::readFile(const QString &fileName)
-{
- m_FileName = fileName;
- QFile saveFile(fileName);
- if (!saveFile.open(QIODevice::ReadOnly)) {
- throw std::runtime_error(QObject::tr("failed to open %1").arg(fileName).toUtf8().constData());
- }
- switch (GameInfo::instance().getType()) {
- case GameInfo::TYPE_FALLOUT3: {
- setCreationTime(fileName);
- readFOSFile(saveFile, false);
- } break;
- case GameInfo::TYPE_FALLOUTNV: {
- setCreationTime(fileName);
- readFOSFile(saveFile, true);
- } break;
- case GameInfo::TYPE_OBLIVION: {
- readESSFile(saveFile);
- } break;
- case GameInfo::TYPE_SKYRIM: {
- setCreationTime(fileName);
- readSkyrimFile(saveFile);
- } break;
- case GameInfo::TYPE_FALLOUT4: {
- setCreationTime(fileName);
- readFO4File(saveFile);
- } break;
- }
-
- saveFile.close();
-}
diff --git a/src/savegamegamebyro.h b/src/savegamegamebyro.h
index af866666..b7a5ba12 100644
--- a/src/savegamegamebyro.h
+++ b/src/savegamegamebyro.h
@@ -20,17 +20,13 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#ifndef SAVEGAMEGAMEBRYO_H
#define SAVEGAMEGAMEBRYO_H
-
#include "savegame.h"
-#include <QString>
-#include <QObject>
#include <QMetaType>
-#include <QFile>
-
-#define WIN32_LEAN_AND_MEAN
-#include <Windows.h>
+#include <QObject>
+#include <QString>
+namespace MOBase { class IPluginGame; class ISaveGame; }
/**
* @brief represents a single save game
@@ -42,30 +38,20 @@ Q_OBJECT
public:
/**
- * @brief construct an empty object
- **/
- SaveGameGamebryo(QObject *parent = 0);
-
- /**
* @brief construct a save game and immediately read out information from the file
*
* @param filename absolute path of the save game file
**/
- SaveGameGamebryo(QObject *parent, const QString &filename);
+ SaveGameGamebryo(QObject *parent, const QString &filename, MOBase::IPluginGame const *game);
+ /*
SaveGameGamebryo(const SaveGameGamebryo &reference);
SaveGameGamebryo &operator=(const SaveGameGamebryo &reference);
~SaveGameGamebryo();
-
- /**
- * @brief read out information from a savegame
- *
- * @param fileName absolute path of the save game file
- **/
- virtual void readFile(const QString &fileName);
+ */
/**
* @return number of plugins that were enabled when the save game was created
@@ -80,23 +66,12 @@ public:
**/
const QString &plugin(int index) const { return m_Plugins.at(index); }
-
private:
- void readESSFile(QFile &saveFile);
- void readFOSFile(QFile &saveFile, bool newVegas);
- void readFO4File(QFile &saveFile);
- void readSkyrimFile(QFile &saveFile);
-
- void setCreationTime(const QString &fileName);
-
-private:
-
- std::vector<QString> m_Plugins;
+ QStringList m_Plugins;
+ //Note: This isn't owned by us so safe to copy
+ MOBase::ISaveGame const *m_Save;
};
-Q_DECLARE_METATYPE(SaveGameGamebryo)
-Q_DECLARE_METATYPE(SaveGameGamebryo*)
-
#endif // SAVEGAMEGAMEBRYO_H
diff --git a/src/selfupdater.cpp b/src/selfupdater.cpp
index 270e2764..af1eb5b2 100644
--- a/src/selfupdater.cpp
+++ b/src/selfupdater.cpp
@@ -18,16 +18,18 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
*/
#include "selfupdater.h"
+
#include "utility.h"
#include "installationmanager.h"
+#include "iplugingame.h"
#include "messagedialog.h"
#include "downloadmanager.h"
#include "nexusinterface.h"
#include "nxmaccessmanager.h"
#include <versioninfo.h>
-#include <gameinfo.h>
-#include <skyriminfo.h>
#include <report.h>
+#include <util.h>
+
#include <QMessageBox>
#include <QNetworkAccessManager>
#include <QNetworkRequest>
@@ -35,7 +37,6 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#include <QLibrary>
#include <QProcess>
#include <QApplication>
-#include <util.h>
#include <boost/bind.hpp>
@@ -62,6 +63,7 @@ SelfUpdater::SelfUpdater(NexusInterface *nexusInterface)
, m_UpdateRequestID(-1)
, m_Reply(nullptr)
, m_Attempts(3)
+ , m_NexusDownload(nullptr)
{
QLibrary archiveLib("dlls\\archive.dll");
if (!archiveLib.load()) {
@@ -70,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()));
}
VS_FIXEDFILEINFO version = GetFileVersion(ToWString(QApplication::applicationFilePath()));
@@ -85,7 +87,7 @@ SelfUpdater::SelfUpdater(NexusInterface *nexusInterface)
SelfUpdater::~SelfUpdater()
{
- delete m_CurrentArchive;
+ delete m_ArchiveHandler;
}
void SelfUpdater::setUserInterface(QWidget *widget)
@@ -99,12 +101,10 @@ void SelfUpdater::testForUpdate()
emit updateAvailable();
return;
}
-
- if (m_UpdateRequestID == -1) {
+ if (m_UpdateRequestID == -1 && m_NexusDownload != nullptr) {
m_UpdateRequestID = m_Interface->requestDescription(
- SkyrimInfo::getNexusModIDStatic(), this, QVariant(),
- QString(), ToQString(SkyrimInfo::getNexusInfoUrlStatic()),
- SkyrimInfo::getNexusGameIDStatic());
+ m_NexusDownload->getNexusModOrganizerID(), this, QVariant(),
+ QString(), m_NexusDownload);
}
}
@@ -121,9 +121,9 @@ void SelfUpdater::startUpdate()
if (QMessageBox::question(m_Parent, tr("Update"),
tr("An update is available (newest version: %1), do you want to install it?").arg(m_NewestVersion),
QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) {
- m_UpdateRequestID = m_Interface->requestFiles(SkyrimInfo::getNexusModIDStatic(),
- this, m_NewestVersion,
- ToQString(SkyrimInfo::getNexusInfoUrlStatic()));
+ m_UpdateRequestID = m_Interface->requestFiles(m_NexusDownload->getNexusModOrganizerID(),
+ this, m_NewestVersion, "",
+ m_NexusDownload);
}
}
}
@@ -158,7 +158,7 @@ void SelfUpdater::download(const QString &downloadLink, const QString &fileName)
QNetworkRequest request(dlUrl);
m_Canceled = false;
m_Reply = accessManager->get(request);
- m_UpdateFile.setFileName(QDir::fromNativeSeparators(ToQString(GameInfo::instance().getOrganizerDirectory()).append("\\").append(fileName)));
+ m_UpdateFile.setFileName(QDir::fromNativeSeparators(qApp->property("dataPath").toString()).append("/").append(fileName));
m_UpdateFile.open(QIODevice::WriteOnly);
showProgress();
@@ -242,32 +242,31 @@ void SelfUpdater::downloadCancel()
void SelfUpdater::installUpdate()
{
- const QString mopath = QDir::fromNativeSeparators(ToQString(GameInfo::instance().getOrganizerDirectory()));
+ const QString mopath = QDir::fromNativeSeparators(qApp->property("dataPath").toString());
QString backupPath = mopath + "/update_backup";
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()) {
@@ -280,14 +279,12 @@ void SelfUpdater::installUpdate()
}
// now unpack the archive into the mo directory
- if (!m_CurrentArchive->extract(GameInfo::instance().getOrganizerDirectory().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();
@@ -302,24 +299,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);
}
@@ -433,18 +415,18 @@ void SelfUpdater::nxmFilesAvailable(int, QVariant userData, QVariant resultData,
if (updateFileID != -1) {
qDebug("update available: %d", updateFileID);
- m_UpdateRequestID = m_Interface->requestDownloadURL(SkyrimInfo::getNexusModIDStatic(),
- updateFileID, this, updateFileName,
- ToQString(SkyrimInfo::getNexusInfoUrlStatic()));
+ m_UpdateRequestID = m_Interface->requestDownloadURL(m_NexusDownload->getNexusModOrganizerID(),
+ updateFileID, this, updateFileName, "",
+ m_NexusDownload);
} else if (mainFileID != -1) {
qDebug("full download required: %d", mainFileID);
if (QMessageBox::question(m_Parent, tr("Update"),
tr("No incremental update available for this version, "
"the complete package needs to be downloaded (%1 kB)").arg(mainFileSize),
QMessageBox::Ok | QMessageBox::Cancel) == QMessageBox::Ok) {
- m_UpdateRequestID = m_Interface->requestDownloadURL(SkyrimInfo::getNexusModIDStatic(),
- mainFileID, this, mainFileName,
- ToQString(SkyrimInfo::getNexusInfoUrlStatic()));
+ m_UpdateRequestID = m_Interface->requestDownloadURL(m_NexusDownload->getNexusModOrganizerID(),
+ mainFileID, this, mainFileName, "",
+ m_NexusDownload);
}
} else {
qCritical("no file for update found");
@@ -488,3 +470,9 @@ void SelfUpdater::nxmDownloadURLsAvailable(int, int, QVariant userData, QVariant
}
}
}
+
+/** Set the game check for updates */
+void SelfUpdater::setNexusDownload(MOBase::IPluginGame const *game)
+{
+ m_NexusDownload = game;
+}
diff --git a/src/selfupdater.h b/src/selfupdater.h
index bb9804e8..0a31b0f3 100644
--- a/src/selfupdater.h
+++ b/src/selfupdater.h
@@ -31,6 +31,7 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#include <windows.h>
+namespace MOBase { class IPluginGame; }
class NexusInterface;
@@ -68,7 +69,7 @@ public:
* @param parent parent widget
* @todo passing the nexus interface is unneccessary
**/
- SelfUpdater(NexusInterface *nexusInterface);
+ explicit SelfUpdater(NexusInterface *nexusInterface);
virtual ~SelfUpdater();
@@ -85,6 +86,9 @@ public:
**/
MOBase::VersionInfo getVersion() const { return m_MOVersion; }
+ /** Set the game check for updates */
+ void setNexusDownload(MOBase::IPluginGame const *game);
+
public slots:
/**
@@ -118,10 +122,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();
@@ -146,8 +147,9 @@ private:
bool m_Canceled;
int m_Attempts;
- Archive *m_CurrentArchive;
+ Archive *m_ArchiveHandler;
+ MOBase::IPluginGame const *m_NexusDownload;
};
diff --git a/src/settings.cpp b/src/settings.cpp
index 4c2a34c8..479dd3ab 100644
--- a/src/settings.cpp
+++ b/src/settings.cpp
@@ -22,26 +22,22 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#include "settingsdialog.h"
#include "utility.h"
#include "helper.h"
-#include "json.h"
#include <gameinfo.h>
#include <appconfig.h>
#include <utility.h>
#include <iplugingame.h>
#include <QCheckBox>
-#include <QLineEdit>
-#include <QDirIterator>
-#include <QRegExp>
#include <QCoreApplication>
-#include <QMessageBox>
#include <QDesktopServices>
+#include <QDirIterator>
+#include <QLineEdit>
+#include <QMessageBox>
+#include <QRegExp>
#include <memory>
-
using namespace MOBase;
-using namespace MOShared;
-
template <typename T>
class QListWidgetItemEx : public QListWidgetItem {
@@ -112,7 +108,7 @@ void Settings::registerAsNXMHandler(bool force)
std::wstring nxmPath = ToWString(QCoreApplication::applicationDirPath() + "/nxmhandler.exe");
std::wstring executable = ToWString(QCoreApplication::applicationFilePath());
std::wstring mode = force ? L"forcereg" : L"reg";
- std::wstring parameters = mode + L" " + GameInfo::instance().getGameShortName() + L" \"" + executable + L"\"";
+ std::wstring parameters = mode + L" " + m_GamePlugin->getGameShortName().toStdWString() + L" \"" + executable + L"\"";
HINSTANCE res = ::ShellExecuteW(nullptr, L"open", nxmPath.c_str(), parameters.c_str(), nullptr, SW_SHOWNORMAL);
if ((int)res <= 32) {
QMessageBox::critical(nullptr, tr("Failed"),
@@ -120,7 +116,7 @@ void Settings::registerAsNXMHandler(bool force)
}
}
-void Settings::managedGameChanged(IPluginGame *gamePlugin)
+void Settings::managedGameChanged(IPluginGame const *gamePlugin)
{
m_GamePlugin = gamePlugin;
}
diff --git a/src/settings.h b/src/settings.h
index def1dc5c..1ee16e76 100644
--- a/src/settings.h
+++ b/src/settings.h
@@ -299,7 +299,7 @@ public:
public slots:
- void managedGameChanged(MOBase::IPluginGame *gamePlugin);
+ void managedGameChanged(MOBase::IPluginGame const *gamePlugin);
private:
@@ -328,7 +328,7 @@ private:
};
/** Display/store the configuration in the 'general' tab of the settings dialogue */
- class GeneralTab : SettingsTab
+ class GeneralTab : public SettingsTab
{
public:
GeneralTab(Settings *m_parent, SettingsDialog &m_dialog);
@@ -347,7 +347,7 @@ private:
};
/** Display/store the configuration in the 'nexus' tab of the settings dialogue */
- class NexusTab : SettingsTab
+ class NexusTab : public SettingsTab
{
public:
NexusTab(Settings *m_parent, SettingsDialog &m_dialog);
@@ -365,7 +365,7 @@ private:
};
/** Display/store the configuration in the 'steam' tab of the settings dialogue */
- class SteamTab : SettingsTab
+ class SteamTab : public SettingsTab
{
public:
SteamTab(Settings *m_parent, SettingsDialog &m_dialog);
@@ -378,7 +378,7 @@ private:
};
/** Display/store the configuration in the 'plugins' tab of the settings dialogue */
- class PluginsTab : SettingsTab
+ class PluginsTab : public SettingsTab
{
public:
PluginsTab(Settings *m_parent, SettingsDialog &m_dialog);
@@ -391,7 +391,7 @@ private:
};
/** Display/store the configuration in the 'workarounds' tab of the settings dialogue */
- class WorkaroundsTab : SettingsTab
+ class WorkaroundsTab : public SettingsTab
{
public:
WorkaroundsTab(Settings *m_parent, SettingsDialog &m_dialog);
@@ -420,7 +420,7 @@ private:
static Settings *s_Instance;
- MOBase::IPluginGame *m_GamePlugin;
+ MOBase::IPluginGame const *m_GamePlugin;
QSettings m_Settings;
diff --git a/src/settingsdialog.cpp b/src/settingsdialog.cpp
index 765858f5..8bc1dbc6 100644
--- a/src/settingsdialog.cpp
+++ b/src/settingsdialog.cpp
@@ -18,22 +18,24 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
*/
#include "settingsdialog.h"
+
#include "ui_settingsdialog.h"
#include "categoriesdialog.h"
#include "helper.h"
#include "noeditdelegate.h"
-#include <gameinfo.h>
+#include "iplugingame.h"
+#include "settings.h"
+
#include <QDirIterator>
#include <QFileDialog>
#include <QMessageBox>
#include <QShortcut>
+
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
-#include "settings.h"
using namespace MOBase;
-using namespace MOShared;
SettingsDialog::SettingsDialog(QWidget *parent)
@@ -87,7 +89,11 @@ void SettingsDialog::on_categoriesBtn_clicked()
void SettingsDialog::on_bsaDateBtn_clicked()
{
- Helper::backdateBSAs(GameInfo::instance().getOrganizerDirectory(), GameInfo::instance().getGameDirectory().append(L"\\data"));
+ IPluginGame const *game = qApp->property("managed_game").value<IPluginGame const *>();
+ QDir dir = game->dataDirectory();
+
+ Helper::backdateBSAs(qApp->property("dataPath").toString().toStdWString(),
+ dir.absolutePath().toStdWString());
}
void SettingsDialog::on_browseDownloadDirBtn_clicked()
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 a4b60410..446d4afe 100644
--- a/src/shared/fallout3info.cpp
+++ b/src/shared/fallout3info.cpp
@@ -30,8 +30,8 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
namespace MOShared {
-Fallout3Info::Fallout3Info(const std::wstring &moDirectory, const std::wstring &moDataDirectory, const std::wstring &gameDirectory)
- : GameInfo(moDirectory, moDataDirectory, gameDirectory)
+Fallout3Info::Fallout3Info(const std::wstring &gameDirectory)
+ : GameInfo(gameDirectory)
{
identifyMyGamesDirectory(L"fallout3");
}
@@ -63,48 +63,9 @@ std::wstring Fallout3Info::getRegPathStatic()
}
-std::vector<std::wstring> Fallout3Info::getDLCPlugins()
-{
- return boost::assign::list_of (L"ThePitt.esm")
- (L"Anchorage.esm")
- (L"BrokenSteel.esm")
- (L"PointLookout.esm")
- (L"Zeta.esm")
- ;
-}
-
-std::vector<std::wstring> Fallout3Info::getSavegameAttachmentExtensions()
-{
- 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()
-{
- return L"Fallout - Meshes.bsa";
-}
-
-std::wstring Fallout3Info::getNexusPage(bool nmmScheme)
-{
- if (nmmScheme) {
- return L"http://nmm.nexusmods.com/fallout3";
- } else {
- return L"http://www.nexusmods.com/fallout3";
- }
-}
-
-std::wstring Fallout3Info::getNexusInfoUrlStatic()
-{
- return L"http://nmm.nexusmods.com/fallout3";
-}
-
-int Fallout3Info::getNexusModIDStatic()
-{
- return 16348;
-}
-
} // namespace MOShared
diff --git a/src/shared/fallout3info.h b/src/shared/fallout3info.h
index 878adc2b..601fc346 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,38 +35,16 @@ public:
virtual ~Fallout3Info() {}
static std::wstring getRegPathStatic();
- virtual std::wstring getRegPath() { return getRegPathStatic(); }
- virtual std::wstring getBinaryName() { return L"Fallout3.exe"; }
-
- virtual GameInfo::Type getType() { return TYPE_FALLOUT3; }
-
- virtual std::wstring getGameName() const { return L"Fallout 3"; }
- virtual std::wstring getGameShortName() const { return L"Fallout3"; }
-
- virtual std::vector<std::wstring> getDLCPlugins();
- virtual std::vector<std::wstring> getSavegameAttachmentExtensions();
+ virtual std::wstring getRegPath() const { return getRegPathStatic(); }
// file name of this games ini (no path)
- virtual std::vector<std::wstring> getIniFileNames();
-
- virtual std::wstring getReferenceDataFile();
-
- virtual std::wstring getNexusPage(bool nmmScheme = true);
- static std::wstring getNexusInfoUrlStatic();
- virtual std::wstring getNexusInfoUrl() { return getNexusInfoUrlStatic(); }
- static int getNexusModIDStatic();
- virtual int getNexusModID() { return getNexusModIDStatic(); }
- virtual int getNexusGameID() { return 120; }
-
- // 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::vector<std::wstring> getIniFileNames() const;
- virtual std::wstring archiveListKey() { return L"SArchiveList"; }
+ virtual std::wstring archiveListKey() const { return L"SArchiveList"; }
private:
- Fallout3Info(const std::wstring &moDirectory, const std::wstring &moDataDirectory, const std::wstring &gameDirectory);
+ Fallout3Info(const std::wstring &gameDirectory);
static bool identifyGame(const std::wstring &searchPath);
diff --git a/src/shared/fallout4info.cpp b/src/shared/fallout4info.cpp
index c9229793..aab431ad 100644
--- a/src/shared/fallout4info.cpp
+++ b/src/shared/fallout4info.cpp
@@ -30,8 +30,8 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
namespace MOShared {
-Fallout4Info::Fallout4Info(const std::wstring &moDirectory, const std::wstring &moDataDirectory, const std::wstring &gameDirectory)
- : GameInfo(moDirectory, moDataDirectory, gameDirectory)
+Fallout4Info::Fallout4Info(const std::wstring &gameDirectory)
+ : GameInfo(gameDirectory)
{
identifyMyGamesDirectory(L"fallout4");
}
@@ -73,16 +73,11 @@ std::vector<std::wstring> Fallout4Info::getSavegameAttachmentExtensions()
return std::vector<std::wstring>();
}
-std::vector<std::wstring> Fallout4Info::getIniFileNames()
+std::vector<std::wstring> Fallout4Info::getIniFileNames() const
{
return boost::assign::list_of(L"fallout4.ini")(L"fallout4prefs.ini");
}
-std::wstring Fallout4Info::getReferenceDataFile()
-{
- return L"Fallout - Meshes.bsa";
-}
-
std::wstring Fallout4Info::getNexusPage(bool nmmScheme)
{
if (nmmScheme) {
diff --git a/src/shared/fallout4info.h b/src/shared/fallout4info.h
index 4a28e867..70c9b7d3 100644
--- a/src/shared/fallout4info.h
+++ b/src/shared/fallout4info.h
@@ -36,11 +36,9 @@ public:
virtual ~Fallout4Info() {}
static std::wstring getRegPathStatic();
- virtual std::wstring getRegPath() { return getRegPathStatic(); }
+ virtual std::wstring getRegPath() const { return getRegPathStatic(); }
virtual std::wstring getBinaryName() { return L"Fallout4.exe"; }
- virtual GameInfo::Type getType() { return TYPE_FALLOUT4; }
-
virtual std::wstring getGameName() const { return L"Fallout 4"; }
virtual std::wstring getGameShortName() const { return L"Fallout4"; }
@@ -48,9 +46,7 @@ public:
virtual std::vector<std::wstring> getSavegameAttachmentExtensions();
// 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 std::wstring getNexusPage(bool nmmScheme = true);
static std::wstring getNexusInfoUrlStatic();
@@ -67,10 +63,11 @@ public:
private:
- Fallout4Info(const std::wstring &moDirectory, const std::wstring &moDataDirectory, const std::wstring &gameDirectory);
+ Fallout4Info(const std::wstring &gameDirectory);
static bool identifyGame(const std::wstring &searchPath);
+
};
} // namespace MOShared
diff --git a/src/shared/falloutnvinfo.cpp b/src/shared/falloutnvinfo.cpp
index 81a75af3..510dfa01 100644
--- a/src/shared/falloutnvinfo.cpp
+++ b/src/shared/falloutnvinfo.cpp
@@ -31,8 +31,8 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
namespace MOShared {
-FalloutNVInfo::FalloutNVInfo(const std::wstring &moDirectory, const std::wstring &moDataDirectory, const std::wstring &gameDirectory)
- : GameInfo(moDirectory, moDataDirectory, gameDirectory)
+FalloutNVInfo::FalloutNVInfo(const std::wstring &gameDirectory)
+ : GameInfo(gameDirectory)
{
identifyMyGamesDirectory(L"falloutnv");
}
@@ -63,54 +63,9 @@ std::wstring FalloutNVInfo::getRegPathStatic()
}
}
-std::vector<std::wstring> FalloutNVInfo::getDLCPlugins()
-{
- return boost::assign::list_of (L"DeadMoney.esm")
- (L"HonestHearts.esm")
- (L"OldWorldBlues.esm")
- (L"LonesomeRoad.esm")
- (L"GunRunnersArsenal.esm")
- (L"CaravanPack.esm")
- (L"ClassicPack.esm")
- (L"MercenaryPack.esm")
- (L"TribalPack.esm")
- ;
-}
-
-std::vector<std::wstring> FalloutNVInfo::getSavegameAttachmentExtensions()
-{
- 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()
-{
- return L"Fallout - Meshes.bsa";
-}
-
-std::wstring FalloutNVInfo::getNexusPage(bool nmmScheme)
-{
- if (nmmScheme) {
- return L"http://nmm.nexusmods.com/newvegas";
- } else {
- return L"http://www.nexusmods.com/newvegas";
- }
-}
-
-
-std::wstring FalloutNVInfo::getNexusInfoUrlStatic()
-{
- return L"http://nmm.nexusmods.com/newvegas";
-}
-
-
-int FalloutNVInfo::getNexusModIDStatic()
-{
- return 42572;
-}
-
} // namespace MOShared
diff --git a/src/shared/falloutnvinfo.h b/src/shared/falloutnvinfo.h
index 5712c2ba..a9b3b9ec 100644
--- a/src/shared/falloutnvinfo.h
+++ b/src/shared/falloutnvinfo.h
@@ -36,71 +36,14 @@ public:
virtual ~FalloutNVInfo() {}
static std::wstring getRegPathStatic();
- virtual std::wstring getRegPath() { return getRegPathStatic(); }
- virtual std::wstring getBinaryName() { return L"FalloutNV.exe"; }
-
- virtual GameInfo::Type getType() { return TYPE_FALLOUTNV; }
-
- virtual std::wstring getGameName() const { return L"New Vegas"; }
- virtual std::wstring getGameShortName() const { return L"FalloutNV"; }
-
-// virtual bool requiresSteam() const { return true; }
-
-/* virtual std::wstring getInvalidationBSA()
- {
- return L"Fallout - Invalidation.bsa";
- }
-
- virtual bool isInvalidationBSA(const std::wstring &bsaName)
- {
- static LPCWSTR invalidation[] = { L"Fallout - AI!.bsa", L"Fallout - Invalidation.bsa", nullptr };
-
- for (int i = 0; invalidation[i] != nullptr; ++i) {
- if (wcscmp(bsaName.c_str(), invalidation[i]) == 0) {
- return true;
- }
- }
- return false;
- }
-
- virtual std::vector<std::wstring> getVanillaBSAs()
- {
- return boost::assign::list_of (L"Fallout - Textures.bsa")
- (L"Fallout - Textures2.bsa")
- (L"Fallout - Meshes.bsa")
- (L"Fallout - Voices1.bsa")
- (L"Fallout - Sound.bsa")
- (L"Fallout - Misc.bsa");
- }
-
- virtual std::vector<std::wstring> getPrimaryPlugins()
- {
- return boost::assign::list_of(L"falloutnv.esm");
- }*/
- virtual std::vector<std::wstring> getDLCPlugins();
- virtual std::vector<std::wstring> getSavegameAttachmentExtensions();
+ virtual std::wstring getRegPath() const { return getRegPathStatic(); }
// file name of this games ini (no path)
- virtual std::vector<std::wstring> getIniFileNames();
-
- virtual std::wstring getReferenceDataFile();
-
- virtual std::wstring getNexusPage(bool nmmScheme = true);
- static std::wstring getNexusInfoUrlStatic();
- virtual std::wstring getNexusInfoUrl() { return getNexusInfoUrlStatic(); }
- static int getNexusModIDStatic();
- virtual int getNexusModID() { return getNexusModIDStatic(); }
- virtual int getNexusGameID() { return 130; }
-
- // 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::vector<std::wstring> getIniFileNames() const;
private:
- FalloutNVInfo(const std::wstring &moDirectory, const std::wstring &moDataDirectory, const std::wstring &gameDirectory);
+ FalloutNVInfo(const std::wstring &gameDirectory);
static bool identifyGame(const std::wstring &searchPath);
};
diff --git a/src/shared/gameinfo.cpp b/src/shared/gameinfo.cpp
index d9dd9bb1..9b097053 100644
--- a/src/shared/gameinfo.cpp
+++ b/src/shared/gameinfo.cpp
@@ -41,8 +41,8 @@ namespace MOShared {
GameInfo* GameInfo::s_Instance = nullptr;
-GameInfo::GameInfo(const std::wstring &moDirectory, const std::wstring &moDataDirectory, const std::wstring &gameDirectory)
- : m_GameDirectory(gameDirectory), m_OrganizerDirectory(moDirectory), m_OrganizerDataDirectory(moDataDirectory)
+GameInfo::GameInfo(const std::wstring &gameDirectory)
+ : m_GameDirectory(gameDirectory)
{
atexit(&cleanup);
}
@@ -87,39 +87,38 @@ void GameInfo::identifyMyGamesDirectory(const std::wstring &file)
}
}
-
-bool GameInfo::identifyGame(const std::wstring &moDirectory, const std::wstring &moDataDirectory, const std::wstring &searchPath)
+bool GameInfo::identifyGame(const std::wstring &searchPath)
{
if (OblivionInfo::identifyGame(searchPath)) {
- s_Instance = new OblivionInfo(moDirectory, moDataDirectory, searchPath);
+ s_Instance = new OblivionInfo(searchPath);
} else if (Fallout3Info::identifyGame(searchPath)) {
- s_Instance = new Fallout3Info(moDirectory, moDataDirectory, searchPath);
+ s_Instance = new Fallout3Info(searchPath);
} else if (FalloutNVInfo::identifyGame(searchPath)) {
- s_Instance = new FalloutNVInfo(moDirectory, moDataDirectory, searchPath);
+ s_Instance = new FalloutNVInfo(searchPath);
} else if (SkyrimInfo::identifyGame(searchPath)) {
- s_Instance = new SkyrimInfo(moDirectory, moDataDirectory, searchPath);
+ s_Instance = new SkyrimInfo(searchPath);
} else if (Fallout4Info::identifyGame(searchPath)) {
- s_Instance = new Fallout4Info(moDirectory, moDataDirectory, searchPath);
+ s_Instance = new Fallout4Info(searchPath);
}
return s_Instance != nullptr;
}
-bool GameInfo::init(const std::wstring &moDirectory, const std::wstring &moDataDirectory, const std::wstring &gamePath)
+bool GameInfo::init(const std::wstring &moDirectory, const std::wstring &gamePath)
{
if (s_Instance == nullptr) {
if (gamePath.length() == 0) {
// search upward in the directory until a recognized game-binary is found
std::wstring searchPath(moDirectory);
- while (!identifyGame(moDirectory, moDataDirectory, searchPath)) {
+ while (!identifyGame(searchPath)) {
size_t lastSep = searchPath.find_last_of(L"/\\");
if (lastSep == std::string::npos) {
return false;
}
searchPath.erase(lastSep);
}
- } else if (!identifyGame(moDirectory, moDataDirectory, gamePath)) {
+ } else if (!identifyGame(gamePath)) {
return false;
}
}
@@ -138,25 +137,6 @@ std::wstring GameInfo::getGameDirectory() const
return m_GameDirectory;
}
-bool GameInfo::requiresSteam() const
-{
- return FileExists(getGameDirectory() + L"\\steam_api.dll")
- || FileExists(getGameDirectory() + L"\\steam_api64.dll");
-}
-
-std::wstring GameInfo::getLocalAppFolder() const
-{
- wchar_t localAppFolder[MAX_PATH];
- memset(localAppFolder, '\0', MAX_PATH * sizeof(wchar_t));
-
- if (::SHGetFolderPathW(nullptr, CSIDL_LOCAL_APPDATA, nullptr, SHGFP_TYPE_CURRENT, localAppFolder) == S_OK) {
- return localAppFolder;
- } else {
- // fallback: try the registry
- return getSpecialPath(L"Local AppData");
- }
-}
-
std::wstring GameInfo::getSpecialPath(LPCWSTR name) const
{
HKEY key;
diff --git a/src/shared/gameinfo.h b/src/shared/gameinfo.h
index 0e0052d7..c99ebef7 100644
--- a/src/shared/gameinfo.h
+++ b/src/shared/gameinfo.h
@@ -40,76 +40,35 @@ class GameInfo
public:
- enum Type {
- TYPE_OBLIVION,
- TYPE_FALLOUT3,
- TYPE_FALLOUT4,
- TYPE_FALLOUTNV,
- TYPE_SKYRIM
- };
-
- enum LoadOrderMechanism {
- TYPE_FILETIME,
- TYPE_PLUGINSTXT
- };
-
-public:
-
virtual ~GameInfo() {}
- std::wstring getOrganizerDirectory() { return m_OrganizerDirectory; }
-
- virtual std::wstring getRegPath() = 0;
- virtual std::wstring getBinaryName() = 0;
-
- virtual GameInfo::Type getType() = 0;
-
- virtual std::wstring getGameName() const = 0;
- virtual std::wstring getGameShortName() const = 0;
+ //**USED IN HOOKDLL and at startup to set up for hookdll to work
+ // initialise with the path to the mo directory (needs to be where hook.dll is stored). This
+ // needs to be called before the instance can be retrieved
+ static bool init(const std::wstring &moDirectory, const std::wstring &gamePath = L"");
- /// determine the load order mechanism used by this game. this may throw an
- /// exception if the mechanism can't be determined
- virtual LoadOrderMechanism getLoadOrderMechanism() const { return TYPE_FILETIME; }
+ //**USED ONLY IN HOOKDLL
+ static GameInfo& instance();
+ //**USED ONLY IN HOOKDLL
virtual std::wstring getGameDirectory() const;
- virtual bool requiresSteam() const;
-
- // get a list of file extensions for additional files belonging to a save game
- virtual std::vector<std::wstring> getSavegameAttachmentExtensions() = 0;
-
- // get a set of esp/esm files that are part of known dlcs
- virtual std::vector<std::wstring> getDLCPlugins() = 0;
+ //**USED ONLY IN HOOKDLL
+ 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::wstring getReferenceDataFile() = 0;
-
- virtual std::wstring getNexusPage(bool nmmScheme = true) = 0;
- virtual std::wstring getNexusInfoUrl() = 0;
- virtual int getNexusModID() = 0;
- virtual int getNexusGameID() = 0;
-
-public:
-
- // initialise with the path to the mo directory (needs to be where hook.dll is stored). This
- // needs to be called before the instance can be retrieved
- static bool init(const std::wstring &moDirectory, const std::wstring &moDataDirectory, const std::wstring &gamePath = L"");
-
- static GameInfo& instance();
+ virtual std::vector<std::wstring> getIniFileNames() const = 0;
protected:
- GameInfo(const std::wstring &moDirectory, const std::wstring &moDataDirectory, const std::wstring &gameDirectory);
+ GameInfo(const std::wstring &gameDirectory);
- std::wstring getLocalAppFolder() const;
- const std::wstring &getMyGamesDirectory() const { return m_MyGamesDirectory; }
void identifyMyGamesDirectory(const std::wstring &file);
private:
- static bool identifyGame(const std::wstring &moDirectory, const std::wstring &moDataDirectory, const std::wstring &searchPath);
+ static bool identifyGame(const std::wstring &searchPath);
std::wstring getSpecialPath(LPCWSTR name) const;
static void cleanup();
@@ -121,8 +80,6 @@ private:
std::wstring m_MyGamesDirectory;
std::wstring m_GameDirectory;
- std::wstring m_OrganizerDirectory;
- std::wstring m_OrganizerDataDirectory;
};
diff --git a/src/shared/oblivioninfo.cpp b/src/shared/oblivioninfo.cpp
index c60f8911..b290fb36 100644
--- a/src/shared/oblivioninfo.cpp
+++ b/src/shared/oblivioninfo.cpp
@@ -31,8 +31,8 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
namespace MOShared {
-OblivionInfo::OblivionInfo(const std::wstring &moDirectory, const std::wstring &moDataDirectory, const std::wstring &gameDirectory)
- : GameInfo(moDirectory, moDataDirectory, gameDirectory)
+OblivionInfo::OblivionInfo(const std::wstring &gameDirectory)
+ : GameInfo(gameDirectory)
{
identifyMyGamesDirectory(L"oblivion");
}
@@ -63,71 +63,9 @@ std::wstring OblivionInfo::getRegPathStatic()
}
}
-
-
-
-
-
-
-
-
-
-
-std::vector<std::wstring> OblivionInfo::getDLCPlugins()
-{
- return boost::assign::list_of (L"DLCShiveringIsles.esp")
- (L"Knights.esp")
- (L"DLCFrostcrag.esp")
- (L"DLCSpellTomes.esp")
- (L"DLCMehrunesRazor.esp")
- (L"DLCOrrery.esp")
- (L"DLCSpellTomes.esp")
- (L"DLCThievesDen.esp")
- (L"DLCVileLair.esp")
- (L"DLCHorseArmor.esp")
- ;
-}
-
-
-std::vector<std::wstring> OblivionInfo::getSavegameAttachmentExtensions()
-{
- 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");
}
-
-
-
-
-std::wstring OblivionInfo::getNexusPage(bool nmmScheme)
-{
- if (nmmScheme) {
- return L"http://nmm.nexusmods.com/oblivion";
- } else {
- return L"http://www.nexusmods.com/oblivion";
- }
-}
-
-
-std::wstring OblivionInfo::getNexusInfoUrlStatic()
-{
- return L"http://nmm.nexusmods.com/oblivion";
-}
-
-
-int OblivionInfo::getNexusModIDStatic()
-{
- return 38277;
-}
-
-std::wstring OblivionInfo::getReferenceDataFile()
-{
- return L"Oblivion - Meshes.bsa";
-}
-
} // namespace MOShared
diff --git a/src/shared/oblivioninfo.h b/src/shared/oblivioninfo.h
index 1ef5b48e..6609921a 100644
--- a/src/shared/oblivioninfo.h
+++ b/src/shared/oblivioninfo.h
@@ -34,71 +34,16 @@ public:
virtual ~OblivionInfo() {}
static std::wstring getRegPathStatic();
- virtual std::wstring getRegPath() { return getRegPathStatic(); }
- virtual std::wstring getBinaryName() { return L"Oblivion.exe"; }
-
- virtual GameInfo::Type getType() { return TYPE_OBLIVION; }
-
- virtual std::wstring getGameName() const { return L"Oblivion"; }
- virtual std::wstring getGameShortName() const { return L"Oblivion"; }
-/*
- virtual std::wstring getInvalidationBSA()
- {
- return L"Oblivion - Invalidation.bsa";
- }
-
- virtual bool isInvalidationBSA(const std::wstring &bsaName)
- {
- static LPCWSTR invalidation[] = { L"Oblivion - Invalidation.bsa", L"ArchiveInvalidationInvalidated!.bsa",
- L"BSARedirection.bsa", nullptr };
-
- for (int i = 0; invalidation[i] != nullptr; ++i) {
- if (wcscmp(bsaName.c_str(), invalidation[i]) == 0) {
- return true;
- }
- }
- return false;
- }
-
- virtual std::vector<std::wstring> getVanillaBSAs()
- {
- return boost::assign::list_of(L"Oblivion - Meshes.bsa")
- (L"Oblivion - Textures - Compressed.bsa")
- (L"Oblivion - Sounds.bsa")
- (L"Oblivion - Voices1.bsa")
- (L"Oblivion - Voices2.bsa")
- (L"Oblivion - Misc.bsa");
- }
-
- virtual std::vector<std::wstring> getPrimaryPlugins()
- {
- return boost::assign::list_of(L"oblivion.esm");
- }*/
-
- virtual std::vector<std::wstring> getDLCPlugins();
- virtual std::vector<std::wstring> getSavegameAttachmentExtensions();
+ virtual std::wstring getRegPath() const { return getRegPathStatic(); }
// file name of this games ini (no path)
- virtual std::vector<std::wstring> getIniFileNames();
-
- virtual std::wstring getReferenceDataFile();
-
- virtual std::wstring getNexusPage(bool nmmScheme = true);
- static std::wstring getNexusInfoUrlStatic();
- virtual std::wstring getNexusInfoUrl() { return getNexusInfoUrlStatic(); }
- static int getNexusModIDStatic();
- virtual int getNexusModID() { return getNexusModIDStatic(); }
- virtual int getNexusGameID() { return 101; }
-
- // 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::vector<std::wstring> getIniFileNames() const;
- virtual std::wstring archiveListKey() { return L"SArchiveList"; }
+ virtual std::wstring archiveListKey() const { return L"SArchiveList"; }
private:
- OblivionInfo(const std::wstring &moDirectory, const std::wstring &moDataDirectory, const std::wstring &gameDirectory);
+ OblivionInfo(const std::wstring &gameDirectory);
static bool identifyGame(const std::wstring &searchPath);
diff --git a/src/shared/skyriminfo.cpp b/src/shared/skyriminfo.cpp
index acd72a3f..fbe13ae0 100644
--- a/src/shared/skyriminfo.cpp
+++ b/src/shared/skyriminfo.cpp
@@ -33,8 +33,8 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
namespace MOShared {
-SkyrimInfo::SkyrimInfo(const std::wstring &moDirectory, const std::wstring &moDataDirectory, const std::wstring &gameDirectory)
- : GameInfo(moDirectory, moDataDirectory, gameDirectory)
+SkyrimInfo::SkyrimInfo(const std::wstring &gameDirectory)
+ : GameInfo(gameDirectory)
{
identifyMyGamesDirectory(L"skyrim");
@@ -73,71 +73,9 @@ std::wstring SkyrimInfo::getRegPathStatic()
}
}
-GameInfo::LoadOrderMechanism SkyrimInfo::getLoadOrderMechanism() const
-{
- std::wstring fileName = getGameDirectory() + L"\\TESV.exe";
-
- try {
- VS_FIXEDFILEINFO versionInfo = GetFileVersion(fileName);
- if ((versionInfo.dwFileVersionMS > 0x10004) || // version >= 1.5.x?
- ((versionInfo.dwFileVersionMS == 0x10004) && (versionInfo.dwFileVersionLS >= 0x1A0000))) { // version >= ?.4.26
- return TYPE_PLUGINSTXT;
- } else {
- return TYPE_FILETIME;
- }
- } catch (const std::exception &e) {
- log("TESV.exe is invalid: %s", e.what());
- return TYPE_FILETIME;
- }
-}
-
-std::vector<std::wstring> SkyrimInfo::getDLCPlugins()
-{
- return boost::assign::list_of (L"Dawnguard.esm")
- (L"Dragonborn.esm")
- (L"HearthFires.esm")
- (L"HighResTexturePack01.esp")
- (L"HighResTexturePack02.esp")
- (L"HighResTexturePack03.esp")
- ;
-}
-
-std::vector<std::wstring> SkyrimInfo::getSavegameAttachmentExtensions()
-{
- 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()
-{
- return L"Skyrim - Meshes.bsa";
-}
-
-
-std::wstring SkyrimInfo::getNexusPage(bool nmmScheme)
-{
- if (nmmScheme) {
- return L"http://nmm.nexusmods.com/skyrim";
- } else {
- return L"http://www.nexusmods.com/skyrim";
- }
-}
-
-
-std::wstring SkyrimInfo::getNexusInfoUrlStatic()
-{
- return L"http://nmm.nexusmods.com/skyrim";
-}
-
-
-int SkyrimInfo::getNexusModIDStatic()
-{
- return 1334;
-}
-
-
} // namespace MOShared
diff --git a/src/shared/skyriminfo.h b/src/shared/skyriminfo.h
index 732b9261..a13b834e 100644
--- a/src/shared/skyriminfo.h
+++ b/src/shared/skyriminfo.h
@@ -36,37 +36,14 @@ public:
virtual ~SkyrimInfo() {}
static std::wstring getRegPathStatic();
- virtual std::wstring getRegPath() { return getRegPathStatic(); }
- virtual std::wstring getBinaryName() { return L"TESV.exe"; }
-
- virtual GameInfo::Type getType() { return TYPE_SKYRIM; }
-
- virtual std::wstring getGameName() const { return L"Skyrim"; }
- virtual std::wstring getGameShortName() const { return L"Skyrim"; }
-
- virtual LoadOrderMechanism getLoadOrderMechanism() const;
-
- virtual std::vector<std::wstring> getDLCPlugins();
-
- virtual std::vector<std::wstring> getSavegameAttachmentExtensions();
+ virtual std::wstring getRegPath() const { return getRegPathStatic(); }
// file name of this games ini (no path)
- virtual std::vector<std::wstring> getIniFileNames();
-
- virtual std::wstring getReferenceDataFile();
-
- virtual std::wstring getNexusPage(bool nmmScheme = true);
-
- static std::wstring getNexusInfoUrlStatic();
- virtual std::wstring getNexusInfoUrl() { return getNexusInfoUrlStatic(); }
- static int getNexusModIDStatic();
- virtual int getNexusModID() { return getNexusModIDStatic(); }
- static int getNexusGameIDStatic() { return 110; }
- virtual int getNexusGameID() { return getNexusGameIDStatic(); }
+ virtual std::vector<std::wstring> getIniFileNames() const;
private:
- SkyrimInfo(const std::wstring &moDirectory, const std::wstring &moDataDirectory, const std::wstring &gameDirectory);
+ SkyrimInfo(const std::wstring &gameDirectory);
static bool identifyGame(const std::wstring &searchPath);
diff --git a/src/shared/stackdata.cpp b/src/shared/stackdata.cpp
index 6c5a0968..b336593a 100644
--- a/src/shared/stackdata.cpp
+++ b/src/shared/stackdata.cpp
@@ -24,7 +24,7 @@ static void initDbgIfNecess()
firstCall = false;
}
if (!::SymInitialize(process, NULL, TRUE)) {
- printf("failed to initialize symbols: %d", ::GetLastError());
+ printf("failed to initialize symbols: %lu", ::GetLastError());
}
initialized.insert(::GetCurrentProcessId());
}
@@ -99,7 +99,8 @@ void StackData::initTrace() {
CONTEXT context;
std::memset(&context, 0, sizeof(CONTEXT));
context.ContextFlags = CONTEXT_CONTROL;
-#if BOOST_ARCH_X86_64
+ //Why only for 64 bit?
+#if BOOST_ARCH_X86_64 || defined(__clang__)
::RtlCaptureContext(&context);
#else
__asm
diff --git a/src/spawn.cpp b/src/spawn.cpp
index 14cdb4d4..19cf304c 100644
--- a/src/spawn.cpp
+++ b/src/spawn.cpp
@@ -18,19 +18,22 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
*/
#include "spawn.h"
+
#include "report.h"
#include "utility.h"
-#include <boost/scoped_array.hpp>
-#include <gameinfo.h>
#include <report.h>
#include <inject.h>
#include <usvfs.h>
#include <Shellapi.h>
#include <appconfig.h>
#include <windows_error.h>
+
#include <QApplication>
#include <QMessageBox>
+#include <Shellapi.h>
+
+#include <boost/scoped_array.hpp>
using namespace MOBase;
using namespace MOShared;
diff --git a/src/syncoverwritedialog.cpp b/src/syncoverwritedialog.cpp
index 0e3e98d7..aeed0a55 100644
--- a/src/syncoverwritedialog.cpp
+++ b/src/syncoverwritedialog.cpp
@@ -18,10 +18,11 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
*/
#include "syncoverwritedialog.h"
+
#include "ui_syncoverwritedialog.h"
#include <utility.h>
#include <report.h>
-#include <gameinfo.h>
+
#include <QDir>
#include <QDirIterator>
#include <QComboBox>
diff --git a/src/transfersavesdialog.cpp b/src/transfersavesdialog.cpp
index 7f9879cf..494834b3 100644
--- a/src/transfersavesdialog.cpp
+++ b/src/transfersavesdialog.cpp
@@ -18,12 +18,15 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
*/
#include "transfersavesdialog.h"
+
#include "ui_transfersavesdialog.h"
+#include "iplugingame.h"
#include "savegamegamebyro.h"
#include "utility.h"
-#include <gameinfo.h>
+
#include <QDir>
#include <QMessageBox>
+
#include <Shlwapi.h>
#include <shlobj.h>
@@ -32,7 +35,7 @@ using namespace MOBase;
using namespace MOShared;
-TransferSavesDialog::TransferSavesDialog(const Profile &profile, IPluginGame *gamePlugin, QWidget *parent)
+TransferSavesDialog::TransferSavesDialog(const Profile &profile, IPluginGame const *gamePlugin, QWidget *parent)
: TutorableDialog("TransferSaves", parent)
, ui(new Ui::TransferSavesDialog)
, m_Profile(profile)
@@ -60,7 +63,7 @@ void TransferSavesDialog::refreshGlobalSaves()
QStringList files = savesDir.entryList(QDir::Files, QDir::Time);
for (const QString &filename : files) {
- SaveGameGamebryo *save = new SaveGameGamebryo(this, savesDir.absoluteFilePath(filename));
+ SaveGameGamebryo *save = new SaveGameGamebryo(this, savesDir.absoluteFilePath(filename), m_GamePlugin);
save->setParent(this);
m_GlobalSaves.push_back(save);
}
@@ -78,7 +81,8 @@ void TransferSavesDialog::refreshLocalSaves()
QStringList files = savesDir.entryList(QDir::Files, QDir::Time);
for (const QString &filename : files) {
- SaveGameGamebryo *save = new SaveGameGamebryo(this, savesDir.absoluteFilePath(filename));
+ SaveGameGamebryo *save = new SaveGameGamebryo(this, savesDir.absoluteFilePath(filename), m_GamePlugin);
+
save->setParent(this);
m_LocalSaves.push_back(save);
}
diff --git a/src/transfersavesdialog.h b/src/transfersavesdialog.h
index b9265b6a..e2c556b4 100644
--- a/src/transfersavesdialog.h
+++ b/src/transfersavesdialog.h
@@ -22,11 +22,9 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#include "tutorabledialog.h"
#include "profile.h"
-#include <iplugingame.h>
-namespace Ui {
-class TransferSavesDialog;
-}
+namespace Ui { class TransferSavesDialog; }
+namespace MOBase { class IPluginGame; }
class SaveGame;
@@ -35,7 +33,7 @@ class TransferSavesDialog : public MOBase::TutorableDialog
Q_OBJECT
public:
- explicit TransferSavesDialog(const Profile &profile, MOBase::IPluginGame *gamePlugin, QWidget *parent = 0);
+ explicit TransferSavesDialog(const Profile &profile, MOBase::IPluginGame const *gamePlugin, QWidget *parent = 0);
~TransferSavesDialog();
private slots:
@@ -76,7 +74,7 @@ private:
Profile m_Profile;
- MOBase::IPluginGame *m_GamePlugin;
+ MOBase::IPluginGame const *m_GamePlugin;
std::vector<SaveGame*> m_GlobalSaves;
std::vector<SaveGame*> m_LocalSaves;