change: add enable/disable to resources
TIL that zip resource packs, when disabled, actually have the effect of not showing up in the game at all. Since this can be useful to someone, I moved the logic for it to the resources. Signed-off-by: flow <flowlnlnln@gmail.com>
This commit is contained in:
parent
c3ceefbafb
commit
e2ab2aea32
@ -56,37 +56,6 @@ Mod::Mod(const QDir& mods_dir, const Metadata::ModStruct& metadata)
|
|||||||
m_local_details.metadata = std::make_shared<Metadata::ModStruct>(std::move(metadata));
|
m_local_details.metadata = std::make_shared<Metadata::ModStruct>(std::move(metadata));
|
||||||
}
|
}
|
||||||
|
|
||||||
auto Mod::enable(bool value) -> bool
|
|
||||||
{
|
|
||||||
if (m_type == ResourceType::UNKNOWN || m_type == ResourceType::FOLDER)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (m_enabled == value)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
QString path = m_file_info.absoluteFilePath();
|
|
||||||
QFile file(path);
|
|
||||||
if (value) {
|
|
||||||
if (!path.endsWith(".disabled"))
|
|
||||||
return false;
|
|
||||||
path.chop(9);
|
|
||||||
|
|
||||||
if (!file.rename(path))
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
path += ".disabled";
|
|
||||||
|
|
||||||
if (!file.rename(path))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (status() == ModStatus::NoMetadata)
|
|
||||||
setFile(QFileInfo(path));
|
|
||||||
|
|
||||||
m_enabled = value;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Mod::setStatus(ModStatus status)
|
void Mod::setStatus(ModStatus status)
|
||||||
{
|
{
|
||||||
m_local_details.status = status;
|
m_local_details.status = status;
|
||||||
@ -108,10 +77,6 @@ std::pair<int, bool> Mod::compare(const Resource& other, SortType type) const
|
|||||||
switch (type) {
|
switch (type) {
|
||||||
default:
|
default:
|
||||||
case SortType::ENABLED:
|
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::NAME:
|
||||||
case SortType::DATE: {
|
case SortType::DATE: {
|
||||||
auto res = Resource::compare(other, type);
|
auto res = Resource::compare(other, type);
|
||||||
|
@ -54,8 +54,6 @@ public:
|
|||||||
Mod(const QDir& mods_dir, const Metadata::ModStruct& metadata);
|
Mod(const QDir& mods_dir, const Metadata::ModStruct& metadata);
|
||||||
Mod(QString file_path) : Mod(QFileInfo(file_path)) {}
|
Mod(QString file_path) : Mod(QFileInfo(file_path)) {}
|
||||||
|
|
||||||
auto enabled() const -> bool { return m_enabled; }
|
|
||||||
|
|
||||||
auto details() const -> const ModDetails&;
|
auto details() const -> const ModDetails&;
|
||||||
auto name() const -> QString override;
|
auto name() const -> QString override;
|
||||||
auto version() const -> QString;
|
auto version() const -> QString;
|
||||||
@ -71,8 +69,6 @@ public:
|
|||||||
void setMetadata(std::shared_ptr<Metadata::ModStruct>&& metadata);
|
void setMetadata(std::shared_ptr<Metadata::ModStruct>&& metadata);
|
||||||
void setMetadata(const Metadata::ModStruct& metadata) { setMetadata(std::make_shared<Metadata::ModStruct>(metadata)); }
|
void setMetadata(const Metadata::ModStruct& metadata) { setMetadata(std::make_shared<Metadata::ModStruct>(metadata)); }
|
||||||
|
|
||||||
auto enable(bool value) -> bool;
|
|
||||||
|
|
||||||
[[nodiscard]] auto compare(Resource const& other, SortType type) const -> std::pair<int, bool> override;
|
[[nodiscard]] auto compare(Resource const& other, SortType type) const -> std::pair<int, bool> override;
|
||||||
[[nodiscard]] bool applyFilter(QRegularExpression filter) const override;
|
[[nodiscard]] bool applyFilter(QRegularExpression filter) const override;
|
||||||
|
|
||||||
@ -83,6 +79,4 @@ public:
|
|||||||
|
|
||||||
protected:
|
protected:
|
||||||
ModDetails m_local_details;
|
ModDetails m_local_details;
|
||||||
|
|
||||||
bool m_enabled = true;
|
|
||||||
};
|
};
|
||||||
|
@ -104,20 +104,6 @@ QVariant ModFolderModel::data(const QModelIndex &index, int role) const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ModFolderModel::setData(const QModelIndex &index, const QVariant &value, int role)
|
|
||||||
{
|
|
||||||
if (index.row() < 0 || index.row() >= rowCount(index) || !index.isValid())
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (role == Qt::CheckStateRole)
|
|
||||||
{
|
|
||||||
return setModStatus(index.row(), Toggle);
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
QVariant ModFolderModel::headerData(int section, Qt::Orientation orientation, int role) const
|
QVariant ModFolderModel::headerData(int section, Qt::Orientation orientation, int role) const
|
||||||
{
|
{
|
||||||
switch (role)
|
switch (role)
|
||||||
@ -305,65 +291,3 @@ void ModFolderModel::onParseSucceeded(int ticket, QString mod_id)
|
|||||||
|
|
||||||
emit dataChanged(index(row), index(row, columnCount(QModelIndex()) - 1));
|
emit dataChanged(index(row), index(row, columnCount(QModelIndex()) - 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool ModFolderModel::setModStatus(const QModelIndexList& indexes, ModStatusAction enable)
|
|
||||||
{
|
|
||||||
if(!m_can_interact) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(indexes.isEmpty())
|
|
||||||
return true;
|
|
||||||
|
|
||||||
for (auto index: indexes)
|
|
||||||
{
|
|
||||||
if(index.column() != 0) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
setModStatus(index.row(), enable);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ModFolderModel::setModStatus(int row, ModFolderModel::ModStatusAction action)
|
|
||||||
{
|
|
||||||
if(row < 0 || row >= m_resources.size()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto mod = at(row);
|
|
||||||
bool desiredStatus;
|
|
||||||
switch(action) {
|
|
||||||
case Enable:
|
|
||||||
desiredStatus = true;
|
|
||||||
break;
|
|
||||||
case Disable:
|
|
||||||
desiredStatus = false;
|
|
||||||
break;
|
|
||||||
case Toggle:
|
|
||||||
default:
|
|
||||||
desiredStatus = !mod->enabled();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(desiredStatus == mod->enabled()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// preserve the row, but change its ID
|
|
||||||
auto oldId = mod->internal_id();
|
|
||||||
if(!mod->enable(!mod->enabled())) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
auto newId = mod->internal_id();
|
|
||||||
if(m_resources_index.contains(newId)) {
|
|
||||||
// NOTE: this could handle a corner case, where we are overwriting a file, because the same 'mod' exists both enabled and disabled
|
|
||||||
// But is it necessary?
|
|
||||||
}
|
|
||||||
m_resources_index.remove(oldId);
|
|
||||||
m_resources_index[newId] = row;
|
|
||||||
emit dataChanged(index(row, 0), index(row, columnCount(QModelIndex()) - 1));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
@ -77,7 +77,6 @@ public:
|
|||||||
ModFolderModel(const QString &dir, bool is_indexed = false);
|
ModFolderModel(const QString &dir, bool is_indexed = false);
|
||||||
|
|
||||||
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
|
||||||
bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override;
|
|
||||||
|
|
||||||
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
|
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
|
||||||
int columnCount(const QModelIndex &parent) const override;
|
int columnCount(const QModelIndex &parent) const override;
|
||||||
@ -91,9 +90,6 @@ public:
|
|||||||
/// Deletes all the selected mods
|
/// Deletes all the selected mods
|
||||||
bool deleteMods(const QModelIndexList &indexes);
|
bool deleteMods(const QModelIndexList &indexes);
|
||||||
|
|
||||||
/// Enable or disable listed mods
|
|
||||||
bool setModStatus(const QModelIndexList &indexes, ModStatusAction action);
|
|
||||||
|
|
||||||
bool isValid();
|
bool isValid();
|
||||||
|
|
||||||
bool startWatching() override;
|
bool startWatching() override;
|
||||||
@ -111,9 +107,6 @@ slots:
|
|||||||
void onUpdateSucceeded() override;
|
void onUpdateSucceeded() override;
|
||||||
void onParseSucceeded(int ticket, QString resource_id) override;
|
void onParseSucceeded(int ticket, QString resource_id) override;
|
||||||
|
|
||||||
private:
|
|
||||||
bool setModStatus(int index, ModStatusAction action);
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool m_is_indexed;
|
bool m_is_indexed;
|
||||||
bool m_first_folder_load = true;
|
bool m_first_folder_load = true;
|
||||||
|
@ -29,8 +29,10 @@ void Resource::parseFile()
|
|||||||
m_type = ResourceType::FOLDER;
|
m_type = ResourceType::FOLDER;
|
||||||
m_name = file_name;
|
m_name = file_name;
|
||||||
} else if (m_file_info.isFile()) {
|
} else if (m_file_info.isFile()) {
|
||||||
if (file_name.endsWith(".disabled"))
|
if (file_name.endsWith(".disabled")) {
|
||||||
file_name.chop(9);
|
file_name.chop(9);
|
||||||
|
m_enabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
if (file_name.endsWith(".zip") || file_name.endsWith(".jar")) {
|
if (file_name.endsWith(".zip") || file_name.endsWith(".jar")) {
|
||||||
m_type = ResourceType::ZIPFILE;
|
m_type = ResourceType::ZIPFILE;
|
||||||
@ -59,6 +61,11 @@ std::pair<int, bool> Resource::compare(const Resource& other, SortType type) con
|
|||||||
{
|
{
|
||||||
switch (type) {
|
switch (type) {
|
||||||
default:
|
default:
|
||||||
|
case SortType::ENABLED:
|
||||||
|
if (enabled() && !other.enabled())
|
||||||
|
return { 1, type == SortType::ENABLED };
|
||||||
|
if (!enabled() && other.enabled())
|
||||||
|
return { -1, type == SortType::ENABLED };
|
||||||
case SortType::NAME: {
|
case SortType::NAME: {
|
||||||
QString this_name{ name() };
|
QString this_name{ name() };
|
||||||
QString other_name{ other.name() };
|
QString other_name{ other.name() };
|
||||||
@ -85,6 +92,54 @@ bool Resource::applyFilter(QRegularExpression filter) const
|
|||||||
return filter.match(name()).hasMatch();
|
return filter.match(name()).hasMatch();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Resource::enable(EnableAction action)
|
||||||
|
{
|
||||||
|
if (m_type == ResourceType::UNKNOWN || m_type == ResourceType::FOLDER)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
|
||||||
|
QString path = m_file_info.absoluteFilePath();
|
||||||
|
QFile file(path);
|
||||||
|
|
||||||
|
bool enable = true;
|
||||||
|
switch (action) {
|
||||||
|
case EnableAction::ENABLE:
|
||||||
|
enable = true;
|
||||||
|
break;
|
||||||
|
case EnableAction::DISABLE:
|
||||||
|
enable = false;
|
||||||
|
break;
|
||||||
|
case EnableAction::TOGGLE:
|
||||||
|
default:
|
||||||
|
enable = !enabled();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_enabled == enable)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (enable) {
|
||||||
|
// m_enabled is false, but there's no '.disabled' suffix.
|
||||||
|
// TODO: Report error?
|
||||||
|
if (!path.endsWith(".disabled"))
|
||||||
|
return false;
|
||||||
|
path.chop(9);
|
||||||
|
|
||||||
|
if (!file.rename(path))
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
path += ".disabled";
|
||||||
|
|
||||||
|
if (!file.rename(path))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
setFile(QFileInfo(path));
|
||||||
|
|
||||||
|
m_enabled = enable;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool Resource::destroy()
|
bool Resource::destroy()
|
||||||
{
|
{
|
||||||
m_type = ResourceType::UNKNOWN;
|
m_type = ResourceType::UNKNOWN;
|
||||||
|
@ -22,6 +22,12 @@ enum class SortType {
|
|||||||
ENABLED,
|
ENABLED,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class EnableAction {
|
||||||
|
ENABLE,
|
||||||
|
DISABLE,
|
||||||
|
TOGGLE
|
||||||
|
};
|
||||||
|
|
||||||
/** 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.
|
||||||
*
|
*
|
||||||
@ -47,6 +53,7 @@ class Resource : public QObject {
|
|||||||
[[nodiscard]] auto dateTimeChanged() const -> QDateTime { return m_changed_date_time; }
|
[[nodiscard]] auto dateTimeChanged() const -> QDateTime { return m_changed_date_time; }
|
||||||
[[nodiscard]] auto internal_id() const -> QString { return m_internal_id; }
|
[[nodiscard]] auto internal_id() const -> QString { return m_internal_id; }
|
||||||
[[nodiscard]] auto type() const -> ResourceType { return m_type; }
|
[[nodiscard]] auto type() const -> ResourceType { return m_type; }
|
||||||
|
[[nodiscard]] bool enabled() const { return m_enabled; }
|
||||||
|
|
||||||
[[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; }
|
||||||
@ -65,6 +72,12 @@ class Resource : public QObject {
|
|||||||
*/
|
*/
|
||||||
[[nodiscard]] virtual bool applyFilter(QRegularExpression filter) const;
|
[[nodiscard]] virtual bool applyFilter(QRegularExpression filter) const;
|
||||||
|
|
||||||
|
/** Changes the enabled property, according to 'action'.
|
||||||
|
*
|
||||||
|
* Returns whether a change was applied to the Resource's properties.
|
||||||
|
*/
|
||||||
|
bool enable(EnableAction action);
|
||||||
|
|
||||||
[[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; }
|
||||||
@ -92,6 +105,9 @@ class Resource : public QObject {
|
|||||||
/* The type of file we're dealing with. */
|
/* The type of file we're dealing with. */
|
||||||
ResourceType m_type = ResourceType::UNKNOWN;
|
ResourceType m_type = ResourceType::UNKNOWN;
|
||||||
|
|
||||||
|
/* Whether the resource is enabled (e.g. shows up in the game) or not. */
|
||||||
|
bool m_enabled = true;
|
||||||
|
|
||||||
/* Used to keep trach of pending / concluded actions on the resource. */
|
/* Used to keep trach of pending / concluded actions on the resource. */
|
||||||
bool m_is_resolving = false;
|
bool m_is_resolving = false;
|
||||||
bool m_is_resolved = false;
|
bool m_is_resolved = false;
|
||||||
|
@ -172,6 +172,44 @@ bool ResourceFolderModel::deleteResources(const QModelIndexList& indexes)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ResourceFolderModel::setResourceEnabled(const QModelIndexList &indexes, EnableAction action)
|
||||||
|
{
|
||||||
|
if (!m_can_interact)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (indexes.isEmpty())
|
||||||
|
return true;
|
||||||
|
|
||||||
|
bool succeeded = true;
|
||||||
|
for (auto const& idx : indexes) {
|
||||||
|
if (!validateIndex(idx) || idx.column() != 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
int row = idx.row();
|
||||||
|
|
||||||
|
auto& resource = m_resources[row];
|
||||||
|
|
||||||
|
// Preserve the row, but change its ID
|
||||||
|
auto old_id = resource->internal_id();
|
||||||
|
if (!resource->enable(action)) {
|
||||||
|
succeeded = false;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto new_id = resource->internal_id();
|
||||||
|
if (m_resources_index.contains(new_id)) {
|
||||||
|
// FIXME: https://github.com/PolyMC/PolyMC/issues/550
|
||||||
|
}
|
||||||
|
|
||||||
|
m_resources_index.remove(old_id);
|
||||||
|
m_resources_index[new_id] = row;
|
||||||
|
|
||||||
|
emit dataChanged(index(row, 0), index(row, columnCount(QModelIndex()) - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
return succeeded;
|
||||||
|
}
|
||||||
|
|
||||||
static QMutex s_update_task_mutex;
|
static QMutex s_update_task_mutex;
|
||||||
bool ResourceFolderModel::update()
|
bool ResourceFolderModel::update()
|
||||||
{
|
{
|
||||||
@ -271,7 +309,6 @@ Task* ResourceFolderModel::createUpdateTask()
|
|||||||
return new BasicFolderLoadTask(m_dir);
|
return new BasicFolderLoadTask(m_dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool ResourceFolderModel::hasPendingParseTasks() const
|
bool ResourceFolderModel::hasPendingParseTasks() const
|
||||||
{
|
{
|
||||||
return !m_active_parse_tasks.isEmpty();
|
return !m_active_parse_tasks.isEmpty();
|
||||||
@ -370,11 +407,30 @@ QVariant ResourceFolderModel::data(const QModelIndex& index, int role) const
|
|||||||
}
|
}
|
||||||
case Qt::ToolTipRole:
|
case Qt::ToolTipRole:
|
||||||
return m_resources[row]->internal_id();
|
return m_resources[row]->internal_id();
|
||||||
|
case Qt::CheckStateRole:
|
||||||
|
switch (column) {
|
||||||
|
case ACTIVE_COLUMN:
|
||||||
|
return m_resources[row]->enabled() ? Qt::Checked : Qt::Unchecked;
|
||||||
|
default:
|
||||||
|
return {};
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ResourceFolderModel::setData(const QModelIndex& index, const QVariant& value, int role)
|
||||||
|
{
|
||||||
|
int row = index.row();
|
||||||
|
if (row < 0 || row >= rowCount(index) || !index.isValid())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (role == Qt::CheckStateRole)
|
||||||
|
return setResourceEnabled({ index }, EnableAction::TOGGLE);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
QVariant ResourceFolderModel::headerData(int section, Qt::Orientation orientation, int role) const
|
QVariant ResourceFolderModel::headerData(int section, Qt::Orientation orientation, int role) const
|
||||||
{
|
{
|
||||||
switch (role) {
|
switch (role) {
|
||||||
@ -389,9 +445,14 @@ QVariant ResourceFolderModel::headerData(int section, Qt::Orientation orientatio
|
|||||||
}
|
}
|
||||||
case Qt::ToolTipRole: {
|
case Qt::ToolTipRole: {
|
||||||
switch (section) {
|
switch (section) {
|
||||||
|
case ACTIVE_COLUMN:
|
||||||
|
//: Here, resource is a generic term for external resources, like Mods, Resource Packs, Shader Packs, etc.
|
||||||
|
return tr("Is the resource enabled?");
|
||||||
case NAME_COLUMN:
|
case NAME_COLUMN:
|
||||||
|
//: Here, resource is a generic term for external resources, like Mods, Resource Packs, Shader Packs, etc.
|
||||||
return tr("The name of the resource.");
|
return tr("The name of the resource.");
|
||||||
case DATE_COLUMN:
|
case DATE_COLUMN:
|
||||||
|
//: Here, resource is a generic term for external resources, like Mods, Resource Packs, Shader Packs, etc.
|
||||||
return tr("The date and time this resource was last changed (or added).");
|
return tr("The date and time this resource was last changed (or added).");
|
||||||
default:
|
default:
|
||||||
return {};
|
return {};
|
||||||
@ -459,4 +520,3 @@ void ResourceFolderModel::enableInteraction(bool enabled)
|
|||||||
return (compare_result.first < 0);
|
return (compare_result.first < 0);
|
||||||
return (compare_result.first > 0);
|
return (compare_result.first > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,9 +55,14 @@ class ResourceFolderModel : public QAbstractListModel {
|
|||||||
* Returns whether the removal was successful.
|
* Returns whether the removal was successful.
|
||||||
*/
|
*/
|
||||||
virtual bool uninstallResource(QString file_name);
|
virtual bool uninstallResource(QString file_name);
|
||||||
|
|
||||||
virtual bool deleteResources(const QModelIndexList&);
|
virtual bool deleteResources(const QModelIndexList&);
|
||||||
|
|
||||||
|
/** Applies the given 'action' to the resources in 'indexes'.
|
||||||
|
*
|
||||||
|
* Returns whether the action was successfully applied to all resources.
|
||||||
|
*/
|
||||||
|
virtual bool setResourceEnabled(const QModelIndexList& indexes, EnableAction action);
|
||||||
|
|
||||||
/** Creates a new update task and start it. Returns false if no update was done, like when an update is already underway. */
|
/** Creates a new update task and start it. Returns false if no update was done, like when an update is already underway. */
|
||||||
virtual bool update();
|
virtual bool update();
|
||||||
|
|
||||||
@ -66,6 +71,7 @@ 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& at(int index) { return *m_resources.at(index); }
|
||||||
[[nodiscard]] Resource const& at(int index) const { return *m_resources.at(index); }
|
[[nodiscard]] Resource const& at(int index) const { return *m_resources.at(index); }
|
||||||
[[nodiscard]] QList<Resource::Ptr> const& all() const { return m_resources; }
|
[[nodiscard]] QList<Resource::Ptr> const& all() const { return m_resources; }
|
||||||
|
|
||||||
@ -81,7 +87,7 @@ class ResourceFolderModel : public QAbstractListModel {
|
|||||||
/* Qt behavior */
|
/* Qt behavior */
|
||||||
|
|
||||||
/* Basic columns */
|
/* Basic columns */
|
||||||
enum Columns { NAME_COLUMN = 0, DATE_COLUMN, NUM_COLUMNS };
|
enum Columns { ACTIVE_COLUMN = 0, NAME_COLUMN, DATE_COLUMN, NUM_COLUMNS };
|
||||||
|
|
||||||
[[nodiscard]] int rowCount(const QModelIndex& = {}) const override { return size(); }
|
[[nodiscard]] int rowCount(const QModelIndex& = {}) const override { return size(); }
|
||||||
[[nodiscard]] int columnCount(const QModelIndex& = {}) const override { return NUM_COLUMNS; };
|
[[nodiscard]] int columnCount(const QModelIndex& = {}) const override { return NUM_COLUMNS; };
|
||||||
@ -96,7 +102,7 @@ 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;
|
[[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;
|
||||||
|
|
||||||
[[nodiscard]] QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
|
[[nodiscard]] QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
|
||||||
|
|
||||||
@ -174,7 +180,7 @@ class ResourceFolderModel : public QAbstractListModel {
|
|||||||
protected:
|
protected:
|
||||||
// Represents the relationship between a column's index (represented by the list index), and it's sorting key.
|
// 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!
|
// As such, the order in with they appear is very important!
|
||||||
QList<SortType> m_column_sort_keys = { SortType::NAME, SortType::DATE };
|
QList<SortType> m_column_sort_keys = { SortType::ENABLED, SortType::NAME, SortType::DATE };
|
||||||
|
|
||||||
bool m_can_interact = true;
|
bool m_can_interact = true;
|
||||||
|
|
||||||
|
@ -212,6 +212,62 @@ slots:
|
|||||||
QCoreApplication::processEvents();
|
QCoreApplication::processEvents();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void test_enable_disable()
|
||||||
|
{
|
||||||
|
QString folder_resource = QFINDTESTDATA("testdata/test_folder");
|
||||||
|
QString file_mod = QFINDTESTDATA("testdata/supercoolmod.jar");
|
||||||
|
|
||||||
|
QTemporaryDir tmp;
|
||||||
|
ResourceFolderModel model(tmp.path());
|
||||||
|
|
||||||
|
QCOMPARE(model.size(), 0);
|
||||||
|
|
||||||
|
{
|
||||||
|
EXEC_UPDATE_TASK(model.installResource(folder_resource), QVERIFY)
|
||||||
|
}
|
||||||
|
{
|
||||||
|
EXEC_UPDATE_TASK(model.installResource(file_mod), QVERIFY)
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto res : model.all())
|
||||||
|
qDebug() << res->name();
|
||||||
|
|
||||||
|
QCOMPARE(model.size(), 2);
|
||||||
|
|
||||||
|
auto& res_1 = model.at(0).type() != ResourceType::FOLDER ? model.at(0) : model.at(1);
|
||||||
|
auto& res_2 = model.at(0).type() == ResourceType::FOLDER ? model.at(0) : model.at(1);
|
||||||
|
auto id_1 = res_1.internal_id();
|
||||||
|
auto id_2 = res_2.internal_id();
|
||||||
|
bool initial_enabled_res_2 = res_2.enabled();
|
||||||
|
bool initial_enabled_res_1 = res_1.enabled();
|
||||||
|
|
||||||
|
QVERIFY(res_1.type() != ResourceType::FOLDER && res_1.type() != ResourceType::UNKNOWN);
|
||||||
|
qDebug() << "res_1 is of the correct type.";
|
||||||
|
QVERIFY(res_1.enabled());
|
||||||
|
qDebug() << "res_1 is initially enabled.";
|
||||||
|
|
||||||
|
QVERIFY(res_1.enable(EnableAction::TOGGLE));
|
||||||
|
|
||||||
|
QVERIFY(res_1.enabled() == !initial_enabled_res_1);
|
||||||
|
qDebug() << "res_1 got successfully toggled.";
|
||||||
|
|
||||||
|
QVERIFY(res_1.enable(EnableAction::TOGGLE));
|
||||||
|
qDebug() << "res_1 got successfully toggled again.";
|
||||||
|
|
||||||
|
QVERIFY(res_1.enabled() == initial_enabled_res_1);
|
||||||
|
QVERIFY(res_1.internal_id() == id_1);
|
||||||
|
qDebug() << "res_1 got back to its initial state.";
|
||||||
|
|
||||||
|
QVERIFY(!res_2.enable(initial_enabled_res_2 ? EnableAction::ENABLE : EnableAction::DISABLE));
|
||||||
|
QVERIFY(res_2.enabled() == initial_enabled_res_2);
|
||||||
|
QVERIFY(res_2.internal_id() == id_2);
|
||||||
|
|
||||||
|
while (model.hasPendingParseTasks()) {
|
||||||
|
QTest::qSleep(20);
|
||||||
|
QCoreApplication::processEvents();
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
QTEST_GUILESS_MAIN(ResourceFolderModelTest)
|
QTEST_GUILESS_MAIN(ResourceFolderModelTest)
|
||||||
|
@ -40,6 +40,7 @@ ExternalResourcesPage::ExternalResourcesPage(BaseInstance* instance, std::shared
|
|||||||
connect(ui->actionViewFolder, &QAction::triggered, this, &ExternalResourcesPage::viewFolder);
|
connect(ui->actionViewFolder, &QAction::triggered, this, &ExternalResourcesPage::viewFolder);
|
||||||
|
|
||||||
connect(ui->treeView, &ModListView::customContextMenuRequested, this, &ExternalResourcesPage::ShowContextMenu);
|
connect(ui->treeView, &ModListView::customContextMenuRequested, this, &ExternalResourcesPage::ShowContextMenu);
|
||||||
|
connect(ui->treeView, &ModListView::activated, this, &ExternalResourcesPage::itemActivated);
|
||||||
|
|
||||||
auto selection_model = ui->treeView->selectionModel();
|
auto selection_model = ui->treeView->selectionModel();
|
||||||
connect(selection_model, &QItemSelectionModel::currentChanged, this, &ExternalResourcesPage::current);
|
connect(selection_model, &QItemSelectionModel::currentChanged, this, &ExternalResourcesPage::current);
|
||||||
@ -81,6 +82,15 @@ void ExternalResourcesPage::retranslate()
|
|||||||
ui->retranslateUi(this);
|
ui->retranslateUi(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ExternalResourcesPage::itemActivated(const QModelIndex&)
|
||||||
|
{
|
||||||
|
if (!m_controlsEnabled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto selection = m_filterModel->mapSelectionToSource(ui->treeView->selectionModel()->selection());
|
||||||
|
m_model->setResourceEnabled(selection.indexes(), EnableAction::TOGGLE);
|
||||||
|
}
|
||||||
|
|
||||||
void ExternalResourcesPage::filterTextChanged(const QString& newContents)
|
void ExternalResourcesPage::filterTextChanged(const QString& newContents)
|
||||||
{
|
{
|
||||||
m_viewFilter = newContents;
|
m_viewFilter = newContents;
|
||||||
@ -157,6 +167,24 @@ void ExternalResourcesPage::removeItem()
|
|||||||
m_model->deleteResources(selection.indexes());
|
m_model->deleteResources(selection.indexes());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ExternalResourcesPage::enableItem()
|
||||||
|
{
|
||||||
|
if (!m_controlsEnabled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto selection = m_filterModel->mapSelectionToSource(ui->treeView->selectionModel()->selection());
|
||||||
|
m_model->setResourceEnabled(selection.indexes(), EnableAction::ENABLE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExternalResourcesPage::disableItem()
|
||||||
|
{
|
||||||
|
if (!m_controlsEnabled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto selection = m_filterModel->mapSelectionToSource(ui->treeView->selectionModel()->selection());
|
||||||
|
m_model->setResourceEnabled(selection.indexes(), EnableAction::DISABLE);
|
||||||
|
}
|
||||||
|
|
||||||
void ExternalResourcesPage::viewConfigs()
|
void ExternalResourcesPage::viewConfigs()
|
||||||
{
|
{
|
||||||
DesktopServices::openDirectory(m_instance->instanceConfigFolder(), true);
|
DesktopServices::openDirectory(m_instance->instanceConfigFolder(), true);
|
||||||
|
@ -45,15 +45,15 @@ class ExternalResourcesPage : public QMainWindow, public BasePage {
|
|||||||
virtual bool onSelectionChanged(const QModelIndex& current, const QModelIndex& previous);
|
virtual bool onSelectionChanged(const QModelIndex& current, const QModelIndex& previous);
|
||||||
|
|
||||||
protected slots:
|
protected slots:
|
||||||
virtual void itemActivated(const QModelIndex& index) {};
|
void itemActivated(const QModelIndex& index);
|
||||||
void filterTextChanged(const QString& newContents);
|
void filterTextChanged(const QString& newContents);
|
||||||
virtual void runningStateChanged(bool running);
|
virtual void runningStateChanged(bool running);
|
||||||
|
|
||||||
virtual void addItem();
|
virtual void addItem();
|
||||||
virtual void removeItem();
|
virtual void removeItem();
|
||||||
|
|
||||||
virtual void enableItem() {};
|
virtual void enableItem();
|
||||||
virtual void disableItem() {};
|
virtual void disableItem();
|
||||||
|
|
||||||
virtual void viewFolder();
|
virtual void viewFolder();
|
||||||
virtual void viewConfigs();
|
virtual void viewConfigs();
|
||||||
|
@ -110,8 +110,6 @@ ModFolderPage::ModFolderPage(BaseInstance* inst, std::shared_ptr<ModFolderModel>
|
|||||||
|
|
||||||
ModFolderPage::runningStateChanged(m_instance && m_instance->isRunning());
|
ModFolderPage::runningStateChanged(m_instance && m_instance->isRunning());
|
||||||
}
|
}
|
||||||
|
|
||||||
connect(ui->treeView, &ModListView::activated, this, &ModFolderPage::itemActivated);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModFolderPage::runningStateChanged(bool running)
|
void ModFolderPage::runningStateChanged(bool running)
|
||||||
@ -126,33 +124,6 @@ bool ModFolderPage::shouldDisplay() const
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModFolderPage::itemActivated(const QModelIndex&)
|
|
||||||
{
|
|
||||||
if (!m_controlsEnabled)
|
|
||||||
return;
|
|
||||||
|
|
||||||
auto selection = m_filterModel->mapSelectionToSource(ui->treeView->selectionModel()->selection());
|
|
||||||
m_model->setModStatus(selection.indexes(), ModFolderModel::Toggle);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ModFolderPage::enableItem()
|
|
||||||
{
|
|
||||||
if (!m_controlsEnabled)
|
|
||||||
return;
|
|
||||||
|
|
||||||
auto selection = m_filterModel->mapSelectionToSource(ui->treeView->selectionModel()->selection());
|
|
||||||
m_model->setModStatus(selection.indexes(), ModFolderModel::Enable);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ModFolderPage::disableItem()
|
|
||||||
{
|
|
||||||
if (!m_controlsEnabled)
|
|
||||||
return;
|
|
||||||
|
|
||||||
auto selection = m_filterModel->mapSelectionToSource(ui->treeView->selectionModel()->selection());
|
|
||||||
m_model->setModStatus(selection.indexes(), ModFolderModel::Disable);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ModFolderPage::onSelectionChanged(const QModelIndex& current, const QModelIndex& previous)
|
bool ModFolderPage::onSelectionChanged(const QModelIndex& current, const QModelIndex& previous)
|
||||||
{
|
{
|
||||||
auto sourceCurrent = m_filterModel->mapToSource(current);
|
auto sourceCurrent = m_filterModel->mapToSource(current);
|
||||||
|
@ -58,11 +58,6 @@ class ModFolderPage : public ExternalResourcesPage {
|
|||||||
public slots:
|
public slots:
|
||||||
bool onSelectionChanged(const QModelIndex& current, const QModelIndex& previous) override;
|
bool onSelectionChanged(const QModelIndex& current, const QModelIndex& previous) override;
|
||||||
|
|
||||||
void itemActivated(const QModelIndex& index) override;
|
|
||||||
|
|
||||||
void enableItem() override;
|
|
||||||
void disableItem() override;
|
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void installMods();
|
void installMods();
|
||||||
void updateMods();
|
void updateMods();
|
||||||
|
Loading…
Reference in New Issue
Block a user