feat: add requireBy and requires columns

Signed-off-by: Trial97 <alexandru.tripon97@gmail.com>
This commit is contained in:
Trial97 2025-05-03 13:27:40 +03:00
parent bc383abfda
commit 2b62b4281f
No known key found for this signature in database
GPG Key ID: 55EF5DA53DB36318
5 changed files with 152 additions and 10 deletions

View File

@ -106,6 +106,20 @@ int Mod::compare(const Resource& other, SortType type) const
return compare_result;
break;
}
case SortType::REQUIRED_BY: {
if (requiredByCount() > cast_other->requiredByCount())
return 1;
if (requiredByCount() < cast_other->requiredByCount())
return -1;
break;
}
case SortType::REQUIRES: {
if (requiresCount() > cast_other->requiresCount())
return 1;
if (requiresCount() < cast_other->requiresCount())
return -1;
break;
}
}
return 0;
}
@ -289,3 +303,19 @@ QStringList Mod::dependencies() const
{
return details().dependencies;
}
int Mod::requiredByCount() const
{
return m_requiredByCount;
}
int Mod::requiresCount() const
{
return m_requiresCount;
}
void Mod::setRequiredByCount(int value)
{
m_requiredByCount = value;
}
void Mod::setRequiresCount(int value)
{
m_requiresCount = value;
}

View File

@ -74,6 +74,12 @@ class Mod : public Resource {
auto releaseType() const -> QString;
QStringList dependencies() const;
int requiredByCount() const;
int requiresCount() const;
void setRequiredByCount(int value);
void setRequiresCount(int value);
/** Get the intneral path to the mod's icon file*/
QString iconPath() const { return m_local_details.icon_file; }
/** Gets the icon of the mod, converted to a QPixmap for drawing, and scaled to size. */
@ -105,4 +111,7 @@ class Mod : public Resource {
bool wasEverUsed = false;
bool wasReadAttempt = false;
} mutable m_packImageCacheKey;
int m_requiredByCount = 0;
int m_requiresCount = 0;
};

View File

