mirror of
https://github.com/vcmi/vcmi.git
synced 2025-08-08 22:26:51 +02:00
Reworked mod handling in Launcher in order to unify code with lib
This commit is contained in:
@@ -7,13 +7,13 @@ set(launcher_SRCS
|
||||
StdInc.cpp
|
||||
aboutProject/aboutproject_moc.cpp
|
||||
modManager/cdownloadmanager_moc.cpp
|
||||
modManager/cmodlist.cpp
|
||||
modManager/cmodlistmodel_moc.cpp
|
||||
modManager/modstateitemmodel_moc.cpp
|
||||
modManager/cmodlistview_moc.cpp
|
||||
modManager/cmodmanager.cpp
|
||||
modManager/modstatecontroller.cpp
|
||||
modManager/modstatemodel.cpp
|
||||
modManager/modstate.cpp
|
||||
modManager/imageviewer_moc.cpp
|
||||
modManager/chroniclesextractor.cpp
|
||||
modManager/modsettingsstorage.cpp
|
||||
settingsView/csettingsview_moc.cpp
|
||||
firstLaunch/firstlaunch_moc.cpp
|
||||
main.cpp
|
||||
@@ -38,13 +38,13 @@ set(launcher_HEADERS
|
||||
StdInc.h
|
||||
aboutProject/aboutproject_moc.h
|
||||
modManager/cdownloadmanager_moc.h
|
||||
modManager/cmodlist.h
|
||||
modManager/cmodlistmodel_moc.h
|
||||
modManager/modstateitemmodel_moc.h
|
||||
modManager/cmodlistview_moc.h
|
||||
modManager/cmodmanager.h
|
||||
modManager/modstatecontroller.h
|
||||
modManager/modstatemodel.h
|
||||
modManager/modstate.h
|
||||
modManager/imageviewer_moc.h
|
||||
modManager/chroniclesextractor.h
|
||||
modManager/modsettingsstorage.h
|
||||
settingsView/csettingsview_moc.h
|
||||
firstLaunch/firstlaunch_moc.h
|
||||
mainwindow_moc.h
|
||||
|
@@ -206,10 +206,10 @@ void MainWindow::on_startEditorButton_clicked()
|
||||
startEditor({});
|
||||
}
|
||||
|
||||
const CModList & MainWindow::getModList() const
|
||||
{
|
||||
return ui->modlistView->getModList();
|
||||
}
|
||||
//const CModList & MainWindow::getModList() const
|
||||
//{
|
||||
// return ui->modlistView->getModList();
|
||||
//}
|
||||
|
||||
CModListView * MainWindow::getModView()
|
||||
{
|
||||
|
@@ -46,7 +46,7 @@ public:
|
||||
explicit MainWindow(QWidget * parent = nullptr);
|
||||
~MainWindow() override;
|
||||
|
||||
const CModList & getModList() const;
|
||||
// const CModList & getModList() const;
|
||||
CModListView * getModView();
|
||||
|
||||
void updateTranslation();
|
||||
|
@@ -1,417 +0,0 @@
|
||||
/*
|
||||
* cmodlist.cpp, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
* License: GNU General Public License v2.0 or later
|
||||
* Full text of license available in license.txt file, in main folder
|
||||
*
|
||||
*/
|
||||
#include "StdInc.h"
|
||||
#include "cmodlist.h"
|
||||
|
||||
#include "../lib/CConfigHandler.h"
|
||||
#include "../../lib/filesystem/CFileInputStream.h"
|
||||
#include "../../lib/GameConstants.h"
|
||||
#include "../../lib/modding/CModVersion.h"
|
||||
|
||||
QString CModEntry::sizeToString(double size)
|
||||
{
|
||||
static const std::array sizes {
|
||||
QT_TRANSLATE_NOOP("File size", "%1 B"),
|
||||
QT_TRANSLATE_NOOP("File size", "%1 KiB"),
|
||||
QT_TRANSLATE_NOOP("File size", "%1 MiB"),
|
||||
QT_TRANSLATE_NOOP("File size", "%1 GiB"),
|
||||
QT_TRANSLATE_NOOP("File size", "%1 TiB")
|
||||
};
|
||||
size_t index = 0;
|
||||
while(size > 1024 && index < sizes.size())
|
||||
{
|
||||
size /= 1024;
|
||||
index++;
|
||||
}
|
||||
return QCoreApplication::translate("File size", sizes[index]).arg(QString::number(size, 'f', 1));
|
||||
}
|
||||
|
||||
CModEntry::CModEntry(QVariantMap repository, QVariantMap localData, bool modActive, QString modname)
|
||||
: repository(repository), localData(localData), modActive(modActive), modname(modname)
|
||||
{
|
||||
}
|
||||
|
||||
bool CModEntry::isEnabled() const
|
||||
{
|
||||
if(!isInstalled())
|
||||
return false;
|
||||
|
||||
if (!isVisible())
|
||||
return false;
|
||||
|
||||
return modActive;
|
||||
}
|
||||
|
||||
bool CModEntry::isDisabled() const
|
||||
{
|
||||
if(!isInstalled())
|
||||
return false;
|
||||
return !isEnabled();
|
||||
}
|
||||
|
||||
bool CModEntry::isAvailable() const
|
||||
{
|
||||
if(isInstalled())
|
||||
return false;
|
||||
return !repository.isEmpty();
|
||||
}
|
||||
|
||||
bool CModEntry::isUpdateable() const
|
||||
{
|
||||
if(!isInstalled())
|
||||
return false;
|
||||
|
||||
auto installedVer = localData["installedVersion"].toString().toStdString();
|
||||
auto availableVer = repository["latestVersion"].toString().toStdString();
|
||||
|
||||
return (CModVersion::fromString(installedVer) < CModVersion::fromString(availableVer));
|
||||
}
|
||||
|
||||
bool isCompatible(const QVariantMap & compatibility)
|
||||
{
|
||||
auto compatibleMin = CModVersion::fromString(compatibility["min"].toString().toStdString());
|
||||
auto compatibleMax = CModVersion::fromString(compatibility["max"].toString().toStdString());
|
||||
|
||||
return (compatibleMin.isNull() || CModVersion::GameVersion().compatible(compatibleMin, true, true))
|
||||
&& (compatibleMax.isNull() || compatibleMax.compatible(CModVersion::GameVersion(), true, true));
|
||||
}
|
||||
|
||||
bool CModEntry::isCompatible() const
|
||||
{
|
||||
return ::isCompatible(localData["compatibility"].toMap());
|
||||
}
|
||||
|
||||
bool CModEntry::isEssential() const
|
||||
{
|
||||
return getName() == "vcmi";
|
||||
}
|
||||
|
||||
bool CModEntry::isInstalled() const
|
||||
{
|
||||
return !localData.isEmpty();
|
||||
}
|
||||
|
||||
bool CModEntry::isVisible() const
|
||||
{
|
||||
if (isCompatibilityPatch())
|
||||
{
|
||||
if (isSubmod())
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isTranslation())
|
||||
{
|
||||
// Do not show not installed translation mods to languages other than player language
|
||||
if (localData.empty() && getBaseValue("language") != QString::fromStdString(settings["general"]["language"].String()) )
|
||||
return false;
|
||||
}
|
||||
|
||||
return !localData.isEmpty() || (!repository.isEmpty() && !repository.contains("mod"));
|
||||
}
|
||||
|
||||
bool CModEntry::isTranslation() const
|
||||
{
|
||||
return getBaseValue("modType").toString() == "Translation";
|
||||
}
|
||||
|
||||
bool CModEntry::isCompatibilityPatch() const
|
||||
{
|
||||
return getBaseValue("modType").toString() == "Compatibility";
|
||||
}
|
||||
|
||||
bool CModEntry::isSubmod() const
|
||||
{
|
||||
return getName().contains('.');
|
||||
}
|
||||
|
||||
int CModEntry::getModStatus() const
|
||||
{
|
||||
int status = 0;
|
||||
if(isEnabled())
|
||||
status |= ModStatus::ENABLED;
|
||||
if(isInstalled())
|
||||
status |= ModStatus::INSTALLED;
|
||||
if(isUpdateable())
|
||||
status |= ModStatus::UPDATEABLE;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
QString CModEntry::getName() const
|
||||
{
|
||||
return modname;
|
||||
}
|
||||
|
||||
QString CModEntry::getTopParentName() const
|
||||
{
|
||||
assert(isSubmod());
|
||||
return modname.section('.', 0, 0);
|
||||
}
|
||||
|
||||
QVariant CModEntry::getValue(QString value) const
|
||||
{
|
||||
return getValueImpl(value, true);
|
||||
}
|
||||
|
||||
QStringList CModEntry::getDependencies() const
|
||||
{
|
||||
QStringList result;
|
||||
for (auto const & entry : getValue("depends").toStringList())
|
||||
result.push_back(entry.toLower());
|
||||
return result;
|
||||
}
|
||||
|
||||
QStringList CModEntry::getConflicts() const
|
||||
{
|
||||
QStringList result;
|
||||
for (auto const & entry : getValue("conflicts").toStringList())
|
||||
result.push_back(entry.toLower());
|
||||
return result;
|
||||
}
|
||||
|
||||
QVariant CModEntry::getBaseValue(QString value) const
|
||||
{
|
||||
return getValueImpl(value, false);
|
||||
}
|
||||
|
||||
QVariant CModEntry::getValueImpl(QString value, bool localized) const
|
||||
|
||||
{
|
||||
QString langValue = QString::fromStdString(settings["general"]["language"].String());
|
||||
|
||||
// Priorities
|
||||
// 1) data from newest version
|
||||
// 2) data from preferred language
|
||||
|
||||
bool useRepositoryData = repository.contains(value);
|
||||
|
||||
if(repository.contains(value) && localData.contains(value))
|
||||
{
|
||||
// value is present in both repo and locally installed. Select one from latest version
|
||||
auto installedVer = localData["installedVersion"].toString().toStdString();
|
||||
auto availableVer = repository["latestVersion"].toString().toStdString();
|
||||
|
||||
useRepositoryData = CModVersion::fromString(installedVer) < CModVersion::fromString(availableVer);
|
||||
}
|
||||
|
||||
auto & storage = useRepositoryData ? repository : localData;
|
||||
|
||||
if(localized && storage.contains(langValue))
|
||||
{
|
||||
auto langStorage = storage[langValue].toMap();
|
||||
if (langStorage.contains(value))
|
||||
return langStorage[value];
|
||||
}
|
||||
|
||||
if(storage.contains(value))
|
||||
return storage[value];
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
QVariantMap CModList::copyField(QVariantMap data, QString from, QString to) const
|
||||
{
|
||||
QVariantMap renamed;
|
||||
|
||||
for(auto it = data.begin(); it != data.end(); it++)
|
||||
{
|
||||
QVariantMap modConf = it.value().toMap();
|
||||
|
||||
modConf.insert(to, modConf.value(from));
|
||||
renamed.insert(it.key(), modConf);
|
||||
}
|
||||
return renamed;
|
||||
}
|
||||
|
||||
void CModList::reloadRepositories()
|
||||
{
|
||||
cachedMods.clear();
|
||||
}
|
||||
|
||||
void CModList::resetRepositories()
|
||||
{
|
||||
repositories.clear();
|
||||
cachedMods.clear();
|
||||
}
|
||||
|
||||
void CModList::addRepository(QVariantMap data)
|
||||
{
|
||||
for(auto & key : data.keys())
|
||||
data[key.toLower()] = data.take(key);
|
||||
repositories.push_back(copyField(data, "version", "latestVersion"));
|
||||
|
||||
cachedMods.clear();
|
||||
}
|
||||
|
||||
void CModList::setLocalModList(QVariantMap data)
|
||||
{
|
||||
localModList = copyField(data, "version", "installedVersion");
|
||||
cachedMods.clear();
|
||||
}
|
||||
|
||||
void CModList::setModSettings(std::shared_ptr<ModSettingsStorage> data)
|
||||
{
|
||||
modSettings = data;
|
||||
cachedMods.clear();
|
||||
}
|
||||
|
||||
void CModList::modChanged(QString modID)
|
||||
{
|
||||
cachedMods.clear();
|
||||
}
|
||||
|
||||
static QVariant getValue(QVariant input, QString path)
|
||||
{
|
||||
if(path.size() > 1)
|
||||
{
|
||||
QString entryName = path.section('/', 0, 1);
|
||||
QString remainder = "/" + path.section('/', 2, -1);
|
||||
|
||||
entryName.remove(0, 1);
|
||||
return getValue(input.toMap().value(entryName), remainder);
|
||||
}
|
||||
else
|
||||
{
|
||||
return input;
|
||||
}
|
||||
}
|
||||
|
||||
const CModEntry & CModList::getMod(QString modName) const
|
||||
{
|
||||
modName = modName.toLower();
|
||||
|
||||
auto it = cachedMods.find(modName);
|
||||
|
||||
if (it != cachedMods.end())
|
||||
return it.value();
|
||||
|
||||
auto itNew = cachedMods.insert(modName, getModUncached(modName));
|
||||
return *itNew;
|
||||
}
|
||||
|
||||
CModEntry CModList::getModUncached(QString modname) const
|
||||
{
|
||||
QVariantMap repo;
|
||||
QVariantMap local = localModList[modname].toMap();
|
||||
|
||||
QString path = modname;
|
||||
path = "/" + path.replace(".", "/mods/");
|
||||
|
||||
bool modActive = modSettings->isModActive(modname);
|
||||
|
||||
if(modActive)
|
||||
{
|
||||
QString rootModName = modname.section('.', 0, 1);
|
||||
if (!modSettings->isModActive(rootModName))
|
||||
modActive = false; // parent mod is inactive -> submod is also inactive
|
||||
}
|
||||
|
||||
if(modActive)
|
||||
{
|
||||
if(!::isCompatible(local.value("compatibility").toMap()))
|
||||
modActive = false; // mod not compatible with our version of vcmi -> inactive
|
||||
}
|
||||
|
||||
for(auto entry : repositories)
|
||||
{
|
||||
QVariant repoVal = getValue(entry, path);
|
||||
if(repoVal.isValid())
|
||||
{
|
||||
auto repoValMap = repoVal.toMap();
|
||||
if(::isCompatible(repoValMap["compatibility"].toMap()))
|
||||
{
|
||||
if(repo.empty()
|
||||
|| CModVersion::fromString(repo["version"].toString().toStdString())
|
||||
< CModVersion::fromString(repoValMap["version"].toString().toStdString()))
|
||||
{
|
||||
//take valid download link, screenshots and mod size before assignment
|
||||
auto download = repo.value("download");
|
||||
auto screenshots = repo.value("screenshots");
|
||||
auto size = repo.value("downloadSize");
|
||||
repo = repoValMap;
|
||||
if(repo.value("download").isNull())
|
||||
{
|
||||
repo["download"] = download;
|
||||
if(repo.value("screenshots").isNull()) //taking screenshot from the downloadable version
|
||||
repo["screenshots"] = screenshots;
|
||||
}
|
||||
if(repo.value("downloadSize").isNull())
|
||||
repo["downloadSize"] = size;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return CModEntry(repo, local, modActive, modname);
|
||||
}
|
||||
|
||||
bool CModList::hasMod(QString modname) const
|
||||
{
|
||||
if(localModList.contains(modname))
|
||||
return true;
|
||||
|
||||
for(auto entry : repositories)
|
||||
if(entry.contains(modname))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
QStringList CModList::getRequirements(QString modname)
|
||||
{
|
||||
QStringList ret;
|
||||
|
||||
if(hasMod(modname))
|
||||
{
|
||||
auto mod = getMod(modname);
|
||||
|
||||
for(auto entry : mod.getDependencies())
|
||||
ret += getRequirements(entry.toLower());
|
||||
}
|
||||
ret += modname;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
QVector<QString> CModList::getModList() const
|
||||
{
|
||||
QSet<QString> knownMods;
|
||||
QVector<QString> modList;
|
||||
for(auto repo : repositories)
|
||||
{
|
||||
for(auto it = repo.begin(); it != repo.end(); it++)
|
||||
{
|
||||
knownMods.insert(it.key().toLower());
|
||||
}
|
||||
}
|
||||
for(auto it = localModList.begin(); it != localModList.end(); it++)
|
||||
{
|
||||
knownMods.insert(it.key().toLower());
|
||||
}
|
||||
|
||||
for(auto entry : knownMods)
|
||||
{
|
||||
modList.push_back(entry);
|
||||
}
|
||||
return modList;
|
||||
}
|
||||
|
||||
QVector<QString> CModList::getChildren(QString parent) const
|
||||
{
|
||||
QVector<QString> children;
|
||||
|
||||
int depth = parent.count('.') + 1;
|
||||
for(const QString & mod : getModList())
|
||||
{
|
||||
if(mod.count('.') == depth && mod.startsWith(parent))
|
||||
children.push_back(mod);
|
||||
}
|
||||
return children;
|
||||
}
|
@@ -1,118 +0,0 @@
|
||||
/*
|
||||
* cmodlist.h, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
* License: GNU General Public License v2.0 or later
|
||||
* Full text of license available in license.txt file, in main folder
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <QVariantMap>
|
||||
#include <QVariant>
|
||||
#include <QVector>
|
||||
|
||||
#include "modsettingsstorage.h"
|
||||
|
||||
namespace ModStatus
|
||||
{
|
||||
enum EModStatus
|
||||
{
|
||||
MASK_NONE = 0,
|
||||
ENABLED = 1,
|
||||
INSTALLED = 2,
|
||||
UPDATEABLE = 4,
|
||||
MASK_ALL = 255
|
||||
};
|
||||
}
|
||||
|
||||
class CModEntry
|
||||
{
|
||||
// repository contains newest version only (if multiple are available)
|
||||
QVariantMap repository;
|
||||
QVariantMap localData;
|
||||
bool modActive;
|
||||
|
||||
QString modname;
|
||||
|
||||
QVariant getValueImpl(QString value, bool localized) const;
|
||||
public:
|
||||
CModEntry(QVariantMap repository, QVariantMap localData, bool modActive, QString modname);
|
||||
|
||||
// installed and enabled
|
||||
bool isEnabled() const;
|
||||
// installed but disabled
|
||||
bool isDisabled() const;
|
||||
// available in any of repositories but not installed
|
||||
bool isAvailable() const;
|
||||
// installed and greater version exists in repository
|
||||
bool isUpdateable() const;
|
||||
// installed
|
||||
bool isInstalled() const;
|
||||
// vcmi essential files
|
||||
bool isEssential() const;
|
||||
// checks if version is compatible with vcmi
|
||||
bool isCompatible() const;
|
||||
// returns true if mod should be visible in Launcher
|
||||
bool isVisible() const;
|
||||
// returns true if mod type is Translation
|
||||
bool isTranslation() const;
|
||||
// returns true if mod type is Compatibility
|
||||
bool isCompatibilityPatch() const;
|
||||
// returns true if this is a submod
|
||||
bool isSubmod() const;
|
||||
|
||||
// see ModStatus enum
|
||||
int getModStatus() const;
|
||||
|
||||
// Returns mod name / identifier (not human-readable)
|
||||
QString getName() const;
|
||||
|
||||
// For submods only. Returns mod name / identifier of a top-level parent mod
|
||||
QString getTopParentName() const;
|
||||
|
||||
// get value of some field in mod structure. Returns empty optional if value is not present
|
||||
QVariant getValue(QString value) const;
|
||||
QVariant getBaseValue(QString value) const;
|
||||
|
||||
QStringList getDependencies() const;
|
||||
QStringList getConflicts() const;
|
||||
|
||||
static QString sizeToString(double size);
|
||||
};
|
||||
|
||||
class CModList
|
||||
{
|
||||
QVector<QVariantMap> repositories;
|
||||
QVariantMap localModList;
|
||||
std::shared_ptr<ModSettingsStorage> modSettings;
|
||||
|
||||
mutable QMap<QString, CModEntry> cachedMods;
|
||||
|
||||
QVariantMap copyField(QVariantMap data, QString from, QString to) const;
|
||||
|
||||
CModEntry getModUncached(QString modname) const;
|
||||
public:
|
||||
virtual void resetRepositories();
|
||||
virtual void reloadRepositories();
|
||||
virtual void addRepository(QVariantMap data);
|
||||
virtual void setLocalModList(QVariantMap data);
|
||||
virtual void setModSettings(std::shared_ptr<ModSettingsStorage> data);
|
||||
virtual void modChanged(QString modID);
|
||||
|
||||
// returns mod by name. Note: mod MUST exist
|
||||
const CModEntry & getMod(QString modname) const;
|
||||
|
||||
// returns list of all mods necessary to run selected one, including mod itself
|
||||
// order is: first mods in list don't have any dependencies, last mod is modname
|
||||
// note: may include mods not present in list
|
||||
QStringList getRequirements(QString modname);
|
||||
|
||||
bool hasMod(QString modname) const;
|
||||
|
||||
// returns list of all available mods
|
||||
QVector<QString> getModList() const;
|
||||
|
||||
QVector<QString> getChildren(QString parent) const;
|
||||
};
|
@@ -17,8 +17,9 @@
|
||||
#include <QCryptographicHash>
|
||||
#include <QRegularExpression>
|
||||
|
||||
#include "cmodlistmodel_moc.h"
|
||||
#include "cmodmanager.h"
|
||||
#include "modstatemodel.h"
|
||||
#include "modstateitemmodel_moc.h"
|
||||
#include "modstatecontroller.h"
|
||||
#include "cdownloadmanager_moc.h"
|
||||
#include "chroniclesextractor.h"
|
||||
#include "../settingsView/csettingsview_moc.h"
|
||||
@@ -34,15 +35,11 @@
|
||||
|
||||
#include <future>
|
||||
|
||||
static double mbToBytes(double mb)
|
||||
{
|
||||
return mb * 1024 * 1024;
|
||||
}
|
||||
|
||||
void CModListView::setupModModel()
|
||||
{
|
||||
modModel = new CModListModel(this);
|
||||
manager = std::make_unique<CModManager>(modModel);
|
||||
modStateModel = std::make_shared<ModStateModel>();
|
||||
modModel = new ModStateItemModel(this);
|
||||
manager = std::make_unique<ModStateController>(modStateModel);
|
||||
}
|
||||
|
||||
void CModListView::changeEvent(QEvent *event)
|
||||
@@ -148,13 +145,7 @@ CModListView::CModListView(QWidget * parent)
|
||||
dlManager = nullptr;
|
||||
|
||||
if(settings["launcher"]["autoCheckRepositories"].Bool())
|
||||
{
|
||||
loadRepositories();
|
||||
}
|
||||
else
|
||||
{
|
||||
manager->resetRepositories();
|
||||
}
|
||||
|
||||
#ifdef VCMI_MOBILE
|
||||
for(auto * scrollWidget : {
|
||||
@@ -171,8 +162,6 @@ CModListView::CModListView(QWidget * parent)
|
||||
|
||||
void CModListView::loadRepositories()
|
||||
{
|
||||
manager->resetRepositories();
|
||||
|
||||
QStringList repositories;
|
||||
|
||||
if (settings["launcher"]["defaultRepositoryEnabled"].Bool())
|
||||
@@ -223,7 +212,7 @@ static QString replaceIfNotEmpty(QStringList value, QString pattern)
|
||||
return "";
|
||||
}
|
||||
|
||||
QString CModListView::genChangelogText(CModEntry & mod)
|
||||
QString CModListView::genChangelogText(ModState & mod)
|
||||
{
|
||||
QString headerTemplate = "<p><span style=\" font-weight:600;\">%1: </span></p>";
|
||||
QString entryBegin = "<p align=\"justify\"><ul>";
|
||||
@@ -233,7 +222,7 @@ QString CModListView::genChangelogText(CModEntry & mod)
|
||||
|
||||
QString result;
|
||||
|
||||
QVariantMap changelog = mod.getValue("changelog").toMap();
|
||||
QMap<QString, QStringList> changelog = mod.getChangelog();
|
||||
QList<QString> versions = changelog.keys();
|
||||
|
||||
std::sort(versions.begin(), versions.end(), [](QString lesser, QString greater)
|
||||
@@ -246,7 +235,7 @@ QString CModListView::genChangelogText(CModEntry & mod)
|
||||
{
|
||||
result += headerTemplate.arg(version);
|
||||
result += entryBegin;
|
||||
for(auto & line : changelog.value(version).toStringList())
|
||||
for(auto & line : changelog.value(version))
|
||||
result += entryLine.arg(line);
|
||||
result += entryEnd;
|
||||
}
|
||||
@@ -259,21 +248,21 @@ QStringList CModListView::getModNames(QStringList input)
|
||||
|
||||
for(const auto & modID : input)
|
||||
{
|
||||
auto mod = modModel->getMod(modID.toLower());
|
||||
auto mod = modStateModel->getMod(modID);
|
||||
|
||||
QString displayName = mod.getValue("name").toString();
|
||||
QString displayName = mod.getName();
|
||||
if (displayName.isEmpty())
|
||||
displayName = modID.toLower();
|
||||
|
||||
if (mod.isSubmod())
|
||||
{
|
||||
auto parentModID = mod.getTopParentName();
|
||||
auto parentMod = modModel->getMod(parentModID.toLower());
|
||||
QString parentDisplayName = parentMod.getValue("name").toString();
|
||||
auto parentModID = mod.getTopParentID();
|
||||
auto parentMod = modStateModel->getMod(parentModID);
|
||||
QString parentDisplayName = parentMod.getName();
|
||||
if (parentDisplayName.isEmpty())
|
||||
parentDisplayName = parentModID.toLower();
|
||||
|
||||
if (mod.isInstalled())
|
||||
|
||||
if (modStateModel->isModInstalled(modID))
|
||||
displayName = QString("%1 (%2)").arg(displayName, parentDisplayName);
|
||||
else
|
||||
displayName = parentDisplayName;
|
||||
@@ -283,7 +272,7 @@ QStringList CModListView::getModNames(QStringList input)
|
||||
return result;
|
||||
}
|
||||
|
||||
QString CModListView::genModInfoText(CModEntry & mod)
|
||||
QString CModListView::genModInfoText(ModState & mod)
|
||||
{
|
||||
QString prefix = "<p><span style=\" font-weight:600;\">%1: </span>"; // shared prefix
|
||||
QString redPrefix = "<p><span style=\" font-weight:600; color:red\">%1: </span>"; // shared prefix
|
||||
@@ -297,29 +286,30 @@ QString CModListView::genModInfoText(CModEntry & mod)
|
||||
|
||||
QString result;
|
||||
|
||||
result += replaceIfNotEmpty(mod.getValue("name"), lineTemplate.arg(tr("Mod name")));
|
||||
result += replaceIfNotEmpty(mod.getValue("installedVersion"), lineTemplate.arg(tr("Installed version")));
|
||||
result += replaceIfNotEmpty(mod.getValue("latestVersion"), lineTemplate.arg(tr("Latest version")));
|
||||
result += replaceIfNotEmpty(mod.getName(), lineTemplate.arg(tr("Mod name")));
|
||||
result += replaceIfNotEmpty(mod.getInstalledVersion(), lineTemplate.arg(tr("Installed version")));
|
||||
result += replaceIfNotEmpty(mod.getRepositoryVersion(), lineTemplate.arg(tr("Latest version")));
|
||||
|
||||
if(mod.getValue("localSizeBytes").isValid())
|
||||
result += replaceIfNotEmpty(CModEntry::sizeToString(mod.getValue("localSizeBytes").toDouble()), lineTemplate.arg(tr("Size")));
|
||||
if((mod.isAvailable() || mod.isUpdateable()) && mod.getValue("downloadSize").isValid())
|
||||
result += replaceIfNotEmpty(CModEntry::sizeToString(mbToBytes(mod.getValue("downloadSize").toDouble())), lineTemplate.arg(tr("Download size")));
|
||||
if(!mod.getLocalSizeFormatted().isEmpty())
|
||||
result += replaceIfNotEmpty(mod.getLocalSizeFormatted(), lineTemplate.arg(tr("Size")));
|
||||
|
||||
if((!mod.isInstalled() || mod.isUpdateAvailable()) && !mod.getDownloadSizeFormatted().isEmpty())
|
||||
result += replaceIfNotEmpty(mod.getDownloadSizeFormatted(), lineTemplate.arg(tr("Download size")));
|
||||
|
||||
result += replaceIfNotEmpty(mod.getValue("author"), lineTemplate.arg(tr("Authors")));
|
||||
result += replaceIfNotEmpty(mod.getAuthors(), lineTemplate.arg(tr("Authors")));
|
||||
|
||||
if(mod.getValue("licenseURL").isValid())
|
||||
result += urlTemplate.arg(tr("License")).arg(mod.getValue("licenseURL").toString()).arg(mod.getValue("licenseName").toString());
|
||||
if(mod.getLicenseName().isEmpty())
|
||||
result += urlTemplate.arg(tr("License")).arg(mod.getLicenseUrl()).arg(mod.getLicenseName());
|
||||
|
||||
if(mod.getValue("contact").isValid())
|
||||
result += urlTemplate.arg(tr("Contact")).arg(mod.getValue("contact").toString()).arg(mod.getValue("contact").toString());
|
||||
if(mod.getContact().isEmpty())
|
||||
result += urlTemplate.arg(tr("Contact")).arg(mod.getContact()).arg(mod.getContact());
|
||||
|
||||
//compatibility info
|
||||
if(!mod.isCompatible())
|
||||
{
|
||||
auto compatibilityInfo = mod.getValue("compatibility").toMap();
|
||||
auto minStr = compatibilityInfo.value("min").toString();
|
||||
auto maxStr = compatibilityInfo.value("max").toString();
|
||||
auto compatibilityInfo = mod.getCompatibleVersionRange();
|
||||
auto minStr = compatibilityInfo.first;
|
||||
auto maxStr = compatibilityInfo.second;
|
||||
|
||||
result += incompatibleString.arg(tr("Compatibility"));
|
||||
if(minStr == maxStr)
|
||||
@@ -338,31 +328,24 @@ QString CModListView::genModInfoText(CModEntry & mod)
|
||||
}
|
||||
}
|
||||
|
||||
QStringList supportedLanguages;
|
||||
QVariant baseLanguageVariant = mod.getBaseValue("language");
|
||||
QVariant baseLanguageVariant = mod.getBaseLanguage();
|
||||
QString baseLanguageID = baseLanguageVariant.isValid() ? baseLanguageVariant.toString() : "english";
|
||||
|
||||
bool needToShowSupportedLanguages = false;
|
||||
QStringList supportedLanguages = mod.getSupportedLanguages();
|
||||
|
||||
for(const auto & language : Languages::getLanguageList())
|
||||
if(supportedLanguages.size() > 1)
|
||||
{
|
||||
QString languageID = QString::fromStdString(language.identifier);
|
||||
QStringList supportedLanguagesTranslated;
|
||||
|
||||
if (languageID != baseLanguageID && !mod.getValue(languageID).isValid())
|
||||
continue;
|
||||
for (const auto & languageID : supportedLanguages)
|
||||
supportedLanguagesTranslated += QApplication::translate("Language", Languages::getLanguageOptions(languageID.toStdString()).nameEnglish.c_str());
|
||||
|
||||
if (languageID != baseLanguageID)
|
||||
needToShowSupportedLanguages = true;
|
||||
|
||||
supportedLanguages += QApplication::translate("Language", language.nameEnglish.c_str());
|
||||
result += replaceIfNotEmpty(supportedLanguagesTranslated, lineTemplate.arg(tr("Languages")));
|
||||
}
|
||||
|
||||
if(needToShowSupportedLanguages)
|
||||
result += replaceIfNotEmpty(supportedLanguages, lineTemplate.arg(tr("Languages")));
|
||||
|
||||
result += replaceIfNotEmpty(getModNames(mod.getDependencies()), lineTemplate.arg(tr("Required mods")));
|
||||
result += replaceIfNotEmpty(getModNames(mod.getConflicts()), lineTemplate.arg(tr("Conflicting mods")));
|
||||
result += replaceIfNotEmpty(mod.getValue("description"), textTemplate.arg(tr("Description")));
|
||||
result += replaceIfNotEmpty(mod.getDescription(), textTemplate.arg(tr("Description")));
|
||||
|
||||
result += "<p></p>"; // to get some empty space
|
||||
|
||||
@@ -413,7 +396,7 @@ void CModListView::selectMod(const QModelIndex & index)
|
||||
else
|
||||
{
|
||||
const auto modName = index.data(ModRoles::ModNameRole).toString();
|
||||
auto mod = modModel->getMod(modName);
|
||||
auto mod = modStateModel->getMod(modName);
|
||||
|
||||
ui->modInfoBrowser->setHtml(genModInfoText(mod));
|
||||
ui->changelogBrowser->setHtml(genChangelogText(mod));
|
||||
@@ -429,15 +412,15 @@ void CModListView::selectMod(const QModelIndex & index)
|
||||
ui->enableButton->setVisible(mod.isDisabled());
|
||||
ui->installButton->setVisible(mod.isAvailable() && !mod.isSubmod());
|
||||
ui->uninstallButton->setVisible(mod.isInstalled() && !mod.isSubmod());
|
||||
ui->updateButton->setVisible(mod.isUpdateable());
|
||||
ui->updateButton->setVisible(mod.isUpdateAvailable());
|
||||
|
||||
// Block buttons if action is not allowed at this time
|
||||
// TODO: automate handling of some of these cases instead of forcing player
|
||||
// to resolve all conflicts manually.
|
||||
ui->disableButton->setEnabled(!hasDependentMods && !mod.isEssential());
|
||||
ui->disableButton->setEnabled(!hasDependentMods && !mod.isHidden());
|
||||
ui->enableButton->setEnabled(!hasBlockingMods && !hasInvalidDeps);
|
||||
ui->installButton->setEnabled(!hasInvalidDeps);
|
||||
ui->uninstallButton->setEnabled(!hasDependentMods && !mod.isEssential());
|
||||
ui->uninstallButton->setEnabled(!hasDependentMods && !mod.isHidden());
|
||||
ui->updateButton->setEnabled(!hasInvalidDeps && !hasDependentMods);
|
||||
|
||||
loadScreenshots();
|
||||
@@ -471,35 +454,16 @@ void CModListView::on_lineEdit_textChanged(const QString & arg1)
|
||||
|
||||
void CModListView::on_comboBox_currentIndexChanged(int index)
|
||||
{
|
||||
switch(index)
|
||||
{
|
||||
case 0:
|
||||
filterModel->setTypeFilter(ModStatus::MASK_NONE, ModStatus::MASK_NONE);
|
||||
break;
|
||||
case 1:
|
||||
filterModel->setTypeFilter(ModStatus::MASK_NONE, ModStatus::INSTALLED);
|
||||
break;
|
||||
case 2:
|
||||
filterModel->setTypeFilter(ModStatus::INSTALLED, ModStatus::INSTALLED);
|
||||
break;
|
||||
case 3:
|
||||
filterModel->setTypeFilter(ModStatus::UPDATEABLE, ModStatus::UPDATEABLE);
|
||||
break;
|
||||
case 4:
|
||||
filterModel->setTypeFilter(ModStatus::ENABLED | ModStatus::INSTALLED, ModStatus::ENABLED | ModStatus::INSTALLED);
|
||||
break;
|
||||
case 5:
|
||||
filterModel->setTypeFilter(ModStatus::INSTALLED, ModStatus::ENABLED | ModStatus::INSTALLED);
|
||||
break;
|
||||
}
|
||||
auto enumIndex = static_cast<ModFilterMask>(index);
|
||||
filterModel->setTypeFilter(enumIndex);
|
||||
}
|
||||
|
||||
QStringList CModListView::findInvalidDependencies(QString mod)
|
||||
{
|
||||
QStringList ret;
|
||||
for(QString requirement : modModel->getRequirements(mod))
|
||||
for(QString requirement : modStateModel->getMod(mod).getDependencies())
|
||||
{
|
||||
if(!modModel->hasMod(requirement) && !modModel->hasMod(requirement.split(QChar('.'))[0]))
|
||||
if(!modStateModel->isModExists(requirement) && !modStateModel->isModExists(modStateModel->getMod(requirement).getTopParentID()))
|
||||
ret += requirement;
|
||||
}
|
||||
return ret;
|
||||
@@ -508,11 +472,11 @@ QStringList CModListView::findInvalidDependencies(QString mod)
|
||||
QStringList CModListView::findBlockingMods(QString modUnderTest)
|
||||
{
|
||||
QStringList ret;
|
||||
auto required = modModel->getRequirements(modUnderTest);
|
||||
auto required = modStateModel->getMod(modUnderTest).getDependencies();
|
||||
|
||||
for(QString name : modModel->getModList())
|
||||
for(QString name : modStateModel->getAllMods())
|
||||
{
|
||||
auto mod = modModel->getMod(name);
|
||||
auto mod = modStateModel->getMod(name);
|
||||
|
||||
if(mod.isEnabled())
|
||||
{
|
||||
@@ -531,9 +495,9 @@ QStringList CModListView::findBlockingMods(QString modUnderTest)
|
||||
QStringList CModListView::findDependentMods(QString mod, bool excludeDisabled)
|
||||
{
|
||||
QStringList ret;
|
||||
for(QString modName : modModel->getModList())
|
||||
for(QString modName : modStateModel->getAllMods())
|
||||
{
|
||||
auto current = modModel->getMod(modName);
|
||||
auto current = modStateModel->getMod(modName);
|
||||
|
||||
if(!current.isInstalled() || !current.isVisible())
|
||||
continue;
|
||||
@@ -561,9 +525,11 @@ void CModListView::enableModByName(QString modName)
|
||||
assert(findBlockingMods(modName).empty());
|
||||
assert(findInvalidDependencies(modName).empty());
|
||||
|
||||
for(auto & name : modModel->getRequirements(modName))
|
||||
auto mod = modStateModel->getMod(modName);
|
||||
|
||||
for(auto & name : mod.getDependencies())
|
||||
{
|
||||
if(modModel->getMod(name).isDisabled())
|
||||
if(modStateModel->getMod(name).isDisabled())
|
||||
manager->enableMod(name);
|
||||
}
|
||||
emit modsChanged();
|
||||
@@ -580,7 +546,7 @@ void CModListView::on_disableButton_clicked()
|
||||
|
||||
void CModListView::disableModByName(QString modName)
|
||||
{
|
||||
if(modModel->hasMod(modName) && modModel->getMod(modName).isEnabled())
|
||||
if(modStateModel->isModExists(modName) && modStateModel->getMod(modName).isEnabled())
|
||||
manager->disableMod(modName);
|
||||
|
||||
emit modsChanged();
|
||||
@@ -592,12 +558,12 @@ void CModListView::on_updateButton_clicked()
|
||||
|
||||
assert(findInvalidDependencies(modName).empty());
|
||||
|
||||
for(auto & name : modModel->getRequirements(modName))
|
||||
for(auto & name : modStateModel->getMod(modName).getDependencies())
|
||||
{
|
||||
auto mod = modModel->getMod(name);
|
||||
auto mod = modStateModel->getMod(name);
|
||||
// update required mod, install missing (can be new dependency)
|
||||
if(mod.isUpdateable() || !mod.isInstalled())
|
||||
downloadFile(name + ".zip", mod.getValue("download").toString(), name, mbToBytes(mod.getValue("downloadSize").toDouble()));
|
||||
if(mod.isUpdateAvailable() || !mod.isInstalled())
|
||||
downloadFile(name + ".zip", mod.getDownloadUrl(), name, mod.getDownloadSizeMegabytes());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -606,9 +572,9 @@ void CModListView::on_uninstallButton_clicked()
|
||||
QString modName = ui->allModsView->currentIndex().data(ModRoles::ModNameRole).toString();
|
||||
// NOTE: perhaps add "manually installed" flag and uninstall those dependencies that don't have it?
|
||||
|
||||
if(modModel->hasMod(modName) && modModel->getMod(modName).isInstalled())
|
||||
if(modStateModel->isModExists(modName) && modStateModel->getMod(modName).isInstalled())
|
||||
{
|
||||
if(modModel->getMod(modName).isEnabled())
|
||||
if(modStateModel->getMod(modName).isEnabled())
|
||||
manager->disableMod(modName);
|
||||
manager->uninstallMod(modName);
|
||||
}
|
||||
@@ -622,19 +588,19 @@ void CModListView::on_installButton_clicked()
|
||||
QString modName = ui->allModsView->currentIndex().data(ModRoles::ModNameRole).toString();
|
||||
|
||||
assert(findInvalidDependencies(modName).empty());
|
||||
|
||||
for(auto & name : modModel->getRequirements(modName))
|
||||
|
||||
for(auto & name : modStateModel->getMod(modName).getDependencies())
|
||||
{
|
||||
auto mod = modModel->getMod(name);
|
||||
auto mod = modStateModel->getMod(name);
|
||||
if(mod.isAvailable())
|
||||
downloadFile(name + ".zip", mod.getValue("download").toString(), name, mbToBytes(mod.getValue("downloadSize").toDouble()));
|
||||
downloadFile(name + ".zip", mod.getDownloadUrl(), name, mod.getDownloadSizeMegabytes());
|
||||
else if(!mod.isEnabled())
|
||||
enableModByName(name);
|
||||
}
|
||||
|
||||
for(auto & name : modModel->getMod(modName).getConflicts())
|
||||
for(auto & name : modStateModel->getMod(modName).getConflicts())
|
||||
{
|
||||
auto mod = modModel->getMod(name);
|
||||
auto mod = modStateModel->getMod(name);
|
||||
if(mod.isEnabled())
|
||||
{
|
||||
//TODO: consider reverse dependencies disabling
|
||||
@@ -697,8 +663,8 @@ void CModListView::manualInstallFile(QString filePath)
|
||||
for(auto widget : qApp->allWidgets())
|
||||
if(auto settingsView = qobject_cast<CSettingsView *>(widget))
|
||||
settingsView->loadSettings();
|
||||
manager->loadMods();
|
||||
manager->loadModSettings();
|
||||
// manager->loadMods();
|
||||
// manager->loadModSettings();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -726,7 +692,7 @@ void CModListView::downloadFile(QString file, QUrl url, QString description, qin
|
||||
connect(manager.get(), SIGNAL(extractionProgress(qint64,qint64)),
|
||||
this, SLOT(extractionProgress(qint64,qint64)));
|
||||
|
||||
connect(modModel, &CModListModel::dataChanged, filterModel, &QAbstractItemModel::dataChanged);
|
||||
connect(modModel, &ModStateItemModel::dataChanged, filterModel, &QAbstractItemModel::dataChanged);
|
||||
|
||||
const auto progressBarFormat = tr("Downloading %1. %p% (%v MB out of %m MB) finished").arg(description);
|
||||
ui->progressBar->setFormat(progressBarFormat);
|
||||
@@ -849,8 +815,8 @@ void CModListView::installFiles(QStringList files)
|
||||
images.push_back(filename);
|
||||
}
|
||||
|
||||
if (!repositories.empty())
|
||||
manager->loadRepositories(repositories);
|
||||
// if (!repositories.empty())
|
||||
// manager->loadRepositories(repositories);
|
||||
|
||||
if(!mods.empty())
|
||||
installMods(mods);
|
||||
@@ -881,8 +847,8 @@ void CModListView::installFiles(QStringList files)
|
||||
{
|
||||
//update
|
||||
CResourceHandler::get("initial")->updateFilteredFiles([](const std::string &){ return true; });
|
||||
manager->loadMods();
|
||||
modModel->reloadRepositories();
|
||||
// manager->loadMods();
|
||||
// modModel->reloadRepositories();
|
||||
emit modsChanged();
|
||||
}
|
||||
}
|
||||
@@ -909,7 +875,7 @@ void CModListView::installMods(QStringList archives)
|
||||
// disable mod(s), to properly recalculate dependencies, if changed
|
||||
for(QString mod : boost::adaptors::reverse(modNames))
|
||||
{
|
||||
CModEntry entry = modModel->getMod(mod);
|
||||
ModState entry = modStateModel->getMod(mod);
|
||||
if(entry.isInstalled())
|
||||
{
|
||||
// enable mod if installed and enabled
|
||||
@@ -927,7 +893,7 @@ void CModListView::installMods(QStringList archives)
|
||||
// uninstall old version of mod, if installed
|
||||
for(QString mod : boost::adaptors::reverse(modNames))
|
||||
{
|
||||
if(modModel->getMod(mod).isInstalled())
|
||||
if(modStateModel->getMod(mod).isInstalled())
|
||||
manager->uninstallMod(mod);
|
||||
}
|
||||
|
||||
@@ -941,19 +907,19 @@ void CModListView::installMods(QStringList archives)
|
||||
|
||||
enableMod = [&](QString modName)
|
||||
{
|
||||
auto mod = modModel->getMod(modName);
|
||||
if(mod.isInstalled() && !mod.getValue("keepDisabled").toBool())
|
||||
auto mod = modStateModel->getMod(modName);
|
||||
if(mod.isInstalled() && !mod.isKeptDisabled())
|
||||
{
|
||||
for (auto const & dependencyName : mod.getDependencies())
|
||||
{
|
||||
auto dependency = modModel->getMod(dependencyName);
|
||||
auto dependency = modStateModel->getMod(dependencyName);
|
||||
if(dependency.isDisabled())
|
||||
manager->enableMod(dependencyName);
|
||||
}
|
||||
|
||||
if(mod.isDisabled() && manager->enableMod(modName))
|
||||
{
|
||||
for(QString child : modModel->getChildren(modName))
|
||||
for(QString child : modStateModel->getSubmods(modName))
|
||||
enableMod(child);
|
||||
}
|
||||
}
|
||||
@@ -1025,9 +991,9 @@ void CModListView::loadScreenshots()
|
||||
|
||||
ui->screenshotsList->clear();
|
||||
QString modName = ui->allModsView->currentIndex().data(ModRoles::ModNameRole).toString();
|
||||
assert(modModel->hasMod(modName)); //should be filtered out by check above
|
||||
assert(modStateModel->isModExists(modName)); //should be filtered out by check above
|
||||
|
||||
for(QString url : modModel->getMod(modName).getValue("screenshots").toStringList())
|
||||
for(QString url : modStateModel->getMod(modName).getScreenshots())
|
||||
{
|
||||
// URL must be encoded to something else to get rid of symbols illegal in file names
|
||||
const auto hashed = QCryptographicHash::hash(url.toUtf8(), QCryptographicHash::Md5);
|
||||
@@ -1061,52 +1027,51 @@ void CModListView::on_screenshotsList_clicked(const QModelIndex & index)
|
||||
}
|
||||
}
|
||||
|
||||
const CModList & CModListView::getModList() const
|
||||
{
|
||||
assert(modModel);
|
||||
return *modModel;
|
||||
}
|
||||
//const CModList & CModListView::getModList() const
|
||||
//{
|
||||
// assert(modModel);
|
||||
// return *modModel;
|
||||
//}
|
||||
|
||||
void CModListView::doInstallMod(const QString & modName)
|
||||
{
|
||||
assert(findInvalidDependencies(modName).empty());
|
||||
|
||||
for(auto & name : modModel->getRequirements(modName))
|
||||
for(auto & name : modStateModel->getMod(modName).getDependencies())
|
||||
{
|
||||
auto mod = modModel->getMod(name);
|
||||
auto mod = modStateModel->getMod(name);
|
||||
if(!mod.isInstalled())
|
||||
downloadFile(name + ".zip", mod.getValue("download").toString(), name, mbToBytes(mod.getValue("downloadSize").toDouble()));
|
||||
downloadFile(name + ".zip", mod.getDownloadUrl(), name, mod.getDownloadSizeMegabytes());
|
||||
}
|
||||
}
|
||||
|
||||
bool CModListView::isModAvailable(const QString & modName)
|
||||
{
|
||||
auto mod = modModel->getMod(modName);
|
||||
return mod.isAvailable();
|
||||
return !modStateModel->isModInstalled(modName);
|
||||
}
|
||||
|
||||
bool CModListView::isModEnabled(const QString & modName)
|
||||
{
|
||||
auto mod = modModel->getMod(modName);
|
||||
auto mod = modStateModel->getMod(modName);
|
||||
return mod.isEnabled();
|
||||
}
|
||||
|
||||
bool CModListView::isModInstalled(const QString & modName)
|
||||
{
|
||||
auto mod = modModel->getMod(modName);
|
||||
auto mod = modStateModel->getMod(modName);
|
||||
return mod.isInstalled();
|
||||
}
|
||||
|
||||
QString CModListView::getTranslationModName(const QString & language)
|
||||
{
|
||||
for(const auto & modName : modModel->getModList())
|
||||
for(const auto & modName : modStateModel->getAllMods())
|
||||
{
|
||||
auto mod = modModel->getMod(modName);
|
||||
auto mod = modStateModel->getMod(modName);
|
||||
|
||||
if (!mod.isTranslation())
|
||||
continue;
|
||||
|
||||
if (mod.getBaseValue("language").toString() != language)
|
||||
if (mod.getBaseLanguage() != language)
|
||||
continue;
|
||||
|
||||
return modName;
|
||||
@@ -1121,7 +1086,7 @@ void CModListView::on_allModsView_doubleClicked(const QModelIndex &index)
|
||||
return;
|
||||
|
||||
auto modName = index.data(ModRoles::ModNameRole).toString();
|
||||
auto mod = modModel->getMod(modName);
|
||||
auto mod = modStateModel->getMod(modName);
|
||||
|
||||
bool hasInvalidDeps = !findInvalidDependencies(modName).empty();
|
||||
bool hasBlockingMods = !findBlockingMods(modName).empty();
|
||||
@@ -1133,7 +1098,7 @@ void CModListView::on_allModsView_doubleClicked(const QModelIndex &index)
|
||||
return;
|
||||
}
|
||||
|
||||
if(!hasInvalidDeps && !hasDependentMods && mod.isUpdateable() && index.column() == ModFields::STATUS_UPDATE)
|
||||
if(!hasInvalidDeps && !hasDependentMods && mod.isUpdateAvailable() && index.column() == ModFields::STATUS_UPDATE)
|
||||
{
|
||||
on_updateButton_clicked();
|
||||
return;
|
||||
@@ -1155,7 +1120,7 @@ void CModListView::on_allModsView_doubleClicked(const QModelIndex &index)
|
||||
return;
|
||||
}
|
||||
|
||||
if(!hasDependentMods && !mod.isEssential() && mod.isEnabled())
|
||||
if(!hasDependentMods && !mod.isVisible() && mod.isEnabled())
|
||||
{
|
||||
on_disableButton_clicked();
|
||||
return;
|
||||
|
@@ -17,21 +17,23 @@ namespace Ui
|
||||
class CModListView;
|
||||
}
|
||||
|
||||
class CModManager;
|
||||
class ModStateController;
|
||||
class CModList;
|
||||
class CModListModel;
|
||||
class ModStateItemModel;
|
||||
class ModStateModel;
|
||||
class CModFilterModel;
|
||||
class CDownloadManager;
|
||||
class QTableWidgetItem;
|
||||
|
||||
class CModEntry;
|
||||
class ModState;
|
||||
|
||||
class CModListView : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
std::unique_ptr<CModManager> manager;
|
||||
CModListModel * modModel;
|
||||
std::shared_ptr<ModStateModel> modStateModel;
|
||||
std::unique_ptr<ModStateController> manager;
|
||||
ModStateItemModel * modModel;
|
||||
CModFilterModel * filterModel;
|
||||
CDownloadManager * dlManager;
|
||||
|
||||
@@ -59,8 +61,8 @@ class CModListView : public QWidget
|
||||
void installMaps(QStringList maps);
|
||||
void installFiles(QStringList mods);
|
||||
|
||||
QString genChangelogText(CModEntry & mod);
|
||||
QString genModInfoText(CModEntry & mod);
|
||||
QString genChangelogText(ModState & mod);
|
||||
QString genModInfoText(ModState & mod);
|
||||
|
||||
void changeEvent(QEvent *event) override;
|
||||
void dragEnterEvent(QDragEnterEvent* event) override;
|
||||
@@ -79,7 +81,7 @@ public:
|
||||
|
||||
void selectMod(const QModelIndex & index);
|
||||
|
||||
const CModList & getModList() const;
|
||||
//const CModList & getModList() const;
|
||||
|
||||
// First Launch View interface
|
||||
|
||||
|
@@ -1,191 +0,0 @@
|
||||
/*
|
||||
* modsettignsstorage.cpp, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
* License: GNU General Public License v2.0 or later
|
||||
* Full text of license available in license.txt file, in main folder
|
||||
*
|
||||
*/
|
||||
#include "StdInc.h"
|
||||
#include "modsettingsstorage.h"
|
||||
|
||||
#include "../../lib/VCMIDirs.h"
|
||||
#include "../vcmiqt/jsonutils.h"
|
||||
|
||||
static QVariant writeValue(QString path, QVariantMap input, QVariant value)
|
||||
{
|
||||
if(path.size() > 1)
|
||||
{
|
||||
QString entryName = path.section('/', 0, 1);
|
||||
QString remainder = "/" + path.section('/', 2, -1);
|
||||
entryName.remove(0, 1);
|
||||
input.insert(entryName, writeValue(remainder, input.value(entryName).toMap(), value));
|
||||
return input;
|
||||
}
|
||||
else
|
||||
{
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
void ModSettingsStorage::createInitialPreset()
|
||||
{
|
||||
// TODO: scan mods directory for all its content?
|
||||
|
||||
QStringList modList;
|
||||
QVariantMap preset;
|
||||
QVariantMap presetList;
|
||||
|
||||
modList.push_back("vcmi");
|
||||
preset.insert("mods", modList);
|
||||
presetList.insert("default", preset);
|
||||
config.insert("presets", presetList);
|
||||
}
|
||||
|
||||
void ModSettingsStorage::importInitialPreset()
|
||||
{
|
||||
QStringList modList;
|
||||
QMap<QString, QVariantMap> modSettings;
|
||||
|
||||
QVariantMap activeMods = config["activeMods"].toMap();
|
||||
for (QVariantMap::const_iterator modEntry = activeMods.begin(); modEntry != activeMods.end(); ++modEntry)
|
||||
{
|
||||
if (modEntry.value().toMap()["active"].toBool())
|
||||
modList.push_back(modEntry.key());
|
||||
|
||||
QVariantMap submods = modEntry.value().toMap()["mods"].toMap();
|
||||
for (QVariantMap::const_iterator submodEntry = submods.begin(); submodEntry != submods.end(); ++submodEntry)
|
||||
modSettings[modEntry.key()].insert(submodEntry.key(), submodEntry.value().toMap()["active"]);
|
||||
}
|
||||
|
||||
QVariantMap importedPreset;
|
||||
QVariantMap modSettingsVariant;
|
||||
QVariantMap presetList;
|
||||
|
||||
for (QMap<QString, QVariantMap>::const_iterator modEntry = modSettings.begin(); modEntry != modSettings.end(); ++modEntry)
|
||||
modSettingsVariant.insert(modEntry.key(), modEntry.value());
|
||||
|
||||
importedPreset.insert("mods", modList);
|
||||
importedPreset.insert("settings", modSettingsVariant);
|
||||
presetList.insert("default", importedPreset);
|
||||
config.insert("presets", presetList);
|
||||
}
|
||||
|
||||
ModSettingsStorage::ModSettingsStorage()
|
||||
{
|
||||
config = JsonUtils::JsonFromFile(settingsPath()).toMap();
|
||||
|
||||
if (!config.contains("presets"))
|
||||
{
|
||||
config.insert("activePreset", QVariant("default"));
|
||||
if (config.contains("activeMods"))
|
||||
importInitialPreset(); // 1.5 format import
|
||||
else
|
||||
createInitialPreset(); // new install
|
||||
|
||||
JsonUtils::JsonToFile(settingsPath(), config);
|
||||
}
|
||||
}
|
||||
|
||||
QString ModSettingsStorage::settingsPath() const
|
||||
{
|
||||
return pathToQString(VCMIDirs::get().userConfigPath() / "modSettings.json");
|
||||
}
|
||||
|
||||
void ModSettingsStorage::setRootModActive(const QString & modName, bool on)
|
||||
{
|
||||
QString presetName = getActivePreset();
|
||||
QStringList activeMods = getActiveMods();
|
||||
|
||||
assert(modName.count('.') == 0); // this method should never be used for submods
|
||||
|
||||
if (on)
|
||||
activeMods.push_back(modName);
|
||||
else
|
||||
activeMods.removeAll(modName);
|
||||
|
||||
config = writeValue("/presets/" + presetName + "/mods", config, activeMods).toMap();
|
||||
|
||||
JsonUtils::JsonToFile(settingsPath(), config);
|
||||
}
|
||||
|
||||
void ModSettingsStorage::registerNewMod(const QString & modName, bool keepDisabled)
|
||||
{
|
||||
if (!modName.contains('.'))
|
||||
return;
|
||||
|
||||
QString rootModName = modName.section('.', 0, 0);
|
||||
QString settingName = modName.section('.', 1);
|
||||
|
||||
QVariantMap modSettings = getModSettings(rootModName);
|
||||
|
||||
if (modSettings.contains(settingName))
|
||||
return;
|
||||
|
||||
setModSettingActive(modName, !keepDisabled);
|
||||
}
|
||||
|
||||
void ModSettingsStorage::setModSettingActive(const QString & modName, bool on)
|
||||
{
|
||||
QString presetName = getActivePreset();
|
||||
QString rootModName = modName.section('.', 0, 0);
|
||||
QString settingName = modName.section('.', 1);
|
||||
QVariantMap modSettings = getModSettings(rootModName);
|
||||
|
||||
assert(modName.count('.') != 0); // this method should only be used for submods
|
||||
|
||||
modSettings.insert(settingName, QVariant(on));
|
||||
|
||||
config = writeValue("/presets/" + presetName + "/settings/" + rootModName, config, modSettings).toMap();
|
||||
|
||||
JsonUtils::JsonToFile(settingsPath(), config);
|
||||
}
|
||||
|
||||
void ModSettingsStorage::setModActive(const QString & modName, bool on)
|
||||
{
|
||||
if (modName.contains('.'))
|
||||
setModSettingActive(modName, on);
|
||||
else
|
||||
setRootModActive(modName, on);
|
||||
}
|
||||
|
||||
void ModSettingsStorage::setActivePreset(const QString & presetName)
|
||||
{
|
||||
config.insert("activePreset", QVariant(presetName));
|
||||
}
|
||||
|
||||
QString ModSettingsStorage::getActivePreset() const
|
||||
{
|
||||
return config["activePreset"].toString();
|
||||
}
|
||||
|
||||
bool ModSettingsStorage::isModActive(const QString & modName) const
|
||||
{
|
||||
if (modName.contains('.'))
|
||||
{
|
||||
QString rootModName = modName.section('.', 0, 0);
|
||||
QString settingName = modName.section('.', 1);
|
||||
|
||||
return getModSettings(rootModName)[settingName].toBool();
|
||||
}
|
||||
else
|
||||
return getActiveMods().contains(modName);
|
||||
}
|
||||
|
||||
QStringList ModSettingsStorage::getActiveMods() const
|
||||
{
|
||||
return getActivePresetData()["mods"].toStringList();
|
||||
}
|
||||
|
||||
QVariantMap ModSettingsStorage::getActivePresetData() const
|
||||
{
|
||||
QString presetName = getActivePreset();
|
||||
return config["presets"].toMap()[presetName].toMap();
|
||||
}
|
||||
|
||||
QVariantMap ModSettingsStorage::getModSettings(const QString & modName) const
|
||||
{
|
||||
QString presetName = getActivePreset();
|
||||
return getActivePresetData()["settings"].toMap()[modName].toMap();
|
||||
}
|
@@ -1,42 +0,0 @@
|
||||
/*
|
||||
* modsettignsstorage.h, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
* License: GNU General Public License v2.0 or later
|
||||
* Full text of license available in license.txt file, in main folder
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <QVariantMap>
|
||||
|
||||
class ModSettingsStorage
|
||||
{
|
||||
QVariantMap config;
|
||||
|
||||
QString settingsPath() const;
|
||||
|
||||
void createInitialPreset();
|
||||
void importInitialPreset();
|
||||
|
||||
void setRootModActive(const QString & modName, bool on);
|
||||
void setModSettingActive(const QString & modName, bool on);
|
||||
|
||||
QVariantMap getActivePresetData() const;
|
||||
QStringList getActiveMods() const;
|
||||
QVariantMap getModSettings(const QString & modName) const;
|
||||
|
||||
public:
|
||||
ModSettingsStorage();
|
||||
|
||||
void registerNewMod(const QString & modName, bool keepDisabled);
|
||||
|
||||
void setModActive(const QString & modName, bool on);
|
||||
void setActivePreset(const QString & presetName);
|
||||
|
||||
QString getActivePreset() const;
|
||||
bool isModActive(const QString & modName) const;
|
||||
//QStringList getPresetsList() const;
|
||||
};
|
||||
|
212
launcher/modManager/modstate.cpp
Normal file
212
launcher/modManager/modstate.cpp
Normal file
@@ -0,0 +1,212 @@
|
||||
/*
|
||||
* modstate.cpp, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
* License: GNU General Public License v2.0 or later
|
||||
* Full text of license available in license.txt file, in main folder
|
||||
*
|
||||
*/
|
||||
#include "StdInc.h"
|
||||
#include "modstate.h"
|
||||
|
||||
#include "../../lib/modding/ModDescription.h"
|
||||
#include "../../lib/json/JsonNode.h"
|
||||
#include "../../lib/texts/CGeneralTextHandler.h"
|
||||
|
||||
ModState::ModState(const ModDescription & impl)
|
||||
: impl(impl)
|
||||
{
|
||||
}
|
||||
|
||||
QString ModState::getName() const
|
||||
{
|
||||
return QString::fromStdString(impl.getName());
|
||||
}
|
||||
|
||||
QString ModState::getType() const
|
||||
{
|
||||
return QString::fromStdString(impl.getValue("modType").String());
|
||||
}
|
||||
|
||||
QString ModState::getDescription() const
|
||||
{
|
||||
return QString::fromStdString(impl.getValue("description").String());
|
||||
}
|
||||
|
||||
QString ModState::getID() const
|
||||
{
|
||||
return QString::fromStdString(impl.getID());
|
||||
}
|
||||
|
||||
QString ModState::getParentID() const
|
||||
{
|
||||
return QString::fromStdString(impl.getParentID());
|
||||
}
|
||||
|
||||
QString ModState::getTopParentID() const
|
||||
{
|
||||
return QString::fromStdString(impl.getParentID());
|
||||
}
|
||||
|
||||
template<typename Container>
|
||||
QStringList stringListStdToQt(const Container & container)
|
||||
{
|
||||
QStringList result;
|
||||
for (const auto & str : container)
|
||||
result.push_back(QString::fromStdString(str));
|
||||
return result;
|
||||
}
|
||||
|
||||
QStringList ModState::getDependencies() const
|
||||
{
|
||||
return stringListStdToQt(impl.getDependencies());
|
||||
}
|
||||
|
||||
QStringList ModState::getConflicts() const
|
||||
{
|
||||
return stringListStdToQt(impl.getConflicts());
|
||||
}
|
||||
|
||||
QStringList ModState::getScreenshots() const
|
||||
{
|
||||
return {}; // TODO
|
||||
}
|
||||
|
||||
QString ModState::getBaseLanguage() const
|
||||
{
|
||||
return QString::fromStdString(impl.getBaseLanguage());
|
||||
}
|
||||
|
||||
QStringList ModState::getSupportedLanguages() const
|
||||
{
|
||||
return {}; //TODO
|
||||
}
|
||||
|
||||
QMap<QString, QStringList> ModState::getChangelog() const
|
||||
{
|
||||
return {}; //TODO
|
||||
}
|
||||
|
||||
QString ModState::getInstalledVersion() const
|
||||
{
|
||||
return QString::fromStdString(impl.getLocalValue("version").String());
|
||||
}
|
||||
|
||||
QString ModState::getRepositoryVersion() const
|
||||
{
|
||||
return QString::fromStdString(impl.getRepositoryValue("version").String());
|
||||
}
|
||||
|
||||
double ModState::getDownloadSizeMegabytes() const
|
||||
{
|
||||
return impl.getRepositoryValue("downloadSize").Float();
|
||||
}
|
||||
|
||||
size_t ModState::getDownloadSizeBytes() const
|
||||
{
|
||||
return getDownloadSizeMegabytes() * 1024 * 1024;
|
||||
}
|
||||
|
||||
QString ModState::getDownloadSizeFormatted() const
|
||||
{
|
||||
return {}; // TODO
|
||||
}
|
||||
|
||||
QString ModState::getLocalSizeFormatted() const
|
||||
{
|
||||
return {}; // TODO
|
||||
}
|
||||
|
||||
QString ModState::getAuthors() const
|
||||
{
|
||||
return QString::fromStdString(impl.getValue("authors").String());
|
||||
}
|
||||
|
||||
QString ModState::getContact() const
|
||||
{
|
||||
return QString::fromStdString(impl.getValue("contact").String());
|
||||
}
|
||||
|
||||
QString ModState::getLicenseUrl() const
|
||||
{
|
||||
return QString::fromStdString(impl.getValue("licenseUrl").String());
|
||||
}
|
||||
|
||||
QString ModState::getLicenseName() const
|
||||
{
|
||||
return QString::fromStdString(impl.getValue("licenseName").String());
|
||||
}
|
||||
|
||||
QString ModState::getDownloadUrl() const
|
||||
{
|
||||
return QString::fromStdString(impl.getRepositoryValue("download").String());
|
||||
}
|
||||
|
||||
QPair<QString, QString> ModState::getCompatibleVersionRange() const
|
||||
{
|
||||
return {}; // TODO
|
||||
}
|
||||
|
||||
bool ModState::isSubmod() const
|
||||
{
|
||||
return !getParentID().isEmpty();
|
||||
}
|
||||
|
||||
bool ModState::isCompatibility() const
|
||||
{
|
||||
return impl.isCompatibility();
|
||||
}
|
||||
|
||||
bool ModState::isTranslation() const
|
||||
{
|
||||
return impl.isTranslation();
|
||||
}
|
||||
|
||||
bool ModState::isVisible() const
|
||||
{
|
||||
return !isHidden();
|
||||
}
|
||||
|
||||
bool ModState::isHidden() const
|
||||
{
|
||||
if (isTranslation() && !isInstalled())
|
||||
return impl.getBaseLanguage() == CGeneralTextHandler::getPreferredLanguage();
|
||||
|
||||
return isCompatibility() || getID() == "vcmi";
|
||||
}
|
||||
|
||||
bool ModState::isDisabled() const
|
||||
{
|
||||
return false; // TODO
|
||||
}
|
||||
|
||||
bool ModState::isEnabled() const
|
||||
{
|
||||
return true; // TODO
|
||||
}
|
||||
|
||||
bool ModState::isAvailable() const
|
||||
{
|
||||
return !isInstalled();
|
||||
}
|
||||
|
||||
bool ModState::isInstalled() const
|
||||
{
|
||||
return impl.isInstalled();
|
||||
}
|
||||
|
||||
bool ModState::isUpdateAvailable() const
|
||||
{
|
||||
return getInstalledVersion() != getRepositoryVersion() && !getRepositoryVersion().isEmpty();
|
||||
}
|
||||
|
||||
bool ModState::isCompatible() const
|
||||
{
|
||||
return true; //TODO
|
||||
}
|
||||
|
||||
bool ModState::isKeptDisabled() const
|
||||
{
|
||||
return impl.keepDisabled();
|
||||
}
|
71
launcher/modManager/modstate.h
Normal file
71
launcher/modManager/modstate.h
Normal file
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* modstate.h, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
* License: GNU General Public License v2.0 or later
|
||||
* Full text of license available in license.txt file, in main folder
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
class ModDescription;
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
||||
/// Class that represent current state of mod in Launcher
|
||||
/// Provides Qt-based interface to library class ModDescription
|
||||
class ModState
|
||||
{
|
||||
const ModDescription & impl;
|
||||
|
||||
public:
|
||||
explicit ModState(const ModDescription & impl);
|
||||
|
||||
QString getName() const;
|
||||
QString getType() const;
|
||||
QString getDescription() const;
|
||||
|
||||
QString getID() const;
|
||||
QString getParentID() const;
|
||||
QString getTopParentID() const;
|
||||
|
||||
QStringList getDependencies() const;
|
||||
QStringList getConflicts() const;
|
||||
QStringList getScreenshots() const;
|
||||
|
||||
QString getBaseLanguage() const;
|
||||
QStringList getSupportedLanguages() const;
|
||||
|
||||
QMap<QString, QStringList> getChangelog() const;
|
||||
|
||||
QString getInstalledVersion() const;
|
||||
QString getRepositoryVersion() const;
|
||||
|
||||
double getDownloadSizeMegabytes() const;
|
||||
size_t getDownloadSizeBytes() const;
|
||||
QString getDownloadSizeFormatted() const;
|
||||
QString getLocalSizeFormatted() const;
|
||||
QString getAuthors() const;
|
||||
QString getContact() const;
|
||||
QString getLicenseUrl() const;
|
||||
QString getLicenseName() const;
|
||||
|
||||
QString getDownloadUrl() const;
|
||||
|
||||
QPair<QString, QString> getCompatibleVersionRange() const;
|
||||
|
||||
bool isSubmod() const;
|
||||
bool isCompatibility() const;
|
||||
bool isTranslation() const;
|
||||
|
||||
bool isVisible() const;
|
||||
bool isHidden() const;
|
||||
bool isDisabled() const;
|
||||
bool isEnabled() const;
|
||||
bool isAvailable() const;
|
||||
bool isInstalled() const;
|
||||
bool isUpdateAvailable() const;
|
||||
bool isCompatible() const;
|
||||
bool isKeptDisabled() const;
|
||||
};
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* cmodmanager.cpp, part of VCMI engine
|
||||
* modstatecontroller.cpp, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
@@ -8,13 +8,16 @@
|
||||
*
|
||||
*/
|
||||
#include "StdInc.h"
|
||||
#include "cmodmanager.h"
|
||||
#include "modstatecontroller.h"
|
||||
|
||||
#include "modstatemodel.h"
|
||||
|
||||
#include "../../lib/VCMIDirs.h"
|
||||
#include "../../lib/filesystem/Filesystem.h"
|
||||
#include "../../lib/filesystem/CZipLoader.h"
|
||||
#include "../../lib/modding/CModHandler.h"
|
||||
#include "../../lib/modding/IdentifierStorage.h"
|
||||
#include "../../lib/json/JsonNode.h"
|
||||
|
||||
#include "../vcmiqt/jsonutils.h"
|
||||
#include "../vcmiqt/launcherdirs.h"
|
||||
@@ -61,37 +64,24 @@ QString detectModArchive(QString path, QString modName, std::vector<std::string>
|
||||
}
|
||||
|
||||
|
||||
CModManager::CModManager(CModList * modList)
|
||||
ModStateController::ModStateController(std::shared_ptr<ModStateModel> modList)
|
||||
: modList(modList)
|
||||
{
|
||||
modSettings = std::make_shared<ModSettingsStorage>();
|
||||
loadMods();
|
||||
loadModSettings();
|
||||
}
|
||||
|
||||
void CModManager::loadModSettings()
|
||||
ModStateController::~ModStateController() = default;
|
||||
|
||||
void ModStateController::loadRepositories(QVector<JsonNode> repomap)
|
||||
{
|
||||
modList->setModSettings(modSettings);
|
||||
modList->setRepositories(repomap);
|
||||
}
|
||||
|
||||
void CModManager::resetRepositories()
|
||||
{
|
||||
modList->resetRepositories();
|
||||
}
|
||||
|
||||
void CModManager::loadRepositories(QVector<QVariantMap> repomap)
|
||||
{
|
||||
for (auto const & entry : repomap)
|
||||
modList->addRepository(entry);
|
||||
modList->reloadRepositories();
|
||||
}
|
||||
|
||||
void CModManager::loadMods()
|
||||
{
|
||||
CModHandler handler;
|
||||
auto installedMods = handler.getAllMods();
|
||||
localMods.clear();
|
||||
|
||||
//void ModStateController::loadMods()
|
||||
//{
|
||||
// CModHandler handler;
|
||||
// auto installedMods = handler.getAllMods();
|
||||
// localMods.clear();
|
||||
//
|
||||
// for(auto modname : installedMods)
|
||||
// {
|
||||
// //calculate mod size
|
||||
@@ -115,43 +105,43 @@ void CModManager::loadMods()
|
||||
// localMods.insert(modNameQt, mod);
|
||||
// modSettings->registerNewMod(modNameQt, json["keepDisabled"].Bool());
|
||||
// }
|
||||
modList->setLocalModList(localMods);
|
||||
}
|
||||
// modList->setLocalModList(localMods);
|
||||
//}
|
||||
|
||||
bool CModManager::addError(QString modname, QString message)
|
||||
bool ModStateController::addError(QString modname, QString message)
|
||||
{
|
||||
recentErrors.push_back(QString("%1: %2").arg(modname).arg(message));
|
||||
return false;
|
||||
}
|
||||
|
||||
QStringList CModManager::getErrors()
|
||||
QStringList ModStateController::getErrors()
|
||||
{
|
||||
QStringList ret = recentErrors;
|
||||
recentErrors.clear();
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool CModManager::installMod(QString modname, QString archivePath)
|
||||
bool ModStateController::installMod(QString modname, QString archivePath)
|
||||
{
|
||||
return canInstallMod(modname) && doInstallMod(modname, archivePath);
|
||||
}
|
||||
|
||||
bool CModManager::uninstallMod(QString modname)
|
||||
bool ModStateController::uninstallMod(QString modname)
|
||||
{
|
||||
return canUninstallMod(modname) && doUninstallMod(modname);
|
||||
}
|
||||
|
||||
bool CModManager::enableMod(QString modname)
|
||||
bool ModStateController::enableMod(QString modname)
|
||||
{
|
||||
return canEnableMod(modname) && doEnableMod(modname, true);
|
||||
}
|
||||
|
||||
bool CModManager::disableMod(QString modname)
|
||||
bool ModStateController::disableMod(QString modname)
|
||||
{
|
||||
return canDisableMod(modname) && doEnableMod(modname, false);
|
||||
}
|
||||
|
||||
bool CModManager::canInstallMod(QString modname)
|
||||
bool ModStateController::canInstallMod(QString modname)
|
||||
{
|
||||
auto mod = modList->getMod(modname);
|
||||
|
||||
@@ -163,7 +153,7 @@ bool CModManager::canInstallMod(QString modname)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CModManager::canUninstallMod(QString modname)
|
||||
bool ModStateController::canUninstallMod(QString modname)
|
||||
{
|
||||
auto mod = modList->getMod(modname);
|
||||
|
||||
@@ -176,11 +166,11 @@ bool CModManager::canUninstallMod(QString modname)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CModManager::canEnableMod(QString modname)
|
||||
bool ModStateController::canEnableMod(QString modname)
|
||||
{
|
||||
auto mod = modList->getMod(modname);
|
||||
|
||||
if(mod.isEnabled())
|
||||
if(modList->isModEnabled(modname))
|
||||
return addError(modname, tr("Mod is already enabled"));
|
||||
|
||||
if(!mod.isInstalled())
|
||||
@@ -192,62 +182,61 @@ bool CModManager::canEnableMod(QString modname)
|
||||
|
||||
for(auto modEntry : mod.getDependencies())
|
||||
{
|
||||
if(!modList->hasMod(modEntry)) // required mod is not available
|
||||
if(!modList->isModExists(modEntry)) // required mod is not available
|
||||
return addError(modname, tr("Required mod %1 is missing").arg(modEntry));
|
||||
|
||||
CModEntry modData = modList->getMod(modEntry);
|
||||
ModState modData = modList->getMod(modEntry);
|
||||
|
||||
if(!modData.isCompatibilityPatch() && !modData.isEnabled())
|
||||
if(!modData.isCompatibility() && !modList->isModEnabled(modEntry))
|
||||
return addError(modname, tr("Required mod %1 is not enabled").arg(modEntry));
|
||||
}
|
||||
|
||||
for(QString modEntry : modList->getModList())
|
||||
for(QString modEntry : modList->getAllMods())
|
||||
{
|
||||
auto mod = modList->getMod(modEntry);
|
||||
|
||||
// "reverse conflict" - enabled mod has this one as conflict
|
||||
if(mod.isEnabled() && mod.getConflicts().contains(modname))
|
||||
if(modList->isModEnabled(modname) && mod.getConflicts().contains(modname))
|
||||
return addError(modname, tr("This mod conflicts with %1").arg(modEntry));
|
||||
}
|
||||
|
||||
for(auto modEntry : mod.getConflicts())
|
||||
{
|
||||
// check if conflicting mod installed and enabled
|
||||
if(modList->hasMod(modEntry) && modList->getMod(modEntry).isEnabled())
|
||||
if(modList->isModExists(modEntry) && modList->isModEnabled(modEntry))
|
||||
return addError(modname, tr("This mod conflicts with %1").arg(modEntry));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CModManager::canDisableMod(QString modname)
|
||||
bool ModStateController::canDisableMod(QString modname)
|
||||
{
|
||||
auto mod = modList->getMod(modname);
|
||||
|
||||
if(mod.isDisabled())
|
||||
if(!modList->isModEnabled(modname))
|
||||
return addError(modname, tr("Mod is already disabled"));
|
||||
|
||||
if(!mod.isInstalled())
|
||||
return addError(modname, tr("Mod must be installed first"));
|
||||
|
||||
for(QString modEntry : modList->getModList())
|
||||
for(QString modEntry : modList->getAllMods())
|
||||
{
|
||||
auto current = modList->getMod(modEntry);
|
||||
|
||||
if(current.getDependencies().contains(modname) && current.isEnabled())
|
||||
if(current.getDependencies().contains(modname) && modList->isModEnabled(modEntry))
|
||||
return addError(modname, tr("This mod is needed to run %1").arg(modEntry));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CModManager::doEnableMod(QString mod, bool on)
|
||||
bool ModStateController::doEnableMod(QString mod, bool on)
|
||||
{
|
||||
modSettings->setModActive(mod, on);
|
||||
modList->modChanged(mod);
|
||||
|
||||
//modSettings->setModActive(mod, on);
|
||||
//modList->modChanged(mod);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CModManager::doInstallMod(QString modname, QString archivePath)
|
||||
bool ModStateController::doInstallMod(QString modname, QString archivePath)
|
||||
{
|
||||
const auto destDir = CLauncherDirs::modsPath() + QChar{'/'};
|
||||
|
||||
@@ -301,13 +290,13 @@ bool CModManager::doInstallMod(QString modname, QString archivePath)
|
||||
removeModDir(destDir + upperLevel);
|
||||
|
||||
CResourceHandler::get("initial")->updateFilteredFiles([](const std::string &) { return true; });
|
||||
loadMods();
|
||||
modList->reloadRepositories();
|
||||
//loadMods();
|
||||
//modList->reloadRepositories();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CModManager::doUninstallMod(QString modname)
|
||||
bool ModStateController::doUninstallMod(QString modname)
|
||||
{
|
||||
ResourcePath resID(std::string("Mods/") + modname.toStdString(), EResType::DIRECTORY);
|
||||
// Get location of the mod, in case-insensitive way
|
||||
@@ -321,13 +310,13 @@ bool CModManager::doUninstallMod(QString modname)
|
||||
return addError(modname, tr("Mod is located in protected directory, please remove it manually:\n") + modFullDir.absolutePath());
|
||||
|
||||
CResourceHandler::get("initial")->updateFilteredFiles([](const std::string &){ return true; });
|
||||
loadMods();
|
||||
modList->reloadRepositories();
|
||||
//loadMods();
|
||||
//modList->reloadRepositories();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CModManager::removeModDir(QString path)
|
||||
bool ModStateController::removeModDir(QString path)
|
||||
{
|
||||
// issues 2673 and 2680 its why you do not recursively remove without sanity check
|
||||
QDir checkDir(path);
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* cmodmanager.h, part of VCMI engine
|
||||
* modstatecontroller.h, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
@@ -9,21 +9,25 @@
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "cmodlist.h"
|
||||
#include "modsettingsstorage.h"
|
||||
#include <QVector>
|
||||
|
||||
class CModManager : public QObject
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
class JsonNode;
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
||||
class ModStateModel;
|
||||
|
||||
class ModStateController : public QObject, public boost::noncopyable
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
CModList * modList;
|
||||
std::shared_ptr<ModStateModel> modList;
|
||||
|
||||
// check-free version of public method
|
||||
bool doEnableMod(QString mod, bool on);
|
||||
bool doInstallMod(QString mod, QString archivePath);
|
||||
bool doUninstallMod(QString mod);
|
||||
|
||||
std::shared_ptr<ModSettingsStorage> modSettings;
|
||||
QVariantMap localMods;
|
||||
|
||||
QStringList recentErrors;
|
||||
@@ -31,12 +35,10 @@ class CModManager : public QObject
|
||||
bool removeModDir(QString mod);
|
||||
|
||||
public:
|
||||
CModManager(CModList * modList);
|
||||
ModStateController(std::shared_ptr<ModStateModel> modList);
|
||||
~ModStateController();
|
||||
|
||||
void resetRepositories();
|
||||
void loadRepositories(QVector<QVariantMap> repomap);
|
||||
void loadModSettings();
|
||||
void loadMods();
|
||||
void loadRepositories(QVector<JsonNode> repositoriesList);
|
||||
|
||||
QStringList getErrors();
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* cmodlistmodel_moc.cpp, part of VCMI engine
|
||||
* modstateview_moc.cpp, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
@@ -8,7 +8,9 @@
|
||||
*
|
||||
*/
|
||||
#include "StdInc.h"
|
||||
#include "cmodlistmodel_moc.h"
|
||||
#include "modstateitemmodel_moc.h"
|
||||
|
||||
#include "modstatemodel.h"
|
||||
|
||||
#include <QIcon>
|
||||
|
||||
@@ -23,12 +25,12 @@ static const QString iconEnabledSubmod = ":/icons/submod-enabled.png";
|
||||
static const QString iconUpdate = ":/icons/mod-update.png";
|
||||
}
|
||||
|
||||
CModListModel::CModListModel(QObject * parent)
|
||||
ModStateItemModel::ModStateItemModel(QObject * parent)
|
||||
: QAbstractItemModel(parent)
|
||||
{
|
||||
}
|
||||
|
||||
QString CModListModel::modIndexToName(const QModelIndex & index) const
|
||||
QString ModStateItemModel::modIndexToName(const QModelIndex & index) const
|
||||
{
|
||||
if(index.isValid())
|
||||
{
|
||||
@@ -38,7 +40,7 @@ QString CModListModel::modIndexToName(const QModelIndex & index) const
|
||||
}
|
||||
|
||||
|
||||
QString CModListModel::modTypeName(QString modTypeID) const
|
||||
QString ModStateItemModel::modTypeName(QString modTypeID) const
|
||||
{
|
||||
static const QMap<QString, QString> modTypes = {
|
||||
{"Translation", tr("Translation")},
|
||||
@@ -71,28 +73,28 @@ QString CModListModel::modTypeName(QString modTypeID) const
|
||||
return tr("Other");
|
||||
}
|
||||
|
||||
QVariant CModListModel::getValue(const CModEntry & mod, int field) const
|
||||
QVariant ModStateItemModel::getValue(const ModState & mod, int field) const
|
||||
{
|
||||
switch(field)
|
||||
{
|
||||
case ModFields::STATUS_ENABLED:
|
||||
return mod.getModStatus() & (ModStatus::ENABLED | ModStatus::INSTALLED);
|
||||
return model->isModEnabled(mod.getID());
|
||||
|
||||
case ModFields::STATUS_UPDATE:
|
||||
return mod.getModStatus() & (ModStatus::UPDATEABLE | ModStatus::INSTALLED);
|
||||
return model->isModUpdateAvailable(mod.getID());
|
||||
|
||||
case ModFields::NAME:
|
||||
return mod.getValue("name");
|
||||
return mod.getName();
|
||||
|
||||
case ModFields::TYPE:
|
||||
return modTypeName(mod.getValue("modType").toString());
|
||||
return modTypeName(mod.getType());
|
||||
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
}
|
||||
|
||||
QVariant CModListModel::getText(const CModEntry & mod, int field) const
|
||||
QVariant ModStateItemModel::getText(const ModState & mod, int field) const
|
||||
{
|
||||
switch(field)
|
||||
{
|
||||
@@ -104,49 +106,52 @@ QVariant CModListModel::getText(const CModEntry & mod, int field) const
|
||||
}
|
||||
}
|
||||
|
||||
QVariant CModListModel::getIcon(const CModEntry & mod, int field) const
|
||||
QVariant ModStateItemModel::getIcon(const ModState & mod, int field) const
|
||||
{
|
||||
|
||||
if (field == ModFields::STATUS_ENABLED)
|
||||
{
|
||||
if (!model->isModInstalled(mod.getID()))
|
||||
return QVariant();
|
||||
|
||||
if(mod.isSubmod())
|
||||
{
|
||||
QString toplevelParent = mod.getName().section('.', 0, 0);
|
||||
if (getMod(toplevelParent).isDisabled())
|
||||
if (!model->isModEnabled(mod.getTopParentID()))
|
||||
{
|
||||
if (mod.isEnabled())
|
||||
if (model->isModEnabled(mod.getID()))
|
||||
return QIcon(ModStatus::iconEnabledSubmod);
|
||||
if(mod.isDisabled())
|
||||
else
|
||||
return QIcon(ModStatus::iconDisabledSubmod);
|
||||
}
|
||||
}
|
||||
|
||||
if (mod.isEnabled())
|
||||
if (model->isModEnabled(mod.getID()))
|
||||
return QIcon(ModStatus::iconEnabled);
|
||||
if(mod.isDisabled())
|
||||
else
|
||||
return QIcon(ModStatus::iconDisabled);
|
||||
}
|
||||
|
||||
if(field == ModFields::STATUS_UPDATE)
|
||||
{
|
||||
if (mod.isUpdateable())
|
||||
if (model->isModUpdateAvailable(mod.getID()))
|
||||
return QIcon(ModStatus::iconUpdate);
|
||||
if(!mod.isInstalled())
|
||||
if (!model->isModInstalled(mod.getID()))
|
||||
return QIcon(ModStatus::iconDownload);
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
QVariant CModListModel::getTextAlign(int field) const
|
||||
QVariant ModStateItemModel::getTextAlign(int field) const
|
||||
{
|
||||
return QVariant(Qt::AlignLeft | Qt::AlignVCenter);
|
||||
}
|
||||
|
||||
QVariant CModListModel::data(const QModelIndex & index, int role) const
|
||||
QVariant ModStateItemModel::data(const QModelIndex & index, int role) const
|
||||
{
|
||||
if(index.isValid())
|
||||
{
|
||||
auto mod = getMod(modIndexToName(index));
|
||||
auto mod = model->getMod(modIndexToName(index));
|
||||
|
||||
switch(role)
|
||||
{
|
||||
@@ -165,24 +170,24 @@ QVariant CModListModel::data(const QModelIndex & index, int role) const
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
int CModListModel::rowCount(const QModelIndex & index) const
|
||||
int ModStateItemModel::rowCount(const QModelIndex & index) const
|
||||
{
|
||||
if(index.isValid())
|
||||
return modIndex[modIndexToName(index)].size();
|
||||
return modIndex[""].size();
|
||||
}
|
||||
|
||||
int CModListModel::columnCount(const QModelIndex &) const
|
||||
int ModStateItemModel::columnCount(const QModelIndex &) const
|
||||
{
|
||||
return ModFields::COUNT;
|
||||
}
|
||||
|
||||
Qt::ItemFlags CModListModel::flags(const QModelIndex &) const
|
||||
Qt::ItemFlags ModStateItemModel::flags(const QModelIndex &) const
|
||||
{
|
||||
return Qt::ItemIsSelectable | Qt::ItemIsEnabled;
|
||||
}
|
||||
|
||||
QVariant CModListModel::headerData(int section, Qt::Orientation orientation, int role) const
|
||||
QVariant ModStateItemModel::headerData(int section, Qt::Orientation orientation, int role) const
|
||||
{
|
||||
static const QString header[ModFields::COUNT] =
|
||||
{
|
||||
@@ -197,32 +202,23 @@ QVariant CModListModel::headerData(int section, Qt::Orientation orientation, int
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
void CModListModel::reloadRepositories()
|
||||
void ModStateItemModel::reloadRepositories()
|
||||
{
|
||||
beginResetModel();
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
void CModListModel::resetRepositories()
|
||||
void ModStateItemModel::modChanged(QString modID)
|
||||
{
|
||||
beginResetModel();
|
||||
CModList::resetRepositories();
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
void CModListModel::modChanged(QString modID)
|
||||
{
|
||||
CModList::modChanged(modID);
|
||||
|
||||
int index = modNameToID.indexOf(modID);
|
||||
QModelIndex parent = this->parent(createIndex(0, 0, index));
|
||||
int row = modIndex[modIndexToName(parent)].indexOf(modID);
|
||||
emit dataChanged(createIndex(row, 0, index), createIndex(row, 4, index));
|
||||
}
|
||||
|
||||
void CModListModel::endResetModel()
|
||||
void ModStateItemModel::endResetModel()
|
||||
{
|
||||
modNameToID = getModList();
|
||||
modNameToID = model->getAllMods();
|
||||
modIndex.clear();
|
||||
for(const QString & str : modNameToID)
|
||||
{
|
||||
@@ -238,7 +234,7 @@ void CModListModel::endResetModel()
|
||||
QAbstractItemModel::endResetModel();
|
||||
}
|
||||
|
||||
QModelIndex CModListModel::index(int row, int column, const QModelIndex & parent) const
|
||||
QModelIndex ModStateItemModel::index(int row, int column, const QModelIndex & parent) const
|
||||
{
|
||||
if(parent.isValid())
|
||||
{
|
||||
@@ -253,7 +249,7 @@ QModelIndex CModListModel::index(int row, int column, const QModelIndex & parent
|
||||
return QModelIndex();
|
||||
}
|
||||
|
||||
QModelIndex CModListModel::parent(const QModelIndex & child) const
|
||||
QModelIndex ModStateItemModel::parent(const QModelIndex & child) const
|
||||
{
|
||||
QString modID = modNameToID[child.internalId()];
|
||||
for(auto entry = modIndex.begin(); entry != modIndex.end(); entry++) // because using range-for entry type is QMap::value_type oO
|
||||
@@ -266,26 +262,25 @@ QModelIndex CModListModel::parent(const QModelIndex & child) const
|
||||
return QModelIndex();
|
||||
}
|
||||
|
||||
void CModFilterModel::setTypeFilter(int filteredType, int filterMask)
|
||||
void CModFilterModel::setTypeFilter(ModFilterMask newFilterMask)
|
||||
{
|
||||
this->filterMask = filterMask;
|
||||
this->filteredType = filteredType;
|
||||
filterMask = newFilterMask;
|
||||
invalidateFilter();
|
||||
}
|
||||
|
||||
bool CModFilterModel::filterMatchesThis(const QModelIndex & source) const
|
||||
{
|
||||
CModEntry mod = base->getMod(source.data(ModRoles::ModNameRole).toString());
|
||||
return (mod.getModStatus() & filterMask) == filteredType &&
|
||||
//QString modID =source.data(ModRoles::ModNameRole).toString();
|
||||
//ModState mod = base->model->getMod(modID);
|
||||
return /*(mod.getModStatus() & filterMask) == filteredType &&*/
|
||||
QSortFilterProxyModel::filterAcceptsRow(source.row(), source.parent());
|
||||
}
|
||||
|
||||
bool CModFilterModel::filterAcceptsRow(int source_row, const QModelIndex & source_parent) const
|
||||
{
|
||||
QModelIndex index = base->index(source_row, 0, source_parent);
|
||||
|
||||
CModEntry mod = base->getMod(index.data(ModRoles::ModNameRole).toString());
|
||||
if (!mod.isVisible())
|
||||
QString modID = index.data(ModRoles::ModNameRole).toString();
|
||||
if (base->model->isModVisible(modID))
|
||||
return false;
|
||||
|
||||
if(filterMatchesThis(index))
|
||||
@@ -309,8 +304,8 @@ bool CModFilterModel::filterAcceptsRow(int source_row, const QModelIndex & sourc
|
||||
return false;
|
||||
}
|
||||
|
||||
CModFilterModel::CModFilterModel(CModListModel * model, QObject * parent)
|
||||
: QSortFilterProxyModel(parent), base(model), filteredType(ModStatus::MASK_NONE), filterMask(ModStatus::MASK_NONE)
|
||||
CModFilterModel::CModFilterModel(ModStateItemModel * model, QObject * parent)
|
||||
: QSortFilterProxyModel(parent), base(model), filterMask(ModFilterMask::ALL)
|
||||
{
|
||||
setSourceModel(model);
|
||||
setSortRole(ModRoles::ValueRole);
|
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* cmodlistmodel_moc.h, part of VCMI engine
|
||||
* modstateview_moc.h, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
@@ -9,11 +9,12 @@
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "cmodlist.h"
|
||||
|
||||
#include <QAbstractTableModel>
|
||||
#include <QSortFilterProxyModel>
|
||||
|
||||
class ModStateModel;
|
||||
class ModState;
|
||||
|
||||
namespace ModFields
|
||||
{
|
||||
enum EModFields
|
||||
@@ -26,6 +27,16 @@ enum EModFields
|
||||
};
|
||||
}
|
||||
|
||||
enum class ModFilterMask : uint8_t
|
||||
{
|
||||
ALL,
|
||||
AVAILABLE,
|
||||
INSTALLED,
|
||||
UPDATEABLE,
|
||||
ENABLED,
|
||||
DISABLED
|
||||
};
|
||||
|
||||
namespace ModRoles
|
||||
{
|
||||
enum EModRoles
|
||||
@@ -35,14 +46,17 @@ enum EModRoles
|
||||
};
|
||||
}
|
||||
|
||||
class CModListModel : public QAbstractItemModel, public CModList
|
||||
class ModStateItemModel : public QAbstractItemModel
|
||||
{
|
||||
friend class CModFilterModel;
|
||||
Q_OBJECT
|
||||
|
||||
QVector<QString> modNameToID;
|
||||
std::shared_ptr<ModStateModel> model;
|
||||
|
||||
QStringList modNameToID;
|
||||
// contains mapping mod -> numbered list of submods
|
||||
// mods that have no parent located under "" key (empty string)
|
||||
QMap<QString, QVector<QString>> modIndex;
|
||||
QMap<QString, QStringList> modIndex;
|
||||
|
||||
void endResetModel();
|
||||
|
||||
@@ -50,17 +64,16 @@ class CModListModel : public QAbstractItemModel, public CModList
|
||||
QString modTypeName(QString modTypeID) const;
|
||||
|
||||
QVariant getTextAlign(int field) const;
|
||||
QVariant getValue(const CModEntry & mod, int field) const;
|
||||
QVariant getText(const CModEntry & mod, int field) const;
|
||||
QVariant getIcon(const CModEntry & mod, int field) const;
|
||||
QVariant getValue(const ModState & mod, int field) const;
|
||||
QVariant getText(const ModState & mod, int field) const;
|
||||
QVariant getIcon(const ModState & mod, int field) const;
|
||||
|
||||
public:
|
||||
explicit CModListModel(QObject * parent = nullptr);
|
||||
explicit ModStateItemModel(QObject * parent = nullptr);
|
||||
|
||||
/// CModListContainer overrides
|
||||
void resetRepositories() override;
|
||||
void reloadRepositories() override;
|
||||
void modChanged(QString modID) override;
|
||||
void reloadRepositories();
|
||||
void modChanged(QString modID);
|
||||
|
||||
QVariant data(const QModelIndex & index, int role) const override;
|
||||
QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
|
||||
@@ -72,25 +85,19 @@ public:
|
||||
QModelIndex parent(const QModelIndex & child) const override;
|
||||
|
||||
Qt::ItemFlags flags(const QModelIndex & index) const override;
|
||||
|
||||
signals:
|
||||
|
||||
public slots:
|
||||
|
||||
};
|
||||
|
||||
class CModFilterModel : public QSortFilterProxyModel
|
||||
{
|
||||
CModListModel * base;
|
||||
int filteredType;
|
||||
int filterMask;
|
||||
ModStateItemModel * base;
|
||||
ModFilterMask filterMask;
|
||||
|
||||
bool filterMatchesThis(const QModelIndex & source) const;
|
||||
|
||||
bool filterAcceptsRow(int source_row, const QModelIndex & source_parent) const override;
|
||||
|
||||
public:
|
||||
void setTypeFilter(int filteredType, int filterMask);
|
||||
void setTypeFilter(ModFilterMask filterMask);
|
||||
|
||||
CModFilterModel(CModListModel * model, QObject * parent = nullptr);
|
||||
CModFilterModel(ModStateItemModel * model, QObject * parent = nullptr);
|
||||
};
|
73
launcher/modManager/modstatemodel.cpp
Normal file
73
launcher/modManager/modstatemodel.cpp
Normal file
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* modstatemodel.cpp, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
* License: GNU General Public License v2.0 or later
|
||||
* Full text of license available in license.txt file, in main folder
|
||||
*
|
||||
*/
|
||||
#include "StdInc.h"
|
||||
#include "modstatemodel.h"
|
||||
|
||||
#include "../../lib/modding/ModManager.h"
|
||||
|
||||
ModStateModel::ModStateModel()
|
||||
:modManager(std::make_unique<ModManager>())
|
||||
{}
|
||||
|
||||
ModStateModel::~ModStateModel() = default;
|
||||
|
||||
void ModStateModel::setRepositories(QVector<JsonNode> repositoriesList)
|
||||
{
|
||||
//TODO
|
||||
}
|
||||
|
||||
ModState ModStateModel::getMod(QString modName) const
|
||||
{
|
||||
return ModState(modManager->getModDescription(modName.toStdString()));
|
||||
}
|
||||
|
||||
template<typename Container>
|
||||
QStringList stringListStdToQt(const Container & container)
|
||||
{
|
||||
QStringList result;
|
||||
for (const auto & str : container)
|
||||
result.push_back(QString::fromStdString(str));
|
||||
return result;
|
||||
}
|
||||
|
||||
QStringList ModStateModel::getAllMods() const
|
||||
{
|
||||
return stringListStdToQt(modManager->getActiveMods());
|
||||
}
|
||||
|
||||
QStringList ModStateModel::getSubmods(QString modName) const
|
||||
{
|
||||
return {}; //TODO
|
||||
}
|
||||
|
||||
bool ModStateModel::isModExists(QString modName) const
|
||||
{
|
||||
return vstd::contains(modManager->getAllMods(), modName.toStdString());
|
||||
}
|
||||
|
||||
bool ModStateModel::isModInstalled(QString modName) const
|
||||
{
|
||||
return getMod(modName).isInstalled();
|
||||
}
|
||||
|
||||
bool ModStateModel::isModEnabled(QString modName) const
|
||||
{
|
||||
return getMod(modName).isEnabled(); // TODO
|
||||
}
|
||||
|
||||
bool ModStateModel::isModUpdateAvailable(QString modName) const
|
||||
{
|
||||
return getMod(modName).isUpdateAvailable();
|
||||
}
|
||||
|
||||
bool ModStateModel::isModVisible(QString modName) const
|
||||
{
|
||||
return getMod(modName).isVisible();
|
||||
}
|
40
launcher/modManager/modstatemodel.h
Normal file
40
launcher/modManager/modstatemodel.h
Normal file
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* modstatemodel.h, part of VCMI engine
|
||||
*
|
||||
* Authors: listed in file AUTHORS in main folder
|
||||
*
|
||||
* License: GNU General Public License v2.0 or later
|
||||
* Full text of license available in license.txt file, in main folder
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "modstate.h"
|
||||
|
||||
VCMI_LIB_NAMESPACE_BEGIN
|
||||
class JsonNode;
|
||||
class ModManager;
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
||||
/// Class that represent current state of available mods
|
||||
/// Provides Qt-based interface to library class ModManager
|
||||
class ModStateModel
|
||||
{
|
||||
std::unique_ptr<ModManager> modManager;
|
||||
|
||||
public:
|
||||
ModStateModel();
|
||||
~ModStateModel();
|
||||
|
||||
void setRepositories(QVector<JsonNode> repositoriesList);
|
||||
|
||||
ModState getMod(QString modName) const;
|
||||
QStringList getAllMods() const;
|
||||
QStringList getSubmods(QString modName) const;
|
||||
|
||||
bool isModExists(QString modName) const;
|
||||
bool isModInstalled(QString modName) const;
|
||||
bool isModEnabled(QString modName) const;
|
||||
bool isModUpdateAvailable(QString modName) const;
|
||||
bool isModVisible(QString modName) const;
|
||||
};
|
@@ -162,48 +162,38 @@ void LibClasses::loadModFilesystem()
|
||||
logGlobal->info("\tMod filesystems: %d ms", loadTime.getDiff());
|
||||
}
|
||||
|
||||
static void logHandlerLoaded(const std::string & name, CStopWatch & timer)
|
||||
{
|
||||
logGlobal->info("\t\t %s handler: %d ms", name, timer.getDiff());
|
||||
}
|
||||
|
||||
template <class Handler> void createHandler(std::shared_ptr<Handler> & handler, const std::string &name, CStopWatch &timer)
|
||||
template <class Handler> void createHandler(std::shared_ptr<Handler> & handler)
|
||||
{
|
||||
handler = std::make_shared<Handler>();
|
||||
logHandlerLoaded(name, timer);
|
||||
}
|
||||
|
||||
void LibClasses::init(bool onlyEssential)
|
||||
{
|
||||
CStopWatch pomtime;
|
||||
CStopWatch totalTime;
|
||||
|
||||
createHandler(settingsHandler, "Game Settings", pomtime);
|
||||
createHandler(settingsHandler);
|
||||
modh->initializeConfig();
|
||||
|
||||
createHandler(generaltexth, "General text", pomtime);
|
||||
createHandler(bth, "Bonus type", pomtime);
|
||||
createHandler(roadTypeHandler, "Road", pomtime);
|
||||
createHandler(riverTypeHandler, "River", pomtime);
|
||||
createHandler(terrainTypeHandler, "Terrain", pomtime);
|
||||
createHandler(heroh, "Hero", pomtime);
|
||||
createHandler(heroclassesh, "Hero classes", pomtime);
|
||||
createHandler(arth, "Artifact", pomtime);
|
||||
createHandler(creh, "Creature", pomtime);
|
||||
createHandler(townh, "Town", pomtime);
|
||||
createHandler(biomeHandler, "Obstacle set", pomtime);
|
||||
createHandler(objh, "Object", pomtime);
|
||||
createHandler(objtypeh, "Object types information", pomtime);
|
||||
createHandler(spellh, "Spell", pomtime);
|
||||
createHandler(skillh, "Skill", pomtime);
|
||||
createHandler(terviewh, "Terrain view pattern", pomtime);
|
||||
createHandler(tplh, "Template", pomtime); //templates need already resolved identifiers (refactor?)
|
||||
createHandler(generaltexth);
|
||||
createHandler(bth);
|
||||
createHandler(roadTypeHandler);
|
||||
createHandler(riverTypeHandler);
|
||||
createHandler(terrainTypeHandler);
|
||||
createHandler(heroh);
|
||||
createHandler(heroclassesh);
|
||||
createHandler(arth);
|
||||
createHandler(creh);
|
||||
createHandler(townh);
|
||||
createHandler(biomeHandler);
|
||||
createHandler(objh);
|
||||
createHandler(objtypeh);
|
||||
createHandler(spellh);
|
||||
createHandler(skillh);
|
||||
createHandler(terviewh);
|
||||
createHandler(tplh); //templates need already resolved identifiers (refactor?)
|
||||
#if SCRIPTING_ENABLED
|
||||
createHandler(scriptHandler, "Script", pomtime);
|
||||
createHandler(scriptHandler);
|
||||
#endif
|
||||
createHandler(battlefieldsHandler, "Battlefields", pomtime);
|
||||
createHandler(obstacleHandler, "Obstacles", pomtime);
|
||||
logGlobal->info("\tInitializing handlers: %d ms", totalTime.getDiff());
|
||||
createHandler(battlefieldsHandler);
|
||||
createHandler(obstacleHandler);
|
||||
|
||||
modh->load();
|
||||
modh->afterLoad(onlyEssential);
|
||||
|
@@ -259,8 +259,8 @@ void CModHandler::initializeConfig()
|
||||
for(const TModID & modName : getActiveMods())
|
||||
{
|
||||
const auto & mod = getModInfo(modName);
|
||||
if (!mod.getConfig()["settings"].isNull())
|
||||
VLC->settingsHandler->loadBase(mod.getConfig()["settings"]);
|
||||
if (!mod.getLocalConfig()["settings"].isNull())
|
||||
VLC->settingsHandler->loadBase(mod.getLocalConfig()["settings"]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -271,8 +271,8 @@ void CModHandler::loadTranslation(const TModID & modName)
|
||||
std::string preferredLanguage = VLC->generaltexth->getPreferredLanguage();
|
||||
std::string modBaseLanguage = getModInfo(modName).getBaseLanguage();
|
||||
|
||||
JsonNode baseTranslation = JsonUtils::assembleFromFiles(mod.getConfig()["translations"]);
|
||||
JsonNode extraTranslation = JsonUtils::assembleFromFiles(mod.getConfig()[preferredLanguage]["translations"]);
|
||||
JsonNode baseTranslation = JsonUtils::assembleFromFiles(mod.getLocalConfig()["translations"]);
|
||||
JsonNode extraTranslation = JsonUtils::assembleFromFiles(mod.getLocalConfig()[preferredLanguage]["translations"]);
|
||||
|
||||
VLC->generaltexth->loadTranslationOverrides(modName, modBaseLanguage, baseTranslation);
|
||||
VLC->generaltexth->loadTranslationOverrides(modName, preferredLanguage, extraTranslation);
|
||||
|
@@ -297,7 +297,7 @@ void CContentHandler::afterLoadFinalization()
|
||||
|
||||
void CContentHandler::preloadData(const ModDescription & mod)
|
||||
{
|
||||
preloadModData(mod.getID(), mod.getConfig(), false);
|
||||
preloadModData(mod.getID(), mod.getLocalConfig(), false);
|
||||
|
||||
// bool validate = validateMod(mod);
|
||||
//
|
||||
|
@@ -19,7 +19,7 @@ VCMI_LIB_NAMESPACE_BEGIN
|
||||
|
||||
ModDescription::ModDescription(const TModID & fullID, const JsonNode & config)
|
||||
: identifier(fullID)
|
||||
, config(std::make_unique<JsonNode>(config))
|
||||
, localConfig(std::make_unique<JsonNode>(config))
|
||||
, dependencies(loadModList(config["depends"]))
|
||||
, softDependencies(loadModList(config["softDepends"]))
|
||||
, conflicts(loadModList(config["conflicts"]))
|
||||
@@ -72,27 +72,42 @@ const std::string & ModDescription::getBaseLanguage() const
|
||||
{
|
||||
static const std::string defaultLanguage = "english";
|
||||
|
||||
return getConfig()["language"].isString() ? getConfig()["language"].String() : defaultLanguage;
|
||||
return getLocalConfig()["language"].isString() ? getLocalConfig()["language"].String() : defaultLanguage;
|
||||
}
|
||||
|
||||
const std::string & ModDescription::getName() const
|
||||
{
|
||||
return getConfig()["name"].String();
|
||||
return getLocalConfig()["name"].String();
|
||||
}
|
||||
|
||||
const JsonNode & ModDescription::getFilesystemConfig() const
|
||||
{
|
||||
return getConfig()["filesystem"];
|
||||
return getLocalConfig()["filesystem"];
|
||||
}
|
||||
|
||||
const JsonNode & ModDescription::getConfig() const
|
||||
const JsonNode & ModDescription::getLocalConfig() const
|
||||
{
|
||||
return *config;
|
||||
return *localConfig;
|
||||
}
|
||||
|
||||
const JsonNode & ModDescription::getValue(const std::string & keyName) const
|
||||
{
|
||||
return getLocalConfig()[keyName];
|
||||
}
|
||||
|
||||
const JsonNode & ModDescription::getLocalValue(const std::string & keyName) const
|
||||
{
|
||||
return getLocalConfig()[keyName];
|
||||
}
|
||||
|
||||
const JsonNode & ModDescription::getRepositoryValue(const std::string & keyName) const
|
||||
{
|
||||
return (*repositoryConfig)[keyName];
|
||||
}
|
||||
|
||||
CModVersion ModDescription::getVersion() const
|
||||
{
|
||||
return CModVersion::fromString(getConfig()["version"].String());
|
||||
return CModVersion::fromString(getLocalConfig()["version"].String());
|
||||
}
|
||||
|
||||
ModVerificationInfo ModDescription::getVerificationInfo() const
|
||||
@@ -108,17 +123,22 @@ ModVerificationInfo ModDescription::getVerificationInfo() const
|
||||
|
||||
bool ModDescription::isCompatibility() const
|
||||
{
|
||||
return getConfig()["modType"].String() == "Compatibility";
|
||||
return getLocalConfig()["modType"].String() == "Compatibility";
|
||||
}
|
||||
|
||||
bool ModDescription::isTranslation() const
|
||||
{
|
||||
return getConfig()["modType"].String() == "Translation";
|
||||
return getLocalConfig()["modType"].String() == "Translation";
|
||||
}
|
||||
|
||||
bool ModDescription::keepDisabled() const
|
||||
{
|
||||
return getConfig()["keepDisabled"].Bool();
|
||||
return getLocalConfig()["keepDisabled"].Bool();
|
||||
}
|
||||
|
||||
bool ModDescription::isInstalled() const
|
||||
{
|
||||
return !localConfig->isNull();
|
||||
}
|
||||
|
||||
bool ModDescription::affectsGameplay() const
|
||||
|
@@ -26,12 +26,14 @@ class DLL_LINKAGE ModDescription : boost::noncopyable
|
||||
TModSet softDependencies;
|
||||
TModSet conflicts;
|
||||
|
||||
std::unique_ptr<JsonNode> config;
|
||||
std::unique_ptr<JsonNode> localConfig;
|
||||
std::unique_ptr<JsonNode> repositoryConfig;
|
||||
|
||||
TModSet loadModList(const JsonNode & configNode) const;
|
||||
|
||||
public:
|
||||
ModDescription(const TModID & fullID, const JsonNode & config);
|
||||
ModDescription(const TModID & fullID, const JsonNode & localConfig);
|
||||
ModDescription(const TModID & fullID, const JsonNode & localConfig, const JsonNode & repositoryConfig);
|
||||
~ModDescription();
|
||||
|
||||
const TModID & getID() const;
|
||||
@@ -45,7 +47,10 @@ public:
|
||||
const std::string & getName() const;
|
||||
|
||||
const JsonNode & getFilesystemConfig() const;
|
||||
const JsonNode & getConfig() const;
|
||||
const JsonNode & getLocalConfig() const;
|
||||
const JsonNode & getValue(const std::string & keyName) const;
|
||||
const JsonNode & getLocalValue(const std::string & keyName) const;
|
||||
const JsonNode & getRepositoryValue(const std::string & keyName) const;
|
||||
|
||||
CModVersion getVersion() const;
|
||||
ModVerificationInfo getVerificationInfo() const;
|
||||
@@ -54,6 +59,7 @@ public:
|
||||
bool isCompatibility() const;
|
||||
bool isTranslation() const;
|
||||
bool keepDisabled() const;
|
||||
bool isInstalled() const;
|
||||
};
|
||||
|
||||
VCMI_LIB_NAMESPACE_END
|
||||
|
@@ -203,7 +203,7 @@ std::vector<TModID> ModsPresetState::getActiveMods() const
|
||||
|
||||
for(const auto & activeMod : activeRootMods)
|
||||
{
|
||||
activeRootMods.push_back(activeMod);
|
||||
allActiveMods.push_back(activeMod);
|
||||
|
||||
for(const auto & submod : getModSettings(activeMod))
|
||||
if(submod.second)
|
||||
@@ -212,7 +212,7 @@ std::vector<TModID> ModsPresetState::getActiveMods() const
|
||||
return allActiveMods;
|
||||
}
|
||||
|
||||
ModsStorage::ModsStorage(const std::vector<TModID> & modsToLoad)
|
||||
ModsStorage::ModsStorage(const std::vector<TModID> & modsToLoad, const std::vector<JsonNode> & repositoryList)
|
||||
{
|
||||
JsonNode coreModConfig(JsonPath::builtin("config/gameConfig.json"));
|
||||
coreModConfig.setModScope(ModScope::scopeBuiltin());
|
||||
@@ -245,14 +245,21 @@ const ModDescription & ModsStorage::getMod(const TModID & fullID) const
|
||||
}
|
||||
|
||||
ModManager::ModManager()
|
||||
:ModManager(std::vector<JsonNode>())
|
||||
{
|
||||
}
|
||||
|
||||
ModManager::ModManager(const std::vector<JsonNode> & repositoryList)
|
||||
: modsState(std::make_unique<ModsState>())
|
||||
, modsPreset(std::make_unique<ModsPresetState>())
|
||||
{
|
||||
|
||||
eraseMissingModsFromPreset();
|
||||
//TODO: load only active mods & all their submods in game mode
|
||||
modsStorage = std::make_unique<ModsStorage>(modsState->getAllMods(), repositoryList);
|
||||
addNewModsToPreset();
|
||||
|
||||
std::vector<TModID> desiredModList = modsPreset->getActiveMods();
|
||||
modsStorage = std::make_unique<ModsStorage>(desiredModList);
|
||||
generateLoadOrder(desiredModList);
|
||||
}
|
||||
|
||||
@@ -273,6 +280,11 @@ const TModList & ModManager::getActiveMods() const
|
||||
return activeMods;
|
||||
}
|
||||
|
||||
const TModList & ModManager::getAllMods() const
|
||||
{
|
||||
return activeMods; //TODO
|
||||
}
|
||||
|
||||
void ModManager::eraseMissingModsFromPreset()
|
||||
{
|
||||
const TModList & installedMods = modsState->getAllMods();
|
||||
@@ -383,6 +395,7 @@ void ModManager::generateLoadOrder(std::vector<TModID> modsToResolve)
|
||||
break;
|
||||
}
|
||||
|
||||
assert(!sortedValidMods.empty());
|
||||
activeMods = sortedValidMods;
|
||||
brokenMods = modsToResolve;
|
||||
}
|
||||
|
@@ -69,13 +69,13 @@ class ModsStorage : boost::noncopyable
|
||||
std::map<TModID, ModDescription> mods;
|
||||
|
||||
public:
|
||||
ModsStorage(const TModList & modsToLoad);
|
||||
ModsStorage(const TModList & modsToLoad, const std::vector<JsonNode> & repositoryList);
|
||||
|
||||
const ModDescription & getMod(const TModID & fullID) const;
|
||||
};
|
||||
|
||||
/// Provides public interface to access mod state
|
||||
class ModManager : boost::noncopyable
|
||||
class DLL_LINKAGE ModManager : boost::noncopyable
|
||||
{
|
||||
/// all currently active mods, in their load order
|
||||
TModList activeMods;
|
||||
@@ -92,11 +92,13 @@ class ModManager : boost::noncopyable
|
||||
void addNewModsToPreset();
|
||||
|
||||
public:
|
||||
ModManager(const std::vector<JsonNode> & repositoryList);
|
||||
ModManager();
|
||||
~ModManager();
|
||||
|
||||
const ModDescription & getModDescription(const TModID & modID) const;
|
||||
const TModList & getActiveMods() const;
|
||||
const TModList & getAllMods() const;
|
||||
bool isModActive(const TModID & modID) const;
|
||||
};
|
||||
|
||||
|
Reference in New Issue
Block a user