aboutsummaryrefslogtreecommitdiff
path: root/launcher/ui/pages
diff options
context:
space:
mode:
authorSefa Eyeoglu <contact@scrumplex.net>2022-07-01 10:00:36 +0200
committerGitHub <noreply@github.com>2022-07-01 10:00:36 +0200
commit63dfc0633faa01ee798b3623b4a1a36a189abef0 (patch)
tree7a04033ff70caa99c37ab3672d8106476d0b812a /launcher/ui/pages
parent50f1847904af43c1e2641b7d66c453edce37ba23 (diff)
parent5f951e8f213e3636f4e64190fe1a720067963108 (diff)
downloadPrismLauncher-63dfc0633faa01ee798b3623b4a1a36a189abef0.tar.gz
PrismLauncher-63dfc0633faa01ee798b3623b4a1a36a189abef0.tar.bz2
PrismLauncher-63dfc0633faa01ee798b3623b4a1a36a189abef0.zip
Merge pull request #652 from flowln/mod_page
Diffstat (limited to 'launcher/ui/pages')
-rw-r--r--launcher/ui/pages/instance/ExternalResourcesPage.cpp297
-rw-r--r--launcher/ui/pages/instance/ExternalResourcesPage.h73
-rw-r--r--launcher/ui/pages/instance/ExternalResourcesPage.ui (renamed from launcher/ui/pages/instance/ModFolderPage.ui)49
-rw-r--r--launcher/ui/pages/instance/ModFolderPage.cpp379
-rw-r--r--launcher/ui/pages/instance/ModFolderPage.h112
-rw-r--r--launcher/ui/pages/instance/ResourcePackPage.h20
-rw-r--r--launcher/ui/pages/instance/ShaderPackPage.h16
-rw-r--r--launcher/ui/pages/instance/TexturePackPage.h18
8 files changed, 494 insertions, 470 deletions
diff --git a/launcher/ui/pages/instance/ExternalResourcesPage.cpp b/launcher/ui/pages/instance/ExternalResourcesPage.cpp
new file mode 100644
index 00000000..02eeae3d
--- /dev/null
+++ b/launcher/ui/pages/instance/ExternalResourcesPage.cpp
@@ -0,0 +1,297 @@
+#include "ExternalResourcesPage.h"
+#include "ui_ExternalResourcesPage.h"
+
+#include "DesktopServices.h"
+#include "Version.h"
+#include "minecraft/mod/ModFolderModel.h"
+#include "ui/GuiUtil.h"
+
+#include <QKeyEvent>
+#include <QMenu>
+
+namespace {
+// FIXME: wasteful
+void RemoveThePrefix(QString& string)
+{
+ QRegularExpression regex(QStringLiteral("^(?:the|teh) +"), QRegularExpression::CaseInsensitiveOption);
+ string.remove(regex);
+ string = string.trimmed();
+}
+} // namespace
+
+class SortProxy : public QSortFilterProxyModel {
+ public:
+ explicit SortProxy(QObject* parent = nullptr) : QSortFilterProxyModel(parent) {}
+
+ protected:
+ bool filterAcceptsRow(int source_row, const QModelIndex& source_parent) const override
+ {
+ ModFolderModel* model = qobject_cast<ModFolderModel*>(sourceModel());
+ if (!model)
+ return false;
+
+ const auto& mod = model->at(source_row);
+
+ if (mod.name().contains(filterRegExp()))
+ return true;
+ if (mod.description().contains(filterRegExp()))
+ return true;
+
+ for (auto& author : mod.authors()) {
+ if (author.contains(filterRegExp())) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ bool lessThan(const QModelIndex& source_left, const QModelIndex& source_right) const override
+ {
+ ModFolderModel* model = qobject_cast<ModFolderModel*>(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 = (ModFolderModel::Columns) source_left.column();
+ bool invert = false;
+ switch (column) {
+ // GH-2550 - sort by enabled/disabled
+ case ModFolderModel::ActiveColumn: {
+ auto dataL = source_left.data(Qt::CheckStateRole).toBool();
+ auto dataR = source_right.data(Qt::CheckStateRole).toBool();
+ if (dataL != dataR)
+ return dataL > dataR;
+
+ // fallthrough
+ invert = sortOrder() == Qt::DescendingOrder;
+ }
+ // GH-2722 - sort mod names in a way that discards "The" prefixes
+ case ModFolderModel::NameColumn: {
+ auto dataL = model->data(model->index(source_left.row(), ModFolderModel::NameColumn)).toString();
+ RemoveThePrefix(dataL);
+ auto dataR = model->data(model->index(source_right.row(), ModFolderModel::NameColumn)).toString();
+ RemoveThePrefix(dataR);
+
+ auto less = dataL.compare(dataR, sortCaseSensitivity());
+ if (less != 0)
+ return invert ? (less > 0) : (less < 0);
+
+ // fallthrough
+ invert = sortOrder() == Qt::DescendingOrder;
+ }
+ // GH-2762 - sort versions by parsing them as versions
+ case ModFolderModel::VersionColumn: {
+ auto dataL = Version(model->data(model->index(source_left.row(), ModFolderModel::VersionColumn)).toString());
+ auto dataR = Version(model->data(model->index(source_right.row(), ModFolderModel::VersionColumn)).toString());
+ return invert ? (dataL > dataR) : (dataL < dataR);
+ }
+ default: {
+ return QSortFilterProxyModel::lessThan(source_left, source_right);
+ }
+ }
+ }
+};
+
+ExternalResourcesPage::ExternalResourcesPage(BaseInstance* instance, std::shared_ptr<ModFolderModel> model, QWidget* parent)
+ : QMainWindow(parent), m_instance(instance), ui(new Ui::ExternalResourcesPage), m_model(model)
+{
+ ui->setupUi(this);
+
+ runningStateChanged(m_instance && m_instance->isRunning());
+
+ ui->actionsToolbar->insertSpacer(ui->actionViewConfigs);
+
+ m_filterModel = new SortProxy(this);
+ m_filterModel->setDynamicSortFilter(true);
+ m_filterModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
+ m_filterModel->setSortCaseSensitivity(Qt::CaseInsensitive);
+ m_filterModel->setSourceModel(m_model.get());
+ m_filterModel->setFilterKeyColumn(-1);
+ ui->treeView->setModel(m_filterModel);
+
+ ui->treeView->installEventFilter(this);
+ ui->treeView->sortByColumn(1, Qt::AscendingOrder);
+ ui->treeView->setContextMenuPolicy(Qt::CustomContextMenu);
+
+ // The default function names by Qt are pretty ugly, so let's just connect the actions manually,
+ // to make it easier to read :)
+ connect(ui->actionAddItem, &QAction::triggered, this, &ExternalResourcesPage::addItem);
+ connect(ui->actionRemoveItem, &QAction::triggered, this, &ExternalResourcesPage::removeItem);
+ connect(ui->actionEnableItem, &QAction::triggered, this, &ExternalResourcesPage::enableItem);
+ connect(ui->actionDisableItem, &QAction::triggered, this, &ExternalResourcesPage::disableItem);
+ connect(ui->actionViewConfigs, &QAction::triggered, this, &ExternalResourcesPage::viewConfigs);
+ connect(ui->actionViewFolder, &QAction::triggered, this, &ExternalResourcesPage::viewFolder);
+
+ connect(ui->treeView, &ModListView::customContextMenuRequested, this, &ExternalResourcesPage::ShowContextMenu);
+ connect(ui->treeView, &ModListView::activated, this, &ExternalResourcesPage::itemActivated);
+
+ auto selection_model = ui->treeView->selectionModel();
+ connect(selection_model, &QItemSelectionModel::currentChanged, this, &ExternalResourcesPage::current);
+ connect(ui->filterEdit, &QLineEdit::textChanged, this, &ExternalResourcesPage::filterTextChanged);
+ connect(m_instance, &BaseInstance::runningStatusChanged, this, &ExternalResourcesPage::runningStateChanged);
+}
+
+ExternalResourcesPage::~ExternalResourcesPage()
+{
+ m_model->stopWatching();
+ delete ui;
+}
+
+void ExternalResourcesPage::itemActivated(const QModelIndex&)
+{
+ if (!m_controlsEnabled)
+ return;
+
+ auto selection = m_filterModel->mapSelectionToSource(ui->treeView->selectionModel()->selection());
+ m_model->setModStatus(selection.indexes(), ModFolderModel::Toggle);
+}
+
+QMenu* ExternalResourcesPage::createPopupMenu()
+{
+ QMenu* filteredMenu = QMainWindow::createPopupMenu();
+ filteredMenu->removeAction(ui->actionsToolbar->toggleViewAction());
+ return filteredMenu;
+}
+
+void ExternalResourcesPage::ShowContextMenu(const QPoint& pos)
+{
+ auto menu = ui->actionsToolbar->createContextMenu(this, tr("Context menu"));
+ menu->exec(ui->treeView->mapToGlobal(pos));
+ delete menu;
+}
+
+void ExternalResourcesPage::openedImpl()
+{
+ m_model->startWatching();
+}
+
+void ExternalResourcesPage::closedImpl()
+{
+ m_model->stopWatching();
+}
+
+void ExternalResourcesPage::retranslate()
+{
+ ui->retranslateUi(this);
+}
+
+void ExternalResourcesPage::filterTextChanged(const QString& newContents)
+{
+ m_viewFilter = newContents;
+ m_filterModel->setFilterFixedString(m_viewFilter);
+}
+
+void ExternalResourcesPage::runningStateChanged(bool running)
+{
+ if (m_controlsEnabled == !running)
+ return;
+
+ m_controlsEnabled = !running;
+ ui->actionAddItem->setEnabled(m_controlsEnabled);
+ ui->actionDisableItem->setEnabled(m_controlsEnabled);
+ ui->actionEnableItem->setEnabled(m_controlsEnabled);
+ ui->actionRemoveItem->setEnabled(m_controlsEnabled);
+}
+
+bool ExternalResourcesPage::shouldDisplay() const
+{
+ return true;
+}
+
+bool ExternalResourcesPage::listFilter(QKeyEvent* keyEvent)
+{
+ switch (keyEvent->key()) {
+ case Qt::Key_Delete:
+ removeItem();
+ return true;
+ case Qt::Key_Plus:
+ addItem();
+ return true;
+ default:
+ break;
+ }
+ return QWidget::eventFilter(ui->treeView, keyEvent);
+}
+
+bool ExternalResourcesPage::eventFilter(QObject* obj, QEvent* ev)
+{
+ if (ev->type() != QEvent::KeyPress)
+ return QWidget::eventFilter(obj, ev);
+
+ QKeyEvent* keyEvent = static_cast<QKeyEvent*>(ev);
+ if (obj == ui->treeView)
+ return listFilter(keyEvent);
+
+ return QWidget::eventFilter(obj, ev);
+}
+
+void ExternalResourcesPage::addItem()
+{
+ if (!m_controlsEnabled)
+ return;
+
+
+ auto list = GuiUtil::BrowseForFiles(
+ helpPage(), tr("Select %1", "Select whatever type of files the page contains. Example: 'Loader Mods'").arg(displayName()),
+ m_fileSelectionFilter.arg(displayName()), APPLICATION->settings()->get("CentralModsDir").toString(), this->parentWidget());
+
+ if (!list.isEmpty()) {
+ for (auto filename : list) {
+ m_model->installMod(filename);
+ }
+ }
+}
+
+void ExternalResourcesPage::removeItem()
+{
+ if (!m_controlsEnabled)
+ return;
+
+ auto selection = m_filterModel->mapSelectionToSource(ui->treeView->selectionModel()->selection());
+ m_model->deleteMods(selection.indexes());
+}
+
+void ExternalResourcesPage::enableItem()
+{
+ if (!m_controlsEnabled)
+ return;
+
+ auto selection = m_filterModel->mapSelectionToSource(ui->treeView->selectionModel()->selection());
+ m_model->setModStatus(selection.indexes(), ModFolderModel::Enable);
+}
+
+void ExternalResourcesPage::disableItem()
+{
+ if (!m_controlsEnabled)
+ return;
+
+ auto selection = m_filterModel->mapSelectionToSource(ui->treeView->selectionModel()->selection());
+ m_model->setModStatus(selection.indexes(), ModFolderModel::Disable);
+}
+
+void ExternalResourcesPage::viewConfigs()
+{
+ DesktopServices::openDirectory(m_instance->instanceConfigFolder(), true);
+}
+
+void ExternalResourcesPage::viewFolder()
+{
+ DesktopServices::openDirectory(m_model->dir().absolutePath(), true);
+}
+
+void ExternalResourcesPage::current(const QModelIndex& current, const QModelIndex& previous)
+{
+ if (!current.isValid()) {
+ ui->frame->clear();
+ return;
+ }
+
+ auto sourceCurrent = m_filterModel->mapToSource(current);
+ int row = sourceCurrent.row();
+ Mod& m = m_model->operator[](row);
+ ui->frame->updateWithMod(m);
+}
diff --git a/launcher/ui/pages/instance/ExternalResourcesPage.h b/launcher/ui/pages/instance/ExternalResourcesPage.h
new file mode 100644
index 00000000..41237139
--- /dev/null
+++ b/launcher/ui/pages/instance/ExternalResourcesPage.h
@@ -0,0 +1,73 @@
+#pragma once
+
+#include <QMainWindow>
+#include <QSortFilterProxyModel>
+
+#include "Application.h"
+#include "minecraft/MinecraftInstance.h"
+#include "ui/pages/BasePage.h"
+
+class ModFolderModel;
+
+namespace Ui {
+class ExternalResourcesPage;
+}
+
+/* This page is used as a base for pages in which the user can manage external resources
+ * related to the game, such as mods, shaders or resource packs. */
+class ExternalResourcesPage : public QMainWindow, public BasePage {
+ Q_OBJECT
+
+ public:
+ // FIXME: Switch to different model (or change the name of this one)
+ explicit ExternalResourcesPage(BaseInstance* instance, std::shared_ptr<ModFolderModel> model, QWidget* parent = nullptr);
+ virtual ~ExternalResourcesPage();
+
+ virtual QString displayName() const override = 0;
+ virtual QIcon icon() const override = 0;
+ virtual QString id() const override = 0;
+ virtual QString helpPage() const override = 0;
+
+ virtual bool shouldDisplay() const override = 0;
+
+ void openedImpl() override;
+ void closedImpl() override;
+
+ void retranslate() override;
+
+ protected:
+ bool eventFilter(QObject* obj, QEvent* ev) override;
+ bool listFilter(QKeyEvent* ev);
+ QMenu* createPopupMenu() override;
+
+ public slots:
+ void current(const QModelIndex& current, const QModelIndex& previous);
+
+ protected slots:
+ void itemActivated(const QModelIndex& index);
+ void filterTextChanged(const QString& newContents);
+ void runningStateChanged(bool running);
+
+ virtual void addItem();
+ virtual void removeItem();
+
+ virtual void enableItem();
+ virtual void disableItem();
+
+ virtual void viewFolder();
+ virtual void viewConfigs();
+
+ void ShowContextMenu(const QPoint& pos);
+
+ protected:
+ BaseInstance* m_instance = nullptr;
+
+ Ui::ExternalResourcesPage* ui = nullptr;
+ std::shared_ptr<ModFolderModel> m_model;
+ QSortFilterProxyModel* m_filterModel = nullptr;
+
+ QString m_fileSelectionFilter;
+ QString m_viewFilter;
+
+ bool m_controlsEnabled = true;
+};
diff --git a/launcher/ui/pages/instance/ModFolderPage.ui b/launcher/ui/pages/instance/ExternalResourcesPage.ui
index ab59b0df..17bf455a 100644
--- a/launcher/ui/pages/instance/ModFolderPage.ui
+++ b/launcher/ui/pages/instance/ExternalResourcesPage.ui
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
- <class>ModFolderPage</class>
- <widget class="QMainWindow" name="ModFolderPage">
+ <class>ExternalResourcesPage</class>
+ <widget class="QMainWindow" name="ExternalResourcesPage">
<property name="geometry">
<rect>
<x>0</x>
@@ -53,7 +53,7 @@
</widget>
</item>
<item row="1" column="1" colspan="3">
- <widget class="ModListView" name="modTreeView">
+ <widget class="ModListView" name="treeView">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
@@ -83,15 +83,15 @@
<attribute name="toolBarBreak">
<bool>false</bool>
</attribute>
- <addaction name="actionAdd"/>
+ <addaction name="actionAddItem"/>
<addaction name="separator"/>
- <addaction name="actionRemove"/>
- <addaction name="actionEnable"/>
- <addaction name="actionDisable"/>
- <addaction name="actionView_configs"/>
- <addaction name="actionView_Folder"/>
+ <addaction name="actionRemoveItem"/>
+ <addaction name="actionEnableItem"/>
+ <addaction name="actionDisableItem"/>
+ <addaction name="actionViewConfigs"/>
+ <addaction name="actionViewFolder"/>
</widget>
- <action name="actionAdd">
+ <action name="actionAddItem">
<property name="text">
<string>&amp;Add</string>
</property>
@@ -99,31 +99,31 @@
<string>Add</string>
</property>
</action>
- <action name="actionRemove">
+ <action name="actionRemoveItem">
<property name="text">
<string>&amp;Remove</string>
</property>
<property name="toolTip">
- <string>Remove selected mods</string>
+ <string>Remove selected item</string>
</property>
</action>
- <action name="actionEnable">
+ <action name="actionEnableItem">
<property name="text">
<string>&amp;Enable</string>
</property>
<property name="toolTip">
- <string>Enable selected mods</string>
+ <string>Enable selected item</string>
</property>
</action>
- <action name="actionDisable">
+ <action name="actionDisableItem">
<property name="text">
<string>&amp;Disable</string>
</property>
<property name="toolTip">
- <string>Disable selected mods</string>
+ <string>Disable selected item</string>
</property>
</action>
- <action name="actionView_configs">
+ <action name="actionViewConfigs">
<property name="text">
<string>View &amp;Configs</string>
</property>
@@ -131,11 +131,22 @@
<string>Open the 'config' folder in the system file manager.</string>
</property>
</action>
- <action name="actionView_Folder">
+ <action name="actionViewFolder">
<property name="text">
<string>View &amp;Folder</string>
</property>
</action>
+ <action name="actionDownloadItem">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>&amp;Download</string>
+ </property>
+ <property name="toolTip">
+ <string>Download a new resource</string>
+ </property>
+ </action>
</widget>
<customwidgets>
<customwidget>
@@ -156,7 +167,7 @@
</customwidget>
</customwidgets>
<tabstops>
- <tabstop>modTreeView</tabstop>
+ <tabstop>treeView</tabstop>
<tabstop>filterEdit</tabstop>
</tabstops>
<resources/>
diff --git a/launcher/ui/pages/instance/ModFolderPage.cpp b/launcher/ui/pages/instance/ModFolderPage.cpp
index d929a0ea..8fd0f86e 100644
--- a/launcher/ui/pages/instance/ModFolderPage.cpp
+++ b/launcher/ui/pages/instance/ModFolderPage.cpp
@@ -35,368 +35,97 @@
*/
#include "ModFolderPage.h"
-#include "ui_ModFolderPage.h"
+#include "ui_ExternalResourcesPage.h"
-#include <QMessageBox>
+#include <QAbstractItemModel>
#include <QEvent>
#include <QKeyEvent>
-#include <QAbstractItemModel>
#include <QMenu>
+#include <QMessageBox>
#include <QSortFilterProxyModel>
#include "Application.h"
+#include "ui/GuiUtil.h"
#include "ui/dialogs/CustomMessageBox.h"
#include "ui/dialogs/ModDownloadDialog.h"
-#include "ui/GuiUtil.h"
#include "DesktopServices.h"
-#include "minecraft/mod/ModFolderModel.h"
-#include "minecraft/mod/Mod.h"
-#include "minecraft/VersionFilterData.h"
#include "minecraft/PackProfile.h"
+#include "minecraft/VersionFilterData.h"
+#include "minecraft/mod/Mod.h"
+#include "minecraft/mod/ModFolderModel.h"
#include "modplatform/ModAPI.h"
#include "Version.h"
-#include "ui/dialogs/ProgressDialog.h"
#include "tasks/SequentialTask.h"
+#include "ui/dialogs/ProgressDialog.h"
-namespace {
- // FIXME: wasteful
- void RemoveThePrefix(QString & string) {
- QRegularExpression regex(QStringLiteral("^(([Tt][Hh][eE])|([Tt][eE][Hh])) +"));
- string.remove(regex);
- string = string.trimmed();
- }
-}
-
-class ModSortProxy : public QSortFilterProxyModel
-{
-public:
- explicit ModSortProxy(QObject *parent = 0) : QSortFilterProxyModel(parent)
- {
- }
-
-protected:
- bool filterAcceptsRow(int source_row, const QModelIndex & source_parent) const override {
- ModFolderModel *model = qobject_cast<ModFolderModel *>(sourceModel());
- if(!model) {
- return false;
- }
- const auto &mod = model->at(source_row);
- if(mod.name().contains(filterRegExp())) {
- return true;
- }
- if(mod.description().contains(filterRegExp())) {
- return true;
- }
- for(auto & author: mod.authors()) {
- if (author.contains(filterRegExp())) {
- return true;
- }
- }
- return false;
- }
-
- bool lessThan(const QModelIndex & source_left, const QModelIndex & source_right) const override
- {
- ModFolderModel *model = qobject_cast<ModFolderModel *>(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 = (ModFolderModel::Columns) source_left.column();
- bool invert = false;
- switch(column) {
- // GH-2550 - sort by enabled/disabled
- case ModFolderModel::ActiveColumn: {
- auto dataL = source_left.data(Qt::CheckStateRole).toBool();
- auto dataR = source_right.data(Qt::CheckStateRole).toBool();
- if(dataL != dataR) {
- return dataL > dataR;
- }
- // fallthrough
- invert = sortOrder() == Qt::DescendingOrder;
- }
- // GH-2722 - sort mod names in a way that discards "The" prefixes
- case ModFolderModel::NameColumn: {
- auto dataL = model->data(model->index(source_left.row(), ModFolderModel::NameColumn)).toString();
- RemoveThePrefix(dataL);
- auto dataR = model->data(model->index(source_right.row(), ModFolderModel::NameColumn)).toString();
- RemoveThePrefix(dataR);
-
- auto less = dataL.compare(dataR, sortCaseSensitivity());
- if(less != 0) {
- return invert ? (less > 0) : (less < 0);
- }
- // fallthrough
- invert = sortOrder() == Qt::DescendingOrder;
- }
- // GH-2762 - sort versions by parsing them as versions
- case ModFolderModel::VersionColumn: {
- auto dataL = Version(model->data(model->index(source_left.row(), ModFolderModel::VersionColumn)).toString());
- auto dataR = Version(model->data(model->index(source_right.row(), ModFolderModel::VersionColumn)).toString());
- return invert ? (dataL > dataR) : (dataL < dataR);
- }
- default: {
- return QSortFilterProxyModel::lessThan(source_left, source_right);
- }
- }
- }
-};
-
-ModFolderPage::ModFolderPage(
- BaseInstance *inst,
- std::shared_ptr<ModFolderModel> mods,
- QString id,
- QString iconName,
- QString displayName,
- QString helpPage,
- QWidget *parent
-) :
- QMainWindow(parent),
- ui(new Ui::ModFolderPage)
+ModFolderPage::ModFolderPage(BaseInstance* inst, std::shared_ptr<ModFolderModel> mods, QWidget* parent)
+ : ExternalResourcesPage(inst, mods, parent)
{
- ui->setupUi(this);
-
// This is structured like that so that these changes
- // do not affect the Resouce pack and Shader pack tabs
- if(id == "mods") {
- auto act = new QAction(tr("Download mods"), this);
- act->setToolTip(tr("Download mods from online mod platforms"));
- ui->actionsToolbar->insertActionBefore(ui->actionAdd, act);
- connect(act, &QAction::triggered, this, &ModFolderPage::on_actionInstall_mods_triggered);
-
- ui->actionAdd->setText(tr("Add .jar"));
- ui->actionAdd->setToolTip(tr("Add mods via local file"));
- }
-
- ui->actionsToolbar->insertSpacer(ui->actionView_configs);
-
- m_inst = inst;
- on_RunningState_changed(m_inst && m_inst->isRunning());
- m_mods = mods;
- m_id = id;
- m_displayName = displayName;
- m_iconName = iconName;
- m_helpName = helpPage;
- m_fileSelectionFilter = "%1 (*.zip *.jar)";
- m_filterModel = new ModSortProxy(this);
- m_filterModel->setDynamicSortFilter(true);
- m_filterModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
- m_filterModel->setSortCaseSensitivity(Qt::CaseInsensitive);
- m_filterModel->setSourceModel(m_mods.get());
- m_filterModel->setFilterKeyColumn(-1);
- ui->modTreeView->setModel(m_filterModel);
- ui->modTreeView->installEventFilter(this);
- ui->modTreeView->sortByColumn(1, Qt::AscendingOrder);
- ui->modTreeView->setContextMenuPolicy(Qt::CustomContextMenu);
- connect(ui->modTreeView, &ModListView::customContextMenuRequested, this, &ModFolderPage::ShowContextMenu);
- connect(ui->modTreeView, &ModListView::activated, this, &ModFolderPage::modItemActivated);
+ // do not affect the Resource pack and Shader pack tabs
+ {
+ ui->actionDownloadItem->setText(tr("Download mods"));
+ ui->actionDownloadItem->setToolTip(tr("Download mods from online mod platforms"));
+ ui->actionDownloadItem->setEnabled(true);
+ ui->actionAddItem->setText(tr("Add file"));
+ ui->actionAddItem->setToolTip(tr("Add a locally downloaded file"));
- auto smodel = ui->modTreeView->selectionModel();
- connect(smodel, &QItemSelectionModel::currentChanged, this, &ModFolderPage::modCurrent);
- connect(ui->filterEdit, &QLineEdit::textChanged, this, &ModFolderPage::on_filterTextChanged);
- connect(m_inst, &BaseInstance::runningStatusChanged, this, &ModFolderPage::on_RunningState_changed);
-}
+ ui->actionsToolbar->insertActionBefore(ui->actionAddItem, ui->actionDownloadItem);
-void ModFolderPage::modItemActivated(const QModelIndex&)
-{
- if(!m_controlsEnabled) {
- return;
+ connect(ui->actionDownloadItem, &QAction::triggered, this, &ModFolderPage::installMods);
}
- auto selection = m_filterModel->mapSelectionToSource(ui->modTreeView->selectionModel()->selection());
- m_mods->setModStatus(selection.indexes(), ModFolderModel::Toggle);
-}
-
-QMenu * ModFolderPage::createPopupMenu()
-{
- QMenu* filteredMenu = QMainWindow::createPopupMenu();
- filteredMenu->removeAction(ui->actionsToolbar->toggleViewAction() );
- return filteredMenu;
-}
-
-void ModFolderPage::ShowContextMenu(const QPoint& pos)
-{
- auto menu = ui->actionsToolbar->createContextMenu(this, tr("Context menu"));
- menu->exec(ui->modTreeView->mapToGlobal(pos));
- delete menu;
-}
-
-void ModFolderPage::openedImpl()
-{
- m_mods->startWatching();
-}
-
-void ModFolderPage::closedImpl()
-{
- m_mods->stopWatching();
-}
-
-void ModFolderPage::on_filterTextChanged(const QString& newContents)
-{
- m_viewFilter = newContents;
- m_filterModel->setFilterFixedString(m_viewFilter);
}
-
-CoreModFolderPage::CoreModFolderPage(BaseInstance *inst, std::shared_ptr<ModFolderModel> mods,
- QString id, QString iconName, QString displayName,
- QString helpPage, QWidget *parent)
- : ModFolderPage(inst, mods, id, iconName, displayName, helpPage, parent)
-{
-}
-
-ModFolderPage::~ModFolderPage()
-{
- m_mods->stopWatching();
- delete ui;
-}
-
-void ModFolderPage::on_RunningState_changed(bool running)
-{
- if(m_controlsEnabled == !running) {
- return;
- }
- m_controlsEnabled = !running;
- ui->actionsToolbar->setEnabled(m_controlsEnabled);
-}
+CoreModFolderPage::CoreModFolderPage(BaseInstance* inst, std::shared_ptr<ModFolderModel> mods, QWidget* parent)
+ : ModFolderPage(inst, mods, parent)
+{}
bool ModFolderPage::shouldDisplay() const
{
return true;
}
-void ModFolderPage::retranslate()
-{
- ui->retranslateUi(this);
-}
-
bool CoreModFolderPage::shouldDisplay() const
{
- if (ModFolderPage::shouldDisplay())
- {
- auto inst = dynamic_cast<MinecraftInstance *>(m_inst);
+ if (ModFolderPage::shouldDisplay()) {
+ auto inst = dynamic_cast<MinecraftInstance*>(m_instance);
if (!inst)
return true;
+
auto version = inst->getPackProfile();
+
if (!version)
return true;
- if(!version->getComponent("net.minecraftforge"))
- {
+ if (!version->getComponent("net.minecraftforge"))
return false;
- }
- if(!version->getComponent("net.minecraft"))
- {
+ if (!version->getComponent("net.minecraft"))
return false;
- }
- if(version->getComponent("net.minecraft")->getReleaseDateTime() < g_VersionFilterData.legacyCutoffDate)
- {
+ if (version->getComponent("net.minecraft")->getReleaseDateTime() < g_VersionFilterData.legacyCutoffDate)
return true;
- }
+
}
return false;
}
-bool ModFolderPage::modListFilter(QKeyEvent *keyEvent)
-{
- switch (keyEvent->key())
- {
- case Qt::Key_Delete:
- on_actionRemove_triggered();
- return true;
- case Qt::Key_Plus:
- on_actionAdd_triggered();
- return true;
- default:
- break;
- }
- return QWidget::eventFilter(ui->modTreeView, keyEvent);
-}
-
-bool ModFolderPage::eventFilter(QObject *obj, QEvent *ev)
-{
- if (ev->type() != QEvent::KeyPress)
- {
- return QWidget::eventFilter(obj, ev);
- }
- QKeyEvent *keyEvent = static_cast<QKeyEvent *>(ev);
- if (obj == ui->modTreeView)
- return modListFilter(keyEvent);
- return QWidget::eventFilter(obj, ev);
-}
-
-void ModFolderPage::on_actionAdd_triggered()
-{
- if(!m_controlsEnabled) {
- return;
- }
- auto list = GuiUtil::BrowseForFiles(
- m_helpName,
- tr("Select %1",
- "Select whatever type of files the page contains. Example: 'Loader Mods'")
- .arg(m_displayName),
- m_fileSelectionFilter.arg(m_displayName), APPLICATION->settings()->get("CentralModsDir").toString(),
- this->parentWidget());
- if (!list.empty())
- {
- for (auto filename : list)
- {
- m_mods->installMod(filename);
- }
- }
-}
-
-void ModFolderPage::on_actionEnable_triggered()
-{
- if(!m_controlsEnabled) {
- return;
- }
- auto selection = m_filterModel->mapSelectionToSource(ui->modTreeView->selectionModel()->selection());
- m_mods->setModStatus(selection.indexes(), ModFolderModel::Enable);
-}
-
-void ModFolderPage::on_actionDisable_triggered()
-{
- if(!m_controlsEnabled) {
- return;
- }
- auto selection = m_filterModel->mapSelectionToSource(ui->modTreeView->selectionModel()->selection());
- m_mods->setModStatus(selection.indexes(), ModFolderModel::Disable);
-}
-
-void ModFolderPage::on_actionRemove_triggered()
-{
- if(!m_controlsEnabled) {
- return;
- }
- auto selection = m_filterModel->mapSelectionToSource(ui->modTreeView->selectionModel()->selection());
- m_mods->deleteMods(selection.indexes());
-}
-
-void ModFolderPage::on_actionInstall_mods_triggered()
+void ModFolderPage::installMods()
{
- if(!m_controlsEnabled) {
+ if (!m_controlsEnabled)
return;
- }
- if(m_inst->typeName() != "Minecraft"){
- return; //this is a null instance or a legacy instance
- }
- auto profile = ((MinecraftInstance *)m_inst)->getPackProfile();
+ if (m_instance->typeName() != "Minecraft")
+ return; // this is a null instance or a legacy instance
+
+ auto profile = static_cast<MinecraftInstance*>(m_instance)->getPackProfile();
if (profile->getModLoaders() == ModAPI::Unspecified) {
- QMessageBox::critical(this,tr("Error"),tr("Please install a mod loader first!"));
+ QMessageBox::critical(this, tr("Error"), tr("Please install a mod loader first!"));
return;
}
- ModDownloadDialog mdownload(m_mods, this, m_inst);
+
+ ModDownloadDialog mdownload(m_model, this, m_instance);
if (mdownload.exec()) {
SequentialTask* tasks = new SequentialTask(this);
connect(tasks, &Task::failed, [this, tasks](QString reason) {
@@ -409,40 +138,20 @@ void ModFolderPage::on_actionInstall_mods_triggered()
});
connect(tasks, &Task::succeeded, [this, tasks]() {
QStringList warnings = tasks->warnings();
- if (warnings.count()) { CustomMessageBox::selectable(this, tr("Warnings"), warnings.join('\n'), QMessageBox::Warning)->show(); }
+ if (warnings.count())
+ CustomMessageBox::selectable(this, tr("Warnings"), warnings.join('\n'), QMessageBox::Warning)->show();
+
tasks->deleteLater();
});
- for (auto task : mdownload.getTasks()) {
+ for (auto& task : mdownload.getTasks()) {
tasks->addTask(task);
}
ProgressDialog loadDialog(this);
loadDialog.setSkipButton(true, tr("Abort"));
loadDialog.execWithTask(tasks);
- m_mods->update();
- }
-}
-
-void ModFolderPage::on_actionView_configs_triggered()
-{
- DesktopServices::openDirectory(m_inst->instanceConfigFolder(), true);
-}
-
-void ModFolderPage::on_actionView_Folder_triggered()
-{
- DesktopServices::openDirectory(m_mods->dir().absolutePath(), true);
-}
-void ModFolderPage::modCurrent(const QModelIndex &current, const QModelIndex &previous)
-{
- if (!current.isValid())
- {
- ui->frame->clear();
- return;
+ m_model->update();
}
- auto sourceCurrent = m_filterModel->mapToSource(current);
- int row = sourceCurrent.row();
- Mod &m = m_mods->operator[](row);
- ui->frame->updateWithMod(m);
}
diff --git a/launcher/ui/pages/instance/ModFolderPage.h b/launcher/ui/pages/instance/ModFolderPage.h
index 2dd44e85..1a9ed7db 100644
--- a/launcher/ui/pages/instance/ModFolderPage.h
+++ b/launcher/ui/pages/instance/ModFolderPage.h
@@ -35,109 +35,31 @@
#pragma once
-#include <QMainWindow>
+#include "ExternalResourcesPage.h"
-#include "minecraft/MinecraftInstance.h"
-#include "ui/pages/BasePage.h"
-
-#include <Application.h>
-#include <QSortFilterProxyModel>
-
-class ModFolderModel;
-namespace Ui
-{
-class ModFolderPage;
-}
-
-class ModFolderPage : public QMainWindow, public BasePage
-{
+class ModFolderPage : public ExternalResourcesPage {
Q_OBJECT
-public:
- explicit ModFolderPage(
- BaseInstance *inst,
- std::shared_ptr<ModFolderModel> mods,
- QString id,
- QString iconName,
- QString displayName,
- QString helpPage = "",
- QWidget *parent = 0
- );
- virtual ~ModFolderPage();
-
- void setFilter(const QString & filter)
- {
- m_fileSelectionFilter = filter;
- }
+ public:
+ explicit ModFolderPage(BaseInstance* inst, std::shared_ptr<ModFolderModel> mods, QWidget* parent = nullptr);
+ virtual ~ModFolderPage() = default;
- virtual QString displayName() const override
- {
- return m_displayName;
- }
- virtual QIcon icon() const override
- {
- return APPLICATION->getThemedIcon(m_iconName);
- }
- virtual QString id() const override
- {
- return m_id;
- }
- virtual QString helpPage() const override
- {
- return m_helpName;
- }
- virtual bool shouldDisplay() const override;
- void retranslate() override;
-
- virtual void openedImpl() override;
- virtual void closedImpl() override;
-protected:
- bool eventFilter(QObject *obj, QEvent *ev) override;
- bool modListFilter(QKeyEvent *ev);
- QMenu * createPopupMenu() override;
+ void setFilter(const QString& filter) { m_fileSelectionFilter = filter; }
-protected:
- BaseInstance *m_inst = nullptr;
+ virtual QString displayName() const override { return tr("Mods"); }
+ virtual QIcon icon() const override { return APPLICATION->getThemedIcon("loadermods"); }
+ virtual QString id() const override { return "mods"; }
+ virtual QString helpPage() const override { return "Loader-mods"; }
-protected:
- Ui::ModFolderPage *ui = nullptr;
- std::shared_ptr<ModFolderModel> m_mods;
- QSortFilterProxyModel *m_filterModel = nullptr;
- QString m_iconName;
- QString m_id;
- QString m_displayName;
- QString m_helpName;
- QString m_fileSelectionFilter;
- QString m_viewFilter;
- bool m_controlsEnabled = true;
-
-public
-slots:
- void modCurrent(const QModelIndex &current, const QModelIndex &previous);
+ virtual bool shouldDisplay() const override;
-private
-slots:
- void modItemActivated(const QModelIndex &index);
- void on_filterTextChanged(const QString & newContents);
- void on_RunningState_changed(bool running);
- void on_actionAdd_triggered();
- void on_actionRemove_triggered();
- void on_actionEnable_triggered();
- void on_actionDisable_triggered();
- void on_actionInstall_mods_triggered();
- void on_actionView_Folder_triggered();
- void on_actionView_configs_triggered();
- void ShowContextMenu(const QPoint &pos);
+ private slots:
+ void installMods();
};
-class CoreModFolderPage : public ModFolderPage
-{
-public:
- explicit CoreModFolderPage(BaseInstance *inst, std::shared_ptr<ModFolderModel> mods, QString id,
- QString iconName, QString displayName, QString helpPage = "",
- QWidget *parent = 0);
- virtual ~CoreModFolderPage()
- {
- }
+class CoreModFolderPage : public ModFolderPage {
+ public:
+ explicit CoreModFolderPage(BaseInstance* inst, std::shared_ptr<ModFolderModel> mods, QWidget* parent = 0);
+ virtual ~CoreModFolderPage() = default;
virtual bool shouldDisplay() const;
};
diff --git a/launcher/ui/pages/instance/ResourcePackPage.h b/launcher/ui/pages/instance/ResourcePackPage.h
index 8054926c..a6c9fdd3 100644
--- a/launcher/ui/pages/instance/ResourcePackPage.h
+++ b/launcher/ui/pages/instance/ResourcePackPage.h
@@ -35,24 +35,28 @@
#pragma once
-#include "ModFolderPage.h"
-#include "ui_ModFolderPage.h"
+#include "ExternalResourcesPage.h"
+#include "ui_ExternalResourcesPage.h"
-class ResourcePackPage : public ModFolderPage
+class ResourcePackPage : public ExternalResourcesPage
{
Q_OBJECT
public:
explicit ResourcePackPage(MinecraftInstance *instance, QWidget *parent = 0)
- : ModFolderPage(instance, instance->resourcePackList(), "resourcepacks",
- "resourcepacks", tr("Resource packs"), "Resource-packs", parent)
+ : ExternalResourcesPage(instance, instance->resourcePackList(), parent)
{
- ui->actionView_configs->setVisible(false);
+ ui->actionViewConfigs->setVisible(false);
}
virtual ~ResourcePackPage() {}
+ QString displayName() const override { return tr("Resource packs"); }
+ QIcon icon() const override { return APPLICATION->getThemedIcon("resourcepacks"); }
+ QString id() const override { return "resourcepacks"; }
+ QString helpPage() const override { return "Resource-packs"; }
+
virtual bool shouldDisplay() const override
{
- return !m_inst->traits().contains("no-texturepacks") &&
- !m_inst->traits().contains("texturepacks");
+ return !m_instance->traits().contains("no-texturepacks") &&
+ !m_instance->traits().contains("texturepacks");
}
};
diff --git a/launcher/ui/pages/instance/ShaderPackPage.h b/launcher/ui/pages/instance/ShaderPackPage.h
index 7d4f5074..2cc056c8 100644
--- a/launcher/ui/pages/instance/ShaderPackPage.h
+++ b/launcher/ui/pages/instance/ShaderPackPage.h
@@ -35,21 +35,25 @@
#pragma once
-#include "ModFolderPage.h"
-#include "ui_ModFolderPage.h"
+#include "ExternalResourcesPage.h"
+#include "ui_ExternalResourcesPage.h"
-class ShaderPackPage : public ModFolderPage
+class ShaderPackPage : public ExternalResourcesPage
{
Q_OBJECT
public:
explicit ShaderPackPage(MinecraftInstance *instance, QWidget *parent = 0)
- : ModFolderPage(instance, instance->shaderPackList(), "shaderpacks",
- "shaderpacks", tr("Shader packs"), "Resource-packs", parent)
+ : ExternalResourcesPage(instance, instance->shaderPackList(), parent)
{
- ui->actionView_configs->setVisible(false);
+ ui->actionViewConfigs->setVisible(false);
}
virtual ~ShaderPackPage() {}
+ QString displayName() const override { return tr("Shader packs"); }
+ QIcon icon() const override { return APPLICATION->getThemedIcon("shaderpacks"); }
+ QString id() const override { return "shaderpacks"; }
+ QString helpPage() const override { return "Resource-packs"; }
+
virtual bool shouldDisplay() const override
{
return true;
diff --git a/launcher/ui/pages/instance/TexturePackPage.h b/launcher/ui/pages/instance/TexturePackPage.h
index e8cefe6e..f550a5bc 100644
--- a/launcher/ui/pages/instance/TexturePackPage.h
+++ b/launcher/ui/pages/instance/TexturePackPage.h
@@ -35,23 +35,27 @@
#pragma once
-#include "ModFolderPage.h"
-#include "ui_ModFolderPage.h"
+#include "ExternalResourcesPage.h"
+#include "ui_ExternalResourcesPage.h"
-class TexturePackPage : public ModFolderPage
+class TexturePackPage : public ExternalResourcesPage
{
Q_OBJECT
public:
explicit TexturePackPage(MinecraftInstance *instance, QWidget *parent = 0)
- : ModFolderPage(instance, instance->texturePackList(), "texturepacks", "resourcepacks",
- tr("Texture packs"), "Texture-packs", parent)
+ : ExternalResourcesPage(instance, instance->texturePackList(), parent)
{
- ui->actionView_configs->setVisible(false);
+ ui->actionViewConfigs->setVisible(false);
}
virtual ~TexturePackPage() {}
+ QString displayName() const override { return tr("Texture packs"); }
+ QIcon icon() const override { return APPLICATION->getThemedIcon("resourcepacks"); }
+ QString id() const override { return "texturepacks"; }
+ QString helpPage() const override { return "Texture-packs"; }
+
virtual bool shouldDisplay() const override
{
- return m_inst->traits().contains("texturepacks");
+ return m_instance->traits().contains("texturepacks");
}
};