@ -48,25 +48,31 @@
#include <QThreadPool>
#include <QUrl>
#include <QUuid>
#include <algorithm>
#include "Application.h"
#include "minecraft/mod/tasks/LocalModParseTask.h"
#include "modplatform/ModIndex.h"
ModFolderModel::ModFolderModel(const QDir& dir, BaseInstance* instance, bool is_indexed, bool create_dir, QObject* parent)
: ResourceFolderModel(QDir(dir), instance, is_indexed, create_dir, parent)
{
m_column_names = QStringList({ "Enable", "Image", "Name", "Version", "Last Modified", "Provider", "Size", "Side", "Loaders",
"Minecraft Versions", "Release Type" });
m_column_names_translated = QStringList({ tr("Enable"), tr("Image"), tr("Name"), tr("Version"), tr("Last Modified"), tr("Provider"),
tr("Size"), tr("Side"), tr("Loaders"), tr("Minecraft Versions"), tr("Release Type") });
m_column_sort_keys = { SortType::ENABLED, SortType::NAME, SortType::NAME, SortType::VERSION,
SortType::DATE, SortType::PROVIDER, SortType::SIZE, SortType::SIDE,
SortType::LOADERS, SortType::MC_VERSIONS, SortType::RELEASE_TYPE };
"Minecraft Versions", "Release Type", "Requires", "Required by" });
m_column_names_translated =
QStringList({ tr("Enable"), tr("Image"), tr("Name"), tr("Version"), tr("Last Modified"), tr("Provider"), tr("Size"), tr("Side"),
tr("Loaders"), tr("Minecraft Versions"), tr("Release Type"), tr("Requires "), tr("Required by") });
m_column_sort_keys = { SortType::ENABLED, SortType::NAME, SortType::NAME, SortType::VERSION, SortType::DATE,
SortType::PROVIDER, SortType::SIZE, SortType::SIDE, SortType::LOADERS, SortType::MC_VERSIONS,
SortType::RELEASE_TYPE, SortType::REQUIRES, SortType::REQUIRED_BY };
m_column_resize_modes = { QHeaderView::Interactive, QHeaderView::Interactive, QHeaderView::Stretch, QHeaderView::Interactive,
QHeaderView::Interactive, QHeaderView::Interactive, QHeaderView::Interactive, QHeaderView::Interactive,
QHeaderView::Interactive, QHeaderView::Interactive, QHeaderView::Interactive };
m_columnsHideable = { false, true, false, true, true, true, true, true, true, true, true };
QHeaderView::Interactive, QHeaderView::Interactive, QHeaderView::Interactive, QHeaderView::Interactive,
QHeaderView::Interactive };
m_columnsHideable = { false, true, false, true, true, true, true, true, true, true, true, true, true };
connect(this, &ModFolderModel::parseFinished, this, &ModFolderModel::onParseFinished);
}
QVariant ModFolderModel::data(const QModelIndex& index, int role) const
@ -110,8 +116,15 @@ QVariant ModFolderModel::data(const QModelIndex& index, int role) const
case ReleaseTypeColumn: {
return at(row).releaseType();
}
case SizeColumn:
case SizeColumn: {
return at(row).sizeStr();
}
case RequiredByColumn: {
return at(row).requiredByCount();
}
case RequiresColumn: {
return at(row).requiresCount();
}
default:
return QVariant();
}
@ -168,6 +181,8 @@ QVariant ModFolderModel::headerData(int section, [[maybe_unused]] Qt::Orientatio
case McVersionsColumn:
case ReleaseTypeColumn:
case SizeColumn:
case RequiredByColumn:
case RequiresColumn:
return columnNames().at(section);
default:
return QVariant();
@ -195,6 +210,10 @@ QVariant ModFolderModel::headerData(int section, [[maybe_unused]] Qt::Orientatio
return tr("The release type.");
case SizeColumn:
return tr("The size of the mod.");
case RequiredByColumn:
return tr("Number of mods for what this is needed.");
case RequiresColumn:
return tr("Number of mods that this requires.");
default:
return QVariant();
}
@ -240,3 +259,64 @@ void ModFolderModel::onParseSucceeded(int ticket, QString mod_id)
emit dataChanged(index(row), index(row, columnCount(QModelIndex()) - 1));
}
void ModFolderModel::onParseFinished()
{
if (hasPendingParseTasks()) {
return;
}
auto mods = allMods();
auto findById = [mods](QString modId) -> Mod* {
auto found = std::find_if(mods.begin(), mods.end(), [modId](Mod* m) { return m->mod_id() == modId; });
return found != mods.end() ? *found : nullptr;
};
auto findByProjectID = [mods](QVariant modId, ModPlatform::ResourceProvider provider) -> Mod* {
auto found = std::find_if(mods.begin(), mods.end(), [modId, provider](Mod* m) {
return m->metadata()->provider == provider && m->metadata()->project_id == modId;
});
return found != mods.end() ? *found : nullptr;
};
for (auto mod : mods) {
auto id = mod->internal_id();
for (auto dep : mod->dependencies()) {
auto d = findById(dep);
if (d) {
m_requires[id] << d;
m_requiredBy[d->internal_id()] << mod;
}
}
for (auto dep : mod->metadata()->dependencies) {
auto d = findByProjectID(dep.addonId, mod->metadata()->provider);
if (d) {
m_requires[id] << d;
m_requiredBy[d->internal_id()] << mod;
}
}
}
auto removeDuplicates = [](QList<Mod*>& list) {
std::set<QString> seen;
auto it = std::remove_if(list.begin(), list.end(), [&seen](Mod* m) {
auto id = m->internal_id();
if (seen.count(id) > 0) {
return true;
}
seen.insert(id);
return false;
});
list.erase(it, list.end());
};
for (auto key : m_requiredBy.keys()) {
removeDuplicates(m_requiredBy[key]);
}
for (auto key : m_requires.keys()) {
removeDuplicates(m_requires[key]);
}
for (auto mod : mods) {
auto id = mod->internal_id();
mod->setRequiredByCount(m_requiredBy[id].count());
mod->setRequiresCount(m_requires[id].count());
int row = m_resources_index[id];
emit dataChanged(index(row), index(row, columnCount(QModelIndex()) - 1));
}
}

View File

@ -39,6 +39,7 @@
#include <QAbstractListModel>
#include <QDir>
#include <QHash>
#include <QList>
#include <QMap>
#include <QSet>
@ -46,6 +47,7 @@
#include "Mod.h"
#include "ResourceFolderModel.h"
#include "minecraft/mod/Resource.h"
class BaseInstance;
class QFileSystemWatcher;
@ -69,6 +71,8 @@ class ModFolderModel : public ResourceFolderModel {
LoadersColumn,
McVersionsColumn,
ReleaseTypeColumn,
RequiresColumn,
RequiredByColumn,
NUM_COLUMNS
};
ModFolderModel(const QDir& dir, BaseInstance* instance, bool is_indexed, bool create_dir, QObject* parent = nullptr);
@ -89,4 +93,9 @@ class ModFolderModel : public ResourceFolderModel {
private slots:
void onParseSucceeded(int ticket, QString resource_id) override;
void onParseFinished();
private:
QHash<QString, QList<Mod*>> m_requiredBy;
QHash<QString, QList<Mod*>> m_requires;
};

View File

@ -58,7 +58,21 @@ enum class ResourceStatus {
UNKNOWN, // Default status
};
enum class SortType { NAME, DATE, VERSION, ENABLED, PACK_FORMAT, PROVIDER, SIZE, SIDE, MC_VERSIONS, LOADERS, RELEASE_TYPE };
enum class SortType {
NAME,
DATE,
VERSION,
ENABLED,
PACK_FORMAT,
PROVIDER,
SIZE,
SIDE,
MC_VERSIONS,
LOADERS,
RELEASE_TYPE,
REQUIRES,
REQUIRED_BY,
};
enum class EnableAction { ENABLE, DISABLE, TOGGLE };