summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTanninOne <seppleviathan@gmx.de>2015-12-04 22:30:35 +0100
committerTanninOne <seppleviathan@gmx.de>2015-12-04 22:30:35 +0100
commit688e149c96c29d8249c9db416f5773cfc7baad6d (patch)
tree3a59b3fce8da8afec776e275aca979681711d4de /src
parent87d5fe28f6000e7a711fe56aa5e9bedfd89128fb (diff)
parentd4754f4d3ca7451d784e89ae1ddef240666dfdf8 (diff)
Merge pull request #334 from ThosRTanner/issue/308
Allow right click on module to see web link if supplied in fomod
Diffstat (limited to 'src')
-rw-r--r--src/CMakeLists.txt10
-rw-r--r--src/installationmanager.cpp5
-rw-r--r--src/installationmanager.h5
-rw-r--r--src/mainwindow.cpp23
-rw-r--r--src/mainwindow.h1
-rw-r--r--src/modinfo.cpp787
-rw-r--r--src/modinfo.h561
-rw-r--r--src/modinfobackup.cpp20
-rw-r--r--src/modinfobackup.h40
-rw-r--r--src/modinfoforeign.cpp50
-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/organizer.pro14
-rw-r--r--src/shared/SConscript10
-rw-r--r--src/shared/fallout3info.cpp17
-rw-r--r--src/shared/fallout3info.h31
-rw-r--r--src/shared/falloutnvinfo.cpp17
-rw-r--r--src/shared/falloutnvinfo.h63
-rw-r--r--src/shared/gameinfo.cpp13
-rw-r--r--src/shared/gameinfo.h30
-rw-r--r--src/shared/oblivioninfo.cpp31
-rw-r--r--src/shared/oblivioninfo.h63
-rw-r--r--src/shared/skyriminfo.cpp17
-rw-r--r--src/shared/skyriminfo.h26
29 files changed, 1615 insertions, 1512 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 9ef5d1bc..86d1e4c8 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
@@ -125,6 +130,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
diff --git a/src/installationmanager.cpp b/src/installationmanager.cpp
index f96cd0f3..9fb9bdbb 100644
--- a/src/installationmanager.cpp
+++ b/src/installationmanager.cpp
@@ -100,6 +100,10 @@ void InstallationManager::setParentWidget(QWidget *widget)
}
}
+void InstallationManager::setURL(QString const &url)
+{
+ m_URL = url;
+}
void InstallationManager::queryPassword(QString *password)
{
@@ -582,6 +586,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
diff --git a/src/installationmanager.h b/src/installationmanager.h
index 5a8ec9d2..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
@@ -166,8 +168,6 @@ private:
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);
@@ -210,6 +210,7 @@ private:
std::set<QString> m_TempFilesToDelete;
+ QString m_URL;
};
diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp
index 26ff4b98..9982e928 100644
--- a/src/mainwindow.cpp
+++ b/src/mainwindow.cpp
@@ -2525,12 +2525,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));
+ linkClicked(QString("%1/mods/%2").arg(ToQString(GameInfo::instance().getNexusPage(false))).arg(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);
@@ -3106,7 +3116,16 @@ void MainWindow::on_modList_customContextMenuRequested(const QPoint &pos)
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 (info->getURL() != "" &&
+ !GameInfo::instance().isValidModURL(info->getNexusID(),
+ info->getURL().toStdWString())) {
+ menu->addAction(tr("Visit web page"), this, SLOT(visitWebPage_clicked()));
+ }
+
menu->addAction(tr("Open in explorer"), this, SLOT(openExplorer_clicked()));
}
diff --git a/src/mainwindow.h b/src/mainwindow.h
index 55ae40b9..3c7f2258 100644
--- a/src/mainwindow.h
+++ b/src/mainwindow.h
@@ -361,6 +361,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..fe5098e8 100644
--- a/src/modinfo.cpp
+++ b/src/modinfo.cpp
@@ -19,29 +19,23 @@ 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 <gameinfo.h>
-#include <iplugingame.h>
-#include <versioninfo.h>
-#include <appconfig.h>
-#include <scriptextender.h>
+#include "versioninfo.h"
#include <QApplication>
-
#include <QDirIterator>
#include <QMutexLocker>
#include <QSettings>
-#include <sstream>
-
using namespace MOBase;
using namespace MOShared;
@@ -386,772 +380,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..7d305c11 100644
--- a/src/modinfo.h
+++ b/src/modinfo.h
@@ -20,22 +20,23 @@ 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 <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 MOShared { class DirectoryEntry; }
/**
* @brief Represents meta information about a single mod.
@@ -556,6 +557,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 +607,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/modinfoforeign.cpp b/src/modinfoforeign.cpp
new file mode 100644
index 00000000..c0e769c9
--- /dev/null
+++ b/src/modinfoforeign.cpp
@@ -0,0 +1,50 @@
+#include "modinfoforeign.h"
+
+#include "gameinfo.h"
+#include "utility.h"
+
+using namespace MOBase;
+using namespace MOShared;
+
+QString ModInfoForeign::name() const
+{
+ return m_Name;
+}
+
+QDateTime ModInfoForeign::creationTime() const
+{
+ return m_CreationTime;
+}
+
+QString ModInfoForeign::absolutePath() const
+{
+ return QDir::fromNativeSeparators(ToQString(GameInfo::instance().getGameDirectory())) + "/data";
+}
+
+std::vector<ModInfo::EFlag> ModInfoForeign::getFlags() const
+{
+ std::vector<ModInfo::EFlag> result = ModInfoWithConflictInfo::getFlags();
+ result.push_back(FLAG_FOREIGN);
+
+ return result;
+}
+
+int ModInfoForeign::getHighlight() const
+{
+ return 0;
+}
+
+QString ModInfoForeign::getDescription() const
+{
+ return tr("This pseudo mod represents content managed outside MO. It isn't modified by MO.");
+}
+
+ModInfoForeign::ModInfoForeign(const QString &referenceFile, const QStringList &archives,
+ DirectoryEntry **directoryStructure)
+ : ModInfoWithConflictInfo(directoryStructure)
+ , m_ReferenceFile(referenceFile)
+ , m_Archives(archives)
+{
+ m_CreationTime = QFileInfo(referenceFile).created();
+ m_Name = "Unmanaged: " + QFileInfo(m_ReferenceFile).baseName();
+}
diff --git a/src/modinfoforeign.h b/src/modinfoforeign.h
new file mode 100644
index 00000000..b8ff2671
--- /dev/null
+++ b/src/modinfoforeign.h
@@ -0,0 +1,67 @@
+#ifndef MODINFOFOREIGN_H
+#define MODINFOFOREIGN_H
+
+#include "modinfowithconflictinfo.h"
+
+class ModInfoForeign : public ModInfoWithConflictInfo
+{
+
+ Q_OBJECT
+
+ friend class ModInfo;
+
+public:
+
+ virtual bool updateAvailable() const { return false; }
+ virtual bool updateIgnored() const { return false; }
+ virtual bool downgradeAvailable() const { return false; }
+ virtual bool updateNXMInfo() { return false; }
+ virtual void setCategory(int, bool) {}
+ virtual bool setName(const QString&) { return false; }
+ virtual void setNotes(const QString&) {}
+ virtual void setNexusID(int) {}
+ virtual void setNewestVersion(const MOBase::VersionInfo&) {}
+ virtual void ignoreUpdate(bool) {}
+ virtual void setNexusDescription(const QString&) {}
+ virtual void setInstallationFile(const QString&) {}
+ virtual void addNexusCategory(int) {}
+ virtual void setIsEndorsed(bool) {}
+ virtual void setNeverEndorse() {}
+ virtual bool remove() { return false; }
+ virtual void endorse(bool) {}
+ virtual bool isEmpty() const { return false; }
+ virtual QString name() const;
+ virtual QString internalName() const { return name(); }
+ virtual QString notes() const { return ""; }
+ virtual QDateTime creationTime() const;
+ virtual QString absolutePath() const;
+ virtual MOBase::VersionInfo getNewestVersion() const { return ""; }
+ virtual QString getInstallationFile() const { return ""; }
+ virtual int getNexusID() const { return -1; }
+ virtual std::vector<QString> getIniTweaks() const { return std::vector<QString>(); }
+ virtual std::vector<ModInfo::EFlag> getFlags() const;
+ virtual int getHighlight() const;
+ virtual QString getDescription() const;
+ virtual QDateTime getLastNexusQuery() const { return QDateTime(); }
+ virtual QString getNexusDescription() const { return QString(); }
+ virtual int getFixedPriority() const { return INT_MIN; }
+ virtual QStringList archives() const { return m_Archives; }
+ virtual QStringList stealFiles() const { return m_Archives + QStringList(m_ReferenceFile); }
+ virtual bool alwaysEnabled() const { return true; }
+ virtual void addInstalledFile(int, int) {}
+
+protected:
+
+ ModInfoForeign(const QString &referenceFile, const QStringList &archives, MOShared::DirectoryEntry **directoryStructure);
+
+private:
+
+ QString m_Name;
+ QString m_ReferenceFile;
+ QStringList m_Archives;
+ QDateTime m_CreationTime;
+ int m_Priority;
+
+};
+
+#endif // MODINFOFOREIGN_H
diff --git a/src/modinfooverwrite.cpp b/src/modinfooverwrite.cpp
new file mode 100644
index 00000000..4380a255
--- /dev/null
+++ b/src/modinfooverwrite.cpp
@@ -0,0 +1,53 @@
+#include "modinfooverwrite.h"
+
+#include "appconfig.h"
+
+#include <QApplication>
+#include <QDirIterator>
+
+ModInfoOverwrite::ModInfoOverwrite()
+{
+ testValid();
+}
+
+bool ModInfoOverwrite::isEmpty() const
+{
+ QDirIterator iter(absolutePath(), QDir::NoDotAndDotDot | QDir::Files | QDir::Dirs);
+ if (!iter.hasNext()) return true;
+ iter.next();
+ if ((iter.fileName() == "meta.ini") && !iter.hasNext()) return true;
+ return false;
+}
+
+QString ModInfoOverwrite::absolutePath() const
+{
+ return QDir::fromNativeSeparators(qApp->property("dataPath").toString() + "/" + QString::fromStdWString(AppConfig::overwritePath()));
+}
+
+std::vector<ModInfo::EFlag> ModInfoOverwrite::getFlags() const
+{
+ std::vector<ModInfo::EFlag> result;
+ result.push_back(FLAG_OVERWRITE);
+ return result;
+}
+
+int ModInfoOverwrite::getHighlight() const
+{
+ return (isValid() ? HIGHLIGHT_IMPORTANT : HIGHLIGHT_INVALID) | HIGHLIGHT_CENTER;
+}
+
+QString ModInfoOverwrite::getDescription() const
+{
+ return tr("This pseudo mod contains files from the virtual data tree that got "
+ "modified (i.e. by the construction kit)");
+}
+
+QStringList ModInfoOverwrite::archives() const
+{
+ QStringList result;
+ QDir dir(this->absolutePath());
+ for (const QString &archive : dir.entryList(QStringList("*.bsa"))) {
+ result.append(this->absolutePath() + "/" + archive);
+ }
+ return result;
+}
diff --git a/src/modinfooverwrite.h b/src/modinfooverwrite.h
new file mode 100644
index 00000000..9184a90c
--- /dev/null
+++ b/src/modinfooverwrite.h
@@ -0,0 +1,59 @@
+#ifndef MODINFOOVERWRITE_H
+#define MODINFOOVERWRITE_H
+
+#include "modinfo.h"
+
+#include <QDateTime>
+
+class ModInfoOverwrite : public ModInfo
+{
+
+ Q_OBJECT
+
+ friend class ModInfo;
+
+public:
+
+ virtual bool updateAvailable() const { return false; }
+ virtual bool updateIgnored() const { return false; }
+ virtual bool downgradeAvailable() const { return false; }
+ virtual bool updateNXMInfo() { return false; }
+ virtual void setCategory(int, bool) {}
+ virtual bool setName(const QString&) { return false; }
+ virtual void setNotes(const QString&) {}
+ virtual void setNexusID(int) {}
+ virtual void setNewestVersion(const MOBase::VersionInfo&) {}
+ virtual void ignoreUpdate(bool) {}
+ virtual void setNexusDescription(const QString&) {}
+ virtual void setInstallationFile(const QString&) {}
+ virtual void addNexusCategory(int) {}
+ virtual void setIsEndorsed(bool) {}
+ virtual void setNeverEndorse() {}
+ virtual bool remove() { return false; }
+ virtual void endorse(bool) {}
+ virtual bool alwaysEnabled() const { return true; }
+ virtual bool isEmpty() const;
+ virtual QString name() const { return "Overwrite"; }
+ virtual QString notes() const { return ""; }
+ virtual QDateTime creationTime() const { return QDateTime(); }
+ virtual QString absolutePath() const;
+ virtual MOBase::VersionInfo getNewestVersion() const { return ""; }
+ virtual QString getInstallationFile() const { return ""; }
+ virtual int getFixedPriority() const { return INT_MAX; }
+ virtual int getNexusID() const { return -1; }
+ virtual std::vector<QString> getIniTweaks() const { return std::vector<QString>(); }
+ virtual std::vector<ModInfo::EFlag> getFlags() const;
+ virtual int getHighlight() const;
+ virtual QString getDescription() const;
+ virtual QDateTime getLastNexusQuery() const { return QDateTime(); }
+ virtual QString getNexusDescription() const { return QString(); }
+ virtual QStringList archives() const;
+ virtual void addInstalledFile(int, int) {}
+
+private:
+
+ ModInfoOverwrite();
+
+};
+
+#endif // MODINFOOVERWRITE_H
diff --git a/src/modinforegular.cpp b/src/modinforegular.cpp
new file mode 100644
index 00000000..b1f73a37
--- /dev/null
+++ b/src/modinforegular.cpp
@@ -0,0 +1,571 @@
+#include "modinforegular.h"
+
+#include "categories.h"
+#include "iplugingame.h"
+#include "messagedialog.h"
+#include "report.h"
+#include "scriptextender.h"
+
+#include <QApplication>
+#include <QDirIterator>
+#include <QSettings>
+
+#include <sstream>
+
+using namespace MOBase;
+using namespace MOShared;
+
+namespace {
+ //Arguably this should be a class static or we should be using FileString rather
+ //than QString for the names. Or both.
+ static bool ByName(const ModInfo::Ptr &LHS, const ModInfo::Ptr &RHS)
+ {
+ return QString::compare(LHS->name(), RHS->name(), Qt::CaseInsensitive) < 0;
+ }
+}
+
+ModInfoRegular::ModInfoRegular(const QDir &path, DirectoryEntry **directoryStructure)
+ : ModInfoWithConflictInfo(directoryStructure)
+ , m_Name(path.dirName())
+ , m_Path(path.absolutePath())
+ , m_Repository()
+ , m_MetaInfoChanged(false)
+ , m_EndorsedState(ENDORSED_UNKNOWN)
+ , m_NexusBridge()
+{
+ testValid();
+ m_CreationTime = QFileInfo(path.absolutePath()).created();
+ // read out the meta-file for information
+ readMeta();
+
+ connect(&m_NexusBridge, SIGNAL(descriptionAvailable(int,QVariant,QVariant))
+ , this, SLOT(nxmDescriptionAvailable(int,QVariant,QVariant)));
+ connect(&m_NexusBridge, SIGNAL(endorsementToggled(int,QVariant,QVariant))
+ , this, SLOT(nxmEndorsementToggled(int,QVariant,QVariant)));
+ connect(&m_NexusBridge, SIGNAL(requestFailed(int,int,QVariant,QString))
+ , this, SLOT(nxmRequestFailed(int,int,QVariant,QString)));
+}
+
+
+ModInfoRegular::~ModInfoRegular()
+{
+ try {
+ saveMeta();
+ } catch (const std::exception &e) {
+ qCritical("failed to save meta information for \"%s\": %s",
+ m_Name.toUtf8().constData(), e.what());
+ }
+}
+
+bool ModInfoRegular::isEmpty() const
+{
+ QDirIterator iter(m_Path, QDir::NoDotAndDotDot | QDir::Files | QDir::Dirs);
+ if (!iter.hasNext()) return true;
+ iter.next();
+ if ((iter.fileName() == "meta.ini") && !iter.hasNext()) return true;
+ return false;
+}
+
+
+void ModInfoRegular::readMeta()
+{
+ QSettings metaFile(m_Path + "/meta.ini", QSettings::IniFormat);
+ m_Notes = metaFile.value("notes", "").toString();
+ m_NexusID = metaFile.value("modid", -1).toInt();
+ m_Version.parse(metaFile.value("version", "").toString());
+ m_NewestVersion = metaFile.value("newestVersion", "").toString();
+ m_IgnoredVersion = metaFile.value("ignoredVersion", "").toString();
+ m_InstallationFile = metaFile.value("installationFile", "").toString();
+ m_NexusDescription = metaFile.value("nexusDescription", "").toString();
+ m_Repository = metaFile.value("repository", "Nexus").toString();
+ m_URL = metaFile.value("url", "").toString();
+ m_LastNexusQuery = QDateTime::fromString(metaFile.value("lastNexusQuery", "").toString(), Qt::ISODate);
+ if (metaFile.contains("endorsed")) {
+ if (metaFile.value("endorsed").canConvert<int>()) {
+ switch (metaFile.value("endorsed").toInt()) {
+ case ENDORSED_FALSE: m_EndorsedState = ENDORSED_FALSE; break;
+ case ENDORSED_TRUE: m_EndorsedState = ENDORSED_TRUE; break;
+ case ENDORSED_NEVER: m_EndorsedState = ENDORSED_NEVER; break;
+ default: m_EndorsedState = ENDORSED_UNKNOWN; break;
+ }
+ } else {
+ m_EndorsedState = metaFile.value("endorsed", false).toBool() ? ENDORSED_TRUE : ENDORSED_FALSE;
+ }
+ }
+
+ QString categoriesString = metaFile.value("category", "").toString();
+
+ QStringList categories = categoriesString.split(',', QString::SkipEmptyParts);
+ for (QStringList::iterator iter = categories.begin(); iter != categories.end(); ++iter) {
+ bool ok = false;
+ int categoryID = iter->toInt(&ok);
+ if (categoryID < 0) {
+ // ignore invalid id
+ continue;
+ }
+ if (ok && (categoryID != 0) && (CategoryFactory::instance().categoryExists(categoryID))) {
+ m_Categories.insert(categoryID);
+ if (iter == categories.begin()) {
+ m_PrimaryCategory = categoryID;
+ }
+ }
+ }
+
+ int numFiles = metaFile.beginReadArray("installedFiles");
+ for (int i = 0; i < numFiles; ++i) {
+ metaFile.setArrayIndex(i);
+ m_InstalledFileIDs.insert(std::make_pair(metaFile.value("modid").toInt(), metaFile.value("fileid").toInt()));
+ }
+ metaFile.endArray();
+
+ m_MetaInfoChanged = false;
+}
+
+void ModInfoRegular::saveMeta()
+{
+ // only write meta data if the mod directory exists
+ if (m_MetaInfoChanged && QFile::exists(absolutePath())) {
+ QSettings metaFile(absolutePath().append("/meta.ini"), QSettings::IniFormat);
+ if (metaFile.status() == QSettings::NoError) {
+ std::set<int> temp = m_Categories;
+ temp.erase(m_PrimaryCategory);
+ metaFile.setValue("category", QString("%1").arg(m_PrimaryCategory) + "," + SetJoin(temp, ","));
+ metaFile.setValue("newestVersion", m_NewestVersion.canonicalString());
+ metaFile.setValue("ignoredVersion", m_IgnoredVersion.canonicalString());
+ metaFile.setValue("version", m_Version.canonicalString());
+ metaFile.setValue("installationFile", m_InstallationFile);
+ metaFile.setValue("repository", m_Repository);
+ metaFile.setValue("modid", m_NexusID);
+ metaFile.setValue("notes", m_Notes);
+ metaFile.setValue("nexusDescription", m_NexusDescription);
+ metaFile.setValue("url", m_URL);
+ metaFile.setValue("lastNexusQuery", m_LastNexusQuery.toString(Qt::ISODate));
+ if (m_EndorsedState != ENDORSED_UNKNOWN) {
+ metaFile.setValue("endorsed", m_EndorsedState);
+ }
+
+ metaFile.beginWriteArray("installedFiles");
+ int idx = 0;
+ for (auto iter = m_InstalledFileIDs.begin(); iter != m_InstalledFileIDs.end(); ++iter) {
+ metaFile.setArrayIndex(idx++);
+ metaFile.setValue("modid", iter->first);
+ metaFile.setValue("fileid", iter->second);
+ }
+ metaFile.endArray();
+
+ metaFile.sync(); // sync needs to be called to ensure the file is created
+
+ if (metaFile.status() == QSettings::NoError) {
+ m_MetaInfoChanged = false;
+ } else {
+ reportError(tr("failed to write %1/meta.ini: error %2").arg(absolutePath()).arg(metaFile.status()));
+ }
+ } else {
+ reportError(tr("failed to write %1/meta.ini: error %2").arg(absolutePath()).arg(metaFile.status()));
+ }
+ }
+}
+
+
+bool ModInfoRegular::updateAvailable() const
+{
+ if (m_IgnoredVersion.isValid() && (m_IgnoredVersion == m_NewestVersion)) {
+ return false;
+ }
+ return m_NewestVersion.isValid() && (m_Version < m_NewestVersion);
+}
+
+
+bool ModInfoRegular::downgradeAvailable() const
+{
+ if (m_IgnoredVersion.isValid() && (m_IgnoredVersion == m_NewestVersion)) {
+ return false;
+ }
+ return m_NewestVersion.isValid() && (m_NewestVersion < m_Version);
+}
+
+
+void ModInfoRegular::nxmDescriptionAvailable(int, QVariant, QVariant resultData)
+{
+ QVariantMap result = resultData.toMap();
+ setNewestVersion(VersionInfo(result["version"].toString()));
+ setNexusDescription(result["description"].toString());
+
+ if ((m_EndorsedState != ENDORSED_NEVER) && (result.contains("voted_by_user"))) {
+ setEndorsedState(result["voted_by_user"].toBool() ? ENDORSED_TRUE : ENDORSED_FALSE);
+ }
+ m_LastNexusQuery = QDateTime::currentDateTime();
+ //m_MetaInfoChanged = true;
+ saveMeta();
+ emit modDetailsUpdated(true);
+}
+
+
+void ModInfoRegular::nxmEndorsementToggled(int, QVariant, QVariant resultData)
+{
+ m_EndorsedState = resultData.toBool() ? ENDORSED_TRUE : ENDORSED_FALSE;
+ m_MetaInfoChanged = true;
+ saveMeta();
+ emit modDetailsUpdated(true);
+}
+
+
+void ModInfoRegular::nxmRequestFailed(int, int, QVariant userData, const QString &errorMessage)
+{
+ QString fullMessage = errorMessage;
+ if (userData.canConvert<int>() && (userData.toInt() == 1)) {
+ fullMessage += "\nNexus will reject endorsements within 15 Minutes of a failed attempt, the error message may be misleading.";
+ }
+ if (QApplication::activeWindow() != nullptr) {
+ MessageDialog::showMessage(fullMessage, QApplication::activeWindow());
+ }
+ emit modDetailsUpdated(false);
+}
+
+
+bool ModInfoRegular::updateNXMInfo()
+{
+ if (m_NexusID > 0) {
+ m_NexusBridge.requestDescription(m_NexusID, QVariant());
+ return true;
+ }
+ return false;
+}
+
+
+void ModInfoRegular::setCategory(int categoryID, bool active)
+{
+ m_MetaInfoChanged = true;
+
+ if (active) {
+ m_Categories.insert(categoryID);
+ if (m_PrimaryCategory == -1) {
+ m_PrimaryCategory = categoryID;
+ }
+ } else {
+ std::set<int>::iterator iter = m_Categories.find(categoryID);
+ if (iter != m_Categories.end()) {
+ m_Categories.erase(iter);
+ }
+ if (categoryID == m_PrimaryCategory) {
+ if (m_Categories.size() == 0) {
+ m_PrimaryCategory = -1;
+ } else {
+ m_PrimaryCategory = *(m_Categories.begin());
+ }
+ }
+ }
+}
+
+
+bool ModInfoRegular::setName(const QString &name)
+{
+ if (name.contains('/') || name.contains('\\')) {
+ return false;
+ }
+
+ QString newPath = m_Path.mid(0).replace(m_Path.length() - m_Name.length(), m_Name.length(), name);
+ QDir modDir(m_Path.mid(0, m_Path.length() - m_Name.length()));
+
+ if (m_Name.compare(name, Qt::CaseInsensitive) == 0) {
+ QString tempName = name;
+ tempName.append("_temp");
+ while (modDir.exists(tempName)) {
+ tempName.append("_");
+ }
+ if (!modDir.rename(m_Name, tempName)) {
+ return false;
+ }
+ if (!modDir.rename(tempName, name)) {
+ qCritical("rename to final name failed after successful rename to intermediate name");
+ modDir.rename(tempName, m_Name);
+ return false;
+ }
+ } else {
+ if (!shellRename(modDir.absoluteFilePath(m_Name), modDir.absoluteFilePath(name))) {
+ qCritical("failed to rename mod %s (errorcode %d)",
+ qPrintable(name), ::GetLastError());
+ return false;
+ }
+ }
+
+ std::map<QString, unsigned int>::iterator nameIter = s_ModsByName.find(m_Name);
+ if (nameIter != s_ModsByName.end()) {
+ unsigned int index = nameIter->second;
+ s_ModsByName.erase(nameIter);
+
+ m_Name = name;
+ m_Path = newPath;
+
+ s_ModsByName[m_Name] = index;
+
+ std::sort(s_Collection.begin(), s_Collection.end(), ByName);
+ updateIndices();
+ } else { // otherwise mod isn't registered yet?
+ m_Name = name;
+ m_Path = newPath;
+ }
+
+ return true;
+}
+
+void ModInfoRegular::setNotes(const QString &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/organizer.pro b/src/organizer.pro
index 261e3c1c..adc606fb 100644
--- a/src/organizer.pro
+++ b/src/organizer.pro
@@ -91,7 +91,12 @@ SOURCES += \
organizerproxy.cpp \
viewmarkingscrollbar.cpp \
plugincontainer.cpp \
- organizercore.cpp
+ organizercore.cpp \
+ modinfowithconflictinfo.cpp \
+ modinforegular.cpp \
+ modinfobackup.cpp \
+ modinfooverwrite.cpp \
+ modinfoforeign.cpp
HEADERS += \
@@ -167,7 +172,12 @@ HEADERS += \
viewmarkingscrollbar.h \
plugincontainer.h \
organizercore.h \
- iuserinterface.h
+ iuserinterface.h \
+ modinfowithconflictinfo.h \
+ modinforegular.h \
+ modinfobackup.h \
+ modinfooverwrite.h \
+ modinfoforeign.h
FORMS += \
transfersavesdialog.ui \
diff --git a/src/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 0b369b50..f0776a7d 100644
--- a/src/shared/fallout3info.cpp
+++ b/src/shared/fallout3info.cpp
@@ -63,7 +63,7 @@ std::wstring Fallout3Info::getRegPathStatic()
}
-std::vector<std::wstring> Fallout3Info::getDLCPlugins()
+std::vector<std::wstring> Fallout3Info::getDLCPlugins() const
{
return boost::assign::list_of (L"ThePitt.esm")
(L"Anchorage.esm")
@@ -73,22 +73,22 @@ std::vector<std::wstring> Fallout3Info::getDLCPlugins()
;
}
-std::vector<std::wstring> Fallout3Info::getSavegameAttachmentExtensions()
+std::vector<std::wstring> Fallout3Info::getSavegameAttachmentExtensions() const
{
return std::vector<std::wstring>();
}
-std::vector<std::wstring> Fallout3Info::getIniFileNames()
+std::vector<std::wstring> Fallout3Info::getIniFileNames() const
{
return boost::assign::list_of(L"fallout.ini")(L"falloutprefs.ini");
}
-std::wstring Fallout3Info::getReferenceDataFile()
+std::wstring Fallout3Info::getReferenceDataFile() const
{
return L"Fallout - Meshes.bsa";
}
-std::wstring Fallout3Info::getNexusPage(bool nmmScheme)
+std::wstring Fallout3Info::getNexusPage(bool nmmScheme) const
{
if (nmmScheme) {
return L"http://nmm.nexusmods.com/fallout3";
@@ -107,7 +107,7 @@ int Fallout3Info::getNexusModIDStatic()
return 16348;
}
-bool Fallout3Info::rerouteToProfile(const wchar_t *fileName, const wchar_t*)
+bool Fallout3Info::rerouteToProfile(const wchar_t *fileName, const wchar_t*) const
{
static LPCWSTR profileFiles[] = { L"fallout.ini", L"falloutprefs.ini", L"plugins.txt", nullptr };
@@ -119,4 +119,9 @@ bool Fallout3Info::rerouteToProfile(const wchar_t *fileName, const wchar_t*)
return false;
}
+bool Fallout3Info::isValidModURL(int modID, const std::wstring &url) const
+{
+ return GameInfo::isValidModURL(modID, url, L"http://fallout3.nexusmods.com");
+}
+
} // namespace MOShared
diff --git a/src/shared/fallout3info.h b/src/shared/fallout3info.h
index 0045581d..0a2b0ebe 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,36 +35,34 @@ public:
virtual ~Fallout3Info() {}
static std::wstring getRegPathStatic();
- virtual std::wstring getRegPath() { return getRegPathStatic(); }
- virtual std::wstring getBinaryName() { return L"Fallout3.exe"; }
+ virtual std::wstring getRegPath() const { return getRegPathStatic(); }
+ virtual std::wstring getBinaryName() const { return L"Fallout3.exe"; }
- virtual GameInfo::Type getType() { return TYPE_FALLOUT3; }
+ virtual GameInfo::Type getType() const { 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::vector<std::wstring> getDLCPlugins() const;
+ virtual std::vector<std::wstring> getSavegameAttachmentExtensions() const;
// file name of this games ini (no path)
- virtual std::vector<std::wstring> getIniFileNames();
+ virtual std::vector<std::wstring> getIniFileNames() const;
- virtual std::wstring getReferenceDataFile();
+ virtual std::wstring getReferenceDataFile() const;
- virtual std::wstring getNexusPage(bool nmmScheme = true);
+ virtual std::wstring getNexusPage(bool nmmScheme = true) const;
static std::wstring getNexusInfoUrlStatic();
- virtual std::wstring getNexusInfoUrl() { return getNexusInfoUrlStatic(); }
+ virtual std::wstring getNexusInfoUrl() const { return getNexusInfoUrlStatic(); }
static int getNexusModIDStatic();
- virtual int getNexusModID() { return getNexusModIDStatic(); }
- virtual int getNexusGameID() { return 120; }
+ virtual int getNexusModID() const { return getNexusModIDStatic(); }
+ virtual int getNexusGameID() const { return 120; }
- virtual bool rerouteToProfile(const wchar_t *fileName, const wchar_t *fullPath);
+ virtual bool rerouteToProfile(const wchar_t *fileName, const wchar_t *fullPath) const;
- // get a list of executables (game binary and known-to-work 3rd party tools). All of these are relative to
- // the game directory
- //virtual std::vector<ExecutableInfo> getExecutables();
+ virtual std::wstring archiveListKey() const { return L"SArchiveList"; }
- virtual std::wstring archiveListKey() { return L"SArchiveList"; }
+ virtual bool isValidModURL(int modID, std::wstring const &url) const;
private:
diff --git a/src/shared/falloutnvinfo.cpp b/src/shared/falloutnvinfo.cpp
index 1203bd25..f6de72e3 100644
--- a/src/shared/falloutnvinfo.cpp
+++ b/src/shared/falloutnvinfo.cpp
@@ -63,7 +63,7 @@ std::wstring FalloutNVInfo::getRegPathStatic()
}
}
-std::vector<std::wstring> FalloutNVInfo::getDLCPlugins()
+std::vector<std::wstring> FalloutNVInfo::getDLCPlugins() const
{
return boost::assign::list_of (L"DeadMoney.esm")
(L"HonestHearts.esm")
@@ -77,22 +77,22 @@ std::vector<std::wstring> FalloutNVInfo::getDLCPlugins()
;
}
-std::vector<std::wstring> FalloutNVInfo::getSavegameAttachmentExtensions()
+std::vector<std::wstring> FalloutNVInfo::getSavegameAttachmentExtensions() const
{
return std::vector<std::wstring>();
}
-std::vector<std::wstring> FalloutNVInfo::getIniFileNames()
+std::vector<std::wstring> FalloutNVInfo::getIniFileNames() const
{
return boost::assign::list_of(L"fallout.ini")(L"falloutprefs.ini");
}
-std::wstring FalloutNVInfo::getReferenceDataFile()
+std::wstring FalloutNVInfo::getReferenceDataFile() const
{
return L"Fallout - Meshes.bsa";
}
-std::wstring FalloutNVInfo::getNexusPage(bool nmmScheme)
+std::wstring FalloutNVInfo::getNexusPage(bool nmmScheme) const
{
if (nmmScheme) {
return L"http://nmm.nexusmods.com/newvegas";
@@ -114,7 +114,7 @@ int FalloutNVInfo::getNexusModIDStatic()
}
-bool FalloutNVInfo::rerouteToProfile(const wchar_t *fileName, const wchar_t*)
+bool FalloutNVInfo::rerouteToProfile(const wchar_t *fileName, const wchar_t*) const
{
static LPCWSTR profileFiles[] = { L"fallout.ini", L"falloutprefs.ini", L"plugins.txt", nullptr };
@@ -126,4 +126,9 @@ bool FalloutNVInfo::rerouteToProfile(const wchar_t *fileName, const wchar_t*)
return false;
}
+bool FalloutNVInfo::isValidModURL(int modID, std::wstring const &url) const
+{
+ return GameInfo::isValidModURL(modID, url, L"http://newvegas.nexusmods.com");
+}
+
} // namespace MOShared
diff --git a/src/shared/falloutnvinfo.h b/src/shared/falloutnvinfo.h
index e1a614d2..d03add9c 100644
--- a/src/shared/falloutnvinfo.h
+++ b/src/shared/falloutnvinfo.h
@@ -36,69 +36,34 @@ public:
virtual ~FalloutNVInfo() {}
static std::wstring getRegPathStatic();
- virtual std::wstring getRegPath() { return getRegPathStatic(); }
- virtual std::wstring getBinaryName() { return L"FalloutNV.exe"; }
+ virtual std::wstring getRegPath() const { return getRegPathStatic(); }
+ virtual std::wstring getBinaryName() const { return L"FalloutNV.exe"; }
- virtual GameInfo::Type getType() { return TYPE_FALLOUTNV; }
+ virtual GameInfo::Type getType() const { 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::vector<std::wstring> getDLCPlugins() const;
+ virtual std::vector<std::wstring> getSavegameAttachmentExtensions() const;
// file name of this games ini (no path)
- virtual std::vector<std::wstring> getIniFileNames();
+ virtual std::vector<std::wstring> getIniFileNames() const;
- virtual std::wstring getReferenceDataFile();
+ virtual std::wstring getReferenceDataFile() const;
- virtual std::wstring getNexusPage(bool nmmScheme = true);
+ virtual std::wstring getNexusPage(bool nmmScheme = true) const;
static std::wstring getNexusInfoUrlStatic();
- virtual std::wstring getNexusInfoUrl() { return getNexusInfoUrlStatic(); }
+ virtual std::wstring getNexusInfoUrl() const { return getNexusInfoUrlStatic(); }
static int getNexusModIDStatic();
- virtual int getNexusModID() { return getNexusModIDStatic(); }
- virtual int getNexusGameID() { return 130; }
+ virtual int getNexusModID() const { return getNexusModIDStatic(); }
+ virtual int getNexusGameID() const { return 130; }
- virtual bool rerouteToProfile(const wchar_t *fileName, const wchar_t *fullPath);
+ virtual bool rerouteToProfile(const wchar_t *fileName, const wchar_t *fullPath) const;
- // get a list of executables (game binary and known-to-work 3rd party tools). All of these are relative to
- // the game directory
- //virtual std::vector<ExecutableInfo> getExecutables();
+ virtual std::wstring archiveListKey() const { return L"SArchiveList"; }
- virtual std::wstring archiveListKey() { return L"SArchiveList"; }
+ virtual bool isValidModURL(int modID, const std::wstring &url) const;
private:
diff --git a/src/shared/gameinfo.cpp b/src/shared/gameinfo.cpp
index 1f25cec1..5338c069 100644
--- a/src/shared/gameinfo.cpp
+++ b/src/shared/gameinfo.cpp
@@ -86,6 +86,19 @@ void GameInfo::identifyMyGamesDirectory(const std::wstring &file)
}
}
+bool GameInfo::isValidModURL(int modID, const std::wstring &url, const std::wstring &alt) const
+{
+ std::wostringstream os;
+ os << getNexusPage(false) << "/mods/" << modID;
+ if (url == os.str()) {
+ return true;
+ }
+ os.clear();
+ os.str(L"");
+ os << alt << "/mods/" << modID;
+ return url == os.str();
+}
+
bool GameInfo::identifyGame(const std::wstring &moDirectory, const std::wstring &moDataDirectory, const std::wstring &searchPath)
{
diff --git a/src/shared/gameinfo.h b/src/shared/gameinfo.h
index a32b6b82..8caa5937 100644
--- a/src/shared/gameinfo.h
+++ b/src/shared/gameinfo.h
@@ -56,12 +56,12 @@ public:
virtual ~GameInfo() {}
- std::wstring getOrganizerDirectory() { return m_OrganizerDirectory; }
+ std::wstring getOrganizerDirectory() const { return m_OrganizerDirectory; }
- virtual std::wstring getRegPath() = 0;
- virtual std::wstring getBinaryName() = 0;
+ virtual std::wstring getRegPath() const = 0;
+ virtual std::wstring getBinaryName() const = 0;
- virtual GameInfo::Type getType() = 0;
+ virtual GameInfo::Type getType() const = 0;
virtual std::wstring getGameName() const = 0;
virtual std::wstring getGameShortName() const = 0;
@@ -75,22 +75,24 @@ public:
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;
+ virtual std::vector<std::wstring> getSavegameAttachmentExtensions() const = 0;
// get a set of esp/esm files that are part of known dlcs
- virtual std::vector<std::wstring> getDLCPlugins() = 0;
+ virtual std::vector<std::wstring> getDLCPlugins() const = 0;
// file name of this games ini file(s)
- virtual std::vector<std::wstring> getIniFileNames() = 0;
+ virtual std::vector<std::wstring> getIniFileNames() const = 0;
- virtual std::wstring getReferenceDataFile() = 0;
+ virtual std::wstring getReferenceDataFile() const = 0;
- virtual std::wstring getNexusPage(bool nmmScheme = true) = 0;
- virtual std::wstring getNexusInfoUrl() = 0;
- virtual int getNexusModID() = 0;
- virtual int getNexusGameID() = 0;
+ virtual std::wstring getNexusPage(bool nmmScheme = true) const = 0;
+ virtual std::wstring getNexusInfoUrl() const = 0;
+ virtual int getNexusModID() const = 0;
+ virtual int getNexusGameID() const = 0;
- virtual bool rerouteToProfile(const wchar_t *fileName, const wchar_t *fullPath) = 0;
+ virtual bool rerouteToProfile(const wchar_t *fileName, const wchar_t *fullPath) const = 0;
+
+ virtual bool isValidModURL(int modID, std::wstring const &url) const = 0;
public:
@@ -108,6 +110,8 @@ protected:
const std::wstring &getMyGamesDirectory() const { return m_MyGamesDirectory; }
void identifyMyGamesDirectory(const std::wstring &file);
+ bool isValidModURL(int modID, const std::wstring &url, const std::wstring &alt) const;
+
private:
static bool identifyGame(const std::wstring &moDirectory, const std::wstring &moDataDirectory, const std::wstring &searchPath);
diff --git a/src/shared/oblivioninfo.cpp b/src/shared/oblivioninfo.cpp
index 16748f58..730c186b 100644
--- a/src/shared/oblivioninfo.cpp
+++ b/src/shared/oblivioninfo.cpp
@@ -63,17 +63,7 @@ std::wstring OblivionInfo::getRegPathStatic()
}
}
-
-
-
-
-
-
-
-
-
-
-std::vector<std::wstring> OblivionInfo::getDLCPlugins()
+std::vector<std::wstring> OblivionInfo::getDLCPlugins() const
{
return boost::assign::list_of (L"DLCShiveringIsles.esp")
(L"Knights.esp")
@@ -89,22 +79,18 @@ std::vector<std::wstring> OblivionInfo::getDLCPlugins()
}
-std::vector<std::wstring> OblivionInfo::getSavegameAttachmentExtensions()
+std::vector<std::wstring> OblivionInfo::getSavegameAttachmentExtensions() const
{
return boost::assign::list_of(L"obse");
}
-std::vector<std::wstring> OblivionInfo::getIniFileNames()
+std::vector<std::wstring> OblivionInfo::getIniFileNames() const
{
return boost::assign::list_of(L"oblivion.ini")(L"oblivionprefs.ini");
}
-
-
-
-
-std::wstring OblivionInfo::getNexusPage(bool nmmScheme)
+std::wstring OblivionInfo::getNexusPage(bool nmmScheme) const
{
if (nmmScheme) {
return L"http://nmm.nexusmods.com/oblivion";
@@ -125,7 +111,7 @@ int OblivionInfo::getNexusModIDStatic()
return 38277;
}
-bool OblivionInfo::rerouteToProfile(const wchar_t *fileName, const wchar_t*)
+bool OblivionInfo::rerouteToProfile(const wchar_t *fileName, const wchar_t*) const
{
static LPCWSTR profileFiles[] = { L"oblivion.ini", L"oblivionprefs.ini", L"plugins.txt", nullptr };
@@ -137,9 +123,14 @@ bool OblivionInfo::rerouteToProfile(const wchar_t *fileName, const wchar_t*)
return false;
}
-std::wstring OblivionInfo::getReferenceDataFile()
+std::wstring OblivionInfo::getReferenceDataFile() const
{
return L"Oblivion - Meshes.bsa";
}
+bool OblivionInfo::isValidModURL(int modID, const std::wstring &url) const
+{
+ return GameInfo::isValidModURL(modID, url, L"http://oblivion.nexusmods.com");
+}
+
} // namespace MOShared
diff --git a/src/shared/oblivioninfo.h b/src/shared/oblivioninfo.h
index 87ba26ff..1adf9cab 100644
--- a/src/shared/oblivioninfo.h
+++ b/src/shared/oblivioninfo.h
@@ -34,69 +34,34 @@ public:
virtual ~OblivionInfo() {}
static std::wstring getRegPathStatic();
- virtual std::wstring getRegPath() { return getRegPathStatic(); }
- virtual std::wstring getBinaryName() { return L"Oblivion.exe"; }
+ virtual std::wstring getRegPath() const { return getRegPathStatic(); }
+ virtual std::wstring getBinaryName() const { return L"Oblivion.exe"; }
- virtual GameInfo::Type getType() { return TYPE_OBLIVION; }
+ virtual GameInfo::Type getType() const { 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::vector<std::wstring> getDLCPlugins() const;
+ virtual std::vector<std::wstring> getSavegameAttachmentExtensions() const;
// file name of this games ini (no path)
- virtual std::vector<std::wstring> getIniFileNames();
+ virtual std::vector<std::wstring> getIniFileNames() const;
- virtual std::wstring getReferenceDataFile();
+ virtual std::wstring getReferenceDataFile() const;
- virtual std::wstring getNexusPage(bool nmmScheme = true);
+ virtual std::wstring getNexusPage(bool nmmScheme = true) const;
static std::wstring getNexusInfoUrlStatic();
- virtual std::wstring getNexusInfoUrl() { return getNexusInfoUrlStatic(); }
+ virtual std::wstring getNexusInfoUrl() const { return getNexusInfoUrlStatic(); }
static int getNexusModIDStatic();
- virtual int getNexusModID() { return getNexusModIDStatic(); }
- virtual int getNexusGameID() { return 101; }
+ virtual int getNexusModID() const { return getNexusModIDStatic(); }
+ virtual int getNexusGameID() const { return 101; }
- virtual bool rerouteToProfile(const wchar_t *fileName, const wchar_t *fullPath);
+ virtual bool rerouteToProfile(const wchar_t *fileName, const wchar_t *fullPath) const;
- // get a list of executables (game binary and known-to-work 3rd party tools). All of these are relative to
- // the game directory
- //virtual std::vector<ExecutableInfo> getExecutables();
+ virtual std::wstring archiveListKey() const { return L"SArchiveList"; }
- virtual std::wstring archiveListKey() { return L"SArchiveList"; }
+ virtual bool isValidModURL(int modID, std::wstring const &url) const;
private:
diff --git a/src/shared/skyriminfo.cpp b/src/shared/skyriminfo.cpp
index f66fcef4..7c85fe10 100644
--- a/src/shared/skyriminfo.cpp
+++ b/src/shared/skyriminfo.cpp
@@ -91,7 +91,7 @@ GameInfo::LoadOrderMechanism SkyrimInfo::getLoadOrderMechanism() const
}
}
-std::vector<std::wstring> SkyrimInfo::getDLCPlugins()
+std::vector<std::wstring> SkyrimInfo::getDLCPlugins() const
{
return boost::assign::list_of (L"Dawnguard.esm")
(L"Dragonborn.esm")
@@ -102,23 +102,23 @@ std::vector<std::wstring> SkyrimInfo::getDLCPlugins()
;
}
-std::vector<std::wstring> SkyrimInfo::getSavegameAttachmentExtensions()
+std::vector<std::wstring> SkyrimInfo::getSavegameAttachmentExtensions() const
{
return boost::assign::list_of(L"skse");
}
-std::vector<std::wstring> SkyrimInfo::getIniFileNames()
+std::vector<std::wstring> SkyrimInfo::getIniFileNames() const
{
return boost::assign::list_of(L"skyrim.ini")(L"skyrimprefs.ini");
}
-std::wstring SkyrimInfo::getReferenceDataFile()
+std::wstring SkyrimInfo::getReferenceDataFile() const
{
return L"Skyrim - Meshes.bsa";
}
-std::wstring SkyrimInfo::getNexusPage(bool nmmScheme)
+std::wstring SkyrimInfo::getNexusPage(bool nmmScheme) const
{
if (nmmScheme) {
return L"http://nmm.nexusmods.com/skyrim";
@@ -139,7 +139,7 @@ int SkyrimInfo::getNexusModIDStatic()
return 1334;
}
-bool SkyrimInfo::rerouteToProfile(const wchar_t *fileName, const wchar_t *fullPath)
+bool SkyrimInfo::rerouteToProfile(const wchar_t *fileName, const wchar_t *fullPath) const
{
static LPCWSTR profileFiles[] = { L"skyrim.ini", L"skyrimprefs.ini", L"loadorder.txt", nullptr };
@@ -157,5 +157,10 @@ bool SkyrimInfo::rerouteToProfile(const wchar_t *fileName, const wchar_t *fullPa
return false;
}
+bool SkyrimInfo::isValidModURL(int modID, const std::wstring &url) const
+{
+ return GameInfo::isValidModURL(modID, url, L"http://skyrim.nexusmods.com");
+}
+
} // namespace MOShared
diff --git a/src/shared/skyriminfo.h b/src/shared/skyriminfo.h
index 5951f910..e2766688 100644
--- a/src/shared/skyriminfo.h
+++ b/src/shared/skyriminfo.h
@@ -36,35 +36,37 @@ public:
virtual ~SkyrimInfo() {}
static std::wstring getRegPathStatic();
- virtual std::wstring getRegPath() { return getRegPathStatic(); }
- virtual std::wstring getBinaryName() { return L"TESV.exe"; }
+ virtual std::wstring getRegPath() const { return getRegPathStatic(); }
+ virtual std::wstring getBinaryName() const { return L"TESV.exe"; }
- virtual GameInfo::Type getType() { return TYPE_SKYRIM; }
+ virtual GameInfo::Type getType() const { 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> getDLCPlugins() const;
- virtual std::vector<std::wstring> getSavegameAttachmentExtensions();
+ virtual std::vector<std::wstring> getSavegameAttachmentExtensions() const;
// file name of this games ini (no path)
- virtual std::vector<std::wstring> getIniFileNames();
+ virtual std::vector<std::wstring> getIniFileNames() const;
- virtual std::wstring getReferenceDataFile();
+ virtual std::wstring getReferenceDataFile() const;
- virtual std::wstring getNexusPage(bool nmmScheme = true);
+ virtual std::wstring getNexusPage(bool nmmScheme = true) const;
static std::wstring getNexusInfoUrlStatic();
- virtual std::wstring getNexusInfoUrl() { return getNexusInfoUrlStatic(); }
+ virtual std::wstring getNexusInfoUrl() const { return getNexusInfoUrlStatic(); }
static int getNexusModIDStatic();
- virtual int getNexusModID() { return getNexusModIDStatic(); }
+ virtual int getNexusModID() const { return getNexusModIDStatic(); }
static int getNexusGameIDStatic() { return 110; }
- virtual int getNexusGameID() { return getNexusGameIDStatic(); }
+ virtual int getNexusGameID() const { return getNexusGameIDStatic(); }
- virtual bool rerouteToProfile(const wchar_t *fileName, const wchar_t *fullPath);
+ virtual bool rerouteToProfile(const wchar_t *fileName, const wchar_t *fullPath) const;
+
+ virtual bool isValidModURL(int modID, std::wstring const &url) const;
private: