diff options
Diffstat (limited to 'launcher/minecraft/mod/ResourceFolderModel.cpp')
-rw-r--r-- | launcher/minecraft/mod/ResourceFolderModel.cpp | 183 |
1 files changed, 138 insertions, 45 deletions
diff --git a/launcher/minecraft/mod/ResourceFolderModel.cpp b/launcher/minecraft/mod/ResourceFolderModel.cpp index f2a77c12..39a61067 100644 --- a/launcher/minecraft/mod/ResourceFolderModel.cpp +++ b/launcher/minecraft/mod/ResourceFolderModel.cpp @@ -1,18 +1,28 @@ #include "ResourceFolderModel.h" +#include <QMessageBox> #include <QCoreApplication> #include <QDebug> +#include <QFileInfo> +#include <QIcon> +#include <QMenu> #include <QMimeData> +#include <QStyle> #include <QThreadPool> #include <QUrl> +#include "Application.h" #include "FileSystem.h" +#include "QVariantUtils.h" #include "minecraft/mod/tasks/BasicFolderLoadTask.h" +#include "settings/Setting.h" #include "tasks/Task.h" +#include "ui/dialogs/CustomMessageBox.h" -ResourceFolderModel::ResourceFolderModel(QDir dir, QObject* parent, bool create_dir) : QAbstractListModel(parent), m_dir(dir), m_watcher(this) +ResourceFolderModel::ResourceFolderModel(QDir dir, BaseInstance* instance, QObject* parent, bool create_dir) + : QAbstractListModel(parent), m_dir(dir), m_instance(instance), m_watcher(this) { if (create_dir) { FS::ensureFolderPathExists(m_dir.absolutePath()); @@ -22,7 +32,7 @@ ResourceFolderModel::ResourceFolderModel(QDir dir, QObject* parent, bool create_ m_dir.setSorting(QDir::Name | QDir::IgnoreCase | QDir::LocaleAware); connect(&m_watcher, &QFileSystemWatcher::directoryChanged, this, &ResourceFolderModel::directoryChanged); - connect(&m_helper_thread_task, &ConcurrentTask::finished, this, [this]{ m_helper_thread_task.clear(); }); + connect(&m_helper_thread_task, &ConcurrentTask::finished, this, [this] { m_helper_thread_task.clear(); }); } ResourceFolderModel::~ResourceFolderModel() @@ -69,10 +79,6 @@ bool ResourceFolderModel::stopWatching(const QStringList paths) bool ResourceFolderModel::installResource(QString original_path) { - if (!m_can_interact) { - return false; - } - // NOTE: fix for GH-1178: remove trailing slash to avoid issues with using the empty result of QFileInfo::fileName original_path = FS::NormalizePath(original_path); QFileInfo file_info(original_path); @@ -151,7 +157,7 @@ bool ResourceFolderModel::uninstallResource(QString file_name) { for (auto& resource : m_resources) { if (resource->fileinfo().fileName() == file_name) { - auto res = resource->destroy(); + auto res = resource->destroy(false); update(); @@ -163,9 +169,6 @@ bool ResourceFolderModel::uninstallResource(QString file_name) bool ResourceFolderModel::deleteResources(const QModelIndexList& indexes) { - if (!m_can_interact) - return false; - if (indexes.isEmpty()) return true; @@ -184,11 +187,8 @@ bool ResourceFolderModel::deleteResources(const QModelIndexList& indexes) return true; } -bool ResourceFolderModel::setResourceEnabled(const QModelIndexList &indexes, EnableAction action) +bool ResourceFolderModel::setResourceEnabled(const QModelIndexList& indexes, EnableAction action) { - if (!m_can_interact) - return false; - if (indexes.isEmpty()) return true; @@ -241,15 +241,18 @@ bool ResourceFolderModel::update() 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::finished, this, [=] { - m_current_update_task.reset(); - if (m_scheduled_update) { - m_scheduled_update = false; - update(); - } else { - emit updateFinished(); - } - }, Qt::ConnectionType::QueuedConnection); + connect( + m_current_update_task.get(), &Task::finished, this, + [=] { + m_current_update_task.reset(); + if (m_scheduled_update) { + m_scheduled_update = false; + update(); + } else { + emit updateFinished(); + } + }, + Qt::ConnectionType::QueuedConnection); QThreadPool::globalInstance()->start(m_current_update_task.get()); @@ -339,15 +342,9 @@ Qt::DropActions ResourceFolderModel::supportedDropActions() const Qt::ItemFlags ResourceFolderModel::flags(const QModelIndex& index) const { Qt::ItemFlags defaultFlags = QAbstractListModel::flags(index); - auto flags = defaultFlags; - if (!m_can_interact) { - flags &= ~Qt::ItemIsDropEnabled; - } else { - flags |= Qt::ItemIsDropEnabled; - if (index.isValid()) { - flags |= Qt::ItemIsUserCheckable; - } - } + auto flags = defaultFlags | Qt::ItemIsDropEnabled; + if (index.isValid()) + flags |= Qt::ItemIsUserCheckable; return flags; } @@ -417,7 +414,27 @@ QVariant ResourceFolderModel::data(const QModelIndex& index, int role) const return {}; } case Qt::ToolTipRole: + if (column == NAME_COLUMN) { + if (at(row).isSymLinkUnder(instDirPath())) { + return m_resources[row]->internal_id() + + tr("\nWarning: This resource is symbolically linked from elsewhere. Editing it will also change the original." + "\nCanonical Path: %1") + .arg(at(row).fileinfo().canonicalFilePath()); + ; + } + if (at(row).isMoreThanOneHardLink()) { + return m_resources[row]->internal_id() + + tr("\nWarning: This resource is hard linked elsewhere. Editing it will also change the original."); + } + } + return m_resources[row]->internal_id(); + case Qt::DecorationRole: { + if (column == NAME_COLUMN && (at(row).isSymLinkUnder(instDirPath()) || at(row).isMoreThanOneHardLink())) + return APPLICATION->getThemedIcon("status-yellow"); + + return {}; + } case Qt::CheckStateRole: switch (column) { case ACTIVE_COLUMN: @@ -436,8 +453,20 @@ bool ResourceFolderModel::setData(const QModelIndex& index, const QVariant& valu if (row < 0 || row >= rowCount(index.parent()) || !index.isValid()) return false; - if (role == Qt::CheckStateRole) + if (role == Qt::CheckStateRole) { + if (m_instance != nullptr && m_instance->isRunning()) { + auto response = + CustomMessageBox::selectable(nullptr, "Confirm toggle", + "If you enable/disable this resource while the game is running it may crash your game.\n" + "Are you sure you want to do this?", + QMessageBox::Warning, QMessageBox::Yes | QMessageBox::No, QMessageBox::No) + ->exec(); + + if (response != QMessageBox::Yes) + return false; + } return setResourceEnabled({ index }, EnableAction::TOGGLE); + } return false; } @@ -447,10 +476,10 @@ QVariant ResourceFolderModel::headerData(int section, Qt::Orientation orientatio switch (role) { case Qt::DisplayRole: switch (section) { + case ACTIVE_COLUMN: case NAME_COLUMN: - return tr("Name"); case DATE_COLUMN: - return tr("Last modified"); + return columnNames().at(section); default: return {}; } @@ -476,6 +505,75 @@ QVariant ResourceFolderModel::headerData(int section, Qt::Orientation orientatio return {}; } +void ResourceFolderModel::setupHeaderAction(QAction* act, int column) +{ + Q_ASSERT(act); + + act->setText(columnNames().at(column)); +} + +void ResourceFolderModel::saveHiddenColumn(int column, bool hidden) +{ + auto const setting_name = QString("UI/%1_Page/HiddenColumns").arg(id()); + auto setting = (m_instance->settings()->contains(setting_name)) ? + m_instance->settings()->getSetting(setting_name) : m_instance->settings()->registerSetting(setting_name); + + auto hiddenColumns = setting->get().toStringList(); + auto name = columnNames(false).at(column); + auto index = hiddenColumns.indexOf(name); + if (index >= 0 && !hidden) { + hiddenColumns.removeAt(index); + } else if ( index < 0 && hidden) { + hiddenColumns.append(name); + } + setting->set(hiddenColumns); +} + +void ResourceFolderModel::loadHiddenColumns(QTreeView *tree) +{ + auto const setting_name = QString("UI/%1_Page/HiddenColumns").arg(id()); + auto setting = (m_instance->settings()->contains(setting_name)) ? + m_instance->settings()->getSetting(setting_name) : m_instance->settings()->registerSetting(setting_name); + + auto hiddenColumns = setting->get().toStringList(); + auto col_names = columnNames(false); + for (auto col_name : hiddenColumns) { + auto index = col_names.indexOf(col_name); + if (index >= 0) + tree->setColumnHidden(index, true); + } + +} + +QMenu* ResourceFolderModel::createHeaderContextMenu(QTreeView* tree) +{ + auto menu = new QMenu(tree); + + menu->addSeparator()->setText(tr("Show / Hide Columns")); + + for (int col = 0; col < columnCount(); ++col) { + auto act = new QAction(menu); + setupHeaderAction(act, col); + + act->setCheckable(true); + act->setChecked(!tree->isColumnHidden(col)); + + connect(act, &QAction::toggled, tree, [this, col, tree](bool toggled){ + tree->setColumnHidden(col, !toggled); + for(int c = 0; c < columnCount(); ++c) { + if (m_column_resize_modes.at(c) == QHeaderView::ResizeToContents) + tree->resizeColumnToContents(c); + } + saveHiddenColumn(col, !toggled); + }); + + menu->addAction(act); + + } + + return menu; +} + QSortFilterProxyModel* ResourceFolderModel::createFilterProxyModel(QObject* parent) { return new ProxyModel(parent); @@ -487,16 +585,6 @@ SortType ResourceFolderModel::columnToSortKey(size_t column) const return m_column_sort_keys.at(column); } -void ResourceFolderModel::enableInteraction(bool enabled) -{ - if (m_can_interact == enabled) - return; - - m_can_interact = enabled; - if (size()) - 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 { @@ -531,3 +619,8 @@ void ResourceFolderModel::enableInteraction(bool enabled) return (compare_result.first < 0); return (compare_result.first > 0); } + +QString ResourceFolderModel::instDirPath() const +{ + return QFileInfo(m_instance->instanceRoot()).absoluteFilePath(); +} |