refactor: move more tied logic to model and move logic to the resources
This moves the QSortFilterProxyModel to the resource model files, acessible via a factory method, and moves the sorting and filtering to the objects themselves, decoupling the code a bit. This also adds a basic implementation of methods in the ResourceFolderModel, simplifying the process of constructing a new model from it. Signed-off-by: flow <flowlnlnln@gmail.com>
This commit is contained in:
parent
af2cf2734d
commit
1e2f0ab308
@ -39,8 +39,10 @@
|
|||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
|
#include <QRegularExpression>
|
||||||
|
|
||||||
#include "MetadataHandler.h"
|
#include "MetadataHandler.h"
|
||||||
|
#include "Version.h"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
@ -111,6 +113,51 @@ void Mod::setMetadata(const Metadata::ModStruct& metadata)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::pair<int, bool> Mod::compare(const Resource& other, SortType type) const
|
||||||
|
{
|
||||||
|
auto cast_other = dynamic_cast<Mod const*>(&other);
|
||||||
|
if (!cast_other)
|
||||||
|
return Resource::compare(other, type);
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
default:
|
||||||
|
case SortType::ENABLED:
|
||||||
|
if (enabled() && !cast_other->enabled())
|
||||||
|
return { 1, type == SortType::ENABLED };
|
||||||
|
if (!enabled() && cast_other->enabled())
|
||||||
|
return { -1, type == SortType::ENABLED };
|
||||||
|
case SortType::NAME:
|
||||||
|
case SortType::DATE: {
|
||||||
|
auto res = Resource::compare(other, type);
|
||||||
|
if (res.first != 0)
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
case SortType::VERSION: {
|
||||||
|
auto this_ver = Version(version());
|
||||||
|
auto other_ver = Version(cast_other->version());
|
||||||
|
if (this_ver > other_ver)
|
||||||
|
return { 1, type == SortType::VERSION };
|
||||||
|
if (this_ver < other_ver)
|
||||||
|
return { -1, type == SortType::VERSION };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return { 0, false };
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Mod::applyFilter(QRegularExpression filter) const
|
||||||
|
{
|
||||||
|
if (filter.match(description()).hasMatch())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
for (auto& author : authors()) {
|
||||||
|
if (filter.match(author).hasMatch()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return Resource::applyFilter(filter);
|
||||||
|
}
|
||||||
|
|
||||||
auto Mod::destroy(QDir& index_dir, bool preserve_metadata) -> bool
|
auto Mod::destroy(QDir& index_dir, bool preserve_metadata) -> bool
|
||||||
{
|
{
|
||||||
if (!preserve_metadata) {
|
if (!preserve_metadata) {
|
||||||
|
@ -70,6 +70,9 @@ public:
|
|||||||
|
|
||||||
auto enable(bool value) -> bool;
|
auto enable(bool value) -> bool;
|
||||||
|
|
||||||
|
[[nodiscard]] auto compare(Resource const& other, SortType type) const -> std::pair<int, bool> override;
|
||||||
|
[[nodiscard]] bool applyFilter(QRegularExpression filter) const override;
|
||||||
|
|
||||||
// Delete all the files of this mod
|
// Delete all the files of this mod
|
||||||
auto destroy(QDir& index_dir, bool preserve_metadata = false) -> bool;
|
auto destroy(QDir& index_dir, bool preserve_metadata = false) -> bool;
|
||||||
|
|
||||||
|
@ -52,6 +52,7 @@
|
|||||||
ModFolderModel::ModFolderModel(const QString &dir, bool is_indexed) : ResourceFolderModel(dir), m_is_indexed(is_indexed)
|
ModFolderModel::ModFolderModel(const QString &dir, bool is_indexed) : ResourceFolderModel(dir), m_is_indexed(is_indexed)
|
||||||
{
|
{
|
||||||
FS::ensureFolderPathExists(m_dir.absolutePath());
|
FS::ensureFolderPathExists(m_dir.absolutePath());
|
||||||
|
m_column_sort_keys = { SortType::ENABLED, SortType::NAME, SortType::VERSION, SortType::DATE };
|
||||||
}
|
}
|
||||||
|
|
||||||
QVariant ModFolderModel::data(const QModelIndex &index, int role) const
|
QVariant ModFolderModel::data(const QModelIndex &index, int role) const
|
||||||
@ -213,16 +214,16 @@ bool ModFolderModel::isValid()
|
|||||||
return m_dir.exists() && m_dir.isReadable();
|
return m_dir.exists() && m_dir.isReadable();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModFolderModel::startWatching()
|
bool ModFolderModel::startWatching()
|
||||||
{
|
{
|
||||||
// Remove orphaned metadata next time
|
// Remove orphaned metadata next time
|
||||||
m_first_folder_load = true;
|
m_first_folder_load = true;
|
||||||
ResourceFolderModel::startWatching({ m_dir.absolutePath(), indexDir().absolutePath() });
|
return ResourceFolderModel::startWatching({ m_dir.absolutePath(), indexDir().absolutePath() });
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModFolderModel::stopWatching()
|
bool ModFolderModel::stopWatching()
|
||||||
{
|
{
|
||||||
ResourceFolderModel::stopWatching({ m_dir.absolutePath(), indexDir().absolutePath() });
|
return ResourceFolderModel::stopWatching({ m_dir.absolutePath(), indexDir().absolutePath() });
|
||||||
}
|
}
|
||||||
|
|
||||||
auto ModFolderModel::selectedMods(QModelIndexList& indexes) -> QList<Mod::Ptr>
|
auto ModFolderModel::selectedMods(QModelIndexList& indexes) -> QList<Mod::Ptr>
|
||||||
|
@ -91,15 +91,13 @@ public:
|
|||||||
/// Deletes all the selected mods
|
/// Deletes all the selected mods
|
||||||
bool deleteMods(const QModelIndexList &indexes);
|
bool deleteMods(const QModelIndexList &indexes);
|
||||||
|
|
||||||
void disableInteraction(bool disabled) { ResourceFolderModel::enableInteraction(!disabled); }
|
|
||||||
|
|
||||||
/// Enable or disable listed mods
|
/// Enable or disable listed mods
|
||||||
bool setModStatus(const QModelIndexList &indexes, ModStatusAction action);
|
bool setModStatus(const QModelIndexList &indexes, ModStatusAction action);
|
||||||
|
|
||||||
bool isValid();
|
bool isValid();
|
||||||
|
|
||||||
void startWatching();
|
bool startWatching() override;
|
||||||
void stopWatching();
|
bool stopWatching() override;
|
||||||
|
|
||||||
QDir indexDir() { return { QString("%1/.index").arg(dir().absolutePath()) }; }
|
QDir indexDir() { return { QString("%1/.index").arg(dir().absolutePath()) }; }
|
||||||
|
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
#include "Resource.h"
|
#include "Resource.h"
|
||||||
|
|
||||||
|
#include <QRegularExpression>
|
||||||
|
|
||||||
#include "FileSystem.h"
|
#include "FileSystem.h"
|
||||||
|
|
||||||
Resource::Resource(QObject* parent) : QObject(parent) {}
|
Resource::Resource(QObject* parent) : QObject(parent) {}
|
||||||
@ -46,6 +48,43 @@ void Resource::parseFile()
|
|||||||
m_changed_date_time = m_file_info.lastModified();
|
m_changed_date_time = m_file_info.lastModified();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void removeThePrefix(QString& string)
|
||||||
|
{
|
||||||
|
QRegularExpression regex(QStringLiteral("^(?:the|teh) +"), QRegularExpression::CaseInsensitiveOption);
|
||||||
|
string.remove(regex);
|
||||||
|
string = string.trimmed();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair<int, bool> Resource::compare(const Resource& other, SortType type) const
|
||||||
|
{
|
||||||
|
switch (type) {
|
||||||
|
default:
|
||||||
|
case SortType::NAME: {
|
||||||
|
QString this_name{ name() };
|
||||||
|
QString other_name{ other.name() };
|
||||||
|
|
||||||
|
removeThePrefix(this_name);
|
||||||
|
removeThePrefix(other_name);
|
||||||
|
|
||||||
|
auto compare_result = QString::compare(this_name, other_name, Qt::CaseInsensitive);
|
||||||
|
if (compare_result != 0)
|
||||||
|
return { compare_result, type == SortType::NAME };
|
||||||
|
}
|
||||||
|
case SortType::DATE:
|
||||||
|
if (dateTimeChanged() > other.dateTimeChanged())
|
||||||
|
return { 1, type == SortType::DATE };
|
||||||
|
if (dateTimeChanged() < other.dateTimeChanged())
|
||||||
|
return { -1, type == SortType::DATE };
|
||||||
|
}
|
||||||
|
|
||||||
|
return { 0, false };
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Resource::applyFilter(QRegularExpression filter) const
|
||||||
|
{
|
||||||
|
return filter.match(name()).hasMatch();
|
||||||
|
}
|
||||||
|
|
||||||
bool Resource::destroy()
|
bool Resource::destroy()
|
||||||
{
|
{
|
||||||
m_type = ResourceType::UNKNOWN;
|
m_type = ResourceType::UNKNOWN;
|
||||||
|
@ -14,6 +14,13 @@ enum class ResourceType {
|
|||||||
LITEMOD, //!< The resource is a litemod
|
LITEMOD, //!< The resource is a litemod
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class SortType {
|
||||||
|
NAME,
|
||||||
|
DATE,
|
||||||
|
VERSION,
|
||||||
|
ENABLED,
|
||||||
|
};
|
||||||
|
|
||||||
/** General class for managed resources. It mirrors a file in disk, with some more info
|
/** General class for managed resources. It mirrors a file in disk, with some more info
|
||||||
* for display and house-keeping purposes.
|
* for display and house-keeping purposes.
|
||||||
*
|
*
|
||||||
@ -40,6 +47,20 @@ class Resource : public QObject {
|
|||||||
[[nodiscard]] virtual auto name() const -> QString { return m_name; }
|
[[nodiscard]] virtual auto name() const -> QString { return m_name; }
|
||||||
[[nodiscard]] virtual bool valid() const { return m_type != ResourceType::UNKNOWN; }
|
[[nodiscard]] virtual bool valid() const { return m_type != ResourceType::UNKNOWN; }
|
||||||
|
|
||||||
|
/** Compares two Resources, for sorting purposes, considering a ascending order, returning:
|
||||||
|
* > 0: 'this' comes after 'other'
|
||||||
|
* = 0: 'this' is equal to 'other'
|
||||||
|
* < 0: 'this' comes before 'other'
|
||||||
|
*
|
||||||
|
* The second argument in the pair is true if the sorting type that decided which one is greater was 'type'.
|
||||||
|
*/
|
||||||
|
[[nodiscard]] virtual auto compare(Resource const& other, SortType type = SortType::NAME) const -> std::pair<int, bool>;
|
||||||
|
|
||||||
|
/** Returns whether the given filter should filter out 'this' (false),
|
||||||
|
* or if such filter includes the Resource (true).
|
||||||
|
*/
|
||||||
|
[[nodiscard]] virtual bool applyFilter(QRegularExpression filter) const;
|
||||||
|
|
||||||
[[nodiscard]] auto shouldResolve() const -> bool { return !m_is_resolving && !m_is_resolved; }
|
[[nodiscard]] auto shouldResolve() const -> bool { return !m_is_resolving && !m_is_resolved; }
|
||||||
[[nodiscard]] auto isResolving() const -> bool { return m_is_resolving; }
|
[[nodiscard]] auto isResolving() const -> bool { return m_is_resolving; }
|
||||||
[[nodiscard]] auto resolutionTicket() const -> int { return m_resolution_ticket; }
|
[[nodiscard]] auto resolutionTicket() const -> int { return m_resolution_ticket; }
|
||||||
|
@ -170,8 +170,11 @@ bool ResourceFolderModel::update()
|
|||||||
}
|
}
|
||||||
|
|
||||||
m_current_update_task.reset(createUpdateTask());
|
m_current_update_task.reset(createUpdateTask());
|
||||||
|
if (!m_current_update_task)
|
||||||
|
return false;
|
||||||
|
|
||||||
connect(m_current_update_task.get(), &Task::succeeded, this, &ResourceFolderModel::onUpdateSucceeded, Qt::ConnectionType::QueuedConnection);
|
connect(m_current_update_task.get(), &Task::succeeded, this, &ResourceFolderModel::onUpdateSucceeded,
|
||||||
|
Qt::ConnectionType::QueuedConnection);
|
||||||
connect(m_current_update_task.get(), &Task::failed, this, &ResourceFolderModel::onUpdateFailed, Qt::ConnectionType::QueuedConnection);
|
connect(m_current_update_task.get(), &Task::failed, this, &ResourceFolderModel::onUpdateFailed, Qt::ConnectionType::QueuedConnection);
|
||||||
|
|
||||||
auto* thread_pool = QThreadPool::globalInstance();
|
auto* thread_pool = QThreadPool::globalInstance();
|
||||||
@ -187,6 +190,8 @@ void ResourceFolderModel::resolveResource(Resource::Ptr res)
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto task = createParseTask(*res);
|
auto task = createParseTask(*res);
|
||||||
|
if (!task)
|
||||||
|
return;
|
||||||
|
|
||||||
m_ticket_mutex.lock();
|
m_ticket_mutex.lock();
|
||||||
int ticket = m_next_resolution_ticket;
|
int ticket = m_next_resolution_ticket;
|
||||||
@ -196,8 +201,10 @@ void ResourceFolderModel::resolveResource(Resource::Ptr res)
|
|||||||
res->setResolving(true, ticket);
|
res->setResolving(true, ticket);
|
||||||
m_active_parse_tasks.insert(ticket, task);
|
m_active_parse_tasks.insert(ticket, task);
|
||||||
|
|
||||||
connect(task, &Task::succeeded, this, [=] { onParseSucceeded(ticket, res->internal_id()); }, Qt::ConnectionType::QueuedConnection);
|
connect(
|
||||||
connect(task, &Task::failed, this, [=] { onParseFailed(ticket, res->internal_id()); }, Qt::ConnectionType::QueuedConnection);
|
task, &Task::succeeded, this, [=] { onParseSucceeded(ticket, res->internal_id()); }, Qt::ConnectionType::QueuedConnection);
|
||||||
|
connect(
|
||||||
|
task, &Task::failed, this, [=] { onParseFailed(ticket, res->internal_id()); }, Qt::ConnectionType::QueuedConnection);
|
||||||
|
|
||||||
auto* thread_pool = QThreadPool::globalInstance();
|
auto* thread_pool = QThreadPool::globalInstance();
|
||||||
thread_pool->start(task);
|
thread_pool->start(task);
|
||||||
@ -325,6 +332,71 @@ bool ResourceFolderModel::validateIndex(const QModelIndex& index) const
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QVariant ResourceFolderModel::data(const QModelIndex& index, int role) const
|
||||||
|
{
|
||||||
|
if (!validateIndex(index))
|
||||||
|
return {};
|
||||||
|
|
||||||
|
int row = index.row();
|
||||||
|
int column = index.column();
|
||||||
|
|
||||||
|
switch (role) {
|
||||||
|
case Qt::DisplayRole:
|
||||||
|
switch (column) {
|
||||||
|
case NAME_COLUMN:
|
||||||
|
return m_resources[row]->name();
|
||||||
|
case DATE_COLUMN:
|
||||||
|
return m_resources[row]->dateTimeChanged();
|
||||||
|
default:
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
case Qt::ToolTipRole:
|
||||||
|
return m_resources[row]->internal_id();
|
||||||
|
default:
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant ResourceFolderModel::headerData(int section, Qt::Orientation orientation, int role) const
|
||||||
|
{
|
||||||
|
switch (role) {
|
||||||
|
case Qt::DisplayRole:
|
||||||
|
switch (section) {
|
||||||
|
case NAME_COLUMN:
|
||||||
|
return tr("Name");
|
||||||
|
case DATE_COLUMN:
|
||||||
|
return tr("Last modified");
|
||||||
|
default:
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
case Qt::ToolTipRole: {
|
||||||
|
switch (section) {
|
||||||
|
case NAME_COLUMN:
|
||||||
|
return tr("The name of the resource.");
|
||||||
|
case DATE_COLUMN:
|
||||||
|
return tr("The date and time this resource was last changed (or added).");
|
||||||
|
default:
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
QSortFilterProxyModel* ResourceFolderModel::createFilterProxyModel(QObject* parent)
|
||||||
|
{
|
||||||
|
return new ProxyModel(parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
SortType ResourceFolderModel::columnToSortKey(size_t column) const
|
||||||
|
{
|
||||||
|
Q_ASSERT(m_column_sort_keys.size() == columnCount());
|
||||||
|
return m_column_sort_keys.at(column);
|
||||||
|
}
|
||||||
|
|
||||||
void ResourceFolderModel::enableInteraction(bool enabled)
|
void ResourceFolderModel::enableInteraction(bool enabled)
|
||||||
{
|
{
|
||||||
if (m_can_interact == enabled)
|
if (m_can_interact == enabled)
|
||||||
@ -334,3 +406,39 @@ void ResourceFolderModel::enableInteraction(bool enabled)
|
|||||||
if (size())
|
if (size())
|
||||||
emit dataChanged(index(0), index(size() - 1));
|
emit dataChanged(index(0), index(size() - 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Standard Proxy Model for createFilterProxyModel */
|
||||||
|
[[nodiscard]] bool ResourceFolderModel::ProxyModel::filterAcceptsRow(int source_row, const QModelIndex& source_parent) const
|
||||||
|
{
|
||||||
|
auto* model = qobject_cast<ResourceFolderModel*>(sourceModel());
|
||||||
|
if (!model)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
const auto& resource = model->at(source_row);
|
||||||
|
|
||||||
|
return resource.applyFilter(filterRegularExpression());
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] bool ResourceFolderModel::ProxyModel::lessThan(const QModelIndex& source_left, const QModelIndex& source_right) const
|
||||||
|
{
|
||||||
|
auto* model = qobject_cast<ResourceFolderModel*>(sourceModel());
|
||||||
|
if (!model || !source_left.isValid() || !source_right.isValid() || source_left.column() != source_right.column()) {
|
||||||
|
return QSortFilterProxyModel::lessThan(source_left, source_right);
|
||||||
|
}
|
||||||
|
|
||||||
|
// we are now guaranteed to have two valid indexes in the same column... we love the provided invariants unconditionally and
|
||||||
|
// proceed.
|
||||||
|
|
||||||
|
auto column_sort_key = model->columnToSortKey(source_left.column());
|
||||||
|
auto const& resource_left = model->at(source_left.row());
|
||||||
|
auto const& resource_right = model->at(source_right.row());
|
||||||
|
|
||||||
|
auto compare_result = resource_left.compare(resource_right, column_sort_key);
|
||||||
|
if (compare_result.first == 0)
|
||||||
|
return QSortFilterProxyModel::lessThan(source_left, source_right);
|
||||||
|
|
||||||
|
if (compare_result.second || sortOrder() != Qt::DescendingOrder)
|
||||||
|
return (compare_result.first < 0);
|
||||||
|
return (compare_result.first > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -5,12 +5,13 @@
|
|||||||
#include <QFileSystemWatcher>
|
#include <QFileSystemWatcher>
|
||||||
#include <QMutex>
|
#include <QMutex>
|
||||||
#include <QSet>
|
#include <QSet>
|
||||||
|
#include <QSortFilterProxyModel>
|
||||||
|
|
||||||
#include "Resource.h"
|
#include "Resource.h"
|
||||||
|
|
||||||
#include "tasks/Task.h"
|
#include "tasks/Task.h"
|
||||||
|
|
||||||
class QRunnable;
|
class QSortFilterProxyModel;
|
||||||
|
|
||||||
/** A basic model for external resources.
|
/** A basic model for external resources.
|
||||||
*
|
*
|
||||||
@ -38,6 +39,10 @@ class ResourceFolderModel : public QAbstractListModel {
|
|||||||
*/
|
*/
|
||||||
bool stopWatching(const QStringList paths);
|
bool stopWatching(const QStringList paths);
|
||||||
|
|
||||||
|
/* Helper methods for subclasses, using a predetermined list of paths. */
|
||||||
|
virtual bool startWatching() { return startWatching({ m_dir.absolutePath() }); };
|
||||||
|
virtual bool stopWatching() { return stopWatching({ m_dir.absolutePath() }); };
|
||||||
|
|
||||||
/** Given a path in the system, install that resource, moving it to its place in the
|
/** Given a path in the system, install that resource, moving it to its place in the
|
||||||
* instance file hierarchy.
|
* instance file hierarchy.
|
||||||
*
|
*
|
||||||
@ -61,13 +66,18 @@ class ResourceFolderModel : public QAbstractListModel {
|
|||||||
|
|
||||||
[[nodiscard]] size_t size() const { return m_resources.size(); };
|
[[nodiscard]] size_t size() const { return m_resources.size(); };
|
||||||
[[nodiscard]] bool empty() const { return size() == 0; }
|
[[nodiscard]] bool empty() const { return size() == 0; }
|
||||||
|
[[nodiscard]] Resource const& at(int index) const { return *m_resources.at(index); }
|
||||||
|
[[nodiscard]] QList<Resource::Ptr> const& all() const { return m_resources; }
|
||||||
|
|
||||||
[[nodiscard]] QDir const& dir() const { return m_dir; }
|
[[nodiscard]] QDir const& dir() const { return m_dir; }
|
||||||
|
|
||||||
/* Qt behavior */
|
/* Qt behavior */
|
||||||
|
|
||||||
[[nodiscard]] int rowCount(const QModelIndex&) const override { return size(); }
|
/* Basic columns */
|
||||||
[[nodiscard]] int columnCount(const QModelIndex&) const override = 0;
|
enum Columns { NAME_COLUMN = 0, DATE_COLUMN, NUM_COLUMNS };
|
||||||
|
|
||||||
|
[[nodiscard]] int rowCount(const QModelIndex& = {}) const override { return size(); }
|
||||||
|
[[nodiscard]] int columnCount(const QModelIndex& = {}) const override { return NUM_COLUMNS; };
|
||||||
|
|
||||||
[[nodiscard]] Qt::DropActions supportedDropActions() const override;
|
[[nodiscard]] Qt::DropActions supportedDropActions() const override;
|
||||||
|
|
||||||
@ -78,13 +88,31 @@ class ResourceFolderModel : public QAbstractListModel {
|
|||||||
|
|
||||||
[[nodiscard]] bool validateIndex(const QModelIndex& index) const;
|
[[nodiscard]] bool validateIndex(const QModelIndex& index) const;
|
||||||
|
|
||||||
[[nodiscard]] QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override = 0;
|
[[nodiscard]] QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
|
||||||
bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole) override { return false; };
|
bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole) override { return false; };
|
||||||
|
|
||||||
[[nodiscard]] QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override = 0;
|
[[nodiscard]] QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
|
||||||
|
|
||||||
|
/** This creates a proxy model to filter / sort the model for a UI.
|
||||||
|
*
|
||||||
|
* The actual comparisons and filtering are done directly by the Resource, so to modify behavior go there instead!
|
||||||
|
*/
|
||||||
|
QSortFilterProxyModel* createFilterProxyModel(QObject* parent = nullptr);
|
||||||
|
|
||||||
|
[[nodiscard]] SortType columnToSortKey(size_t column) const;
|
||||||
|
|
||||||
|
class ProxyModel : public QSortFilterProxyModel {
|
||||||
|
public:
|
||||||
|
explicit ProxyModel(QObject* parent = nullptr) : QSortFilterProxyModel(parent) {}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
[[nodiscard]] bool filterAcceptsRow(int source_row, const QModelIndex& source_parent) const override;
|
||||||
|
[[nodiscard]] bool lessThan(const QModelIndex& source_left, const QModelIndex& source_right) const override;
|
||||||
|
};
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void enableInteraction(bool enabled);
|
void enableInteraction(bool enabled);
|
||||||
|
void disableInteraction(bool disabled) { enableInteraction(!disabled); }
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void updateFinished();
|
void updateFinished();
|
||||||
@ -137,6 +165,10 @@ class ResourceFolderModel : public QAbstractListModel {
|
|||||||
virtual void onParseFailed(int ticket, QString resource_id) {}
|
virtual void onParseFailed(int ticket, QString resource_id) {}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
// Represents the relationship between a column's index (represented by the list index), and it's sorting key.
|
||||||
|
// As such, the order in with they appear is very important!
|
||||||
|
QList<SortType> m_column_sort_keys = { SortType::NAME, SortType::DATE };
|
||||||
|
|
||||||
bool m_can_interact = true;
|
bool m_can_interact = true;
|
||||||
|
|
||||||
QDir m_dir;
|
QDir m_dir;
|
||||||
|
Loading…
Reference in New Issue
Block a user