summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/installationmanager.cpp39
-rw-r--r--src/installationmanager.h22
-rw-r--r--src/mainwindow.cpp113
-rw-r--r--src/modinfo.cpp46
-rw-r--r--src/modinfo.h860
-rw-r--r--src/modinfodialogcategories.cpp2
-rw-r--r--src/modinfodialognexus.cpp36
-rw-r--r--src/modinfodialogtab.cpp6
-rw-r--r--src/modinfoforeign.h17
-rw-r--r--src/modinfooverwrite.h17
-rw-r--r--src/modinforegular.cpp143
-rw-r--r--src/modinforegular.h57
-rw-r--r--src/modinfoseparator.h6
-rw-r--r--src/modinfowithconflictinfo.cpp1
-rw-r--r--src/modlist.cpp40
-rw-r--r--src/modlistsortproxy.cpp30
-rw-r--r--src/organizercore.cpp50
-rw-r--r--src/organizercore.h2
-rw-r--r--src/organizerproxy.cpp2
-rw-r--r--src/profilesdialog.cpp6
20 files changed, 901 insertions, 594 deletions
diff --git a/src/installationmanager.cpp b/src/installationmanager.cpp
index 801b2a67..a755b0cb 100644
--- a/src/installationmanager.cpp
+++ b/src/installationmanager.cpp
@@ -369,7 +369,7 @@ QString InstallationManager::generateBackupName(const QString &directoryName) co
}
-bool InstallationManager::testOverwrite(GuessedValue<QString> &modName, bool *merge)
+IPluginInstaller::EInstallResult InstallationManager::testOverwrite(GuessedValue<QString> &modName, bool *merge)
{
QString targetDirectory = QDir::fromNativeSeparators(m_ModsDirectory + "\\" + modName);
@@ -388,7 +388,7 @@ bool InstallationManager::testOverwrite(GuessedValue<QString> &modName, bool *me
QString backupDirectory = generateBackupName(targetDirectory);
if (!copyDir(targetDirectory, backupDirectory, false)) {
reportError(tr("Failed to create backup"));
- return false;
+ return IPluginInstaller::RESULT_FAILED;
}
}
if (merge != nullptr) {
@@ -401,7 +401,7 @@ bool InstallationManager::testOverwrite(GuessedValue<QString> &modName, bool *me
if (ok && !name.isEmpty()) {
modName.update(name, GUESS_USER);
if (!ensureValidModName(modName)) {
- return false;
+ return IPluginInstaller::RESULT_FAILED;
}
targetDirectory = QDir::fromNativeSeparators(m_ModsDirectory) + "/" + modName;
}
@@ -410,7 +410,7 @@ bool InstallationManager::testOverwrite(GuessedValue<QString> &modName, bool *me
if (idx != UINT_MAX) {
auto modInfo = ModInfo::getByIndex(idx);
// mark the old install file as uninstalled
- emit modReplaced(modInfo->getInstallationFile());
+ emit modReplaced(modInfo->installationFile());
}
// save original settings like categories. Because it makes sense
QString metaFilename = targetDirectory + "/meta.ini";
@@ -436,18 +436,20 @@ bool InstallationManager::testOverwrite(GuessedValue<QString> &modName, bool *me
} else {
log::error("failed to restore original settings: {}", metaFilename);
}
- return true;
+ return IPluginInstaller::RESULT_SUCCESS;
} else if (overwriteDialog.action() == QueryOverwriteDialog::ACT_MERGE) {
- return true;
+ return IPluginInstaller::RESULT_SUCCESS;
+ } else /* if (overwriteDialog.action() == QueryOverwriteDialog::ACT_NONE) */ {
+ return IPluginInstaller::RESULT_CANCELED;
}
} else {
- return false;
+ return IPluginInstaller::RESULT_CANCELED;
}
}
QDir().mkdir(targetDirectory);
- return true;
+ return IPluginInstaller::RESULT_SUCCESS;;
}
@@ -476,8 +478,9 @@ IPluginInstaller::EInstallResult InstallationManager::doInstall(GuessedValue<QSt
bool merge = false;
// determine target directory
- if (!testOverwrite(modName, &merge)) {
- return IPluginInstaller::RESULT_FAILED;
+ IPluginInstaller::EInstallResult result = testOverwrite(modName, &merge);
+ if (result != IPluginInstaller::RESULT_SUCCESS) {
+ return result;
}
QString targetDirectory = QDir(m_ModsDirectory + "/" + modName).canonicalPath();
@@ -865,3 +868,19 @@ QStringList InstallationManager::getSupportedExtensions() const
{
return QStringList(std::begin(m_SupportedExtensions), std::end(m_SupportedExtensions));
}
+
+void InstallationManager::notifyInstallationStart(QString const& archive, bool reinstallation, ModInfo::Ptr currentMod)
+{
+ for (auto* installer : m_Installers) {
+ installer->onInstallationStart(archive, reinstallation, currentMod.get());
+ }
+}
+
+void InstallationManager::notifyInstallationEnd(
+ MOBase::IPluginInstaller::EInstallResult result,
+ ModInfo::Ptr newMod)
+{
+ for (auto* installer : m_Installers) {
+ installer->onInstallationEnd(result, newMod.get());
+ }
+}
diff --git a/src/installationmanager.h b/src/installationmanager.h
index b3a7362f..149295a6 100644
--- a/src/installationmanager.h
+++ b/src/installationmanager.h
@@ -34,6 +34,8 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#include <map>
#include <errorcodes.h>
+#include "modinfo.h"
+
/**
* @brief manages the installation of mod archives
@@ -63,6 +65,24 @@ public:
void setURL(const QString &url);
/**
+ * @brief Notify all installer plugins that an installation is about to start.
+ *
+ * @param archive Path to the archive that is going to be installed.
+ * @param reinstallation True if this is a reinstallation, false otherwise.
+ * @param currentMod The installed mod corresponding to the archive being installed, or a null
+ * if there is no such mod.
+ */
+ void notifyInstallationStart(QString const& archive, bool reinstallation, ModInfo::Ptr currentMod);
+
+ /**
+ * @brief notify all installer plugins that an installation has ended.
+ *
+ * @param result The result of the installation process.
+ * @param currentMod The newly install mod, if result is SUCCESS, a null pointer otherwise.
+ */
+ void notifyInstallationEnd(MOBase::IPluginInstaller::EInstallResult result, ModInfo::Ptr newMod);
+
+ /**
* @brief update the directory where mods are to be installed
* @param modsDirectory the mod directory
* @note this is called a lot, probably redundantly
@@ -185,7 +205,7 @@ public:
* @param merge if this value is not null, the value will be set to whether the use chose to merge or replace
* @return true if we can proceed with the installation, false if the user canceled or in case of an unrecoverable error
*/
- virtual bool testOverwrite(MOBase::GuessedValue<QString> &modName, bool *merge = nullptr);
+ virtual MOBase::IPluginInstaller::EInstallResult testOverwrite(MOBase::GuessedValue<QString> &modName, bool *merge = nullptr);
QString generateBackupName(const QString &directoryName) const;
diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp
index dc8e6141..fb71eca3 100644
--- a/src/mainwindow.cpp
+++ b/src/mainwindow.cpp
@@ -1893,12 +1893,16 @@ QDir MainWindow::currentSavesDir() const
iniPath += "/" + iniFiles[0];
wchar_t path[MAX_PATH];
- ::GetPrivateProfileStringW(
- L"General", L"SLocalSavePath", L"Saves",
- path, MAX_PATH,
- iniPath.toStdWString().c_str()
- );
- savesDir.setPath(m_OrganizerCore.managedGame()->documentsDirectory().absoluteFilePath(QString::fromWCharArray(path)));
+ if (::GetPrivateProfileStringW(
+ L"General", L"SLocalSavePath", L"",
+ path, MAX_PATH,
+ iniPath.toStdWString().c_str()
+ )) {
+ savesDir.setPath(m_OrganizerCore.managedGame()->documentsDirectory().absoluteFilePath(QString::fromWCharArray(path)));
+ }
+ else {
+ savesDir = m_OrganizerCore.managedGame()->savesDirectory();
+ }
}
return savesDir;
@@ -2315,7 +2319,7 @@ void MainWindow::installMod(QString fileName)
if (fileName.isEmpty()) {
return;
} else {
- m_OrganizerCore.installMod(fileName, QString());
+ m_OrganizerCore.installMod(fileName, false, nullptr, QString());
}
} catch (const std::exception &e) {
reportError(e.what());
@@ -2577,7 +2581,7 @@ void MainWindow::modInstalled(const QString &modName)
// force an update to happen
std::multimap<QString, int> IDs;
ModInfo::Ptr info = ModInfo::getByIndex(ModInfo::getIndex(modName));
- IDs.insert(std::make_pair<QString, int>(info->getGameName(), info->getNexusID()));
+ IDs.insert(std::make_pair<QString, int>(info->gameName(), info->nexusId()));
modUpdateCheck(IDs);
}
@@ -2790,7 +2794,7 @@ void MainWindow::modRemoved(const QString &fileName)
void MainWindow::reinstallMod_clicked()
{
ModInfo::Ptr modInfo = ModInfo::getByIndex(m_ContextRow);
- QString installationFile = modInfo->getInstallationFile();
+ QString installationFile = modInfo->installationFile();
if (installationFile.length() != 0) {
QString fullInstallationFile;
QFileInfo fileInfo(installationFile);
@@ -2804,7 +2808,7 @@ void MainWindow::reinstallMod_clicked()
fullInstallationFile = m_OrganizerCore.downloadManager()->getOutputDirectory() + "/" + installationFile;
}
if (QFile::exists(fullInstallationFile)) {
- m_OrganizerCore.installMod(fullInstallationFile, modInfo->name());
+ m_OrganizerCore.installMod(fullInstallationFile, true, modInfo, modInfo->name());
} else {
QMessageBox::information(this, tr("Failed"), tr("Installation file no longer exists"));
}
@@ -3254,8 +3258,8 @@ void MainWindow::visitOnNexus_clicked()
for (QModelIndex idx : selection->selectedRows()) {
row_idx = idx.data(Qt::UserRole + 1).toInt();
info = ModInfo::getByIndex(row_idx);
- int modID = info->getNexusID();
- gameName = info->getGameName();
+ int modID = info->nexusId();
+ gameName = info->gameName();
if (modID > 0) {
linkClicked(NexusInterface::instance(&m_PluginContainer)->getModURL(modID, gameName));
} else {
@@ -3319,8 +3323,8 @@ void MainWindow::visitNexusOrWebPage(const QModelIndex& idx)
return;
}
- int modID = info->getNexusID();
- QString gameName = info->getGameName();
+ int modID = info->nexusId();
+ QString gameName = info->gameName();
const auto url = info->parseCustomURL();
if (modID > 0) {
@@ -3665,7 +3669,7 @@ void MainWindow::setColor_clicked()
QColorDialog dialog(this);
dialog.setOption(QColorDialog::ShowAlphaChannel);
- QColor currentColor = modInfo->getColor();
+ QColor currentColor = modInfo->color();
if (currentColor.isValid()) {
dialog.setCurrentColor(currentColor);
}
@@ -4199,7 +4203,7 @@ void MainWindow::checkModsForUpdates()
m_OrganizerCore.doAfterLogin([this] () { this->checkModsForUpdates(); });
NexusInterface::instance(&m_PluginContainer)->getAccessManager()->apiCheck(apiKey);
} else {
- log::warn("You are not currently authenticated with Nexus. Please do so under Settings -> Nexus.");
+ log::warn("{}", tr("You are not currently authenticated with Nexus. Please do so under Settings -> Nexus."));
}
}
@@ -4240,8 +4244,8 @@ void MainWindow::changeVersioningScheme() {
static VersionInfo::VersionScheme schemes[] = { VersionInfo::SCHEME_REGULAR, VersionInfo::SCHEME_DECIMALMARK, VersionInfo::SCHEME_NUMBERSANDLETTERS };
for (int i = 0; i < sizeof(schemes) / sizeof(VersionInfo::VersionScheme) && !success; ++i) {
- VersionInfo verOld(info->getVersion().canonicalString(), schemes[i]);
- VersionInfo verNew(info->getNewestVersion().canonicalString(), schemes[i]);
+ VersionInfo verOld(info->version().canonicalString(), schemes[i]);
+ VersionInfo verNew(info->newestVersion().canonicalString(), schemes[i]);
if (verOld < verNew) {
info->setVersion(verOld);
info->setNewestVersion(verNew);
@@ -4250,7 +4254,7 @@ void MainWindow::changeVersioningScheme() {
}
if (!success) {
QMessageBox::information(this, tr("Sorry"),
- tr("I don't know a versioning scheme where %1 is newer than %2.").arg(info->getNewestVersion().canonicalString()).arg(info->getVersion().canonicalString()),
+ tr("I don't know a versioning scheme where %1 is newer than %2.").arg(info->newestVersion().canonicalString()).arg(info->version().canonicalString()),
QMessageBox::Ok);
}
}
@@ -4279,11 +4283,11 @@ void MainWindow::checkModUpdates_clicked()
if (selection->hasSelection() && selection->selectedRows().count() > 1) {
for (QModelIndex idx : selection->selectedRows()) {
ModInfo::Ptr info = ModInfo::getByIndex(idx.data(Qt::UserRole + 1).toInt());
- IDs.insert(std::make_pair<QString, int>(info->getGameName(), info->getNexusID()));
+ IDs.insert(std::make_pair<QString, int>(info->gameName(), info->nexusId()));
}
} else {
ModInfo::Ptr info = ModInfo::getByIndex(m_ContextRow);
- IDs.insert(std::make_pair<QString, int>(info->getGameName(), info->getNexusID()));
+ IDs.insert(std::make_pair<QString, int>(info->gameName(), info->nexusId()));
}
modUpdateCheck(IDs);
}
@@ -4320,7 +4324,7 @@ void MainWindow::addPrimaryCategoryCandidates(QMenu *primaryCategoryMenu,
info->setPrimaryCategory(categoryID);
}
});
- categoryBox->setChecked(categoryID == info->getPrimaryCategory());
+ categoryBox->setChecked(categoryID == info->primaryCategory());
action->setDefaultWidget(categoryBox);
} catch (const std::exception &e) {
log::error("failed to create category checkbox: {}", e.what());
@@ -4568,17 +4572,17 @@ void MainWindow::exportModListCSV()
if (mod_Note->isChecked())
builder.setRowField("#Note", QString("%1").arg(info->comments().remove(',')));
if (primary_Category->isChecked())
- builder.setRowField("#Primary_Category", (m_CategoryFactory.categoryExists(info->getPrimaryCategory())) ? m_CategoryFactory.getCategoryNameByID(info->getPrimaryCategory()) : "");
+ builder.setRowField("#Primary_Category", (m_CategoryFactory.categoryExists(info->primaryCategory())) ? m_CategoryFactory.getCategoryNameByID(info->primaryCategory()) : "");
if (nexus_ID->isChecked())
- builder.setRowField("#Nexus_ID", info->getNexusID());
+ builder.setRowField("#Nexus_ID", info->nexusId());
if (mod_Nexus_URL->isChecked())
- builder.setRowField("#Mod_Nexus_URL",(info->getNexusID()>0)? NexusInterface::instance(&m_PluginContainer)->getModURL(info->getNexusID(), info->getGameName()) : "");
+ builder.setRowField("#Mod_Nexus_URL",(info->nexusId()>0)? NexusInterface::instance(&m_PluginContainer)->getModURL(info->nexusId(), info->gameName()) : "");
if (mod_Version->isChecked())
- builder.setRowField("#Mod_Version", info->getVersion().canonicalString());
+ builder.setRowField("#Mod_Version", info->version().canonicalString());
if (install_Date->isChecked())
builder.setRowField("#Install_Date", info->creationTime().toString("yyyy/MM/dd HH:mm:ss"));
if (download_File_Name->isChecked())
- builder.setRowField("#Download_File_Name", info->getInstallationFile());
+ builder.setRowField("#Download_File_Name", info->installationFile());
builder.writeRow();
}
@@ -4726,7 +4730,7 @@ void MainWindow::on_modList_customContextMenuRequested(const QPoint &pos)
menu.addAction(tr("Mark as converted/working"), this, SLOT(markConverted_clicked()));
}
menu.addSeparator();
- if (info->getNexusID() > 0) {
+ if (info->nexusId() > 0) {
menu.addAction(tr("Visit on Nexus"), this, SLOT(visitOnNexus_clicked()));
}
@@ -4755,7 +4759,7 @@ void MainWindow::on_modList_customContextMenuRequested(const QPoint &pos)
addModSendToContextMenu(&menu);
menu.addAction(tr("Select Color..."), this, SLOT(setColor_clicked()));
- if(info->getColor().isValid())
+ if(info->color().isValid())
menu.addAction(tr("Reset Color"), this, SLOT(resetColor_clicked()));
menu.addSeparator();
@@ -4779,7 +4783,7 @@ void MainWindow::on_modList_customContextMenuRequested(const QPoint &pos)
menu.addAction(tr("Change versioning scheme"), this, SLOT(changeVersioningScheme()));
}
- if (info->getNexusID() > 0)
+ if (info->nexusId() > 0)
menu.addAction(tr("Force-check updates"), this, SLOT(checkModUpdates_clicked()));
if (info->updateIgnored()) {
menu.addAction(tr("Un-ignore update"), this, SLOT(unignoreUpdate()));
@@ -4811,22 +4815,22 @@ void MainWindow::on_modList_customContextMenuRequested(const QPoint &pos)
if (contextColumn == ModList::COL_NOTES) {
menu.addAction(tr("Select Color..."), this, SLOT(setColor_clicked()));
- if (info->getColor().isValid())
+ if (info->color().isValid())
menu.addAction(tr("Reset Color"), this, SLOT(resetColor_clicked()));
menu.addSeparator();
}
- if (info->getNexusID() > 0 && Settings::instance().nexus().endorsementIntegration()) {
+ if (info->nexusId() > 0 && Settings::instance().nexus().endorsementIntegration()) {
switch (info->endorsedState()) {
- case ModInfo::ENDORSED_TRUE: {
+ case EndorsedState::ENDORSED_TRUE: {
menu.addAction(tr("Un-Endorse"), this, SLOT(unendorse_clicked()));
} break;
- case ModInfo::ENDORSED_FALSE: {
+ case EndorsedState::ENDORSED_FALSE: {
menu.addAction(tr("Endorse"), this, SLOT(endorse_clicked()));
menu.addAction(tr("Won't endorse"), this, SLOT(dontendorse_clicked()));
} break;
- case ModInfo::ENDORSED_NEVER: {
+ case EndorsedState::ENDORSED_NEVER: {
menu.addAction(tr("Endorse"), this, SLOT(endorse_clicked()));
} break;
default: {
@@ -4837,12 +4841,12 @@ void MainWindow::on_modList_customContextMenuRequested(const QPoint &pos)
}
}
- if (info->getNexusID() > 0) {
+ if (info->nexusId() > 0) {
switch (info->trackedState()) {
- case ModInfo::TRACKED_FALSE: {
+ case TrackedState::TRACKED_FALSE: {
menu.addAction(tr("Start tracking"), this, SLOT(track_clicked()));
} break;
- case ModInfo::TRACKED_TRUE: {
+ case TrackedState::TRACKED_TRUE: {
menu.addAction(tr("Stop tracking"), this, SLOT(untrack_clicked()));
} break;
default: {
@@ -4866,7 +4870,7 @@ void MainWindow::on_modList_customContextMenuRequested(const QPoint &pos)
menu.addSeparator();
- if (info->getNexusID() > 0) {
+ if (info->nexusId() > 0) {
menu.addAction(tr("Visit on Nexus"), this, SLOT(visitOnNexus_clicked()));
}
@@ -5406,7 +5410,7 @@ void MainWindow::modUpdateCheck(std::multimap<QString, int> IDs)
m_OrganizerCore.doAfterLogin([=]() { this->modUpdateCheck(IDs); });
NexusInterface::instance(&m_PluginContainer)->getAccessManager()->apiCheck(apiKey);
} else
- log::warn("You are not currently authenticated with Nexus. Please do so under Settings -> Nexus.");
+ log::warn("{}", tr("You are not currently authenticated with Nexus. Please do so under Settings -> Nexus."));
}
}
@@ -5524,10 +5528,10 @@ void MainWindow::nxmUpdateInfoAvailable(QString gameName, QVariant userData, QVa
}
QVariantList resultList = resultData.toList();
- QFutureWatcher<std::set<QSharedPointer<ModInfo>>> *watcher = new QFutureWatcher<std::set<QSharedPointer<ModInfo>>>();
+ QFutureWatcher<std::pair<QString, std::set<QSharedPointer<ModInfo>>>> *watcher = new QFutureWatcher<std::pair<QString, std::set<QSharedPointer<ModInfo>>>>();
QObject::connect(watcher, &QFutureWatcher<std::set<QSharedPointer<ModInfo>>>::finished, this, &MainWindow::finishUpdateInfo);
- QFuture<std::set<QSharedPointer<ModInfo>>> future = QtConcurrent::run([=]() -> std::set<QSharedPointer<ModInfo>> {
- return ModInfo::filteredMods(gameNameReal, resultList, userData.toBool(), true);
+ QFuture<std::pair<QString, std::set<QSharedPointer<ModInfo>>>> future = QtConcurrent::run([=]() -> std::pair<QString, std::set<QSharedPointer<ModInfo>>> {
+ return std::make_pair(gameNameReal, ModInfo::filteredMods(gameNameReal, resultList, userData.toBool(), true));
});
watcher->setFuture(future);
if (m_ModListSortProxy != nullptr)
@@ -5536,23 +5540,24 @@ void MainWindow::nxmUpdateInfoAvailable(QString gameName, QVariant userData, QVa
void MainWindow::finishUpdateInfo()
{
- QFutureWatcher<std::set<QSharedPointer<ModInfo>>> *watcher = static_cast<QFutureWatcher<std::set<QSharedPointer<ModInfo>>> *>(sender());
-
- auto finalMods = watcher->result();
+ QFutureWatcher<std::pair<QString, std::set<QSharedPointer<ModInfo>>>> *watcher = static_cast<QFutureWatcher<std::pair<QString, std::set<QSharedPointer<ModInfo>>>> *>(sender());
+
+ QString game = watcher->result().first;
+ auto finalMods = watcher->result().second;
if (finalMods.empty()) {
- log::info("None of your mods appear to have had recent file updates.");
+ log::info("{}", tr("None of your %1 mods appear to have had recent file updates.").arg(game));
}
std::set<std::pair<QString, int>> organizedGames;
for (auto mod : finalMods) {
if (mod->canBeUpdated()) {
- organizedGames.insert(std::make_pair<QString, int>(mod->getGameName().toLower(), mod->getNexusID()));
+ organizedGames.insert(std::make_pair<QString, int>(mod->gameName().toLower(), mod->nexusId()));
}
}
if (!finalMods.empty() && organizedGames.empty())
- log::warn("All of your mods have been checked recently. We restrict update checks to help preserve your available API requests.");
+ log::warn("{}", tr("All of your mods have been checked recently. We restrict update checks to help preserve your available API requests."));
for (auto game : organizedGames)
NexusInterface::instance(&m_PluginContainer)->requestUpdates(game.second, this, QVariant(), game.first, QString());
@@ -5579,7 +5584,7 @@ void MainWindow::nxmUpdatesAvailable(QString gameName, int modID, QVariant userD
for (auto mod : modsList) {
bool foundUpdate = false;
bool oldFile = false;
- QString installedFile = mod->getInstallationFile();
+ QString installedFile = mod->installationFile();
if (!installedFile.isEmpty()) {
QVariantMap foundFile;
for (auto file : files) {
@@ -5671,7 +5676,7 @@ void MainWindow::nxmModInfoAvailable(QString gameName, int modID, QVariant userD
mod->setLastNexusUpdate(QDateTime::currentDateTimeUtc());
}
mod->setNexusDescription(result["description"].toString());
- if ((mod->endorsedState() != ModInfo::ENDORSED_NEVER) && (result.contains("endorsement"))) {
+ if ((mod->endorsedState() != EndorsedState::ENDORSED_NEVER) && (result.contains("endorsement"))) {
QVariantMap endorsement = result["endorsement"].toMap();
QString endorsementStatus = endorsement["endorse_status"].toString();
if (endorsementStatus.compare("Endorsed") == 00)
@@ -5741,15 +5746,15 @@ void MainWindow::nxmTrackedModsAvailable(QVariant userData, QVariant resultData,
for (unsigned int i = 0; i < ModInfo::getNumMods(); i++) {
auto modInfo = ModInfo::getByIndex(i);
- if (modInfo->getNexusID() <= 0)
+ if (modInfo->nexusId() <= 0)
continue;
bool found = false;
auto resultsList = resultData.toList();
for (auto item : resultsList) {
auto results = item.toMap();
- if ((gameNames[results["domain_name"].toString()].compare(modInfo->getGameName(), Qt::CaseInsensitive) == 0) &&
- (results["mod_id"].toInt() == modInfo->getNexusID())) {
+ if ((gameNames[results["domain_name"].toString()].compare(modInfo->gameName(), Qt::CaseInsensitive) == 0) &&
+ (results["mod_id"].toInt() == modInfo->nexusId())) {
found = true;
break;
}
diff --git a/src/modinfo.cpp b/src/modinfo.cpp
index 826aa5c9..bbeefb12 100644
--- a/src/modinfo.cpp
+++ b/src/modinfo.cpp
@@ -180,11 +180,11 @@ bool ModInfo::removeMod(unsigned int index)
ModInfo::Ptr modInfo = s_Collection[index];
s_ModsByName.erase(s_ModsByName.find(modInfo->name()));
- auto iter = s_ModsByModID.find(std::pair<QString, int>(modInfo->getGameName(), modInfo->getNexusID()));
+ auto iter = s_ModsByModID.find(std::pair<QString, int>(modInfo->gameName(), modInfo->nexusId()));
if (iter != s_ModsByModID.end()) {
std::vector<unsigned int> indices = iter->second;
indices.erase(std::remove(indices.begin(), indices.end(), index), indices.end());
- s_ModsByModID[std::pair<QString, int>(modInfo->getGameName(), modInfo->getNexusID())] = indices;
+ s_ModsByModID[std::pair<QString, int>(modInfo->gameName(), modInfo->nexusId())] = indices;
}
// physically remove the mod directory
@@ -281,8 +281,8 @@ void ModInfo::updateIndices()
for (unsigned int i = 0; i < s_Collection.size(); ++i) {
QString modName = s_Collection[i]->internalName();
- QString game = s_Collection[i]->getGameName();
- int modID = s_Collection[i]->getNexusID();
+ QString game = s_Collection[i]->gameName();
+ int modID = s_Collection[i]->nexusId();
s_ModsByName[modName] = i;
s_ModsByModID[std::pair<QString, int>(game, modID)].push_back(i);
}
@@ -308,7 +308,25 @@ bool ModInfo::checkAllForUpdate(PluginContainer *pluginContainer, QObject *recei
earliest = mod->getLastNexusUpdate();
if (mod->getLastNexusUpdate() > latest)
latest = mod->getLastNexusUpdate();
- games.insert(mod->getGameName().toLower());
+ games.insert(mod->gameName().toLower());
+ }
+ }
+
+ // Detect invalid source games
+ for (auto itr = games.begin(); itr != games.end();) {
+ auto gamePlugins = pluginContainer->plugins<IPluginGame>();
+ IPluginGame* gamePlugin = qApp->property("managed_game").value<IPluginGame*>();
+ for (auto plugin : gamePlugins) {
+ if (plugin != nullptr && plugin->gameShortName().compare(*itr, Qt::CaseInsensitive) == 0) {
+ gamePlugin = plugin;
+ break;
+ }
+ }
+ if (gamePlugin != nullptr && gamePlugin->gameNexusName().isEmpty()) {
+ log::warn("{}", tr("The update check has found a mod with a Nexus ID and source game of %1, but this game is not a valid Nexus source.").arg(gamePlugin->gameName()));
+ itr = games.erase(itr);
+ } else {
+ ++itr;
}
}
@@ -316,7 +334,7 @@ bool ModInfo::checkAllForUpdate(PluginContainer *pluginContainer, QObject *recei
std::set<std::pair<QString, int>> organizedGames;
for (auto mod : s_Collection) {
if (mod->canBeUpdated() && mod->getLastNexusUpdate() < QDateTime::currentDateTimeUtc().addMonths(-1)) {
- organizedGames.insert(std::make_pair<QString, int>(mod->getGameName().toLower(), mod->getNexusID()));
+ organizedGames.insert(std::make_pair<QString, int>(mod->gameName().toLower(), mod->nexusId()));
}
}
@@ -354,7 +372,7 @@ std::set<QSharedPointer<ModInfo>> ModInfo::filteredMods(QString gameName, QVaria
for (QVariant result : updateData) {
QVariantMap update = result.toMap();
std::copy_if(s_Collection.begin(), s_Collection.end(), std::inserter(finalMods, finalMods.end()), [=](QSharedPointer<ModInfo> info) -> bool {
- if (info->getNexusID() == update["mod_id"].toInt() && info->getGameName().compare(gameName, Qt::CaseInsensitive) == 0)
+ if (info->nexusId() == update["mod_id"].toInt() && info->gameName().compare(gameName, Qt::CaseInsensitive) == 0)
if (info->getLastNexusUpdate().addSecs(-3600) < QDateTime::fromSecsSinceEpoch(update["latest_file_update"].toInt(), Qt::UTC))
return true;
return false;
@@ -363,13 +381,13 @@ std::set<QSharedPointer<ModInfo>> ModInfo::filteredMods(QString gameName, QVaria
if (addOldMods)
for (auto mod : s_Collection)
- if (mod->getLastNexusUpdate() < QDateTime::currentDateTimeUtc().addMonths(-1) && mod->getGameName().compare(gameName, Qt::CaseInsensitive) == 0)
+ if (mod->getLastNexusUpdate() < QDateTime::currentDateTimeUtc().addMonths(-1) && mod->gameName().compare(gameName, Qt::CaseInsensitive) == 0)
finalMods.insert(mod);
if (markUpdated) {
std::set<QSharedPointer<ModInfo>> updates;
std::copy_if(s_Collection.begin(), s_Collection.end(), std::inserter(updates, updates.end()), [=](QSharedPointer<ModInfo> info) -> bool {
- if (info->getGameName().compare(gameName, Qt::CaseInsensitive) == 0 && info->canBeUpdated())
+ if (info->gameName().compare(gameName, Qt::CaseInsensitive) == 0 && info->canBeUpdated())
return true;
return false;
});
@@ -401,7 +419,7 @@ void ModInfo::manualUpdateCheck(PluginContainer *pluginContainer, QObject *recei
}
}
mods.erase(
- std::remove_if(mods.begin(), mods.end(), [](ModInfo::Ptr mod) -> bool { return mod->getNexusID() <= 0; }),
+ std::remove_if(mods.begin(), mods.end(), [](ModInfo::Ptr mod) -> bool { return mod->nexusId() <= 0; }),
mods.end()
);
for (auto mod : mods) {
@@ -416,7 +434,7 @@ void ModInfo::manualUpdateCheck(PluginContainer *pluginContainer, QObject *recei
log::info("Checking updates for {} mods...", mods.size());
for (auto mod : mods) {
- organizedGames.insert(std::make_pair<QString, int>(mod->getGameName().toLower(), mod->getNexusID()));
+ organizedGames.insert(std::make_pair<QString, int>(mod->gameName().toLower(), mod->nexusId()));
}
for (auto game : organizedGames) {
@@ -508,14 +526,14 @@ bool ModInfo::categorySet(int categoryID) const
QUrl ModInfo::parseCustomURL() const
{
- if (!hasCustomURL() || getCustomURL().isEmpty()) {
+ if (!hasCustomURL() || url().isEmpty()) {
return {};
}
- const auto url = QUrl::fromUserInput(getCustomURL());
+ const auto url = QUrl::fromUserInput(this->url());
if (!url.isValid()) {
- log::error("mod '{}' has an invalid custom url '{}'", name(), getCustomURL());
+ log::error("mod '{}' has an invalid custom url '{}'", name(), this->url());
return {};
}
diff --git a/src/modinfo.h b/src/modinfo.h
index a6c8ea65..0533d9fe 100644
--- a/src/modinfo.h
+++ b/src/modinfo.h
@@ -48,13 +48,13 @@ namespace MOShared { class DirectoryEntry; }
* Represents meta information about a single mod. The class interface is used
* to manage the mod collection
*
- **/
+ */
class ModInfo : public QObject, public MOBase::IModInterface
{
Q_OBJECT
-public:
+public: // Type definitions:
typedef QSharedPointer<ModInfo> Ptr;
@@ -95,19 +95,6 @@ public:
HIGHLIGHT_PLUGIN = 8
};
- enum EEndorsedState {
- ENDORSED_FALSE,
- ENDORSED_TRUE,
- ENDORSED_UNKNOWN,
- ENDORSED_NEVER
- };
-
- enum ETrackedState {
- TRACKED_FALSE,
- TRACKED_TRUE,
- TRACKED_UNKNOWN,
- };
-
enum EModType {
MOD_DEFAULT,
MOD_DLC,
@@ -115,11 +102,11 @@ public:
};
-public:
+public: // Static functions:
/**
- * @brief read the mod directory and Mod ModInfo objects for all subdirectories
- **/
+ * @brief Read the mod directory and Mod ModInfo objects for all subdirectories.
+ */
static void updateFromDisc(const QString &modDirectory,
MOShared::DirectoryEntry **directoryStructure,
PluginContainer *pluginContainer,
@@ -130,415 +117,554 @@ public:
static void clear() { s_Collection.clear(); s_ModsByName.clear(); s_ModsByModID.clear(); }
/**
- * @brief retrieve the number of mods
+ * @brief Retrieve the number of mods.
*
- * @return number of mods
- **/
+ * @return the number of mods.
+ */
static unsigned int getNumMods();
/**
- * @brief retrieve a ModInfo object based on its index
+ * @brief Retrieve a ModInfo object based on its index.
+ *
+ * @param index The index to look up. The maximum value is getNumMods() - 1.
*
- * @param index the index to look up. the maximum is getNumMods() - 1
* @return a reference counting pointer to the mod info.
- * @note since the pointer is reference counting, the pointer remains valid even if the collection is refreshed in a different thread
- **/
+ *
+ * @note since the pointer is reference counting, the pointer remains valid even if the
+ * collection is refreshed in a different thread.
+ */
static ModInfo::Ptr getByIndex(unsigned int index);
/**
- * @brief retrieve a ModInfo object based on its nexus mod id
+ * @brief Retrieve ModInfo objects based on mod id.
+ *
+ * @param modID The mod id to look up.
*
- * @param modID the nexus mod id to look up
- * @return a reference counting pointer to the mod info
- * @todo in its current form, this function is broken! There may be multiple mods with the same nexus id,
- * this function will return only one of them
- **/
+ * @return a vector of reference counting pointer to the mod info objects with the given mod ID.
+ */
static std::vector<ModInfo::Ptr> getByModID(QString game, int modID);
/**
- * @brief retrieve a ModInfo object based on its name
+ * @brief Retrieve a ModInfo object based on its name.
+ *
+ * @param name The name to look up.
*
- * @param name the name to look up
- * @return a reference counting pointer to the mod info
- * @note since the pointer is reference counter, the pointer remains valid even if the collection is refreshed in a different thread
- **/
+ * @return a reference counting pointer to the mod info.
+ *
+ * @note Since the pointer is reference counter, the pointer remains valid even if the
+ * collection is refreshed in a different thread.
+ */
static ModInfo::Ptr getByName(const QString &name);
/**
- * @brief remove a mod by index
+ * @brief Remove a mod by index.
*
- * this physically deletes the specified mod from the disc and updates the ModInfo collection
- * but not other structures that reference mods
- * @param index index of the mod to delete
- * @return true if removal was successful, fals otherwise
- **/
+ * This physically deletes the specified mod from the disc and updates the ModInfo collection
+ * but not other structures that reference mods.
+ *
+ * @param index Index of the mod to delete.
+ *
+ * @return true if removal was successful, false otherwise.
+ */
static bool removeMod(unsigned int index);
/**
- * @brief retrieve the mod index by the mod name
+ * @brief Retrieve the mod index by the mod name.
+ *
+ * @param name Name of the mod to look up.
*
- * @param name name of the mod to look up
- * @return the index of the mod. If the mod doesn't exist, UINT_MAX is returned
- **/
+ * @return The index of the mod. If the mod doesn't exist, UINT_MAX is returned.
+ */
static unsigned int getIndex(const QString &name);
/**
- * @brief find the first mod that fulfills the filter function (after no particular order)
- * @param filter a function to filter by. should return true for a match
- * @return index of the matching mod or UINT_MAX if there wasn't a match
+ * @brief Find the first mod that fulfills the filter function (after no particular order).
+ *
+ * @param filter A function to filter mods by. Should return true for a match.
+ *
+ * @return index of the matching mod or UINT_MAX if there was no match.
*/
static unsigned int findMod(const boost::function<bool (ModInfo::Ptr)> &filter);
/**
- * @brief run a limited batch of mod update checks for "newest version" information
+ * @brief Run a limited batch of mod update checks for "newest version" information.
+ *
*/
- static void manualUpdateCheck(PluginContainer *pluginContainer, QObject *receiver, std::multimap<QString, int> IDs);
+ static void manualUpdateCheck(
+ PluginContainer *pluginContainer, QObject *receiver, std::multimap<QString, int> IDs);
/**
- * @brief query nexus information for every mod and update the "newest version" information
- * @return true if any mods are checked for update
- **/
+ * @brief Query nexus information for every mod and update the "newest version" information.
+ *
+ * @return true if any mods are checked for update.
+ */
static bool checkAllForUpdate(PluginContainer *pluginContainer, QObject *receiver);
- static std::set<QSharedPointer<ModInfo>> filteredMods(QString gameName, QVariantList updateData, bool addOldMods = false, bool markUpdated = false);
+ /**
+ *
+ */
+ static std::set<ModInfo::Ptr> filteredMods(
+ QString gameName, QVariantList updateData, bool addOldMods = false, bool markUpdated = false);
/**
- * @brief create a new mod from the specified directory and add it to the collection
- * @param dir directory to create from
- * @return pointer to the info-structure of the newly created/added mod
+ * @brief Create a new mod from the specified directory and add it to the collection.
+ *
+ * @param dir Directory to create from.
+ *
+ * @return pointer to the info-structure of the newly created/added mod.
*/
- static ModInfo::Ptr createFrom(PluginContainer *pluginContainer, const MOBase::IPluginGame *game, const QDir &dir, MOShared::DirectoryEntry **directoryStructure);
+ static ModInfo::Ptr createFrom(
+ PluginContainer *pluginContainer, const MOBase::IPluginGame *game,
+ const QDir &dir, MOShared::DirectoryEntry **directoryStructure);
/**
- * @brief create a new "foreign-managed" mod from a tuple of plugin and archives
- * @param espName name of the plugin
- * @param bsaNames names of archives
- * @return a new mod
+ * @brief Create a new "foreign-managed" mod from a tuple of plugin and archives.
+ *
+ * @param espName Name of the plugin.
+ * @param bsaNames Names of archives.
+ *
+ * @return a new mod.
*/
- static ModInfo::Ptr createFromPlugin(const QString &modName, const QString &espName, const QStringList &bsaNames, ModInfo::EModType modType,
- const MOBase::IPluginGame* game, MOShared::DirectoryEntry **directoryStructure, PluginContainer *pluginContainer);
+ static ModInfo::Ptr createFromPlugin(
+ const QString &modName, const QString &espName, const QStringList &bsaNames,
+ ModInfo::EModType modType, const MOBase::IPluginGame* game,
+ MOShared::DirectoryEntry **directoryStructure, PluginContainer *pluginContainer);
- // whether the given name is used for separators
- //
+ /**
+ * @brief Check wheter a name corresponds to a separator or not,
+ *
+ * @return whether the given name is used for separators.
+ */
static bool isSeparatorName(const QString& name);
- // whether the given name is used for backups
- //
+ /**
+ * @brief Check wheter a name corresponds to a backup or not,
+ *
+ * @return whether the given name is used for backups.
+ */
static bool isBackupName(const QString& name);
- // whether the given name is used for regular mods
- //
+ /**
+ * @brief Check wheter a name corresponds to a regular mod or not,
+ *
+ * @return whether the given name corresponds to a regular mod.
+ */
static bool isRegularName(const QString& name);
- virtual bool isRegular() const { return false; }
+public: // IModInterface implementations / Re-declaration
- virtual bool isEmpty() const { return false; }
+ // Note: This section contains default-implementation for some of the virtual methods from
+ // IModInterface, but also redeclaration of all the pure-virtual methods to centralize all
+ // of them in a single place.
/**
- * @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
- **/
- virtual bool updateAvailable() const = 0;
+ * @return the name of the mod.
+ */
+ virtual QString name() const = 0;
/**
- * @return true if the update currently available is ignored
+ * @return the absolute path to the mod to be used in file system operations.
*/
- virtual bool updateIgnored() const = 0;
+ virtual QString absolutePath() const = 0;
/**
- * @brief test if the "newest" version of the mod is older than the installed version
- *
- * 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 the newest version is older than the installed one
- **/
- virtual bool downgradeAvailable() const = 0;
+ * @return the comments for this mod, if any.
+ */
+ virtual QString comments() const = 0;
/**
- * @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.
- * Right now, Mod Organizer interprets the "newest version" and "description" from the
- * response, though the description is only stored in memory
- *
- **/
- virtual bool updateNXMInfo() = 0;
+ * @return the notes for this mod, if any.
+ */
+ virtual QString notes() const = 0;
/**
- * @brief assign or unassign the specified category
- *
- * Every mod can have an arbitrary number of categories assigned to it
+ * @brief Retrieve the short name of the game associated with this mod. This may differ
+ * from the current game plugin (e.g. you can install a Skyrim LE game in a SSE
+ * installation).
*
- * @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
- **/
- virtual void setCategory(int categoryID, bool active) = 0;
+ * @return the name of the game associated with this mod.
+ */
+ virtual QString gameName() const = 0;
/**
- * @brief changes the comments (manually set information displayed in the mod list) for this mod
- * @param comments new comments
+ * @return the name of the repository from which this mod was installed.
*/
- virtual void setComments(const QString &comments) = 0;
+ virtual QString repository() const override { return ""; }
/**
- * @brief change the notes (manually set information) for this mod
- * @param notes new notes
+ * @return the nexus ID of this mod on the repository.
*/
- virtual void setNotes(const QString &notes) = 0;
+ virtual int nexusId() const = 0;
/**
- * @brief set/change the source game of this mod
- *
- * @param gameName the source game shortName
+ * @return the current version of this mod.
*/
- virtual void setGameName(const QString& gameName) = 0;
+ virtual MOBase::VersionInfo version() const override { return m_Version; }
/**
- * @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
+ * @return the newest version of thid mod (as known by MO2). If this matches version(),
+ * then the mod is up-to-date.
+ */
+ virtual MOBase::VersionInfo newestVersion() const = 0;
+
+ /**
+ * @return the ignored version of this mod (for update), or an invalid version if the user
+ * did not ignore version for this mod.
+ */
+ virtual MOBase::VersionInfo ignoredVersion() const = 0;
+
+ /**
+ * @return the absolute path to the file that was used to install this mod.
+ */
+ virtual QString installationFile() const = 0;
+
+ virtual std::set<std::pair<int, int>> installedFiles() const = 0;
+
+ /**
+ * @return true if this mod was marked as converted by the user.
*
- * @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)
- **/
- virtual bool setName(const QString& name) = 0;
+ * @note When a mod is for a different game, a flag is shown to users to warn them, but
+ * they can mark mods as converted to remove this flag.
+ */
+ virtual bool converted() const = 0;
/**
- * @brief set/change the nexus mod id of this mod
+ * @return true if th is mod was marked as containing valid game data.
*
- * @param modID the nexus mod id
- **/
- virtual void setNexusID(int modID) = 0;
+ * @note MO2 uses ModDataChecker to check the content of mods, but sometimes these fail, in
+ * which case mods are incorrectly marked as 'not containing valid games data'. Users can
+ * choose to mark these mods as valid to hide the warning / flag.
+ */
+ virtual bool validated() const = 0;
/**
- * @brief set/change the version of this mod
- * @param version new version of the mod
+ * @return the color of the 'Notes' column chosen by the user.
*/
- virtual void setVersion(const MOBase::VersionInfo &version) override;
+ virtual QColor color() const override { return QColor(); }
/**
- * @brief Controls if mod should be highlighted based on plugin selection
- * @param isSelected whether or not the plugin has a selected mod
- **/
- virtual void setPluginSelected(const bool &isSelected);
+ * @return the URL of this mod, or an empty QString() if no URL is associated
+ * with this mod.
+ */
+ virtual QString url() const override { return ""; }
+
+ /**
+ * @return the ID of the primary category of this mod.
+ */
+ int primaryCategory() const override { return m_PrimaryCategory; }
+
+ /**
+ * @return the list of categories this mod belongs to.
+ */
+ virtual QStringList categories() const override;
+
+ /**
+ * @return the tracked state of this mod.
+ */
+ virtual MOBase::TrackedState trackedState() const override { return MOBase::TrackedState::TRACKED_FALSE; }
+
+ /**
+ * @return the endorsement state of this mod.
+ */
+ virtual MOBase::EndorsedState endorsedState() const override { return MOBase::EndorsedState::ENDORSED_NEVER; }
+
+public: // Mutable operations:
/**
- * @brief set the newest version of this mod on the nexus
+ * @brief Sets or changes the version of this mod.
*
- * this can be used to overwrite the version of a mod without actually
- * updating the mod
+ * @param version New version of the mod.
+ */
+ virtual void setVersion(const MOBase::VersionInfo& version) override;
+
+ /**
+ * @brief Sets the installation file for this 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
- **/
- virtual void setNewestVersion(const MOBase::VersionInfo &version) = 0;
+ * @param fileName archive file name.
+ */
+ virtual void setInstallationFile(const QString& fileName) = 0;
/**
- * @brief sets the repository that was used to download the mod
+ * @brief Sets or changes the latest known version of this mod.
+ *
+ * @param version Newest known version of the mod.
*/
- virtual void setRepository(const QString &) {}
+ virtual void setNewestVersion(const MOBase::VersionInfo& version) = 0;
/**
- * @brief changes/updates the nexus description text
- * @param description the current description text
+ * @brief Sets endorsement state of the mod.
+ *
+ * @param endorsed New endorsement state.
*/
- virtual void setNexusDescription(const QString &description) = 0;
+ virtual void setIsEndorsed(bool endorsed) = 0;
/**
- * @brief sets the file this mod was installed from
- * @param fileName name of the file
+ * @brief Sets the mod id on nexus for this mod.
+ *
+ * @param nexusID The new Nexus id to set.
*/
- virtual void setInstallationFile(const QString &fileName) = 0;
+ virtual void setNexusID(int nexusID) = 0;
/**
- * @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
+ * @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) = 0;
- virtual void addCategory(const QString &categoryName) override;
- virtual bool removeCategory(const QString &categoryName) override;
- virtual QStringList categories() const override;
+ /**
+ * @brief Assigns a category to the mod. If the named category does not exist it is created.
+ *
+ * @param categoryName Name of the new category.
+ */
+ virtual void addCategory(const QString& categoryName) override;
/**
- * 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
+ * @brief Unassigns a category from this mod.
+ *
+ * @param categoryName Name of the category to be removed.
+ *
+ * @return true if the category was removed successfully, false if no such category
+ * was assigned.
*/
- virtual void setIsEndorsed(bool endorsed) = 0;
+ virtual bool removeCategory(const QString& categoryName) override;
/**
- * set the mod to "i don't intend to endorse". The mod will not show as unendorsed but can still be endorsed
+ * @brief Sets or changes the source game of this mod.
+ *
+ * @param gameName The source game short name.
*/
- virtual void setNeverEndorse() = 0;
+ virtual void setGameName(const QString& gameName) = 0;
/**
- * update the tracked state for the mod. This only changes the
- * buffered state, it does not sync with Nexus
- * @param tracked the new tracked state
+ * @brief Sets 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).
*/
- virtual void setIsTracked(bool tracked) = 0;
+ virtual bool setName(const QString& name) = 0;
/**
- * @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
- **/
+ * @brief Deletes the mod from the disc. This does not update the global ModInfo structure or
+ * indices.
+ *
+ * @return true on success, false otherwise.
+ */
virtual bool remove() = 0;
+public: // Methods after this do not come from IModInterface:
+
/**
- * @brief endorse or un-endorse the mod. This will sync with nexus!
- * @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.
+ * @return true if this mod is a regular mod, false otherwise.
*/
- virtual void endorse(bool doEndorse) = 0;
+ virtual bool isRegular() const { return false; }
/**
- * @brief track or untrack the mod. This will sync with nexus!
- * @param doTrack if true, the mod is tracked, if false, it's untracked.
- * @note if doTrack doesn't differ from the current value, nothing happens.
+ * @return true if this mod is empty, false otherwise.
*/
- virtual void track(bool doTrack) = 0;
+ virtual bool isEmpty() const { return false; }
/**
- * @brief clear all caches held for this mod
+ * @brief Check if there is a newer version of the mod.
+ *
+ * Check 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, false otherwise.
*/
- virtual void clearCaches() {}
+ virtual bool updateAvailable() const = 0;
+
+ /**
+ * @return true if the update currently available is ignored.
+ */
+ virtual bool updateIgnored() const = 0;
/**
- * @brief getter for the mod name
+ * @brief Check if the "newest" version of the mod is older than the installed version.
*
- * @return the mod name
- **/
- virtual QString name() const = 0;
+ * Check 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 the newest version is older than the installed one.
+ */
+ virtual bool downgradeAvailable() const = 0;
/**
- * @brief getter for an internal name. This is usually the same as the regular name, but with special mod types it might be
- * this is used to distinguish between mods that have the same visible name
- * @return internal mod name
+ * @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. Right now, Mod Organizer interprets the
+ * "newest version" and "description" from the response, though the description is only
+ * stored in memory.
+ *
*/
- virtual QString internalName() const { return name(); }
+ virtual bool updateNXMInfo() = 0;
/**
- * @brief getter for the mod path
+ * @brief Assigns or unassigns the specified category/
*
- * @return the (absolute) path to the mod
- **/
- virtual QString absolutePath() const = 0;
+ * Every mod can have an arbitrary number of categories assigned to it.
+ *
+ * @param categoryID ID of the category to set.
+ * @param active Determines whether the category is assigned or unassigned.
+ *
+ * @note This function does not test whether categoryID actually identifies a valid category.
+ */
+ virtual void setCategory(int categoryID, bool active) = 0;
+
+ /**
+ * @brief Changes the comments (manually set information displayed in the mod list) for this mod.
+ *
+ * @param comments The new comments.
+ */
+ virtual void setComments(const QString &comments) = 0;
/**
- * @brief getter for the installation file
+ * @brief Change the notes (manually set information) for this mod.
*
- * @return file used to install this mod from
+ * @param notes The new notes.
+ */
+ virtual void setNotes(const QString &notes) = 0;
+
+ /**
+ * @brief Controls if mod should be highlighted based on plugin selection.
+ *
+ * @param isSelected Whether or not the plugin has a selected mod.
+ */
+ virtual void setPluginSelected(const bool &isSelected);
+
+ /**
+ * @brief Sets the repository that was used to download the mod.
*/
- virtual QString getInstallationFile() const = 0;
+ virtual void setRepository(const QString &) {}
/**
- * @return version object for machine based comparisons
- **/
- virtual MOBase::VersionInfo getVersion() const { return m_Version; }
+ * @brief Set the mod to "I do not intend to endorse.". The mod will not show as unendorsed
+ * but can still be endorsed.
+ */
+ virtual void setNeverEndorse() = 0;
/**
- * @brief getter for the newest version number of this mod
+ * @brief Updates the tracked state for the mod. This only changes the buffered state,
+ * it does not sync with Nexus.
*
- * @return newest version of the mod
- **/
- virtual MOBase::VersionInfo getNewestVersion() const = 0;
+ * @param tracked The new tracked state.
+ *
+ * @see track(bool)
+ */
+ virtual void setIsTracked(bool tracked) = 0;
/**
- * @return the repository from which the file was downloaded. Only relevant regular mods
+ * @brief Endorses or un-endorses the mod. This will sync with nexus!
+ *
+ * @param doEndorse If true, the mod is endorsed, if false, it's un-endorsed.
+ *
+ * @note If doEndorse does not differ from the current value, nothing happens.
*/
- virtual QString repository() const { return ""; }
+ virtual void endorse(bool doEndorse) = 0;
/**
- * @brief ignore the newest version for updates
+ * @brief Tracks or untracks the mod. This will sync with nexus!
+ *
+ * @param doTrack If true, the mod is tracked, if false, it's untracked.
+ *
+ * @note If doTrack does not differ from the current value, nothing happens.
*/
- virtual void ignoreUpdate(bool ignore) = 0;
+ virtual void track(bool doTrack) = 0;
/**
- * @brief getter for the nexus mod id
+ * @brief Clear all caches held for this mod.
+ */
+ virtual void clearCaches() {}
+
+ /**
+ * @brief Retrieve the internal name of the mod. This is usually the same as the regular name,
+ * but with special mod types it might be used to distinguish between mods that have the same
+ * visible name.
*
- * @return the nexus mod id. may be 0 if the mod id isn't known or doesn't exist
- **/
- virtual int getNexusID() const = 0;
+ * @return the internal mod name.
+ */
+ virtual QString internalName() const { return name(); }
/**
- * @brief getter for the source game repository
- *
- * @return the source game repository. should default to the active game.
- **/
- virtual QString getGameName() const = 0;
+ * @brief Ignores the newest version for updates.
+ */
+ virtual void ignoreUpdate(bool ignore) = 0;
/**
* @return the fixed priority of mods of this type or INT_MIN if the priority of mods
- * needs to be user-modifiable. Can be < 0 to force a priority below user-modifable mods
- * or INT_MAX to force priority above all user-modifiables
+ * needs to be user-modifiable. Can be < 0 to force a priority below user-modifable mods
+ * or INT_MAX to force priority above all user-modifiables.
*/
virtual int getFixedPriority() const = 0;
/**
- * @return true if the mod is always enabled
+ * @return true if the mod is always enabled.
*/
virtual bool alwaysEnabled() const { return false; }
/**
- * @return true if the mod can be updated
+ * @return true if the mod can be updated.
*/
virtual bool canBeUpdated() const { return false; }
/**
- * @return the mod update check expiration date
+ * @return the mod update check expiration date.
*/
virtual QDateTime getExpires() const = 0;
/**
- * @return true if the mod can be enabled/disabled
+ * @return true if the mod can be enabled/disabled.
*/
virtual bool canBeEnabled() const { return false; }
/**
- * @return a list of flags for this mod
+ * @return a list of flags for this mod.
*/
virtual std::vector<EFlag> getFlags() const = 0;
/**
- * @return a list of conflict flags for this mod
+ * @return a list of conflict flags for this mod.
*/
virtual std::vector<EConflictFlag> getConflictFlags() const = 0;
/**
- * @return a list of content types contained in a mod
+ * @return a list of content types contained in a mod.
+ *
+ * @note The IDs of the content are game-dependent. See the ModDataContent game feature
+ * for more details on this.
*/
virtual const std::set<int>& getContents() const = 0;
/**
- * @brief test if the specified flag is set for this mod
- * @param flag the flag to test
- * @return true if the flag is set, false otherwise
+ * @brief Check if the specified flag is set for this mod.
+ *
+ * @param flag The flag to test.
+ *
+ * @return true if the flag is set, false otherwise.
*/
bool hasFlag(EFlag flag) const;
/**
- * @brief test if any of the provided flags are set for this mod
- * @param flags the flags to test
- * @return true if any of the flags are set, false otherwise
+ * @brief Check if any of the provided flags are set for this mod.
+ *
+ * @param flags The flags to test.
+ *
+ * @return true if any of the flags are set, false otherwise.
*/
bool hasAnyOfTheseFlags(std::vector<ModInfo::EFlag> flags) const;
/**
- * @brief Test if the mod contains the specified content.
+ * @brief Check if this mod contains the specified content.
*
* @param content ID of the content to test.
*
@@ -547,232 +673,232 @@ public:
virtual bool hasContent(int content) const = 0;
/**
- * @return an indicator if and how this mod should be highlighted by the UI
+ * @return an indicator if and how this mod should be highlighted in the UI.
*/
virtual int getHighlight() const { return HIGHLIGHT_NONE; }
/**
- * @return list of names of ini tweaks
- **/
+ * @return the list of INI tweaks in this mod.
+ */
virtual std::vector<QString> getIniTweaks() const = 0;
/**
- * @return a description about the mod, to be displayed in the ui
+ * @return the description of the mod, to display in the UI.
*/
virtual QString getDescription() const = 0;
/**
- * @return the nexus file status (aka category ID)
+ * @return the creation time of this mod.
*/
- virtual int getNexusFileStatus() const = 0;
-
+ virtual QDateTime creationTime() const = 0;
/**
- * @brief sets the file status (category ID) from Nexus
- * @param status the status id of the installed file
+ * @return the list of files that, if they exist in the data directory are treated as files in
+ * THIS mod.
*/
- virtual void setNexusFileStatus(int status) = 0;
+ virtual QStringList stealFiles() const { return QStringList(); }
/**
- * @return comments for this mod
+ * @return the list of archives belonging to this mod (as absolute file paths).
*/
- virtual QString comments() const = 0;
+ virtual QStringList archives(bool checkOnDisk = false) = 0;
/**
- * @return notes for this mod
+ * @brief Set the color of this mod for display.
+ *
+ * @param color New color of this mod.
+ *
+ * @note Currently, this changes the color of the cell under the "Notes" column.
*/
- virtual QString notes() const = 0;
+ virtual void setColor(QColor color) { }
/**
- * @return creation time of this mod
+ * @brief Adds the information that a file has been installed into this mod.
+ *
+ * @param modId ID of the mod installed.
+ * @param fileId ID of the file installed.
*/
- virtual QDateTime creationTime() const = 0;
+ virtual void addInstalledFile(int modId, int fileId) = 0;
/**
- * @return nexus description of the mod (html)
+ * @brief Check if the mod belongs to the specified category.
+ *
+ * @param categoryID ID of the category to test for.
+ *
+ * @return true if the mod belongs to the specified category.
+ *
+ * @note This does not verify the id actually identifies a category.
*/
- virtual QString getNexusDescription() const = 0;
+ bool categorySet(int categoryID) const;
/**
- * @brief get the last time nexus was checked for file updates on this mod
+ * @brief Retrieves the whole list of categories (as ids) this mod belongs to.
+ *
+ * @return the IDs of categories this mod belongs to.
*/
- virtual QDateTime getLastNexusUpdate() const = 0;
+ const std::set<int> &getCategories() const { return m_Categories; }
/**
- * @brief set the last time nexus was checked for file updates on this mod
+ * @brief Sets the new primary category of the mod.
+ *
+ * @param categoryID ID of the primary category to set.
*/
- virtual void setLastNexusUpdate(QDateTime time) = 0;
+ virtual void setPrimaryCategory(int categoryID) { m_PrimaryCategory = categoryID; }
/**
- * @return last time nexus was queried for infos on this mod
+ * @return true if this mod is considered "valid", that is it contains data used by the game.
*/
- virtual QDateTime getLastNexusQuery() const = 0;
+ virtual bool isValid() const = 0;
/**
- * @brief set the last time nexus was queried for info on this mod
+ * @brief Updates the mod to flag it as converted in order to ignore the alternate game
+ * warning.
*/
- virtual void setLastNexusQuery(QDateTime time) = 0;
+ virtual void markConverted(bool) {}
/**
- * @return last time the mod was updated on Nexus
- */
- virtual QDateTime getNexusLastModified() const = 0;
+ * @brief Updates the mod to flag it as valid in order to ignore the invalid game data
+ * flag.
+ */
+ virtual void markValidated(bool) {}
/**
- * @brief set the last time the mod was updated on Nexus
+ * @brief Reads meta information from disk.
*/
- virtual void setNexusLastModified(QDateTime time) = 0;
+ virtual void readMeta() {}
/**
- * @return a list of files that, if they exist in the data directory are treated as files in THIS mod
+ * @brief Stores meta information back to disk.
*/
- virtual QStringList stealFiles() const { return QStringList(); }
+ virtual void saveMeta() {}
/**
- * @return a list of archives belonging to this mod (as absolute file paths)
+ * @brief Sets whether this mod uses a custom url.
*/
- virtual QStringList archives(bool checkOnDisk = false) = 0;
+ virtual void setHasCustomURL(bool) {}
- /*
- *@return the color choosen by the user for the mod/separator
+ /**
+ * @brief Check whether this mod uses a custom url.
+ *
+ * @return true if this mod has a custom URL, false otherwise.
*/
- virtual QColor getColor() const { return QColor(); }
+ virtual bool hasCustomURL() const { return false; }
- /*
- *@return true if the color has been set successfully.
+ /**
+ * @brief Sets the custom url.
*/
- virtual void setColor(QColor) { }
+ virtual void setCustomURL(QString const&) {}
/**
- * @brief adds the information that a file has been installed into this mod
- * @param modId id of the mod installed
- * @param fileId id of the file installed
+ * If hasCustomURL() is true and getCustomURL() is not empty, tries to parse
+ * the url using QUrl::fromUserInput() and returns it. Otherwise, returns an
+ * empty QUrl.
*/
- virtual void addInstalledFile(int modId, int fileId) = 0;
+ QUrl parseCustomURL() const;
- /**
- * @brief test if the mod belongs to the specified category
- *
- * @param categoryID the category to test for.
- * @return true if the mod belongs to the specified category
- * @note this does not verify the id actually identifies a category
- **/
- bool categorySet(int categoryID) const;
+public: // Nexus stuff
/**
- * @brief retrive the whole list of categories (as ids) this mod belongs to
+ * @brief Changes the nexus description text.
*
- * @return list of categories
- **/
- const std::set<int> &getCategories() const { return m_Categories; }
-
- /**
- * @return id of the primary category of this mod
+ * @param description The current description text.
*/
- int getPrimaryCategory() const { return m_PrimaryCategory; }
+ virtual void setNexusDescription(const QString& description) = 0;
/**
- * @brief sets the new primary category of the mod
- * @param categoryID the category to set
+ * @return the nexus file status (aka category ID).
*/
- virtual void setPrimaryCategory(int categoryID) { m_PrimaryCategory = categoryID; }
-
- /**
- * @return true if this mod is considered "valid", that is: it contains data used by the game
- **/
- virtual bool isValid() const = 0;
+ virtual int getNexusFileStatus() const = 0;
/**
- * @return true if the file has been endorsed on nexus
+ * @brief Sets the file status (category ID) from Nexus.
+ *
+ * @param status The status id of the installed file.
*/
- virtual EEndorsedState endorsedState() const { return ENDORSED_NEVER; }
+ virtual void setNexusFileStatus(int status) = 0;
/**
- * @return true if the file is being tracked on nexus
+ * @return the nexus description of the mod (html).
*/
- virtual ETrackedState trackedState() const { return TRACKED_FALSE; }
+ virtual QString getNexusDescription() const = 0;
/**
- * @brief updates the mod to flag it as converted in order to ignore the alternate game warning
+ * @brief Get the last time nexus was checked for file updates on this mod.
*/
- virtual void markConverted(bool) {}
-
- /**
- * @brief updates the mod to flag it as valid in order to ignore the invalid game data flag
- */
- virtual void markValidated(bool) {}
+ virtual QDateTime getLastNexusUpdate() const = 0;
/**
- * @brief reads meta information from disk
+ * @brief Sets the last time nexus was checked for file updates on this mod.
*/
- virtual void readMeta() {}
+ virtual void setLastNexusUpdate(QDateTime time) = 0;
/**
- * @brief stores meta information back to disk
+ * @return the last time nexus was queried for infos on this mod.
*/
- virtual void saveMeta() {}
+ virtual QDateTime getLastNexusQuery() const = 0;
/**
- * @return retrieve list of mods (as mod index) that are overwritten by this one. Updates may be delayed
+ * @brief Sets the last time nexus was queried for info on this mod.
*/
- virtual std::set<unsigned int> getModOverwrite() const { return std::set<unsigned int>(); }
+ virtual void setLastNexusQuery(QDateTime time) = 0;
/**
- * @return list of mods (as mod index) that overwrite this one. Updates may be delayed
+ * @return the last time the mod was updated on Nexus.
*/
- virtual std::set<unsigned int> getModOverwritten() const { return std::set<unsigned int>(); }
-
- /**
- * @return retrieve list of mods (as mod index) with archives that are overwritten by this one. Updates may be delayed
- */
- virtual std::set<unsigned int> getModArchiveOverwrite() const { return std::set<unsigned int>(); }
+ virtual QDateTime getNexusLastModified() const = 0;
/**
- * @return list of mods (as mod index) with archives that overwrite this one. Updates may be delayed
- */
- virtual std::set<unsigned int> getModArchiveOverwritten() const { return std::set<unsigned int>(); }
+ * @brief Set the last time the mod was updated on Nexus.
+ */
+ virtual void setNexusLastModified(QDateTime time) = 0;
- /**
- * @return retrieve list of mods (as mod index) with archives that are overwritten by thos mod's loose files. Updates may be delayed
- */
- virtual std::set<unsigned int> getModArchiveLooseOverwrite() const { return std::set<unsigned int>(); }
+public: // Conflicts
/**
- * @return list of mods (as mod index) with loose files that overwrite this one's archive files. Updates may be delayed
- */
- virtual std::set<unsigned int> getModArchiveLooseOverwritten() const { return std::set<unsigned int>(); }
+ * @return retrieve list of mods (as mod index) that are overwritten by this one.
+ * Updates may be delayed.
+ */
+ virtual std::set<unsigned int> getModOverwrite() const {
+ return std::set<unsigned int>(); }
/**
- * @brief update conflict information
+ * @return list of mods (as mod index) that overwrite this one. Updates may be delayed.
*/
- virtual void doConflictCheck() const {}
+ virtual std::set<unsigned int> getModOverwritten() const {
+ return std::set<unsigned int>(); }
/**
- * @brief sets whether this mod uses a custom url
- **/
- virtual void setHasCustomURL(bool) {}
+ * @return retrieve list of mods (as mod index) with archives that are overwritten by
+ * this one. Updates may be delayed
+ */
+ virtual std::set<unsigned int> getModArchiveOverwrite() const {
+ return std::set<unsigned int>(); }
/**
- * @brief returns whether this mod uses a custom url
- **/
- virtual bool hasCustomURL() const { return false; }
+ * @return list of mods (as mod index) with archives that overwrite this one. Updates
+ * may be delayed.
+ */
+ virtual std::set<unsigned int> getModArchiveOverwritten() const {
+ return std::set<unsigned int>(); }
/**
- * @brief sets the custom url
- **/
- virtual void setCustomURL(QString const &) {}
+ * @return the list of mods (as mod index) with archives that are overwritten by loose
+ * files of this mod. Updates may be delayed.
+ */
+ virtual std::set<unsigned int> getModArchiveLooseOverwrite() const {
+ return std::set<unsigned int>(); }
/**
- * @brief returns the custom url
- **/
- virtual QString getCustomURL() const { return ""; }
+ * @return the list of mods (as mod index) with loose files that overwrite this one's
+ * archive files. Updates may be delayed.
+ */
+ virtual std::set<unsigned int> getModArchiveLooseOverwritten() const {
+ return std::set<unsigned int>(); }
/**
- * If hasCustomURL() is true and getCustomURL() is not empty, tries to parse
- * the url using QUrl::fromUserInput() and returns it. Otherwise, returns an
- * empty QUrl.
- **/
- QUrl parseCustomURL() const;
+ * @brief Update conflict information.
+ */
+ virtual void doConflictCheck() const {}
public slots:
@@ -784,10 +910,10 @@ public slots:
signals:
/**
- * @brief emitted whenever the information of a mod changes
+ * @brief Emitted whenever the information of a mod changes.
*
- * @param success true if the mod details were updated successfully, false if not
- **/
+ * @param success true if the mod details were updated successfully, false if not.
+ */
void modDetailsUpdated(bool success);
protected:
@@ -809,12 +935,6 @@ protected:
static void updateIndices();
static bool ByName(const ModInfo::Ptr &LHS, const ModInfo::Ptr &RHS);
-private:
-
- static void createFromOverwrite(PluginContainer *pluginContainer,
- const MOBase::IPluginGame* game,
- MOShared::DirectoryEntry **directoryStructure);
-
protected:
static std::vector<ModInfo::Ptr> s_Collection;
@@ -829,6 +949,12 @@ protected:
private:
+ static void createFromOverwrite(PluginContainer* pluginContainer,
+ const MOBase::IPluginGame* game,
+ MOShared::DirectoryEntry** directoryStructure);
+
+private:
+
static QMutex s_Mutex;
static std::map<std::pair<QString, int>, std::vector<unsigned int> > s_ModsByModID;
static int s_NextID;
diff --git a/src/modinfodialogcategories.cpp b/src/modinfodialogcategories.cpp
index c61e248e..8bdea6e8 100644
--- a/src/modinfodialogcategories.cpp
+++ b/src/modinfodialogcategories.cpp
@@ -79,7 +79,7 @@ void CategoriesTab::updatePrimary()
{
ui->primaryCategories->clear();
- int primaryCategory = mod().getPrimaryCategory();
+ int primaryCategory = mod().primaryCategory();
addChecked(ui->categories->invisibleRootItem());
diff --git a/src/modinfodialognexus.cpp b/src/modinfodialognexus.cpp
index 8d99d230..dd95cdaa 100644
--- a/src/modinfodialognexus.cpp
+++ b/src/modinfodialognexus.cpp
@@ -68,9 +68,9 @@ void NexusTab::update()
clear();
- ui->modID->setText(QString("%1").arg(mod().getNexusID()));
+ ui->modID->setText(QString("%1").arg(mod().nexusId()));
- QString gameName = mod().getGameName();
+ QString gameName = mod().gameName();
ui->sourceGame->addItem(
core().managedGame()->gameName(),
core().managedGame()->gameShortName());
@@ -98,10 +98,10 @@ void NexusTab::update()
[&](const QUrl& url){ shell::Open(url); });
ui->endorse->setEnabled(
- (mod().endorsedState() == ModInfo::ENDORSED_FALSE) ||
- (mod().endorsedState() == ModInfo::ENDORSED_NEVER));
+ (mod().endorsedState() == EndorsedState::ENDORSED_FALSE) ||
+ (mod().endorsedState() == EndorsedState::ENDORSED_NEVER));
- setHasData(mod().getNexusID() >= 0);
+ setHasData(mod().nexusId() >= 0);
}
void NexusTab::firstActivation()
@@ -126,10 +126,10 @@ bool NexusTab::usesOriginFiles() const
void NexusTab::updateVersionColor()
{
- if (mod().getVersion() != mod().getNewestVersion()) {
+ if (mod().version() != mod().newestVersion()) {
ui->version->setStyleSheet("color: red");
ui->version->setToolTip(tr("Current Version: %1").arg(
- mod().getNewestVersion().canonicalString()));
+ mod().newestVersion().canonicalString()));
} else {
ui->version->setStyleSheet("color: green");
ui->version->setToolTip(tr("No update available"));
@@ -138,11 +138,11 @@ void NexusTab::updateVersionColor()
void NexusTab::updateWebpage()
{
- const int modID = mod().getNexusID();
+ const int modID = mod().nexusId();
if (isValidModID(modID)) {
const QString nexusLink = NexusInterface::instance(&plugin())
- ->getModURL(modID, mod().getGameName());
+ ->getModURL(modID, mod().gameName());
ui->visitNexus->setToolTip(nexusLink);
refreshData(modID);
@@ -150,9 +150,9 @@ void NexusTab::updateWebpage()
onModChanged();
}
- ui->version->setText(mod().getVersion().displayString());
+ ui->version->setText(mod().version().displayString());
ui->hasCustomURL->setChecked(mod().hasCustomURL());
- ui->customURL->setText(mod().getCustomURL());
+ ui->customURL->setText(mod().url());
ui->customURL->setEnabled(mod().hasCustomURL());
ui->visitCustomURL->setEnabled(mod().hasCustomURL());
ui->visitCustomURL->setToolTip(mod().parseCustomURL().toString());
@@ -162,7 +162,7 @@ void NexusTab::updateWebpage()
void NexusTab::updateTracking()
{
- if (mod().trackedState() == ModInfo::TRACKED_TRUE) {
+ if (mod().trackedState() == TrackedState::TRACKED_TRUE) {
ui->track->setChecked(true);
ui->track->setText(tr("Tracked"));
} else {
@@ -301,7 +301,7 @@ void NexusTab::onModIDChanged()
return;
}
- const int oldID = mod().getNexusID();
+ const int oldID = mod().nexusId();
const int newID = ui->modID->text().toInt();
if (oldID != newID){
@@ -326,7 +326,7 @@ void NexusTab::onSourceGameChanged()
if (game->gameName() == ui->sourceGame->currentText()) {
mod().setGameName(game->gameShortName());
mod().setLastNexusQuery(QDateTime::fromSecsSinceEpoch(0));
- refreshData(mod().getNexusID());
+ refreshData(mod().nexusId());
return;
}
}
@@ -345,7 +345,7 @@ void NexusTab::onVersionChanged()
void NexusTab::onRefreshBrowser()
{
- const auto modID = mod().getNexusID();
+ const auto modID = mod().nexusId();
if (isValidModID(modID)) {
mod().setLastNexusQuery(QDateTime::fromSecsSinceEpoch(0));
@@ -357,11 +357,11 @@ void NexusTab::onRefreshBrowser()
void NexusTab::onVisitNexus()
{
- const int modID = mod().getNexusID();
+ const int modID = mod().nexusId();
if (isValidModID(modID)) {
const QString nexusLink = NexusInterface::instance(&plugin())
- ->getModURL(modID, mod().getGameName());
+ ->getModURL(modID, mod().gameName());
shell::Open(QUrl(nexusLink));
}
@@ -379,7 +379,7 @@ void NexusTab::onTrack()
// use modPtr() instead of mod() or this because the callback may be
// executed after the dialog is closed
core().loggedInAction(parentWidget(), [m=modPtr()] {
- if (m->trackedState() == ModInfo::TRACKED_TRUE) {
+ if (m->trackedState() == TrackedState::TRACKED_TRUE) {
m->track(false);
} else {
m->track(true);
diff --git a/src/modinfodialogtab.cpp b/src/modinfodialogtab.cpp
index f795cdf9..e5ced4f7 100644
--- a/src/modinfodialogtab.cpp
+++ b/src/modinfodialogtab.cpp
@@ -163,7 +163,7 @@ void NotesTab::updateCommentsColor(bool clear)
QPalette commentPalette = QPalette();
if (!clear) {
- auto modColor = mod().getColor();
+ auto modColor = mod().color();
if (modColor.isValid()) {
commentPalette.setColor(QPalette::Base, modColor);
commentPalette.setColor(QPalette::Text, ColorSettings::idealTextColor(modColor));
@@ -219,7 +219,7 @@ void NotesTab::onSetColor()
QColorDialog dialog(m_parent);
dialog.setOption(QColorDialog::ShowAlphaChannel);
- QColor currentColor = mod().getColor();
+ QColor currentColor = mod().color();
if (currentColor.isValid()) {
dialog.setCurrentColor(currentColor);
@@ -256,5 +256,5 @@ void NotesTab::checkHasData()
setHasData(
!ui->comments->text().isEmpty() ||
!ui->notes->toPlainText().isEmpty() ||
- mod().getColor().isValid());
+ mod().color().isValid());
}
diff --git a/src/modinfoforeign.h b/src/modinfoforeign.h
index ae4241ee..4f830799 100644
--- a/src/modinfoforeign.h
+++ b/src/modinfoforeign.h
@@ -42,10 +42,13 @@ public:
virtual QString notes() const override { return ""; }
virtual QDateTime creationTime() const override;
virtual QString absolutePath() const override;
- virtual MOBase::VersionInfo getNewestVersion() const override { return QString(); }
- virtual QString getInstallationFile() const override { return ""; }
- virtual QString getGameName() const override { return ""; }
- virtual int getNexusID() const override { return -1; }
+ virtual MOBase::VersionInfo newestVersion() const override { return QString(); }
+ virtual MOBase::VersionInfo ignoredVersion() const override { return QString(); }
+ virtual QString installationFile() const override { return ""; }
+ virtual bool converted() const override { return false; }
+ virtual bool validated() const override { return false; }
+ virtual QString gameName() const override { return ""; }
+ virtual int nexusId() const override { return -1; }
virtual QDateTime getExpires() const override { return QDateTime(); }
virtual std::vector<QString> getIniTweaks() const override { return std::vector<QString>(); }
virtual std::vector<ModInfo::EFlag> getFlags() const override;
@@ -65,6 +68,12 @@ public:
virtual QStringList stealFiles() const override { return m_Archives + QStringList(m_ReferenceFile); }
virtual bool alwaysEnabled() const override { return true; }
virtual void addInstalledFile(int, int) override {}
+ virtual std::set<std::pair<int, int>> installedFiles() const override { return {}; }
+
+ virtual QVariant pluginSetting(const QString& pluginName, const QString& key, const QVariant& defaultValue) const override { return defaultValue; }
+ virtual std::map<QString, QVariant> pluginSettings(const QString& pluginName) const override { return {}; }
+ virtual bool setPluginSetting(const QString& pluginName, const QString& key, const QVariant& value) override { return false; }
+ virtual std::map<QString, QVariant> clearPluginSettings(const QString& pluginName) override { return {}; }
ModInfo::EModType modType() const { return m_ModType; }
diff --git a/src/modinfooverwrite.h b/src/modinfooverwrite.h
index 9770ecbb..502581ce 100644
--- a/src/modinfooverwrite.h
+++ b/src/modinfooverwrite.h
@@ -44,11 +44,14 @@ public:
virtual QString notes() const override { return ""; }
virtual QDateTime creationTime() const override { return QDateTime(); }
virtual QString absolutePath() const override;
- virtual MOBase::VersionInfo getNewestVersion() const override { return QString(); }
- virtual QString getInstallationFile() const override { return ""; }
+ virtual MOBase::VersionInfo newestVersion() const override { return QString(); }
+ virtual MOBase::VersionInfo ignoredVersion() const override { return QString(); }
+ virtual QString installationFile() const override { return ""; }
+ virtual bool converted() const override { return false; }
+ virtual bool validated() const override { return false; }
virtual int getFixedPriority() const override { return std::numeric_limits<int>::max(); }
- virtual QString getGameName() const override { return ""; }
- virtual int getNexusID() const override { return -1; }
+ virtual QString gameName() const override { return ""; }
+ virtual int nexusId() const override { return -1; }
virtual QDateTime getExpires() const override { return QDateTime(); }
virtual std::vector<QString> getIniTweaks() const override { return std::vector<QString>(); }
virtual std::vector<ModInfo::EFlag> getFlags() const override;
@@ -66,6 +69,12 @@ public:
virtual QString getNexusDescription() const override { return QString(); }
virtual QStringList archives(bool checkOnDisk = false) override;
virtual void addInstalledFile(int, int) override {}
+ virtual std::set<std::pair<int, int>> installedFiles() const override { return {}; }
+
+ virtual QVariant pluginSetting(const QString& pluginName, const QString& key, const QVariant& defaultValue) const override { return defaultValue; }
+ virtual std::map<QString, QVariant> pluginSettings(const QString& pluginName) const override { return {}; }
+ virtual bool setPluginSetting(const QString& pluginName, const QString& key, const QVariant& value) override { return false; }
+ virtual std::map<QString, QVariant> clearPluginSettings(const QString& pluginName) override { return {}; }
private:
ModInfoOverwrite(PluginContainer *pluginContainer, const MOBase::IPluginGame* game, MOShared::DirectoryEntry **directoryStructure);
diff --git a/src/modinforegular.cpp b/src/modinforegular.cpp
index 8ef8e007..78c04f2d 100644
--- a/src/modinforegular.cpp
+++ b/src/modinforegular.cpp
@@ -34,8 +34,8 @@ ModInfoRegular::ModInfoRegular(PluginContainer *pluginContainer, const IPluginGa
, m_Converted(false)
, m_Validated(false)
, m_MetaInfoChanged(false)
- , m_EndorsedState(ENDORSED_UNKNOWN)
- , m_TrackedState(TRACKED_UNKNOWN)
+ , m_EndorsedState(EndorsedState::ENDORSED_UNKNOWN)
+ , m_TrackedState(TrackedState::TRACKED_UNKNOWN)
, m_NexusBridge(pluginContainer)
{
m_CreationTime = QFileInfo(path.absolutePath()).birthTime();
@@ -166,17 +166,18 @@ void ModInfoRegular::readMeta()
m_LastNexusUpdate = QDateTime::fromString(metaFile.value("lastNexusUpdate", "").toString(), Qt::ISODate);
m_NexusLastModified = QDateTime::fromString(metaFile.value("nexusLastModified", QDateTime::currentDateTimeUtc()).toString(), Qt::ISODate);
m_Color = metaFile.value("color",QColor()).value<QColor>();
- m_TrackedState = metaFile.value("tracked", false).toBool() ? TRACKED_TRUE : TRACKED_FALSE;
+ m_TrackedState = metaFile.value("tracked", false).toBool() ? TrackedState::TRACKED_TRUE : TrackedState::TRACKED_FALSE;
if (metaFile.contains("endorsed")) {
if (metaFile.value("endorsed").canConvert<int>()) {
+ using ut = std::underlying_type_t<EndorsedState>;
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;
+ case static_cast<ut>(EndorsedState::ENDORSED_FALSE): m_EndorsedState = EndorsedState::ENDORSED_FALSE; break;
+ case static_cast<ut>(EndorsedState::ENDORSED_TRUE): m_EndorsedState = EndorsedState::ENDORSED_TRUE; break;
+ case static_cast<ut>(EndorsedState::ENDORSED_NEVER): m_EndorsedState = EndorsedState::ENDORSED_NEVER; break;
+ default: m_EndorsedState = EndorsedState::ENDORSED_UNKNOWN; break;
}
} else {
- m_EndorsedState = metaFile.value("endorsed", false).toBool() ? ENDORSED_TRUE : ENDORSED_FALSE;
+ m_EndorsedState = metaFile.value("endorsed", false).toBool() ? EndorsedState::ENDORSED_TRUE : EndorsedState::ENDORSED_FALSE;
}
}
@@ -205,6 +206,17 @@ void ModInfoRegular::readMeta()
}
metaFile.endArray();
+ // Plugin settings:
+ metaFile.beginGroup("Plugins");
+ for (auto pluginName: metaFile.childGroups()) {
+ metaFile.beginGroup(pluginName);
+ for (auto settingKey : metaFile.childKeys()) {
+ m_PluginSettings[pluginName][settingKey] = metaFile.value(settingKey);
+ }
+ metaFile.endGroup();
+ }
+ metaFile.endGroup();
+
m_MetaInfoChanged = false;
}
@@ -236,10 +248,10 @@ void ModInfoRegular::saveMeta()
metaFile.setValue("converted", m_Converted);
metaFile.setValue("validated", m_Validated);
metaFile.setValue("color", m_Color);
- if (m_EndorsedState != ENDORSED_UNKNOWN) {
- metaFile.setValue("endorsed", m_EndorsedState);
+ if (m_EndorsedState != EndorsedState::ENDORSED_UNKNOWN) {
+ metaFile.setValue("endorsed", static_cast<std::underlying_type_t<EndorsedState>>(m_EndorsedState));
}
- metaFile.setValue("tracked", m_TrackedState);
+ metaFile.setValue("tracked", static_cast<std::underlying_type_t<TrackedState>>(m_TrackedState));
metaFile.remove("installedFiles");
metaFile.beginWriteArray("installedFiles");
@@ -251,6 +263,18 @@ void ModInfoRegular::saveMeta()
}
metaFile.endArray();
+ // Plugin settings:
+ metaFile.remove("Plugins");
+ metaFile.beginGroup("Plugins");
+ for (const auto& [pluginName, pluginSettings]: m_PluginSettings) {
+ metaFile.beginGroup(pluginName);
+ for (const auto& [settingName, settingValue]: pluginSettings) {
+ metaFile.setValue(settingName, settingValue);
+ }
+ metaFile.endGroup();
+ }
+ metaFile.endGroup();
+
metaFile.sync(); // sync needs to be called to ensure the file is created
if (metaFile.status() == QSettings::NoError) {
@@ -295,15 +319,15 @@ void ModInfoRegular::nxmDescriptionAvailable(QString, int, QVariant, QVariant re
QVariantMap result = resultData.toMap();
setNexusDescription(result["description"].toString());
- if ((m_EndorsedState != ENDORSED_NEVER) && (result.contains("endorsement"))) {
+ if ((m_EndorsedState != EndorsedState::ENDORSED_NEVER) && (result.contains("endorsement"))) {
QVariantMap endorsement = result["endorsement"].toMap();
QString endorsementStatus = endorsement["endorse_status"].toString();
if (endorsementStatus.compare("Endorsed", Qt::CaseInsensitive) == 00)
- setEndorsedState(ENDORSED_TRUE);
+ setEndorsedState(EndorsedState::ENDORSED_TRUE);
else if (endorsementStatus.compare("Abstained", Qt::CaseInsensitive) == 00)
- setEndorsedState(ENDORSED_NEVER);
+ setEndorsedState(EndorsedState::ENDORSED_NEVER);
else
- setEndorsedState(ENDORSED_FALSE);
+ setEndorsedState(EndorsedState::ENDORSED_FALSE);
}
m_LastNexusQuery = QDateTime::currentDateTimeUtc();
m_NexusLastModified = QDateTime::fromSecsSinceEpoch(result["updated_timestamp"].toInt(), Qt::UTC);
@@ -318,11 +342,11 @@ void ModInfoRegular::nxmEndorsementToggled(QString, int, QVariant, QVariant resu
{
QMap results = resultData.toMap();
if (results["status"].toString().compare("Endorsed") == 0) {
- m_EndorsedState = ENDORSED_TRUE;
+ m_EndorsedState = EndorsedState::ENDORSED_TRUE;
} else if (results["status"].toString().compare("Abstained") == 0) {
- m_EndorsedState = ENDORSED_NEVER;
+ m_EndorsedState = EndorsedState::ENDORSED_NEVER;
} else {
- m_EndorsedState = ENDORSED_FALSE;
+ m_EndorsedState = EndorsedState::ENDORSED_FALSE;
}
m_MetaInfoChanged = true;
saveMeta();
@@ -333,9 +357,9 @@ void ModInfoRegular::nxmEndorsementToggled(QString, int, QVariant, QVariant resu
void ModInfoRegular::nxmTrackingToggled(QString, int, QVariant, bool tracked)
{
if (tracked)
- m_TrackedState = TRACKED_TRUE;
+ m_TrackedState = TrackedState::TRACKED_TRUE;
else
- m_TrackedState = TRACKED_FALSE;
+ m_TrackedState = TrackedState::TRACKED_FALSE;
m_MetaInfoChanged = true;
saveMeta();
emit modDetailsUpdated(true);
@@ -500,7 +524,7 @@ void ModInfoRegular::setNexusDescription(const QString &description)
}
}
-void ModInfoRegular::setEndorsedState(EEndorsedState endorsedState)
+void ModInfoRegular::setEndorsedState(EndorsedState endorsedState)
{
if (endorsedState != m_EndorsedState) {
m_EndorsedState = endorsedState;
@@ -508,7 +532,7 @@ void ModInfoRegular::setEndorsedState(EEndorsedState endorsedState)
}
}
-void ModInfoRegular::setTrackedState(ETrackedState trackedState)
+void ModInfoRegular::setTrackedState(TrackedState trackedState)
{
if (trackedState != m_TrackedState) {
m_TrackedState = trackedState;
@@ -529,22 +553,22 @@ void ModInfoRegular::addNexusCategory(int categoryID)
void ModInfoRegular::setIsEndorsed(bool endorsed)
{
- if (m_EndorsedState != ENDORSED_NEVER) {
- m_EndorsedState = endorsed ? ENDORSED_TRUE : ENDORSED_FALSE;
+ if (m_EndorsedState != EndorsedState::ENDORSED_NEVER) {
+ m_EndorsedState = endorsed ? EndorsedState::ENDORSED_TRUE : EndorsedState::ENDORSED_FALSE;
m_MetaInfoChanged = true;
}
}
void ModInfoRegular::setNeverEndorse()
{
- m_EndorsedState = ENDORSED_NEVER;
+ m_EndorsedState = EndorsedState::ENDORSED_NEVER;
m_MetaInfoChanged = true;
}
void ModInfoRegular::setIsTracked(bool tracked)
{
- if (tracked != (m_TrackedState == TRACKED_TRUE)) {
- m_TrackedState = tracked ? TRACKED_TRUE : TRACKED_FALSE;
+ if (tracked != (m_TrackedState == TrackedState::TRACKED_TRUE)) {
+ m_TrackedState = tracked ? TrackedState::TRACKED_TRUE : TrackedState::TRACKED_FALSE;
m_MetaInfoChanged = true;
}
}
@@ -555,7 +579,7 @@ void ModInfoRegular::setColor(QColor color)
m_MetaInfoChanged = true;
}
-QColor ModInfoRegular::getColor() const
+QColor ModInfoRegular::color() const
{
return m_Color;
}
@@ -568,15 +592,15 @@ bool ModInfoRegular::remove()
void ModInfoRegular::endorse(bool doEndorse)
{
- if (doEndorse != (m_EndorsedState == ENDORSED_TRUE)) {
- m_NexusBridge.requestToggleEndorsement(m_GameName, getNexusID(), m_Version.canonicalString(), doEndorse, QVariant(1));
+ if (doEndorse != (m_EndorsedState == EndorsedState::ENDORSED_TRUE)) {
+ m_NexusBridge.requestToggleEndorsement(m_GameName, nexusId(), m_Version.canonicalString(), doEndorse, QVariant(1));
}
}
void ModInfoRegular::track(bool doTrack)
{
- if (doTrack != (m_TrackedState == TRACKED_TRUE)) {
- m_NexusBridge.requestToggleTracking(m_GameName, getNexusID(), doTrack, QVariant(1));
+ if (doTrack != (m_TrackedState == TrackedState::TRACKED_TRUE)) {
+ m_NexusBridge.requestToggleTracking(m_GameName, nexusId(), doTrack, QVariant(1));
}
}
@@ -629,12 +653,12 @@ std::vector<ModInfo::EFlag> ModInfoRegular::getFlags() const
{
std::vector<ModInfo::EFlag> result = ModInfoWithConflictInfo::getFlags();
if ((m_NexusID > 0) &&
- (endorsedState() == ENDORSED_FALSE) &&
+ (endorsedState() == EndorsedState::ENDORSED_FALSE) &&
Settings::instance().nexus().endorsementIntegration()) {
result.push_back(ModInfo::FLAG_NOTENDORSED);
}
if ((m_NexusID > 0) &&
- (trackedState() == TRACKED_TRUE)) {
+ (trackedState() == TrackedState::TRACKED_TRUE)) {
result.push_back(ModInfo::FLAG_TRACKED);
}
if (!isValid() && !m_Validated) {
@@ -736,12 +760,12 @@ QString ModInfoRegular::repository() const
return m_Repository;
}
-ModInfoRegular::EEndorsedState ModInfoRegular::endorsedState() const
+EndorsedState ModInfoRegular::endorsedState() const
{
return m_EndorsedState;
}
-ModInfoRegular::ETrackedState ModInfoRegular::trackedState() const
+TrackedState ModInfoRegular::trackedState() const
{
return m_TrackedState;
}
@@ -791,7 +815,7 @@ void ModInfoRegular::setCustomURL(QString const &url)
m_MetaInfoChanged = true;
}
-QString ModInfoRegular::getCustomURL() const
+QString ModInfoRegular::url() const
{
return m_CustomURL;
}
@@ -850,3 +874,48 @@ std::vector<QString> ModInfoRegular::getIniTweaks() const
metaFile.endArray();
return result;
}
+
+
+std::map<QString, QVariant> ModInfoRegular::pluginSettings(const QString& pluginName) const
+{
+ auto itp = m_PluginSettings.find(pluginName);
+ if (itp == std::end(m_PluginSettings)) {
+ return {};
+ }
+ return itp->second;
+}
+
+QVariant ModInfoRegular::pluginSetting(const QString& pluginName, const QString& key, const QVariant& defaultValue) const
+{
+ auto itp = m_PluginSettings.find(pluginName);
+ if (itp == std::end(m_PluginSettings)) {
+ return defaultValue;
+ }
+
+ auto its = itp->second.find(key);
+ if (its == std::end(itp->second)) {
+ return defaultValue;
+ }
+
+ return its->second;
+}
+
+bool ModInfoRegular::setPluginSetting(const QString& pluginName, const QString& key, const QVariant& value)
+{
+ m_PluginSettings[pluginName][key] = value;
+ m_MetaInfoChanged = true;
+ saveMeta();
+ return true;
+}
+
+std::map<QString, QVariant> ModInfoRegular::clearPluginSettings(const QString& pluginName)
+{
+ auto itp = m_PluginSettings.find(pluginName);
+ if (itp == std::end(m_PluginSettings)) {
+ return {};
+ }
+ auto settings = itp->second;
+ m_PluginSettings.erase(itp);
+ saveMeta();
+ return settings;
+}
diff --git a/src/modinforegular.h b/src/modinforegular.h
index 7e70631e..f2e0b82d 100644
--- a/src/modinforegular.h
+++ b/src/modinforegular.h
@@ -235,33 +235,26 @@ public:
*
* @return newest version of the mod
**/
- MOBase::VersionInfo getNewestVersion() const override { return m_NewestVersion; }
+ MOBase::VersionInfo newestVersion() const override { return m_NewestVersion; }
/**
- * @brief ignore the newest version for updates
- */
- void ignoreUpdate(bool ignore) override;
-
- /**
- * @brief getter for the installation file
+ * @brief getter for the newest version number of this mod
*
- * @return file used to install this mod from
- */
- virtual QString getInstallationFile() const override { return m_InstallationFile; }
+ * @return newest version of the mod
+ **/
+ MOBase::VersionInfo ignoredVersion() const override { return m_IgnoredVersion; }
/**
- * @brief getter for the source game repository
- *
- * @return the source game repository. should default to the active game.
- **/
- QString getGameName() const override { return m_GameName; }
+ * @brief ignore the newest version for updates
+ */
+ void ignoreUpdate(bool ignore) override;
/**
* @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 override { return m_NexusID; }
+ int nexusId() const override { return m_NexusID; }
/**
* @return the fixed priority of mods of this type or INT_MIN if the priority of mods
@@ -345,12 +338,12 @@ public:
/**
* @return true if the file has been endorsed on nexus
*/
- virtual EEndorsedState endorsedState() const override;
+ virtual MOBase::EndorsedState endorsedState() const override;
/**
* @return true if the file is being tracked on nexus
*/
- virtual ETrackedState trackedState() const override;
+ virtual MOBase::TrackedState trackedState() const override;
/**
* @brief get the last time nexus was checked for file updates on this mod
@@ -386,7 +379,7 @@ public:
virtual void setColor(QColor color) override;
- virtual QColor getColor() const override;
+ virtual QColor color() const override;
virtual void addInstalledFile(int modId, int fileId) override;
@@ -400,12 +393,25 @@ public:
virtual void setHasCustomURL(bool b) override;
virtual bool hasCustomURL() const override;
virtual void setCustomURL(QString const &) override;
- virtual QString getCustomURL() const override;
+ virtual QString url() const override;
+
+ virtual QString gameName() const override { return m_GameName; }
+ virtual QString installationFile() const override { return m_InstallationFile; }
+ virtual bool converted() const override { return m_Converted; }
+ virtual bool validated() const override { return m_Validated; }
+ virtual std::set<std::pair<int, int>> installedFiles() const override { return m_InstalledFileIDs; }
+
+public: // Plugin operations:
+
+ virtual QVariant pluginSetting(const QString& pluginName, const QString& key, const QVariant& defaultValue) const override;
+ virtual std::map<QString, QVariant> pluginSettings(const QString& pluginName) const override;
+ virtual bool setPluginSetting(const QString& pluginName, const QString& key, const QVariant& value) override;
+ virtual std::map<QString, QVariant> clearPluginSettings(const QString& pluginName) override;
private:
- void setEndorsedState(EEndorsedState endorsedState);
- void setTrackedState(ETrackedState trackedState);
+ void setEndorsedState(MOBase::EndorsedState endorsedState);
+ void setTrackedState(MOBase::TrackedState trackedState);
private slots:
@@ -449,6 +455,9 @@ private:
int m_NexusID;
std::set<std::pair<int, int>> m_InstalledFileIDs;
+ // List of plugin settings:
+ std::map<QString, std::map<QString, QVariant>> m_PluginSettings;
+
bool m_MetaInfoChanged;
bool m_IsAlternate;
bool m_Converted;
@@ -457,8 +466,8 @@ private:
MOBase::VersionInfo m_NewestVersion;
MOBase::VersionInfo m_IgnoredVersion;
- EEndorsedState m_EndorsedState;
- ETrackedState m_TrackedState;
+ MOBase::EndorsedState m_EndorsedState;
+ MOBase::TrackedState m_TrackedState;
NexusBridge m_NexusBridge;
diff --git a/src/modinfoseparator.h b/src/modinfoseparator.h
index a7a6cb5f..26c03e27 100644
--- a/src/modinfoseparator.h
+++ b/src/modinfoseparator.h
@@ -20,7 +20,7 @@ public:
//TODO: Fix renaming method to avoid priority reset
virtual bool setName(const QString& name);
- virtual int getNexusID() const override { return -1; }
+ virtual int nexusId() const override { return -1; }
virtual void setGameName(const QString& gameName) override {}
virtual void setNexusID(int /*modID*/) override {}
virtual void endorse(bool /*doEndorse*/) override {}
@@ -33,8 +33,8 @@ public:
virtual int getHighlight() const override;
virtual QString getDescription() const override;
virtual QString name() const override;
- virtual QString getGameName() const override { return ""; }
- virtual QString getInstallationFile() const override { return ""; }
+ virtual QString gameName() const override { return ""; }
+ virtual QString installationFile() const override { return ""; }
virtual QString repository() const override { return ""; }
virtual int getNexusFileStatus() const override { return 0; }
virtual void setNexusFileStatus(int) override {}
diff --git a/src/modinfowithconflictinfo.cpp b/src/modinfowithconflictinfo.cpp
index 5c76a0cf..70f9b3f1 100644
--- a/src/modinfowithconflictinfo.cpp
+++ b/src/modinfowithconflictinfo.cpp
@@ -5,6 +5,7 @@
#include "shared/fileentry.h"
#include <filesystem>
+#include "iplugingame.h"
#include "moddatachecker.h"
#include "qdirfiletree.h"
diff --git a/src/modlist.cpp b/src/modlist.cpp
index cbd9f30c..2499bac0 100644
--- a/src/modlist.cpp
+++ b/src/modlist.cpp
@@ -224,7 +224,7 @@ QVariant ModList::data(const QModelIndex &modelIndex, int role) const
else
return modInfo->name();
} else if (column == COL_VERSION) {
- VersionInfo verInfo = modInfo->getVersion();
+ VersionInfo verInfo = modInfo->version();
QString version = verInfo.displayString();
if (role != Qt::EditRole) {
if (version.isEmpty() && modInfo->canBeUpdated()) {
@@ -240,7 +240,7 @@ QVariant ModList::data(const QModelIndex &modelIndex, int role) const
return m_Profile->getModPriority(modIndex);
}
} else if (column == COL_MODID) {
- int modID = modInfo->getNexusID();
+ int modID = modInfo->nexusId();
if (modID > 0) {
return modID;
}
@@ -250,16 +250,16 @@ QVariant ModList::data(const QModelIndex &modelIndex, int role) const
} else if (column == COL_GAME) {
if (m_PluginContainer != nullptr) {
for (auto game : m_PluginContainer->plugins<IPluginGame>()) {
- if (game->gameShortName().compare(modInfo->getGameName(), Qt::CaseInsensitive) == 0)
+ if (game->gameShortName().compare(modInfo->gameName(), Qt::CaseInsensitive) == 0)
return game->gameName();
}
}
- return modInfo->getGameName();
+ return modInfo->gameName();
} else if (column == COL_CATEGORY) {
if (modInfo->hasFlag(ModInfo::FLAG_FOREIGN)) {
return tr("Non-MO");
} else {
- int category = modInfo->getPrimaryCategory();
+ int category = modInfo->primaryCategory();
if (category != -1) {
CategoryFactory &categoryFactory = CategoryFactory::instance();
if (categoryFactory.categoryExists(category)) {
@@ -333,7 +333,7 @@ QVariant ModList::data(const QModelIndex &modelIndex, int role) const
return m_Profile->getModPriority(modIndex);
}
} else {
- return modInfo->getNexusID();
+ return modInfo->nexusId();
}
} else if (role == Qt::UserRole + 1) {
return modIndex;
@@ -348,7 +348,7 @@ QVariant ModList::data(const QModelIndex &modelIndex, int role) const
} else if (role == Qt::UserRole + 3) {
return contentsToIcons(modInfo->getContents());
} else if (role == Qt::UserRole + 4) {
- return modInfo->getGameName();
+ return modInfo->gameName();
} else if (role == Qt::FontRole) {
QFont result;
auto flags = modInfo->getFlags();
@@ -379,14 +379,14 @@ QVariant ModList::data(const QModelIndex &modelIndex, int role) const
return QIcon(":/MO/gui/update_available");
} else if (modInfo->downgradeAvailable()) {
return QIcon(":/MO/gui/warning");
- } else if (modInfo->getVersion().scheme() == VersionInfo::SCHEME_DATE) {
+ } else if (modInfo->version().scheme() == VersionInfo::SCHEME_DATE) {
return QIcon(":/MO/gui/version_date");
}
}
return QVariant();
} else if (role == Qt::ForegroundRole) {
- if ((modInfo->hasFlag(ModInfo::FLAG_SEPARATOR) || (column == COL_NOTES)) && modInfo->getColor().isValid()) {
- return ColorSettings::idealTextColor(modInfo->getColor());
+ if ((modInfo->hasFlag(ModInfo::FLAG_SEPARATOR) || (column == COL_NOTES)) && modInfo->color().isValid()) {
+ return ColorSettings::idealTextColor(modInfo->color());
} else if (column == COL_NAME) {
int highlight = modInfo->getHighlight();
if (highlight & ModInfo::HIGHLIGHT_IMPORTANT)
@@ -394,7 +394,7 @@ QVariant ModList::data(const QModelIndex &modelIndex, int role) const
else if (highlight & ModInfo::HIGHLIGHT_INVALID)
return QBrush(Qt::darkGray);
} else if (column == COL_VERSION) {
- if (!modInfo->getNewestVersion().isValid()) {
+ if (!modInfo->newestVersion().isValid()) {
return QVariant();
} else if (modInfo->updateAvailable() || modInfo->downgradeAvailable()) {
return QBrush(Qt::red);
@@ -411,8 +411,8 @@ QVariant ModList::data(const QModelIndex &modelIndex, int role) const
bool overwritten = m_Overwritten.find(modIndex) != m_Overwritten.end();
bool archiveOverwritten = m_ArchiveOverwritten.find(modIndex) != m_ArchiveOverwritten.end();
bool archiveLooseOverwritten = m_ArchiveLooseOverwritten.find(modIndex) != m_ArchiveLooseOverwritten.end();
- if (column == COL_NOTES && modInfo->getColor().isValid()) {
- return modInfo->getColor();
+ if (column == COL_NOTES && modInfo->color().isValid()) {
+ return modInfo->color();
} else if (modInfo->getHighlight() & ModInfo::HIGHLIGHT_PLUGIN) {
return Settings::instance().colors().modlistContainsPlugin();
} else if (overwritten || archiveLooseOverwritten) {
@@ -424,10 +424,10 @@ QVariant ModList::data(const QModelIndex &modelIndex, int role) const
} else if (archiveOverwrite) {
return Settings::instance().colors().modlistOverwrittenArchive();
} else if (modInfo->hasFlag(ModInfo::FLAG_SEPARATOR)
- && modInfo->getColor().isValid()
+ && modInfo->color().isValid()
&& ((role != ViewMarkingScrollBar::DEFAULT_ROLE)
|| Settings::instance().colors().colorSeparatorScrollbar())) {
- return modInfo->getColor();
+ return modInfo->color();
} else {
return QVariant();
}
@@ -460,7 +460,7 @@ QVariant ModList::data(const QModelIndex &modelIndex, int role) const
return QString();
}
} else if (column == COL_VERSION) {
- QString text = tr("installed version: \"%1\", newest version: \"%2\"").arg(modInfo->getVersion().displayString(3)).arg(modInfo->getNewestVersion().displayString(3));
+ QString text = tr("installed version: \"%1\", newest version: \"%2\"").arg(modInfo->version().displayString(3)).arg(modInfo->newestVersion().displayString(3));
if (modInfo->downgradeAvailable()) {
text += "<br>" + tr("The newest version on Nexus seems to be older than the one you have installed. This could either mean the version you have has been withdrawn "
"(i.e. due to a bug) or the author uses a non-standard versioning scheme and that newest version is actually newer. "
@@ -471,7 +471,7 @@ QVariant ModList::data(const QModelIndex &modelIndex, int role) const
} else if (modInfo->getNexusFileStatus() == 6) {
text += "<br>" + tr("This file has been marked as \"Deleted\"! You may want to check for an update or remove the nexus ID from this mod!");
}
- if (modInfo->getNexusID() > 0) {
+ if (modInfo->nexusId() > 0) {
if (!modInfo->canBeUpdated()) {
qint64 remains = QDateTime::currentDateTimeUtc().secsTo(modInfo->getExpires());
qint64 minutes = remains / 60;
@@ -611,7 +611,7 @@ bool ModList::setData(const QModelIndex &index, const QVariant &value, int role)
}
} break;
case COL_VERSION: {
- VersionInfo::VersionScheme scheme = info->getVersion().scheme();
+ VersionInfo::VersionScheme scheme = info->version().scheme();
VersionInfo version(value.toString(), scheme, true);
if (version.isValid()) {
info->setVersion(version);
@@ -885,7 +885,7 @@ IModList::ModStates ModList::state(unsigned int modIndex) const
if (modInfo->isEmpty()) {
result |= IModList::STATE_EMPTY;
}
- if (modInfo->endorsedState() == ModInfo::ENDORSED_TRUE) {
+ if (modInfo->endorsedState() == EndorsedState::ENDORSED_TRUE) {
result |= IModList::STATE_ENDORSED;
}
if (modInfo->isValid()) {
@@ -1181,7 +1181,7 @@ void ModList::removeRowForce(int row, const QModelIndex &parent)
}
auto flags = modInfo->getFlags();
if (std::find(flags.begin(), flags.end(), ModInfo::FLAG_BACKUP) == flags.end()) {
- emit modUninstalled(modInfo->getInstallationFile());
+ emit modUninstalled(modInfo->installationFile());
}
}
diff --git a/src/modlistsortproxy.cpp b/src/modlistsortproxy.cpp
index ab6dd852..ca0f3bb1 100644
--- a/src/modlistsortproxy.cpp
+++ b/src/modlistsortproxy.cpp
@@ -198,14 +198,14 @@ bool ModListSortProxy::lessThan(const QModelIndex &left,
lt = comp < 0;
} break;
case ModList::COL_CATEGORY: {
- if (leftMod->getPrimaryCategory() != rightMod->getPrimaryCategory()) {
- if (leftMod->getPrimaryCategory() < 0) lt = false;
- else if (rightMod->getPrimaryCategory() < 0) lt = true;
+ if (leftMod->primaryCategory() != rightMod->primaryCategory()) {
+ if (leftMod->primaryCategory() < 0) lt = false;
+ else if (rightMod->primaryCategory() < 0) lt = true;
else {
try {
CategoryFactory &categories = CategoryFactory::instance();
- QString leftCatName = categories.getCategoryName(categories.getCategoryIndex(leftMod->getPrimaryCategory()));
- QString rightCatName = categories.getCategoryName(categories.getCategoryIndex(rightMod->getPrimaryCategory()));
+ QString leftCatName = categories.getCategoryName(categories.getCategoryIndex(leftMod->primaryCategory()));
+ QString rightCatName = categories.getCategoryName(categories.getCategoryIndex(rightMod->primaryCategory()));
lt = leftCatName < rightCatName;
} catch (const std::exception &e) {
log::error("failed to compare categories: {}", e.what());
@@ -214,12 +214,12 @@ bool ModListSortProxy::lessThan(const QModelIndex &left,
}
} break;
case ModList::COL_MODID: {
- if (leftMod->getNexusID() != rightMod->getNexusID())
- lt = leftMod->getNexusID() < rightMod->getNexusID();
+ if (leftMod->nexusId() != rightMod->nexusId())
+ lt = leftMod->nexusId() < rightMod->nexusId();
} break;
case ModList::COL_VERSION: {
- if (leftMod->getVersion() != rightMod->getVersion())
- lt = leftMod->getVersion() < rightMod->getVersion();
+ if (leftMod->version() != rightMod->version())
+ lt = leftMod->version() < rightMod->version();
} break;
case ModList::COL_INSTALLTIME: {
QDateTime leftTime = left.data().toDateTime();
@@ -228,8 +228,8 @@ bool ModListSortProxy::lessThan(const QModelIndex &left,
return leftTime < rightTime;
} break;
case ModList::COL_GAME: {
- if (leftMod->getGameName() != rightMod->getGameName()) {
- lt = leftMod->getGameName() < rightMod->getGameName();
+ if (leftMod->gameName() != rightMod->gameName()) {
+ lt = leftMod->gameName() < rightMod->gameName();
}
else {
int comp = QString::compare(leftMod->name(), rightMod->name(), Qt::CaseInsensitive);
@@ -392,7 +392,7 @@ bool ModListSortProxy::categoryMatchesMod(
case CategoryFactory::Endorsed:
{
- b = (info->endorsedState() == ModInfo::ENDORSED_TRUE);
+ b = (info->endorsedState() == EndorsedState::ENDORSED_TRUE);
break;
}
@@ -425,13 +425,13 @@ bool ModListSortProxy::categoryMatchesMod(
return false;
}
- b = (info->getNexusID() > 0);
+ b = (info->nexusId() > 0);
break;
}
case CategoryFactory::Tracked:
{
- b = (info->trackedState() == ModInfo::TRACKED_TRUE);
+ b = (info->trackedState() == TrackedState::TRACKED_TRUE);
break;
}
@@ -531,7 +531,7 @@ bool ModListSortProxy::filterMatchesMod(ModInfo::Ptr info, bool enabled) const
bool ok;
int filterID = currentKeyword.toInt(&ok);
if (ok) {
- int modID = info->getNexusID();
+ int modID = info->nexusId();
while (modID > 0) {
if (modID == filterID) {
foundKeyword = true;
diff --git a/src/organizercore.cpp b/src/organizercore.cpp
index 815c80c2..d33b4e39 100644
--- a/src/organizercore.cpp
+++ b/src/organizercore.cpp
@@ -713,6 +713,8 @@ QString OrganizerCore::pluginDataPath() const
}
MOBase::IModInterface *OrganizerCore::installMod(const QString &fileName,
+ bool reinstallation,
+ ModInfo::Ptr currentMod,
const QString &initModName)
{
if (m_CurrentProfile == nullptr) {
@@ -733,7 +735,9 @@ MOBase::IModInterface *OrganizerCore::installMod(const QString &fileName,
}
m_CurrentProfile->writeModlistNow();
m_InstallationManager.setModsDirectory(m_Settings.paths().mods());
- if (m_InstallationManager.install(fileName, modName, hasIniTweaks) == IPluginInstaller::RESULT_SUCCESS) {
+ m_InstallationManager.notifyInstallationStart(fileName, reinstallation, currentMod);
+ auto result = m_InstallationManager.install(fileName, modName, hasIniTweaks);
+ if (result == IPluginInstaller::RESULT_SUCCESS) {
MessageDialog::showMessage(tr("Installation successful"),
qApp->activeWindow());
refreshModList();
@@ -758,18 +762,22 @@ MOBase::IModInterface *OrganizerCore::installMod(const QString &fileName,
}
m_ModInstalled(modName);
m_DownloadManager.markInstalled(fileName);
+ m_InstallationManager.notifyInstallationEnd(result, modInfo);
emit modInstalled(modName);
return modInfo.data();
} else {
reportError(tr("mod not found: %1").arg(qUtf8Printable(modName)));
}
- } else if (m_InstallationManager.wasCancelled()) {
- QMessageBox::information(qApp->activeWindow(), tr("Extraction cancelled"),
- tr("The installation was cancelled while extracting files. "
- "If this was prior to a FOMOD setup, this warning may be ignored. "
- "However, if this was during installation, the mod will likely be missing files."),
- QMessageBox::Ok);
- refreshModList();
+ } else {
+ m_InstallationManager.notifyInstallationEnd(result, nullptr);
+ if (m_InstallationManager.wasCancelled()) {
+ QMessageBox::information(qApp->activeWindow(), tr("Extraction cancelled"),
+ tr("The installation was cancelled while extracting files. "
+ "If this was prior to a FOMOD setup, this warning may be ignored. "
+ "However, if this was during installation, the mod will likely be missing files."),
+ QMessageBox::Ok);
+ refreshModList();
+ }
}
return nullptr;
}
@@ -788,6 +796,7 @@ void OrganizerCore::installDownload(int index)
QString gameName = m_DownloadManager.getGameName(index);
int modID = m_DownloadManager.getModID(index);
int fileID = m_DownloadManager.getFileInfo(index)->fileID;
+ ModInfo::Ptr currentMod = nullptr;
GuessedValue<QString> modName;
// see if there already are mods with the specified mod id
@@ -798,6 +807,7 @@ void OrganizerCore::installDownload(int index)
if (std::find(flags.begin(), flags.end(), ModInfo::FLAG_BACKUP)
== flags.end()) {
modName.update((*iter)->name(), GUESS_PRESET);
+ currentMod = *iter;
(*iter)->saveMeta();
}
}
@@ -807,7 +817,9 @@ void OrganizerCore::installDownload(int index)
bool hasIniTweaks = false;
m_InstallationManager.setModsDirectory(m_Settings.paths().mods());
- if (m_InstallationManager.install(fileName, modName, hasIniTweaks) == IPluginInstaller::RESULT_SUCCESS) {
+ m_InstallationManager.notifyInstallationStart(fileName, false, currentMod);
+ auto result = m_InstallationManager.install(fileName, modName, hasIniTweaks);
+ if (result == IPluginInstaller::RESULT_SUCCESS) {
MessageDialog::showMessage(tr("Installation successful"),
qApp->activeWindow());
refreshModList();
@@ -828,19 +840,23 @@ void OrganizerCore::installDownload(int index)
}
m_ModInstalled(modName);
+ m_InstallationManager.notifyInstallationEnd(IPluginInstaller::RESULT_SUCCESS, modInfo);
} else {
reportError(tr("mod not found: %1").arg(qUtf8Printable(modName)));
}
m_DownloadManager.markInstalled(index);
-
emit modInstalled(modName);
- } else if (m_InstallationManager.wasCancelled()) {
- QMessageBox::information(qApp->activeWindow(), tr("Extraction cancelled"),
- tr("The installation was cancelled while extracting files. "
- "If this was prior to a FOMOD setup, this warning may be ignored. "
- "However, if this was during installation, the mod will likely be missing files."),
- QMessageBox::Ok);
- refreshModList();
+ }
+ else {
+ m_InstallationManager.notifyInstallationEnd(result, nullptr);
+ if (m_InstallationManager.wasCancelled()) {
+ QMessageBox::information(qApp->activeWindow(), tr("Extraction cancelled"),
+ tr("The installation was cancelled while extracting files. "
+ "If this was prior to a FOMOD setup, this warning may be ignored. "
+ "However, if this was during installation, the mod will likely be missing files."),
+ QMessageBox::Ok);
+ refreshModList();
+ }
}
} catch (const std::exception &e) {
reportError(e.what());
diff --git a/src/organizercore.h b/src/organizercore.h
index 2588d332..813bf084 100644
--- a/src/organizercore.h
+++ b/src/organizercore.h
@@ -309,7 +309,7 @@ public:
QVariant persistent(const QString &pluginName, const QString &key, const QVariant &def) const;
void setPersistent(const QString &pluginName, const QString &key, const QVariant &value, bool sync);
QString pluginDataPath() const;
- virtual MOBase::IModInterface *installMod(const QString &fileName, const QString &initModName);
+ virtual MOBase::IModInterface *installMod(const QString &fileName, bool reinstallation, ModInfo::Ptr currentMod, const QString &initModName);
QString resolvePath(const QString &fileName) const;
QStringList listDirectories(const QString &directoryName) const;
QStringList findFiles(const QString &path, const std::function<bool (const QString &)> &filter) const;
diff --git a/src/organizerproxy.cpp b/src/organizerproxy.cpp
index 9ccc3c17..a5047b43 100644
--- a/src/organizerproxy.cpp
+++ b/src/organizerproxy.cpp
@@ -208,7 +208,7 @@ void OrganizerProxy::refreshModList(bool saveChanges)
IModInterface *OrganizerProxy::installMod(const QString &fileName, const QString &nameSuggestion)
{
- return m_Proxied->installMod(fileName, nameSuggestion);
+ return m_Proxied->installMod(fileName, false, nullptr, nameSuggestion);
}
QString OrganizerProxy::resolvePath(const QString &fileName) const
diff --git a/src/profilesdialog.cpp b/src/profilesdialog.cpp
index 6f06a6be..bf6a1d5e 100644
--- a/src/profilesdialog.cpp
+++ b/src/profilesdialog.cpp
@@ -29,6 +29,7 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#include "transfersavesdialog.h"
#include "utility.h"
#include "settings.h"
+#include "localsavegames.h"
#include <QDir>
#include <QDirIterator>
@@ -77,6 +78,11 @@ ProfilesDialog::ProfilesDialog(const QString &profileName, MOBase::IPluginGame c
ui->invalidationBox->setToolTip(tr("Archive invalidation isn't required for this game."));
ui->invalidationBox->setEnabled(false);
}
+
+ if (!game->feature<LocalSavegames>()) {
+ ui->localSavesBox->setToolTip(tr("This game does not support profile-specific game saves."));
+ ui->localSavesBox->setEnabled(false);
+ }
}
ProfilesDialog::~ProfilesDialog()