refactor: Create a more clear hierarchy for some instance pages
Previously, the Shaders, Texture packs and Resource packs tabs had as parent the ModFolderPage, making it so that making changes only to the Mods page would require checking the id of the page for the correct one. This was hackish and error-prone. Now, those pages all inherit from a single class, ExternalResourcesPage, that handles the basic behaviour of all of them, while allowing for individual modification in code. This is still not a clear separation, since internally, all those resources are derived from Mods, so for now there's still some awkward common code :/
This commit is contained in:
parent
349fc4143d
commit
d394235ee0
@ -717,6 +717,8 @@ SET(LAUNCHER_SOURCES
|
|||||||
ui/pages/BasePageProvider.h
|
ui/pages/BasePageProvider.h
|
||||||
|
|
||||||
# GUI - instance pages
|
# GUI - instance pages
|
||||||
|
ui/pages/instance/ExternalResourcesPage.cpp
|
||||||
|
ui/pages/instance/ExternalResourcesPage.h
|
||||||
ui/pages/instance/GameOptionsPage.cpp
|
ui/pages/instance/GameOptionsPage.cpp
|
||||||
ui/pages/instance/GameOptionsPage.h
|
ui/pages/instance/GameOptionsPage.h
|
||||||
ui/pages/instance/VersionPage.cpp
|
ui/pages/instance/VersionPage.cpp
|
||||||
@ -924,7 +926,7 @@ qt5_wrap_ui(LAUNCHER_UI
|
|||||||
ui/pages/global/ProxyPage.ui
|
ui/pages/global/ProxyPage.ui
|
||||||
ui/pages/global/MinecraftPage.ui
|
ui/pages/global/MinecraftPage.ui
|
||||||
ui/pages/global/ExternalToolsPage.ui
|
ui/pages/global/ExternalToolsPage.ui
|
||||||
ui/pages/instance/ModFolderPage.ui
|
ui/pages/instance/ExternalResourcesPage.ui
|
||||||
ui/pages/instance/NotesPage.ui
|
ui/pages/instance/NotesPage.ui
|
||||||
ui/pages/instance/LogPage.ui
|
ui/pages/instance/LogPage.ui
|
||||||
ui/pages/instance/ServersPage.ui
|
ui/pages/instance/ServersPage.ui
|
||||||
|
@ -33,10 +33,10 @@ public:
|
|||||||
values.append(new LogPage(inst));
|
values.append(new LogPage(inst));
|
||||||
std::shared_ptr<MinecraftInstance> onesix = std::dynamic_pointer_cast<MinecraftInstance>(inst);
|
std::shared_ptr<MinecraftInstance> onesix = std::dynamic_pointer_cast<MinecraftInstance>(inst);
|
||||||
values.append(new VersionPage(onesix.get()));
|
values.append(new VersionPage(onesix.get()));
|
||||||
auto modsPage = new ModFolderPage(onesix.get(), onesix->loaderModList(), "mods", "loadermods", tr("Mods"), "Loader-mods");
|
auto modsPage = new ModFolderPage(onesix.get(), onesix->loaderModList());
|
||||||
modsPage->setFilter("%1 (*.zip *.jar *.litemod)");
|
modsPage->setFilter("%1 (*.zip *.jar *.litemod)");
|
||||||
values.append(modsPage);
|
values.append(modsPage);
|
||||||
values.append(new CoreModFolderPage(onesix.get(), onesix->coreModList(), "coremods", "coremods", tr("Core mods"), "Core-mods"));
|
values.append(new CoreModFolderPage(onesix.get(), onesix->coreModList()));
|
||||||
values.append(new ResourcePackPage(onesix.get()));
|
values.append(new ResourcePackPage(onesix.get()));
|
||||||
values.append(new TexturePackPage(onesix.get()));
|
values.append(new TexturePackPage(onesix.get()));
|
||||||
values.append(new ShaderPackPage(onesix.get()));
|
values.append(new ShaderPackPage(onesix.get()));
|
||||||
|
297
launcher/ui/pages/instance/ExternalResourcesPage.cpp
Normal file
297
launcher/ui/pages/instance/ExternalResourcesPage.cpp
Normal file
@ -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("^(([Tt][Hh][eE])|([Tt][eE][Hh])) +"));
|
||||||
|
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);
|
||||||
|
}
|
73
launcher/ui/pages/instance/ExternalResourcesPage.h
Normal file
73
launcher/ui/pages/instance/ExternalResourcesPage.h
Normal file
@ -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;
|
||||||
|
};
|
@ -1,7 +1,7 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<ui version="4.0">
|
<ui version="4.0">
|
||||||
<class>ModFolderPage</class>
|
<class>ExternalResourcesPage</class>
|
||||||
<widget class="QMainWindow" name="ModFolderPage">
|
<widget class="QMainWindow" name="ExternalResourcesPage">
|
||||||
<property name="geometry">
|
<property name="geometry">
|
||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
@ -53,7 +53,7 @@
|
|||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item row="1" column="1" colspan="3">
|
<item row="1" column="1" colspan="3">
|
||||||
<widget class="ModListView" name="modTreeView">
|
<widget class="ModListView" name="treeView">
|
||||||
<property name="sizePolicy">
|
<property name="sizePolicy">
|
||||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||||
<horstretch>0</horstretch>
|
<horstretch>0</horstretch>
|
||||||
@ -83,15 +83,15 @@
|
|||||||
<attribute name="toolBarBreak">
|
<attribute name="toolBarBreak">
|
||||||
<bool>false</bool>
|
<bool>false</bool>
|
||||||
</attribute>
|
</attribute>
|
||||||
<addaction name="actionAdd"/>
|
<addaction name="actionAddItem"/>
|
||||||
<addaction name="separator"/>
|
<addaction name="separator"/>
|
||||||
<addaction name="actionRemove"/>
|
<addaction name="actionRemoveItem"/>
|
||||||
<addaction name="actionEnable"/>
|
<addaction name="actionEnableItem"/>
|
||||||
<addaction name="actionDisable"/>
|
<addaction name="actionDisableItem"/>
|
||||||
<addaction name="actionView_configs"/>
|
<addaction name="actionViewConfigs"/>
|
||||||
<addaction name="actionView_Folder"/>
|
<addaction name="actionViewFolder"/>
|
||||||
</widget>
|
</widget>
|
||||||
<action name="actionAdd">
|
<action name="actionAddItem">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>&Add</string>
|
<string>&Add</string>
|
||||||
</property>
|
</property>
|
||||||
@ -99,31 +99,31 @@
|
|||||||
<string>Add</string>
|
<string>Add</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="actionRemove">
|
<action name="actionRemoveItem">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>&Remove</string>
|
<string>&Remove</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string>Remove selected mods</string>
|
<string>Remove selected item</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="actionEnable">
|
<action name="actionEnableItem">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>&Enable</string>
|
<string>&Enable</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string>Enable selected mods</string>
|
<string>Enable selected item</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="actionDisable">
|
<action name="actionDisableItem">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>&Disable</string>
|
<string>&Disable</string>
|
||||||
</property>
|
</property>
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string>Disable selected mods</string>
|
<string>Disable selected item</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="actionView_configs">
|
<action name="actionViewConfigs">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>View &Configs</string>
|
<string>View &Configs</string>
|
||||||
</property>
|
</property>
|
||||||
@ -131,7 +131,7 @@
|
|||||||
<string>Open the 'config' folder in the system file manager.</string>
|
<string>Open the 'config' folder in the system file manager.</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="actionView_Folder">
|
<action name="actionViewFolder">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>View &Folder</string>
|
<string>View &Folder</string>
|
||||||
</property>
|
</property>
|
||||||
@ -156,7 +156,7 @@
|
|||||||
</customwidget>
|
</customwidget>
|
||||||
</customwidgets>
|
</customwidgets>
|
||||||
<tabstops>
|
<tabstops>
|
||||||
<tabstop>modTreeView</tabstop>
|
<tabstop>treeView</tabstop>
|
||||||
<tabstop>filterEdit</tabstop>
|
<tabstop>filterEdit</tabstop>
|
||||||
</tabstops>
|
</tabstops>
|
||||||
<resources/>
|
<resources/>
|
@ -35,368 +35,95 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "ModFolderPage.h"
|
#include "ModFolderPage.h"
|
||||||
#include "ui_ModFolderPage.h"
|
#include "ui_ExternalResourcesPage.h"
|
||||||
|
|
||||||
#include <QMessageBox>
|
#include <QAbstractItemModel>
|
||||||
#include <QEvent>
|
#include <QEvent>
|
||||||
#include <QKeyEvent>
|
#include <QKeyEvent>
|
||||||
#include <QAbstractItemModel>
|
|
||||||
#include <QMenu>
|
#include <QMenu>
|
||||||
|
#include <QMessageBox>
|
||||||
#include <QSortFilterProxyModel>
|
#include <QSortFilterProxyModel>
|
||||||
|
|
||||||
#include "Application.h"
|
#include "Application.h"
|
||||||
|
|
||||||
|
#include "ui/GuiUtil.h"
|
||||||
#include "ui/dialogs/CustomMessageBox.h"
|
#include "ui/dialogs/CustomMessageBox.h"
|
||||||
#include "ui/dialogs/ModDownloadDialog.h"
|
#include "ui/dialogs/ModDownloadDialog.h"
|
||||||
#include "ui/GuiUtil.h"
|
|
||||||
|
|
||||||
#include "DesktopServices.h"
|
#include "DesktopServices.h"
|
||||||
|
|
||||||
#include "minecraft/mod/ModFolderModel.h"
|
|
||||||
#include "minecraft/mod/Mod.h"
|
|
||||||
#include "minecraft/VersionFilterData.h"
|
|
||||||
#include "minecraft/PackProfile.h"
|
#include "minecraft/PackProfile.h"
|
||||||
|
#include "minecraft/VersionFilterData.h"
|
||||||
|
#include "minecraft/mod/Mod.h"
|
||||||
|
#include "minecraft/mod/ModFolderModel.h"
|
||||||
|
|
||||||
#include "modplatform/ModAPI.h"
|
#include "modplatform/ModAPI.h"
|
||||||
|
|
||||||
#include "Version.h"
|
#include "Version.h"
|
||||||
#include "ui/dialogs/ProgressDialog.h"
|
|
||||||
#include "tasks/SequentialTask.h"
|
#include "tasks/SequentialTask.h"
|
||||||
|
#include "ui/dialogs/ProgressDialog.h"
|
||||||
|
|
||||||
namespace {
|
ModFolderPage::ModFolderPage(BaseInstance* inst, std::shared_ptr<ModFolderModel> mods, QWidget* parent)
|
||||||
// FIXME: wasteful
|
: ExternalResourcesPage(inst, mods, parent)
|
||||||
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)
|
|
||||||
{
|
|
||||||
ui->setupUi(this);
|
|
||||||
|
|
||||||
// This is structured like that so that these changes
|
// This is structured like that so that these changes
|
||||||
// do not affect the Resouce pack and Shader pack tabs
|
// do not affect the Resource pack and Shader pack tabs
|
||||||
if(id == "mods") {
|
{
|
||||||
auto act = new QAction(tr("Download mods"), this);
|
auto act = new QAction(tr("Download mods"), this);
|
||||||
act->setToolTip(tr("Download mods from online mod platforms"));
|
act->setToolTip(tr("Download mods from online mod platforms"));
|
||||||
ui->actionsToolbar->insertActionBefore(ui->actionAdd, act);
|
ui->actionsToolbar->insertActionBefore(ui->actionAddItem, act);
|
||||||
connect(act, &QAction::triggered, this, &ModFolderPage::on_actionInstall_mods_triggered);
|
connect(act, &QAction::triggered, this, &ModFolderPage::installMods);
|
||||||
|
|
||||||
ui->actionAdd->setText(tr("Add .jar"));
|
ui->actionAddItem->setText(tr("Add .jar"));
|
||||||
ui->actionAdd->setToolTip(tr("Add mods via local file"));
|
ui->actionAddItem->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);
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModFolderPage::modItemActivated(const QModelIndex&)
|
CoreModFolderPage::CoreModFolderPage(BaseInstance* inst, std::shared_ptr<ModFolderModel> mods, QWidget* parent)
|
||||||
{
|
: ModFolderPage(inst, mods, parent)
|
||||||
if(!m_controlsEnabled) {
|
{}
|
||||||
return;
|
|
||||||
}
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ModFolderPage::shouldDisplay() const
|
bool ModFolderPage::shouldDisplay() const
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ModFolderPage::retranslate()
|
|
||||||
{
|
|
||||||
ui->retranslateUi(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CoreModFolderPage::shouldDisplay() const
|
bool CoreModFolderPage::shouldDisplay() const
|
||||||
{
|
{
|
||||||
if (ModFolderPage::shouldDisplay())
|
if (ModFolderPage::shouldDisplay()) {
|
||||||
{
|
auto inst = dynamic_cast<MinecraftInstance*>(m_instance);
|
||||||
auto inst = dynamic_cast<MinecraftInstance *>(m_inst);
|
|
||||||
if (!inst)
|
if (!inst)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
auto version = inst->getPackProfile();
|
auto version = inst->getPackProfile();
|
||||||
|
|
||||||
if (!version)
|
if (!version)
|
||||||
return true;
|
return true;
|
||||||
if(!version->getComponent("net.minecraftforge"))
|
if (!version->getComponent("net.minecraftforge"))
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
if (!version->getComponent("net.minecraft"))
|
||||||
if(!version->getComponent("net.minecraft"))
|
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
if (version->getComponent("net.minecraft")->getReleaseDateTime() < g_VersionFilterData.legacyCutoffDate)
|
||||||
if(version->getComponent("net.minecraft")->getReleaseDateTime() < g_VersionFilterData.legacyCutoffDate)
|
|
||||||
{
|
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ModFolderPage::modListFilter(QKeyEvent *keyEvent)
|
void ModFolderPage::installMods()
|
||||||
{
|
{
|
||||||
switch (keyEvent->key())
|
if (!m_controlsEnabled)
|
||||||
{
|
|
||||||
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;
|
return;
|
||||||
}
|
if (m_instance->typeName() != "Minecraft")
|
||||||
auto list = GuiUtil::BrowseForFiles(
|
return; // this is a null instance or a legacy instance
|
||||||
m_helpName,
|
|
||||||
tr("Select %1",
|
auto profile = static_cast<MinecraftInstance*>(m_instance)->getPackProfile();
|
||||||
"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()
|
|
||||||
{
|
|
||||||
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 (profile->getModLoaders() == ModAPI::Unspecified) {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
ModDownloadDialog mdownload(m_mods, this, m_inst);
|
|
||||||
|
ModDownloadDialog mdownload(m_model, this, m_instance);
|
||||||
if (mdownload.exec()) {
|
if (mdownload.exec()) {
|
||||||
SequentialTask* tasks = new SequentialTask(this);
|
SequentialTask* tasks = new SequentialTask(this);
|
||||||
connect(tasks, &Task::failed, [this, tasks](QString reason) {
|
connect(tasks, &Task::failed, [this, tasks](QString reason) {
|
||||||
@ -409,40 +136,20 @@ void ModFolderPage::on_actionInstall_mods_triggered()
|
|||||||
});
|
});
|
||||||
connect(tasks, &Task::succeeded, [this, tasks]() {
|
connect(tasks, &Task::succeeded, [this, tasks]() {
|
||||||
QStringList warnings = tasks->warnings();
|
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();
|
tasks->deleteLater();
|
||||||
});
|
});
|
||||||
|
|
||||||
for (auto task : mdownload.getTasks()) {
|
for (auto& task : mdownload.getTasks()) {
|
||||||
tasks->addTask(task);
|
tasks->addTask(task);
|
||||||
}
|
}
|
||||||
|
|
||||||
ProgressDialog loadDialog(this);
|
ProgressDialog loadDialog(this);
|
||||||
loadDialog.setSkipButton(true, tr("Abort"));
|
loadDialog.setSkipButton(true, tr("Abort"));
|
||||||
loadDialog.execWithTask(tasks);
|
loadDialog.execWithTask(tasks);
|
||||||
m_mods->update();
|
|
||||||
|
m_model->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 ¤t, const QModelIndex &previous)
|
|
||||||
{
|
|
||||||
if (!current.isValid())
|
|
||||||
{
|
|
||||||
ui->frame->clear();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
auto sourceCurrent = m_filterModel->mapToSource(current);
|
|
||||||
int row = sourceCurrent.row();
|
|
||||||
Mod &m = m_mods->operator[](row);
|
|
||||||
ui->frame->updateWithMod(m);
|
|
||||||
}
|
|
||||||
|
@ -35,109 +35,31 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QMainWindow>
|
#include "ExternalResourcesPage.h"
|
||||||
|
|
||||||
#include "minecraft/MinecraftInstance.h"
|
class ModFolderPage : public ExternalResourcesPage {
|
||||||
#include "ui/pages/BasePage.h"
|
|
||||||
|
|
||||||
#include <Application.h>
|
|
||||||
#include <QSortFilterProxyModel>
|
|
||||||
|
|
||||||
class ModFolderModel;
|
|
||||||
namespace Ui
|
|
||||||
{
|
|
||||||
class ModFolderPage;
|
|
||||||
}
|
|
||||||
|
|
||||||
class ModFolderPage : public QMainWindow, public BasePage
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit ModFolderPage(
|
explicit ModFolderPage(BaseInstance* inst, std::shared_ptr<ModFolderModel> mods, QWidget* parent = nullptr);
|
||||||
BaseInstance *inst,
|
virtual ~ModFolderPage() = default;
|
||||||
std::shared_ptr<ModFolderModel> mods,
|
|
||||||
QString id,
|
|
||||||
QString iconName,
|
|
||||||
QString displayName,
|
|
||||||
QString helpPage = "",
|
|
||||||
QWidget *parent = 0
|
|
||||||
);
|
|
||||||
virtual ~ModFolderPage();
|
|
||||||
|
|
||||||
void setFilter(const QString & filter)
|
void setFilter(const QString& filter) { m_fileSelectionFilter = filter; }
|
||||||
{
|
|
||||||
m_fileSelectionFilter = filter;
|
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"; }
|
||||||
|
|
||||||
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;
|
virtual bool shouldDisplay() const override;
|
||||||
void retranslate() override;
|
|
||||||
|
|
||||||
virtual void openedImpl() override;
|
private slots:
|
||||||
virtual void closedImpl() override;
|
void installMods();
|
||||||
protected:
|
|
||||||
bool eventFilter(QObject *obj, QEvent *ev) override;
|
|
||||||
bool modListFilter(QKeyEvent *ev);
|
|
||||||
QMenu * createPopupMenu() override;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
BaseInstance *m_inst = nullptr;
|
|
||||||
|
|
||||||
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 ¤t, const QModelIndex &previous);
|
|
||||||
|
|
||||||
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);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class CoreModFolderPage : public ModFolderPage
|
class CoreModFolderPage : public ModFolderPage {
|
||||||
{
|
public:
|
||||||
public:
|
explicit CoreModFolderPage(BaseInstance* inst, std::shared_ptr<ModFolderModel> mods, QWidget* parent = 0);
|
||||||
explicit CoreModFolderPage(BaseInstance *inst, std::shared_ptr<ModFolderModel> mods, QString id,
|
virtual ~CoreModFolderPage() = default;
|
||||||
QString iconName, QString displayName, QString helpPage = "",
|
|
||||||
QWidget *parent = 0);
|
|
||||||
virtual ~CoreModFolderPage()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
virtual bool shouldDisplay() const;
|
virtual bool shouldDisplay() const;
|
||||||
};
|
};
|
||||||
|
@ -35,24 +35,28 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "ModFolderPage.h"
|
#include "ExternalResourcesPage.h"
|
||||||
#include "ui_ModFolderPage.h"
|
#include "ui_ExternalResourcesPage.h"
|
||||||
|
|
||||||
class ResourcePackPage : public ModFolderPage
|
class ResourcePackPage : public ExternalResourcesPage
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit ResourcePackPage(MinecraftInstance *instance, QWidget *parent = 0)
|
explicit ResourcePackPage(MinecraftInstance *instance, QWidget *parent = 0)
|
||||||
: ModFolderPage(instance, instance->resourcePackList(), "resourcepacks",
|
: ExternalResourcesPage(instance, instance->resourcePackList(), parent)
|
||||||
"resourcepacks", tr("Resource packs"), "Resource-packs", parent)
|
|
||||||
{
|
{
|
||||||
ui->actionView_configs->setVisible(false);
|
ui->actionViewConfigs->setVisible(false);
|
||||||
}
|
}
|
||||||
virtual ~ResourcePackPage() {}
|
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
|
virtual bool shouldDisplay() const override
|
||||||
{
|
{
|
||||||
return !m_inst->traits().contains("no-texturepacks") &&
|
return !m_instance->traits().contains("no-texturepacks") &&
|
||||||
!m_inst->traits().contains("texturepacks");
|
!m_instance->traits().contains("texturepacks");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -35,21 +35,25 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "ModFolderPage.h"
|
#include "ExternalResourcesPage.h"
|
||||||
#include "ui_ModFolderPage.h"
|
#include "ui_ExternalResourcesPage.h"
|
||||||
|
|
||||||
class ShaderPackPage : public ModFolderPage
|
class ShaderPackPage : public ExternalResourcesPage
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit ShaderPackPage(MinecraftInstance *instance, QWidget *parent = 0)
|
explicit ShaderPackPage(MinecraftInstance *instance, QWidget *parent = 0)
|
||||||
: ModFolderPage(instance, instance->shaderPackList(), "shaderpacks",
|
: ExternalResourcesPage(instance, instance->shaderPackList(), parent)
|
||||||
"shaderpacks", tr("Shader packs"), "Resource-packs", parent)
|
|
||||||
{
|
{
|
||||||
ui->actionView_configs->setVisible(false);
|
ui->actionViewConfigs->setVisible(false);
|
||||||
}
|
}
|
||||||
virtual ~ShaderPackPage() {}
|
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
|
virtual bool shouldDisplay() const override
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
|
@ -35,23 +35,27 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "ModFolderPage.h"
|
#include "ExternalResourcesPage.h"
|
||||||
#include "ui_ModFolderPage.h"
|
#include "ui_ExternalResourcesPage.h"
|
||||||
|
|
||||||
class TexturePackPage : public ModFolderPage
|
class TexturePackPage : public ExternalResourcesPage
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit TexturePackPage(MinecraftInstance *instance, QWidget *parent = 0)
|
explicit TexturePackPage(MinecraftInstance *instance, QWidget *parent = 0)
|
||||||
: ModFolderPage(instance, instance->texturePackList(), "texturepacks", "resourcepacks",
|
: ExternalResourcesPage(instance, instance->texturePackList(), parent)
|
||||||
tr("Texture packs"), "Texture-packs", parent)
|
|
||||||
{
|
{
|
||||||
ui->actionView_configs->setVisible(false);
|
ui->actionViewConfigs->setVisible(false);
|
||||||
}
|
}
|
||||||
virtual ~TexturePackPage() {}
|
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
|
virtual bool shouldDisplay() const override
|
||||||
{
|
{
|
||||||
return m_inst->traits().contains("texturepacks");
|
return m_instance->traits().contains("texturepacks");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user