Merge branch 'develop' into feature/java-downloader
Signed-off-by: TheKodeToad <TheKodeToad@proton.me>
This commit is contained in:
@ -1,4 +1,40 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* Prism Launcher - Minecraft Launcher
|
||||
* Copyright (c) 2023 Trial97 <alexandru.tripon97@gmail.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* This file incorporates work covered by the following copyright and
|
||||
* permission notice:
|
||||
*
|
||||
* Copyright 2013-2021 MultiMC Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "ExternalResourcesPage.h"
|
||||
#include "ui/dialogs/CustomMessageBox.h"
|
||||
#include "ui_ExternalResourcesPage.h"
|
||||
|
||||
#include "DesktopServices.h"
|
||||
@ -8,14 +44,13 @@
|
||||
|
||||
#include <QKeyEvent>
|
||||
#include <QMenu>
|
||||
#include <algorithm>
|
||||
|
||||
ExternalResourcesPage::ExternalResourcesPage(BaseInstance* instance, std::shared_ptr<ResourceFolderModel> model, QWidget* parent)
|
||||
: QMainWindow(parent), m_instance(instance), ui(new Ui::ExternalResourcesPage), m_model(model)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
ExternalResourcesPage::runningStateChanged(m_instance && m_instance->isRunning());
|
||||
|
||||
ui->actionsToolbar->insertSpacer(ui->actionViewConfigs);
|
||||
|
||||
m_filterModel = model->createFilterProxyModel(this);
|
||||
@ -25,6 +60,8 @@ ExternalResourcesPage::ExternalResourcesPage(BaseInstance* instance, std::shared
|
||||
m_filterModel->setSourceModel(m_model.get());
|
||||
m_filterModel->setFilterKeyColumn(-1);
|
||||
ui->treeView->setModel(m_filterModel);
|
||||
// must come after setModel
|
||||
ui->treeView->setResizeModes(m_model->columnResizeModes());
|
||||
|
||||
ui->treeView->installEventFilter(this);
|
||||
ui->treeView->sortByColumn(1, Qt::AscendingOrder);
|
||||
@ -44,8 +81,21 @@ ExternalResourcesPage::ExternalResourcesPage(BaseInstance* instance, std::shared
|
||||
|
||||
auto selection_model = ui->treeView->selectionModel();
|
||||
connect(selection_model, &QItemSelectionModel::currentChanged, this, &ExternalResourcesPage::current);
|
||||
auto updateExtra = [this]() {
|
||||
if (updateExtraInfo)
|
||||
updateExtraInfo(id(), extraHeaderInfoString());
|
||||
};
|
||||
connect(selection_model, &QItemSelectionModel::selectionChanged, this, updateExtra);
|
||||
connect(model.get(), &ResourceFolderModel::updateFinished, this, updateExtra);
|
||||
|
||||
connect(ui->filterEdit, &QLineEdit::textChanged, this, &ExternalResourcesPage::filterTextChanged);
|
||||
connect(m_instance, &BaseInstance::runningStatusChanged, this, &ExternalResourcesPage::runningStateChanged);
|
||||
|
||||
auto viewHeader = ui->treeView->header();
|
||||
viewHeader->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
|
||||
connect(viewHeader, &QHeaderView::customContextMenuRequested, this, &ExternalResourcesPage::ShowHeaderContextMenu);
|
||||
|
||||
m_model->loadHiddenColumns(ui->treeView);
|
||||
}
|
||||
|
||||
ExternalResourcesPage::~ExternalResourcesPage()
|
||||
@ -67,14 +117,31 @@ void ExternalResourcesPage::ShowContextMenu(const QPoint& pos)
|
||||
delete menu;
|
||||
}
|
||||
|
||||
void ExternalResourcesPage::ShowHeaderContextMenu(const QPoint& pos)
|
||||
{
|
||||
auto menu = m_model->createHeaderContextMenu(ui->treeView);
|
||||
menu->exec(ui->treeView->mapToGlobal(pos));
|
||||
menu->deleteLater();
|
||||
}
|
||||
|
||||
void ExternalResourcesPage::openedImpl()
|
||||
{
|
||||
m_model->startWatching();
|
||||
|
||||
auto const setting_name = QString("WideBarVisibility_%1").arg(id());
|
||||
if (!APPLICATION->settings()->contains(setting_name))
|
||||
m_wide_bar_setting = APPLICATION->settings()->registerSetting(setting_name);
|
||||
else
|
||||
m_wide_bar_setting = APPLICATION->settings()->getSetting(setting_name);
|
||||
|
||||
ui->actionsToolbar->setVisibilityState(m_wide_bar_setting->get().toByteArray());
|
||||
}
|
||||
|
||||
void ExternalResourcesPage::closedImpl()
|
||||
{
|
||||
m_model->stopWatching();
|
||||
|
||||
m_wide_bar_setting->set(ui->actionsToolbar->getVisibilityState());
|
||||
}
|
||||
|
||||
void ExternalResourcesPage::retranslate()
|
||||
@ -84,11 +151,7 @@ void ExternalResourcesPage::retranslate()
|
||||
|
||||
void ExternalResourcesPage::itemActivated(const QModelIndex&)
|
||||
{
|
||||
if (!m_controlsEnabled)
|
||||
return;
|
||||
|
||||
auto selection = m_filterModel->mapSelectionToSource(ui->treeView->selectionModel()->selection());
|
||||
m_model->setResourceEnabled(selection.indexes(), EnableAction::TOGGLE);
|
||||
}
|
||||
|
||||
void ExternalResourcesPage::filterTextChanged(const QString& newContents)
|
||||
@ -97,14 +160,6 @@ void ExternalResourcesPage::filterTextChanged(const QString& newContents)
|
||||
m_filterModel->setFilterRegularExpression(m_viewFilter);
|
||||
}
|
||||
|
||||
void ExternalResourcesPage::runningStateChanged(bool running)
|
||||
{
|
||||
if (m_controlsEnabled == !running)
|
||||
return;
|
||||
|
||||
m_controlsEnabled = !running;
|
||||
}
|
||||
|
||||
bool ExternalResourcesPage::shouldDisplay() const
|
||||
{
|
||||
return true;
|
||||
@ -129,7 +184,7 @@ 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);
|
||||
@ -139,10 +194,6 @@ bool ExternalResourcesPage::eventFilter(QObject* obj, QEvent* 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());
|
||||
@ -156,27 +207,80 @@ void ExternalResourcesPage::addItem()
|
||||
|
||||
void ExternalResourcesPage::removeItem()
|
||||
{
|
||||
if (!m_controlsEnabled)
|
||||
return;
|
||||
|
||||
auto selection = m_filterModel->mapSelectionToSource(ui->treeView->selectionModel()->selection());
|
||||
|
||||
int count = 0;
|
||||
bool folder = false;
|
||||
for (auto& i : selection.indexes()) {
|
||||
if (i.column() == 0) {
|
||||
count++;
|
||||
|
||||
// if a folder is selected, show the confirmation dialog
|
||||
if (m_model->at(i.row()).fileinfo().isDir())
|
||||
folder = true;
|
||||
}
|
||||
}
|
||||
|
||||
QString text;
|
||||
bool multiple = count > 1;
|
||||
|
||||
if (multiple) {
|
||||
text = tr("You are about to remove %1 items.\n"
|
||||
"This may be permanent and they will be gone from the folder.\n\n"
|
||||
"Are you sure?")
|
||||
.arg(count);
|
||||
} else if (folder) {
|
||||
text = tr("You are about to remove the folder \"%1\".\n"
|
||||
"This may be permanent and it will be gone from the parent folder.\n\n"
|
||||
"Are you sure?")
|
||||
.arg(m_model->at(selection.indexes().at(0).row()).fileinfo().fileName());
|
||||
}
|
||||
|
||||
if (!text.isEmpty()) {
|
||||
auto response = CustomMessageBox::selectable(this, tr("Confirm Removal"), text, QMessageBox::Warning,
|
||||
QMessageBox::Yes | QMessageBox::No, QMessageBox::No)
|
||||
->exec();
|
||||
|
||||
if (response != QMessageBox::Yes)
|
||||
return;
|
||||
}
|
||||
|
||||
removeItems(selection);
|
||||
}
|
||||
|
||||
void ExternalResourcesPage::removeItems(const QItemSelection& selection)
|
||||
{
|
||||
if (m_instance != nullptr && m_instance->isRunning()) {
|
||||
auto response = CustomMessageBox::selectable(this, "Confirm Delete",
|
||||
"If you remove 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;
|
||||
}
|
||||
m_model->deleteResources(selection.indexes());
|
||||
}
|
||||
|
||||
void ExternalResourcesPage::enableItem()
|
||||
{
|
||||
if (!m_controlsEnabled)
|
||||
return;
|
||||
|
||||
auto selection = m_filterModel->mapSelectionToSource(ui->treeView->selectionModel()->selection());
|
||||
m_model->setResourceEnabled(selection.indexes(), EnableAction::ENABLE);
|
||||
}
|
||||
|
||||
void ExternalResourcesPage::disableItem()
|
||||
{
|
||||
if (!m_controlsEnabled)
|
||||
return;
|
||||
if (m_instance != nullptr && m_instance->isRunning()) {
|
||||
auto response = CustomMessageBox::selectable(this, "Confirm disable",
|
||||
"If you 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;
|
||||
}
|
||||
auto selection = m_filterModel->mapSelectionToSource(ui->treeView->selectionModel()->selection());
|
||||
m_model->setResourceEnabled(selection.indexes(), EnableAction::DISABLE);
|
||||
}
|
||||
@ -207,7 +311,15 @@ bool ExternalResourcesPage::onSelectionChanged(const QModelIndex& current, const
|
||||
int row = sourceCurrent.row();
|
||||
Resource const& resource = m_model->at(row);
|
||||
ui->frame->updateWithResource(resource);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
QString ExternalResourcesPage::extraHeaderInfoString()
|
||||
{
|
||||
if (ui && ui->treeView && ui->treeView->selectionModel()) {
|
||||
auto selection = m_filterModel->mapSelectionToSource(ui->treeView->selectionModel()->selection()).indexes();
|
||||
if (auto count = std::count_if(selection.cbegin(), selection.cend(), [](auto v) { return v.column() == 0; }); count != 0)
|
||||
return tr(" (%1 installed, %2 selected)").arg(m_model->size()).arg(count);
|
||||
}
|
||||
return tr(" (%1 installed)").arg(m_model->size());
|
||||
}
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include <QSortFilterProxyModel>
|
||||
|
||||
#include "Application.h"
|
||||
#include "settings/Setting.h"
|
||||
#include "minecraft/MinecraftInstance.h"
|
||||
#include "ui/pages/BasePage.h"
|
||||
|
||||
@ -28,6 +29,7 @@ class ExternalResourcesPage : public QMainWindow, public BasePage {
|
||||
virtual QString helpPage() const override = 0;
|
||||
|
||||
virtual bool shouldDisplay() const override = 0;
|
||||
QString extraHeaderInfoString();
|
||||
|
||||
void openedImpl() override;
|
||||
void closedImpl() override;
|
||||
@ -47,10 +49,10 @@ class ExternalResourcesPage : public QMainWindow, public BasePage {
|
||||
protected slots:
|
||||
void itemActivated(const QModelIndex& index);
|
||||
void filterTextChanged(const QString& newContents);
|
||||
virtual void runningStateChanged(bool running);
|
||||
|
||||
virtual void addItem();
|
||||
virtual void removeItem();
|
||||
void removeItem();
|
||||
virtual void removeItems(const QItemSelection &selection);
|
||||
|
||||
virtual void enableItem();
|
||||
virtual void disableItem();
|
||||
@ -59,6 +61,7 @@ class ExternalResourcesPage : public QMainWindow, public BasePage {
|
||||
virtual void viewConfigs();
|
||||
|
||||
void ShowContextMenu(const QPoint& pos);
|
||||
void ShowHeaderContextMenu(const QPoint& pos);
|
||||
|
||||
protected:
|
||||
BaseInstance* m_instance = nullptr;
|
||||
@ -70,5 +73,5 @@ class ExternalResourcesPage : public QMainWindow, public BasePage {
|
||||
QString m_fileSelectionFilter;
|
||||
QString m_viewFilter;
|
||||
|
||||
bool m_controlsEnabled = true;
|
||||
std::shared_ptr<Setting> m_wide_bar_setting = nullptr;
|
||||
};
|
||||
|
@ -27,11 +27,7 @@
|
||||
<item row="4" column="1" colspan="3">
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="filterEdit">
|
||||
<property name="clearButtonEnabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLineEdit" name="filterEdit"/>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="filterLabel">
|
||||
@ -66,6 +62,9 @@
|
||||
<property name="dragDropMode">
|
||||
<enum>QAbstractItemView::DropOnly</enum>
|
||||
</property>
|
||||
<property name="uniformRowHeights">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
@ -158,6 +157,17 @@
|
||||
<string>Try to check or update all selected resources (all resources if none are selected)</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionVisitItemPage">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Visit mod's page</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Go to mods home page</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
|
@ -48,29 +48,27 @@
|
||||
|
||||
#include "JavaCommon.h"
|
||||
#include "Application.h"
|
||||
#include "minecraft/auth/AccountList.h"
|
||||
|
||||
#include "JavaDownloader.h"
|
||||
#include "java/JavaInstallList.h"
|
||||
#include "java/JavaUtils.h"
|
||||
#include "FileSystem.h"
|
||||
|
||||
|
||||
InstanceSettingsPage::InstanceSettingsPage(BaseInstance *inst, QWidget *parent)
|
||||
: QWidget(parent), ui(new Ui::InstanceSettingsPage), m_instance(inst)
|
||||
{
|
||||
m_settings = inst->settings();
|
||||
ui->setupUi(this);
|
||||
auto sysMB = Sys::getSystemRam() / Sys::mebibyte;
|
||||
ui->maxMemSpinBox->setMaximum(sysMB);
|
||||
|
||||
connect(ui->openGlobalJavaSettingsButton, &QCommandLinkButton::clicked, this, &InstanceSettingsPage::globalSettingsButtonClicked);
|
||||
connect(APPLICATION, &Application::globalSettingsAboutToOpen, this, &InstanceSettingsPage::applySettings);
|
||||
connect(APPLICATION, &Application::globalSettingsClosed, this, &InstanceSettingsPage::loadSettings);
|
||||
connect(ui->instanceAccountSelector, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
|
||||
&InstanceSettingsPage::changeInstanceAccount);
|
||||
loadSettings();
|
||||
}
|
||||
|
||||
bool InstanceSettingsPage::shouldDisplay() const
|
||||
{
|
||||
return !m_instance->isRunning();
|
||||
updateThresholds();
|
||||
}
|
||||
|
||||
InstanceSettingsPage::~InstanceSettingsPage()
|
||||
@ -84,12 +82,12 @@ void InstanceSettingsPage::globalSettingsButtonClicked(bool)
|
||||
case 0:
|
||||
APPLICATION->ShowGlobalSettings(this, "java-settings");
|
||||
return;
|
||||
case 1:
|
||||
APPLICATION->ShowGlobalSettings(this, "minecraft-settings");
|
||||
return;
|
||||
case 2:
|
||||
APPLICATION->ShowGlobalSettings(this, "custom-commands");
|
||||
return;
|
||||
default:
|
||||
APPLICATION->ShowGlobalSettings(this, "minecraft-settings");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@ -276,6 +274,13 @@ void InstanceSettingsPage::applySettings()
|
||||
m_settings->reset("JoinServerOnLaunchAddress");
|
||||
}
|
||||
|
||||
// Use an account for this instance
|
||||
bool useAccountForInstance = ui->instanceAccountGroupBox->isChecked();
|
||||
m_settings->set("UseAccountForInstance", useAccountForInstance);
|
||||
if (!useAccountForInstance) {
|
||||
m_settings->reset("InstanceAccountId");
|
||||
}
|
||||
|
||||
// FIXME: This should probably be called by a signal instead
|
||||
m_instance->updateRuntimeContext();
|
||||
}
|
||||
@ -373,6 +378,9 @@ void InstanceSettingsPage::loadSettings()
|
||||
|
||||
ui->serverJoinGroupBox->setChecked(m_settings->get("JoinServerOnLaunch").toBool());
|
||||
ui->serverJoinAddress->setText(m_settings->get("JoinServerOnLaunchAddress").toString());
|
||||
|
||||
ui->instanceAccountGroupBox->setChecked(m_settings->get("UseAccountForInstance").toBool());
|
||||
updateAccountsMenu();
|
||||
}
|
||||
|
||||
void InstanceSettingsPage::on_javaDownloadBtn_clicked()
|
||||
@ -443,6 +451,44 @@ void InstanceSettingsPage::on_javaTestBtn_clicked()
|
||||
checker->run();
|
||||
}
|
||||
|
||||
void InstanceSettingsPage::updateAccountsMenu()
|
||||
{
|
||||
ui->instanceAccountSelector->clear();
|
||||
auto accounts = APPLICATION->accounts();
|
||||
int accountIndex = accounts->findAccountByProfileId(m_settings->get("InstanceAccountId").toString());
|
||||
|
||||
for (int i = 0; i < accounts->count(); i++) {
|
||||
MinecraftAccountPtr account = accounts->at(i);
|
||||
ui->instanceAccountSelector->addItem(getFaceForAccount(account), account->profileName(), i);
|
||||
if (i == accountIndex)
|
||||
ui->instanceAccountSelector->setCurrentIndex(i);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
QIcon InstanceSettingsPage::getFaceForAccount(MinecraftAccountPtr account)
|
||||
{
|
||||
if (auto face = account->getFace(); !face.isNull()) {
|
||||
return face;
|
||||
}
|
||||
|
||||
return APPLICATION->getThemedIcon("noaccount");
|
||||
}
|
||||
|
||||
void InstanceSettingsPage::changeInstanceAccount(int index)
|
||||
{
|
||||
auto accounts = APPLICATION->accounts();
|
||||
if (index != -1 && accounts->at(index) && ui->instanceAccountGroupBox->isChecked()) {
|
||||
auto account = accounts->at(index);
|
||||
m_settings->set("InstanceAccountId", account->profileId());
|
||||
}
|
||||
}
|
||||
|
||||
void InstanceSettingsPage::on_maxMemSpinBox_valueChanged(int i)
|
||||
{
|
||||
updateThresholds();
|
||||
}
|
||||
|
||||
void InstanceSettingsPage::checkerFinished()
|
||||
{
|
||||
checker.reset();
|
||||
@ -453,3 +499,29 @@ void InstanceSettingsPage::retranslate()
|
||||
ui->retranslateUi(this);
|
||||
ui->customCommands->retranslate(); // TODO: why is this seperate from the others?
|
||||
}
|
||||
|
||||
void InstanceSettingsPage::updateThresholds()
|
||||
{
|
||||
auto sysMiB = Sys::getSystemRam() / Sys::mebibyte;
|
||||
unsigned int maxMem = ui->maxMemSpinBox->value();
|
||||
|
||||
QString iconName;
|
||||
|
||||
if (maxMem >= sysMiB) {
|
||||
iconName = "status-bad";
|
||||
ui->labelMaxMemIcon->setToolTip(tr("Your maximum memory allocation exceeds your system memory capacity."));
|
||||
} else if (maxMem > (sysMiB * 0.9)) {
|
||||
iconName = "status-yellow";
|
||||
ui->labelMaxMemIcon->setToolTip(tr("Your maximum memory allocation approaches your system memory capacity."));
|
||||
} else {
|
||||
iconName = "status-good";
|
||||
ui->labelMaxMemIcon->setToolTip("");
|
||||
}
|
||||
|
||||
{
|
||||
auto height = ui->labelMaxMemIcon->fontInfo().pixelSize();
|
||||
QIcon icon = APPLICATION->getThemedIcon(iconName);
|
||||
QPixmap pix = icon.pixmap(height, height);
|
||||
ui->labelMaxMemIcon->setPixmap(pix);
|
||||
}
|
||||
}
|
||||
|
@ -37,12 +37,13 @@
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
#include "java/JavaChecker.h"
|
||||
#include "BaseInstance.h"
|
||||
#include <QObjectPtr.h>
|
||||
#include "ui/pages/BasePage.h"
|
||||
#include "JavaCommon.h"
|
||||
#include <QMenu>
|
||||
#include "Application.h"
|
||||
#include "BaseInstance.h"
|
||||
#include "JavaCommon.h"
|
||||
#include "java/JavaChecker.h"
|
||||
#include "ui/pages/BasePage.h"
|
||||
|
||||
class JavaChecker;
|
||||
namespace Ui
|
||||
@ -74,14 +75,16 @@ public:
|
||||
{
|
||||
return "Instance-settings";
|
||||
}
|
||||
virtual bool shouldDisplay() const override;
|
||||
void retranslate() override;
|
||||
|
||||
private slots:
|
||||
void updateThresholds();
|
||||
|
||||
private slots:
|
||||
void on_javaDetectBtn_clicked();
|
||||
void on_javaTestBtn_clicked();
|
||||
void on_javaBrowseBtn_clicked();
|
||||
void on_javaDownloadBtn_clicked();
|
||||
void on_maxMemSpinBox_valueChanged(int i);
|
||||
|
||||
void applySettings();
|
||||
void loadSettings();
|
||||
@ -90,6 +93,10 @@ private slots:
|
||||
|
||||
void globalSettingsButtonClicked(bool checked);
|
||||
|
||||
void updateAccountsMenu();
|
||||
QIcon getFaceForAccount(MinecraftAccountPtr account);
|
||||
void changeInstanceAccount(int index);
|
||||
|
||||
private:
|
||||
Ui::InstanceSettingsPage *ui;
|
||||
BaseInstance *m_instance;
|
||||
|
@ -119,7 +119,14 @@
|
||||
<property name="checked">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<layout class="QGridLayout" name="gridLayout_2" columnstretch="1,0,0,0">
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="labelPermGen">
|
||||
<property name="text">
|
||||
<string notr="true">PermGen:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="labelMinMem">
|
||||
<property name="text">
|
||||
@ -127,29 +134,21 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QSpinBox" name="maxMemSpinBox">
|
||||
<property name="toolTip">
|
||||
<string>The maximum amount of memory Minecraft is allowed to use.</string>
|
||||
</property>
|
||||
<property name="suffix">
|
||||
<string notr="true"> MiB</string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>128</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>65536</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<number>128</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>1024</number>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="labelMaxMem">
|
||||
<property name="text">
|
||||
<string>Maximum memory allocation:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<item row="3" column="0" colspan="3">
|
||||
<widget class="QLabel" name="labelPermgenNote">
|
||||
<property name="text">
|
||||
<string>Note: Permgen is set automatically by Java 8 and later</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QSpinBox" name="minMemSpinBox">
|
||||
<property name="toolTip">
|
||||
<string>The amount of memory Minecraft is started with.</string>
|
||||
@ -161,7 +160,7 @@
|
||||
<number>128</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>65536</number>
|
||||
<number>1048576</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<number>128</number>
|
||||
@ -171,7 +170,29 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<item row="1" column="2">
|
||||
<widget class="QSpinBox" name="maxMemSpinBox">
|
||||
<property name="toolTip">
|
||||
<string>The maximum amount of memory Minecraft is allowed to use.</string>
|
||||
</property>
|
||||
<property name="suffix">
|
||||
<string notr="true"> MiB</string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>128</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>1048576</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<number>128</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>1024</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="2">
|
||||
<widget class="QSpinBox" name="permGenSpinBox">
|
||||
<property name="toolTip">
|
||||
<string>The amount of memory available to store loaded Java classes.</string>
|
||||
@ -193,24 +214,16 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="labelPermGen">
|
||||
<item row="1" column="3">
|
||||
<widget class="QLabel" name="labelMaxMemIcon">
|
||||
<property name="text">
|
||||
<string notr="true">PermGen:</string>
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="labelMaxMem">
|
||||
<property name="text">
|
||||
<string>Maximum memory allocation:</string>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0" colspan="2">
|
||||
<widget class="QLabel" name="labelPermgenNote">
|
||||
<property name="text">
|
||||
<string>Note: Permgen is set automatically by Java 8 and later</string>
|
||||
<property name="buddy">
|
||||
<cstring>maxMemSpinBox</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -263,7 +276,7 @@
|
||||
<item>
|
||||
<widget class="QCheckBox" name="maximizedCheckBox">
|
||||
<property name="text">
|
||||
<string>Start Minecraft maximized?</string>
|
||||
<string>Start Minecraft maximized</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -335,21 +348,21 @@
|
||||
<item>
|
||||
<widget class="QCheckBox" name="showConsoleCheck">
|
||||
<property name="text">
|
||||
<string>Show console while the game is running?</string>
|
||||
<string>Show console while the game is running</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="autoCloseConsoleCheck">
|
||||
<property name="text">
|
||||
<string>Automatically close console when the game quits?</string>
|
||||
<string>Automatically close console when the game quits</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="showConsoleErrorCheck">
|
||||
<property name="text">
|
||||
<string>Show console when the game crashes?</string>
|
||||
<string>Show console when the game crashes</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -602,6 +615,41 @@
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="instanceAccountGroupBox">
|
||||
<property name="title">
|
||||
<string>Override default account</string>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_15">
|
||||
<item>
|
||||
<layout class="QGridLayout" name="instanceAccountLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="instanceAccountNameLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Account:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QComboBox" name="instanceAccountSelector"/>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacerMiscellaneous">
|
||||
<property name="orientation">
|
||||
|
@ -1,8 +1,9 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Prism Launcher - Minecraft Launcher
|
||||
* Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||
* Copyright (C) 2022 TheKodeToad <TheKodeToad@proton.me>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@ -39,7 +40,7 @@
|
||||
|
||||
#include "Application.h"
|
||||
|
||||
#include <QIcon>
|
||||
#include <QIdentityProxyModel>
|
||||
#include <QScrollBar>
|
||||
#include <QShortcut>
|
||||
|
||||
@ -277,28 +278,22 @@ void LogPage::on_btnPaste_clicked()
|
||||
//FIXME: turn this into a proper task and move the upload logic out of GuiUtil!
|
||||
m_model->append(
|
||||
MessageLevel::Launcher,
|
||||
QString("%2: Log upload triggered at: %1").arg(
|
||||
QDateTime::currentDateTime().toString(Qt::RFC2822Date),
|
||||
BuildConfig.LAUNCHER_DISPLAYNAME
|
||||
QString("Log upload triggered at: %1").arg(
|
||||
QDateTime::currentDateTime().toString(Qt::RFC2822Date)
|
||||
)
|
||||
);
|
||||
auto url = GuiUtil::uploadPaste(m_model->toPlainText(), this);
|
||||
if(!url.isEmpty())
|
||||
auto url = GuiUtil::uploadPaste(tr("Minecraft Log"), m_model->toPlainText(), this);
|
||||
if(!url.has_value())
|
||||
{
|
||||
m_model->append(
|
||||
MessageLevel::Launcher,
|
||||
QString("%2: Log uploaded to: %1").arg(
|
||||
url,
|
||||
BuildConfig.LAUNCHER_DISPLAYNAME
|
||||
)
|
||||
);
|
||||
m_model->append(MessageLevel::Error, QString("Log upload canceled"));
|
||||
}
|
||||
else if (url->isNull())
|
||||
{
|
||||
m_model->append(MessageLevel::Error, QString("Log upload failed!"));
|
||||
}
|
||||
else
|
||||
{
|
||||
m_model->append(
|
||||
MessageLevel::Error,
|
||||
QString("%1: Log upload failed!").arg(BuildConfig.LAUNCHER_DISPLAYNAME)
|
||||
);
|
||||
m_model->append(MessageLevel::Launcher, QString("Log uploaded to: %1").arg(url.value()));
|
||||
}
|
||||
}
|
||||
|
||||
|
477
launcher/ui/pages/instance/ManagedPackPage.cpp
Normal file
477
launcher/ui/pages/instance/ManagedPackPage.cpp
Normal file
@ -0,0 +1,477 @@
|
||||
// SPDX-FileCopyrightText: 2022 flowln <flowlnlnln@gmail.com>
|
||||
//
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
#include "ManagedPackPage.h"
|
||||
#include "ui_ManagedPackPage.h"
|
||||
|
||||
#include <QListView>
|
||||
#include <QProxyStyle>
|
||||
#include <QStyleFactory>
|
||||
|
||||
#include "Application.h"
|
||||
#include "BuildConfig.h"
|
||||
#include "InstanceImportTask.h"
|
||||
#include "InstanceList.h"
|
||||
#include "InstanceTask.h"
|
||||
#include "Json.h"
|
||||
#include "Markdown.h"
|
||||
|
||||
#include "modplatform/modrinth/ModrinthPackManifest.h"
|
||||
|
||||
#include "ui/InstanceWindow.h"
|
||||
#include "ui/dialogs/CustomMessageBox.h"
|
||||
#include "ui/dialogs/ProgressDialog.h"
|
||||
|
||||
/** This is just to override the combo box popup behavior so that the combo box doesn't take the whole screen.
|
||||
* ... thanks Qt.
|
||||
*/
|
||||
class NoBigComboBoxStyle : public QProxyStyle {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
// clang-format off
|
||||
int styleHint(QStyle::StyleHint hint, const QStyleOption* option = nullptr, const QWidget* widget = nullptr, QStyleHintReturn* returnData = nullptr) const override
|
||||
{
|
||||
if (hint == QStyle::SH_ComboBox_Popup)
|
||||
return false;
|
||||
|
||||
return QProxyStyle::styleHint(hint, option, widget, returnData);
|
||||
}
|
||||
// clang-format on
|
||||
|
||||
/**
|
||||
* Something about QProxyStyle and QStyle objects means they can't be free'd just
|
||||
* because all the widgets using them are gone.
|
||||
* They seems to be tied to the QApplicaiton lifecycle.
|
||||
* So make singletons tied to the lifetime of the application to clean them up and ensure they aren't
|
||||
* being remade over and over again, thus leaking memory.
|
||||
*/
|
||||
public:
|
||||
static NoBigComboBoxStyle* getInstance(QStyle* style)
|
||||
{
|
||||
static QHash<QStyle*, NoBigComboBoxStyle*> s_singleton_instances_ = {};
|
||||
static std::mutex s_singleton_instances_mutex_;
|
||||
|
||||
std::lock_guard<std::mutex> lock(s_singleton_instances_mutex_);
|
||||
auto inst_iter = s_singleton_instances_.constFind(style);
|
||||
NoBigComboBoxStyle* inst = nullptr;
|
||||
if (inst_iter == s_singleton_instances_.constEnd() || *inst_iter == nullptr) {
|
||||
inst = new NoBigComboBoxStyle(style);
|
||||
inst->setParent(APPLICATION);
|
||||
s_singleton_instances_.insert(style, inst);
|
||||
qDebug() << "QProxyStyle NoBigComboBox created for" << style->objectName() << style;
|
||||
} else {
|
||||
inst = *inst_iter;
|
||||
}
|
||||
return inst;
|
||||
}
|
||||
|
||||
private:
|
||||
NoBigComboBoxStyle(QStyle* style) : QProxyStyle(style) {}
|
||||
};
|
||||
|
||||
ManagedPackPage* ManagedPackPage::createPage(BaseInstance* inst, QString type, QWidget* parent)
|
||||
{
|
||||
if (type == "modrinth")
|
||||
return new ModrinthManagedPackPage(inst, nullptr, parent);
|
||||
if (type == "flame" && (APPLICATION->capabilities() & Application::SupportsFlame))
|
||||
return new FlameManagedPackPage(inst, nullptr, parent);
|
||||
|
||||
return new GenericManagedPackPage(inst, nullptr, parent);
|
||||
}
|
||||
|
||||
ManagedPackPage::ManagedPackPage(BaseInstance* inst, InstanceWindow* instance_window, QWidget* parent)
|
||||
: QWidget(parent), m_instance_window(instance_window), ui(new Ui::ManagedPackPage), m_inst(inst)
|
||||
{
|
||||
Q_ASSERT(inst);
|
||||
|
||||
ui->setupUi(this);
|
||||
|
||||
// NOTE: GTK2 themes crash with the proxy style.
|
||||
// This seems like an upstream bug, so there's not much else that can be done.
|
||||
if (!QStyleFactory::keys().contains("gtk2")) {
|
||||
auto comboStyle = NoBigComboBoxStyle::getInstance(ui->versionsComboBox->style());
|
||||
ui->versionsComboBox->setStyle(comboStyle);
|
||||
}
|
||||
|
||||
ui->reloadButton->setVisible(false);
|
||||
connect(ui->reloadButton, &QPushButton::clicked, this, [this](bool) {
|
||||
ui->reloadButton->setVisible(false);
|
||||
|
||||
m_loaded = false;
|
||||
// Pretend we're opening the page again
|
||||
openedImpl();
|
||||
});
|
||||
}
|
||||
|
||||
ManagedPackPage::~ManagedPackPage()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void ManagedPackPage::openedImpl()
|
||||
{
|
||||
ui->packName->setText(m_inst->getManagedPackName());
|
||||
ui->packVersion->setText(m_inst->getManagedPackVersionName());
|
||||
ui->packOrigin->setText(tr("Website: <a href=%1>%2</a> | Pack ID: %3 | Version ID: %4")
|
||||
.arg(url(), displayName(), m_inst->getManagedPackID(), m_inst->getManagedPackVersionID()));
|
||||
|
||||
parseManagedPack();
|
||||
}
|
||||
|
||||
QString ManagedPackPage::displayName() const
|
||||
{
|
||||
auto type = m_inst->getManagedPackType();
|
||||
if (type.isEmpty())
|
||||
return {};
|
||||
if (type == "flame")
|
||||
type = "CurseForge";
|
||||
return type.replace(0, 1, type[0].toUpper());
|
||||
}
|
||||
|
||||
QIcon ManagedPackPage::icon() const
|
||||
{
|
||||
return APPLICATION->getThemedIcon(m_inst->getManagedPackType());
|
||||
}
|
||||
|
||||
QString ManagedPackPage::helpPage() const
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
void ManagedPackPage::retranslate()
|
||||
{
|
||||
ui->retranslateUi(this);
|
||||
}
|
||||
|
||||
bool ManagedPackPage::shouldDisplay() const
|
||||
{
|
||||
return m_inst->isManagedPack();
|
||||
}
|
||||
|
||||
bool ManagedPackPage::runUpdateTask(InstanceTask* task)
|
||||
{
|
||||
Q_ASSERT(task);
|
||||
|
||||
unique_qobject_ptr<Task> wrapped_task(APPLICATION->instances()->wrapInstanceTask(task));
|
||||
|
||||
connect(task, &Task::failed,
|
||||
[this](QString reason) { CustomMessageBox::selectable(this, tr("Error"), reason, QMessageBox::Critical)->show(); });
|
||||
connect(task, &Task::succeeded, [this, task]() {
|
||||
QStringList warnings = task->warnings();
|
||||
if (warnings.count())
|
||||
CustomMessageBox::selectable(this, tr("Warnings"), warnings.join('\n'), QMessageBox::Warning)->show();
|
||||
});
|
||||
connect(task, &Task::aborted, [this] {
|
||||
CustomMessageBox::selectable(this, tr("Task aborted"), tr("The task has been aborted by the user."), QMessageBox::Information)
|
||||
->show();
|
||||
});
|
||||
|
||||
ProgressDialog loadDialog(this);
|
||||
loadDialog.setSkipButton(true, tr("Abort"));
|
||||
loadDialog.execWithTask(task);
|
||||
|
||||
return task->wasSuccessful();
|
||||
}
|
||||
|
||||
void ManagedPackPage::suggestVersion()
|
||||
{
|
||||
ui->updateButton->setText(tr("Update pack"));
|
||||
ui->updateButton->setDisabled(false);
|
||||
}
|
||||
|
||||
void ManagedPackPage::setFailState()
|
||||
{
|
||||
qDebug() << "Setting fail state!";
|
||||
|
||||
// We block signals here so that suggestVersion() doesn't get called, causing an assertion fail.
|
||||
ui->versionsComboBox->blockSignals(true);
|
||||
ui->versionsComboBox->clear();
|
||||
ui->versionsComboBox->addItem(tr("Failed to search for available versions."), {});
|
||||
ui->versionsComboBox->blockSignals(false);
|
||||
|
||||
ui->changelogTextBrowser->setText(tr("Failed to request changelog data for this modpack."));
|
||||
|
||||
ui->updateButton->setText(tr("Cannot update!"));
|
||||
ui->updateButton->setDisabled(true);
|
||||
|
||||
ui->reloadButton->setVisible(true);
|
||||
}
|
||||
|
||||
ModrinthManagedPackPage::ModrinthManagedPackPage(BaseInstance* inst, InstanceWindow* instance_window, QWidget* parent)
|
||||
: ManagedPackPage(inst, instance_window, parent)
|
||||
{
|
||||
Q_ASSERT(inst->isManagedPack());
|
||||
connect(ui->versionsComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(suggestVersion()));
|
||||
connect(ui->updateButton, &QPushButton::clicked, this, &ModrinthManagedPackPage::update);
|
||||
}
|
||||
|
||||
// MODRINTH
|
||||
|
||||
void ModrinthManagedPackPage::parseManagedPack()
|
||||
{
|
||||
qDebug() << "Parsing Modrinth pack";
|
||||
|
||||
// No need for the extra work because we already have everything we need.
|
||||
if (m_loaded)
|
||||
return;
|
||||
|
||||
if (m_fetch_job && m_fetch_job->isRunning())
|
||||
m_fetch_job->abort();
|
||||
|
||||
m_fetch_job.reset(new NetJob(QString("Modrinth::PackVersions(%1)").arg(m_inst->getManagedPackName()), APPLICATION->network()));
|
||||
auto response = std::make_shared<QByteArray>();
|
||||
|
||||
QString id = m_inst->getManagedPackID();
|
||||
|
||||
m_fetch_job->addNetAction(
|
||||
Net::Download::makeByteArray(QString("%1/project/%2/version").arg(BuildConfig.MODRINTH_PROD_URL, id), response));
|
||||
|
||||
QObject::connect(m_fetch_job.get(), &NetJob::succeeded, this, [this, response, id] {
|
||||
QJsonParseError parse_error{};
|
||||
QJsonDocument doc = QJsonDocument::fromJson(*response, &parse_error);
|
||||
if (parse_error.error != QJsonParseError::NoError) {
|
||||
qWarning() << "Error while parsing JSON response from Modrinth at " << parse_error.offset
|
||||
<< " reason: " << parse_error.errorString();
|
||||
qWarning() << *response;
|
||||
|
||||
setFailState();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
Modrinth::loadIndexedVersions(m_pack, doc);
|
||||
} catch (const JSONValidationError& e) {
|
||||
qDebug() << *response;
|
||||
qWarning() << "Error while reading modrinth modpack version: " << e.cause();
|
||||
|
||||
setFailState();
|
||||
return;
|
||||
}
|
||||
|
||||
// We block signals here so that suggestVersion() doesn't get called, causing an assertion fail.
|
||||
ui->versionsComboBox->blockSignals(true);
|
||||
ui->versionsComboBox->clear();
|
||||
ui->versionsComboBox->blockSignals(false);
|
||||
|
||||
for (auto version : m_pack.versions) {
|
||||
QString name = version.version;
|
||||
|
||||
if (!version.name.contains(version.version))
|
||||
name = QString("%1 — %2").arg(version.name, version.version);
|
||||
|
||||
// NOTE: the id from version isn't the same id in the modpack format spec...
|
||||
// e.g. HexMC's 4.4.0 has versionId 4.0.0 in the modpack index..............
|
||||
if (version.version == m_inst->getManagedPackVersionName())
|
||||
name = tr("%1 (Current)").arg(name);
|
||||
|
||||
ui->versionsComboBox->addItem(name, QVariant(version.id));
|
||||
}
|
||||
|
||||
suggestVersion();
|
||||
|
||||
m_loaded = true;
|
||||
});
|
||||
QObject::connect(m_fetch_job.get(), &NetJob::failed, this, &ModrinthManagedPackPage::setFailState);
|
||||
QObject::connect(m_fetch_job.get(), &NetJob::aborted, this, &ModrinthManagedPackPage::setFailState);
|
||||
|
||||
ui->changelogTextBrowser->setText(tr("Fetching changelogs..."));
|
||||
|
||||
m_fetch_job->start();
|
||||
}
|
||||
|
||||
QString ModrinthManagedPackPage::url() const
|
||||
{
|
||||
return "https://modrinth.com/mod/" + m_inst->getManagedPackID();
|
||||
}
|
||||
|
||||
void ModrinthManagedPackPage::suggestVersion()
|
||||
{
|
||||
auto index = ui->versionsComboBox->currentIndex();
|
||||
if (m_pack.versions.length() == 0) {
|
||||
setFailState();
|
||||
return;
|
||||
}
|
||||
auto version = m_pack.versions.at(index);
|
||||
|
||||
ui->changelogTextBrowser->setHtml(markdownToHTML(version.changelog.toUtf8()));
|
||||
|
||||
ManagedPackPage::suggestVersion();
|
||||
}
|
||||
|
||||
void ModrinthManagedPackPage::update()
|
||||
{
|
||||
auto index = ui->versionsComboBox->currentIndex();
|
||||
if (m_pack.versions.length() == 0) {
|
||||
setFailState();
|
||||
return;
|
||||
}
|
||||
auto version = m_pack.versions.at(index);
|
||||
|
||||
QMap<QString, QString> extra_info;
|
||||
// NOTE: Don't use 'm_pack.id' here, since we didn't completely parse all the metadata for the pack, including this field.
|
||||
extra_info.insert("pack_id", m_inst->getManagedPackID());
|
||||
extra_info.insert("pack_version_id", version.id);
|
||||
extra_info.insert("original_instance_id", m_inst->id());
|
||||
|
||||
auto extracted = new InstanceImportTask(version.download_url, this, std::move(extra_info));
|
||||
|
||||
InstanceName inst_name(m_inst->getManagedPackName(), version.version);
|
||||
inst_name.setName(m_inst->name().replace(m_inst->getManagedPackVersionName(), version.version));
|
||||
extracted->setName(inst_name);
|
||||
|
||||
extracted->setGroup(APPLICATION->instances()->getInstanceGroup(m_inst->id()));
|
||||
extracted->setIcon(m_inst->iconKey());
|
||||
extracted->setConfirmUpdate(false);
|
||||
|
||||
auto did_succeed = runUpdateTask(extracted);
|
||||
|
||||
if (m_instance_window && did_succeed)
|
||||
m_instance_window->close();
|
||||
}
|
||||
|
||||
// FLAME
|
||||
|
||||
FlameManagedPackPage::FlameManagedPackPage(BaseInstance* inst, InstanceWindow* instance_window, QWidget* parent)
|
||||
: ManagedPackPage(inst, instance_window, parent)
|
||||
{
|
||||
Q_ASSERT(inst->isManagedPack());
|
||||
connect(ui->versionsComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(suggestVersion()));
|
||||
connect(ui->updateButton, &QPushButton::clicked, this, &FlameManagedPackPage::update);
|
||||
}
|
||||
|
||||
void FlameManagedPackPage::parseManagedPack()
|
||||
{
|
||||
qDebug() << "Parsing Flame pack";
|
||||
|
||||
// We need to tell the user to redownload the pack, since we didn't save the required info previously
|
||||
if (m_inst->getManagedPackID().isEmpty()) {
|
||||
setFailState();
|
||||
QString message =
|
||||
tr("<h1>Hey there!</h1>"
|
||||
"<h4>"
|
||||
"It seems like your Pack ID is null. This is because of a bug in older versions of the launcher.<br/>"
|
||||
"Unfortunately, we can't do the proper API requests without this information.<br/>"
|
||||
"<br/>"
|
||||
"So, in order for this feature to work, you will need to re-download the modpack from the built-in downloader.<br/>"
|
||||
"<br/>"
|
||||
"Don't worry though, it will ask you to update this instance instead, so you'll not lose this instance!"
|
||||
"</h4>");
|
||||
|
||||
ui->changelogTextBrowser->setHtml(message);
|
||||
return;
|
||||
}
|
||||
|
||||
// No need for the extra work because we already have everything we need.
|
||||
if (m_loaded)
|
||||
return;
|
||||
|
||||
if (m_fetch_job && m_fetch_job->isRunning())
|
||||
m_fetch_job->abort();
|
||||
|
||||
m_fetch_job.reset(new NetJob(QString("Flame::PackVersions(%1)").arg(m_inst->getManagedPackName()), APPLICATION->network()));
|
||||
auto response = std::make_shared<QByteArray>();
|
||||
|
||||
QString id = m_inst->getManagedPackID();
|
||||
|
||||
m_fetch_job->addNetAction(Net::Download::makeByteArray(QString("%1/mods/%2/files").arg(BuildConfig.FLAME_BASE_URL, id), response));
|
||||
|
||||
QObject::connect(m_fetch_job.get(), &NetJob::succeeded, this, [this, response, id] {
|
||||
QJsonParseError parse_error{};
|
||||
QJsonDocument doc = QJsonDocument::fromJson(*response, &parse_error);
|
||||
if (parse_error.error != QJsonParseError::NoError) {
|
||||
qWarning() << "Error while parsing JSON response from Flame at " << parse_error.offset
|
||||
<< " reason: " << parse_error.errorString();
|
||||
qWarning() << *response;
|
||||
|
||||
setFailState();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
auto obj = doc.object();
|
||||
auto data = Json::ensureArray(obj, "data");
|
||||
Flame::loadIndexedPackVersions(m_pack, data);
|
||||
} catch (const JSONValidationError& e) {
|
||||
qDebug() << *response;
|
||||
qWarning() << "Error while reading flame modpack version: " << e.cause();
|
||||
|
||||
setFailState();
|
||||
return;
|
||||
}
|
||||
|
||||
// We block signals here so that suggestVersion() doesn't get called, causing an assertion fail.
|
||||
ui->versionsComboBox->blockSignals(true);
|
||||
ui->versionsComboBox->clear();
|
||||
ui->versionsComboBox->blockSignals(false);
|
||||
|
||||
for (auto version : m_pack.versions) {
|
||||
QString name = version.version;
|
||||
|
||||
if (version.fileId == m_inst->getManagedPackVersionID().toInt())
|
||||
name = tr("%1 (Current)").arg(name);
|
||||
|
||||
ui->versionsComboBox->addItem(name, QVariant(version.fileId));
|
||||
}
|
||||
|
||||
suggestVersion();
|
||||
|
||||
m_loaded = true;
|
||||
});
|
||||
QObject::connect(m_fetch_job.get(), &NetJob::failed, this, &FlameManagedPackPage::setFailState);
|
||||
QObject::connect(m_fetch_job.get(), &NetJob::aborted, this, &FlameManagedPackPage::setFailState);
|
||||
|
||||
m_fetch_job->start();
|
||||
}
|
||||
|
||||
QString FlameManagedPackPage::url() const
|
||||
{
|
||||
// FIXME: We should display the websiteUrl field, but this requires doing the API request first :(
|
||||
return {};
|
||||
}
|
||||
|
||||
void FlameManagedPackPage::suggestVersion()
|
||||
{
|
||||
auto index = ui->versionsComboBox->currentIndex();
|
||||
if (m_pack.versions.length() == 0) {
|
||||
setFailState();
|
||||
return;
|
||||
}
|
||||
auto version = m_pack.versions.at(index);
|
||||
|
||||
ui->changelogTextBrowser->setHtml(m_api.getModFileChangelog(m_inst->getManagedPackID().toInt(), version.fileId));
|
||||
|
||||
ManagedPackPage::suggestVersion();
|
||||
}
|
||||
|
||||
void FlameManagedPackPage::update()
|
||||
{
|
||||
auto index = ui->versionsComboBox->currentIndex();
|
||||
if (m_pack.versions.length() == 0) {
|
||||
setFailState();
|
||||
return;
|
||||
}
|
||||
auto version = m_pack.versions.at(index);
|
||||
|
||||
QMap<QString, QString> extra_info;
|
||||
extra_info.insert("pack_id", m_inst->getManagedPackID());
|
||||
extra_info.insert("pack_version_id", QString::number(version.fileId));
|
||||
extra_info.insert("original_instance_id", m_inst->id());
|
||||
|
||||
auto extracted = new InstanceImportTask(version.downloadUrl, this, std::move(extra_info));
|
||||
|
||||
extracted->setName(m_inst->name());
|
||||
extracted->setGroup(APPLICATION->instances()->getInstanceGroup(m_inst->id()));
|
||||
extracted->setIcon(m_inst->iconKey());
|
||||
extracted->setConfirmUpdate(false);
|
||||
|
||||
auto did_succeed = runUpdateTask(extracted);
|
||||
|
||||
if (m_instance_window && did_succeed)
|
||||
m_instance_window->close();
|
||||
}
|
||||
|
||||
#include "ManagedPackPage.moc"
|
154
launcher/ui/pages/instance/ManagedPackPage.h
Normal file
154
launcher/ui/pages/instance/ManagedPackPage.h
Normal file
@ -0,0 +1,154 @@
|
||||
// SPDX-FileCopyrightText: 2022 flowln <flowlnlnln@gmail.com>
|
||||
//
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "BaseInstance.h"
|
||||
|
||||
#include "modplatform/modrinth/ModrinthAPI.h"
|
||||
#include "modplatform/modrinth/ModrinthPackManifest.h"
|
||||
|
||||
#include "modplatform/flame/FlameAPI.h"
|
||||
#include "modplatform/flame/FlamePackIndex.h"
|
||||
|
||||
#include "net/NetJob.h"
|
||||
|
||||
#include "ui/pages/BasePage.h"
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
namespace Ui {
|
||||
class ManagedPackPage;
|
||||
}
|
||||
|
||||
class InstanceTask;
|
||||
class InstanceWindow;
|
||||
|
||||
class ManagedPackPage : public QWidget, public BasePage {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
inline static ManagedPackPage* createPage(BaseInstance* inst, QWidget* parent = nullptr)
|
||||
{
|
||||
return ManagedPackPage::createPage(inst, inst->getManagedPackType(), parent);
|
||||
}
|
||||
|
||||
static ManagedPackPage* createPage(BaseInstance* inst, QString type, QWidget* parent = nullptr);
|
||||
~ManagedPackPage() override;
|
||||
|
||||
[[nodiscard]] QString displayName() const override;
|
||||
[[nodiscard]] QIcon icon() const override;
|
||||
[[nodiscard]] QString helpPage() const override;
|
||||
[[nodiscard]] QString id() const override { return "managed_pack"; }
|
||||
[[nodiscard]] bool shouldDisplay() const override;
|
||||
|
||||
void openedImpl() override;
|
||||
|
||||
bool apply() override { return true; }
|
||||
void retranslate() override;
|
||||
|
||||
/** Gets the necessary information about the managed pack, such as
|
||||
* available versions*/
|
||||
virtual void parseManagedPack(){};
|
||||
|
||||
/** URL of the managed pack.
|
||||
* Not the version-specific one.
|
||||
*/
|
||||
[[nodiscard]] virtual QString url() const { return {}; };
|
||||
|
||||
void setInstanceWindow(InstanceWindow* window) { m_instance_window = window; }
|
||||
|
||||
public slots:
|
||||
/** Gets the current version selection and update the UI, including the update button and the changelog.
|
||||
*/
|
||||
virtual void suggestVersion();
|
||||
|
||||
virtual void update(){};
|
||||
|
||||
protected slots:
|
||||
/** Does the necessary UI changes for when something failed.
|
||||
*
|
||||
* This includes:
|
||||
* - Setting an appropriate text on the version selector to indicate a fail;
|
||||
* - Setting an appropriate text on the changelog text browser to indicate a fail;
|
||||
* - Disable the update button.
|
||||
*/
|
||||
void setFailState();
|
||||
|
||||
protected:
|
||||
ManagedPackPage(BaseInstance* inst, InstanceWindow* instance_window, QWidget* parent = nullptr);
|
||||
|
||||
/** Run the InstanceTask, with a progress dialog and all.
|
||||
* Similar to MainWindow::instanceFromInstanceTask
|
||||
*
|
||||
* Returns whether the task was successful.
|
||||
*/
|
||||
bool runUpdateTask(InstanceTask*);
|
||||
|
||||
protected:
|
||||
InstanceWindow* m_instance_window = nullptr;
|
||||
|
||||
Ui::ManagedPackPage* ui;
|
||||
BaseInstance* m_inst;
|
||||
|
||||
bool m_loaded = false;
|
||||
};
|
||||
|
||||
/** Simple page for when we aren't a managed pack. */
|
||||
class GenericManagedPackPage final : public ManagedPackPage {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
GenericManagedPackPage(BaseInstance* inst, InstanceWindow* instance_window, QWidget* parent = nullptr)
|
||||
: ManagedPackPage(inst, instance_window, parent)
|
||||
{}
|
||||
~GenericManagedPackPage() override = default;
|
||||
|
||||
// TODO: We may want to show this page with some useful info at some point.
|
||||
[[nodiscard]] bool shouldDisplay() const override { return false; };
|
||||
};
|
||||
|
||||
class ModrinthManagedPackPage final : public ManagedPackPage {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ModrinthManagedPackPage(BaseInstance* inst, InstanceWindow* instance_window, QWidget* parent = nullptr);
|
||||
~ModrinthManagedPackPage() override = default;
|
||||
|
||||
void parseManagedPack() override;
|
||||
[[nodiscard]] QString url() const override;
|
||||
|
||||
public slots:
|
||||
void suggestVersion() override;
|
||||
|
||||
void update() override;
|
||||
|
||||
private:
|
||||
NetJob::Ptr m_fetch_job = nullptr;
|
||||
|
||||
Modrinth::Modpack m_pack;
|
||||
ModrinthAPI m_api;
|
||||
};
|
||||
|
||||
class FlameManagedPackPage final : public ManagedPackPage {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
FlameManagedPackPage(BaseInstance* inst, InstanceWindow* instance_window, QWidget* parent = nullptr);
|
||||
~FlameManagedPackPage() override = default;
|
||||
|
||||
void parseManagedPack() override;
|
||||
[[nodiscard]] QString url() const override;
|
||||
|
||||
public slots:
|
||||
void suggestVersion() override;
|
||||
|
||||
void update() override;
|
||||
|
||||
private:
|
||||
NetJob::Ptr m_fetch_job = nullptr;
|
||||
|
||||
Flame::IndexedPack m_pack;
|
||||
FlameAPI m_api;
|
||||
};
|
193
launcher/ui/pages/instance/ManagedPackPage.ui
Normal file
193
launcher/ui/pages/instance/ManagedPackPage.ui
Normal file
@ -0,0 +1,193 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>ManagedPackPage</class>
|
||||
<widget class="QWidget" name="ManagedPackPage">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>731</width>
|
||||
<height>538</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<property name="leftMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>9</number>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="packInformationBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Pack information</string>
|
||||
</property>
|
||||
<layout class="QFormLayout" name="formLayout_2">
|
||||
<item row="0" column="0">
|
||||
<layout class="QHBoxLayout" name="packNameLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="packNameLabel">
|
||||
<property name="text">
|
||||
<string>Pack name:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="packName">
|
||||
<property name="text">
|
||||
<string notr="true">placeholder</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<layout class="QHBoxLayout" name="packVersionLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="packVersionLabel">
|
||||
<property name="text">
|
||||
<string>Current version:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="packVersion">
|
||||
<property name="cursor">
|
||||
<cursorShape>IBeamCursor</cursorShape>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true">placeholder</string>
|
||||
</property>
|
||||
<property name="textInteractionFlags">
|
||||
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<layout class="QHBoxLayout" name="packOriginLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="packOriginLabel">
|
||||
<property name="text">
|
||||
<string>Provider information:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="packOrigin">
|
||||
<property name="cursor">
|
||||
<cursorShape>IBeamCursor</cursorShape>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true">placeholder</string>
|
||||
</property>
|
||||
<property name="textFormat">
|
||||
<enum>Qt::RichText</enum>
|
||||
</property>
|
||||
<property name="openExternalLinks">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="textInteractionFlags">
|
||||
<set>Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Line" name="line">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="updateToVersionLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Update to version:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="versionsComboBox"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="updateButton">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Fetching versions...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="changelogBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Changelog</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item>
|
||||
<widget class="QTextBrowser" name="changelogTextBrowser">
|
||||
<property name="placeholderText">
|
||||
<string>No changelog available for this version!</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QPushButton" name="reloadButton">
|
||||
<property name="text">
|
||||
<string>Reload page</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
@ -1,8 +1,10 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Prism Launcher - Minecraft Launcher
|
||||
* Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||
* Copyright (C) 2022 TheKodeToad <TheKodeToad@proton.me>
|
||||
* Copyright (c) 2023 Trial97 <alexandru.tripon97@gmail.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@ -43,13 +45,14 @@
|
||||
#include <QMenu>
|
||||
#include <QMessageBox>
|
||||
#include <QSortFilterProxyModel>
|
||||
#include <algorithm>
|
||||
|
||||
#include "Application.h"
|
||||
|
||||
#include "ui/GuiUtil.h"
|
||||
#include "ui/dialogs/CustomMessageBox.h"
|
||||
#include "ui/dialogs/ModDownloadDialog.h"
|
||||
#include "ui/dialogs/ModUpdateDialog.h"
|
||||
#include "ui/dialogs/ResourceDownloadDialog.h"
|
||||
|
||||
#include "DesktopServices.h"
|
||||
|
||||
@ -58,7 +61,8 @@
|
||||
#include "minecraft/mod/Mod.h"
|
||||
#include "minecraft/mod/ModFolderModel.h"
|
||||
|
||||
#include "modplatform/ModAPI.h"
|
||||
#include "modplatform/ModIndex.h"
|
||||
#include "modplatform/ResourceAPI.h"
|
||||
|
||||
#include "Version.h"
|
||||
#include "tasks/ConcurrentTask.h"
|
||||
@ -84,45 +88,40 @@ ModFolderPage::ModFolderPage(BaseInstance* inst, std::shared_ptr<ModFolderModel>
|
||||
ui->actionsToolbar->insertActionAfter(ui->actionAddItem, ui->actionUpdateItem);
|
||||
connect(ui->actionUpdateItem, &QAction::triggered, this, &ModFolderPage::updateMods);
|
||||
|
||||
auto check_allow_update = [this] {
|
||||
return (!m_instance || !m_instance->isRunning()) &&
|
||||
(ui->treeView->selectionModel()->hasSelection() || !m_model->empty());
|
||||
};
|
||||
ui->actionVisitItemPage->setToolTip(tr("Go to mod's home page"));
|
||||
ui->actionsToolbar->addAction(ui->actionVisitItemPage);
|
||||
connect(ui->actionVisitItemPage, &QAction::triggered, this, &ModFolderPage::visitModPages);
|
||||
|
||||
auto check_allow_update = [this] { return ui->treeView->selectionModel()->hasSelection() || !m_model->empty(); };
|
||||
|
||||
connect(ui->treeView->selectionModel(), &QItemSelectionModel::selectionChanged, this, [this, check_allow_update] {
|
||||
ui->actionUpdateItem->setEnabled(check_allow_update());
|
||||
|
||||
auto selection = m_filterModel->mapSelectionToSource(ui->treeView->selectionModel()->selection()).indexes();
|
||||
auto mods_list = m_model->selectedMods(selection);
|
||||
auto selected = std::count_if(mods_list.cbegin(), mods_list.cend(),
|
||||
[](Mod* v) { return v->metadata() != nullptr || v->homeurl().size() != 0; });
|
||||
if (selected <= 1) {
|
||||
ui->actionVisitItemPage->setText(tr("Visit mod's page"));
|
||||
ui->actionVisitItemPage->setToolTip(tr("Go to mod's home page"));
|
||||
} else {
|
||||
ui->actionVisitItemPage->setText(tr("Visit mods' pages"));
|
||||
ui->actionVisitItemPage->setToolTip(tr("Go to the pages of the selected mods"));
|
||||
}
|
||||
ui->actionVisitItemPage->setEnabled(selected != 0);
|
||||
});
|
||||
|
||||
connect(mods.get(), &ModFolderModel::rowsInserted, this, [this, check_allow_update] {
|
||||
ui->actionUpdateItem->setEnabled(check_allow_update());
|
||||
});
|
||||
connect(mods.get(), &ModFolderModel::rowsInserted, this,
|
||||
[this, check_allow_update] { ui->actionUpdateItem->setEnabled(check_allow_update()); });
|
||||
|
||||
connect(mods.get(), &ModFolderModel::rowsRemoved, this, [this, check_allow_update] {
|
||||
ui->actionUpdateItem->setEnabled(check_allow_update());
|
||||
});
|
||||
connect(mods.get(), &ModFolderModel::rowsRemoved, this,
|
||||
[this, check_allow_update] { ui->actionUpdateItem->setEnabled(check_allow_update()); });
|
||||
|
||||
connect(mods.get(), &ModFolderModel::updateFinished, this, [this, check_allow_update, mods] {
|
||||
ui->actionUpdateItem->setEnabled(check_allow_update());
|
||||
|
||||
// Prevent a weird crash when trying to open the mods page twice in a session o.O
|
||||
disconnect(mods.get(), &ModFolderModel::updateFinished, this, 0);
|
||||
});
|
||||
|
||||
ModFolderPage::runningStateChanged(m_instance && m_instance->isRunning());
|
||||
connect(mods.get(), &ModFolderModel::updateFinished, this,
|
||||
[this, check_allow_update] { ui->actionUpdateItem->setEnabled(check_allow_update()); });
|
||||
}
|
||||
}
|
||||
|
||||
void ModFolderPage::runningStateChanged(bool running)
|
||||
{
|
||||
ExternalResourcesPage::runningStateChanged(running);
|
||||
ui->actionDownloadItem->setEnabled(!running);
|
||||
ui->actionUpdateItem->setEnabled(!running);
|
||||
ui->actionAddItem->setEnabled(!running);
|
||||
ui->actionEnableItem->setEnabled(!running);
|
||||
ui->actionDisableItem->setEnabled(!running);
|
||||
ui->actionRemoveItem->setEnabled(!running);
|
||||
}
|
||||
|
||||
bool ModFolderPage::shouldDisplay() const
|
||||
{
|
||||
return true;
|
||||
@ -139,30 +138,33 @@ bool ModFolderPage::onSelectionChanged(const QModelIndex& current, const QModelI
|
||||
return true;
|
||||
}
|
||||
|
||||
void ModFolderPage::removeItem()
|
||||
void ModFolderPage::removeItems(const QItemSelection& selection)
|
||||
{
|
||||
if (m_instance != nullptr && m_instance->isRunning()) {
|
||||
auto response = CustomMessageBox::selectable(this, "Confirm Delete",
|
||||
"If you remove mods 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 (!m_controlsEnabled)
|
||||
return;
|
||||
|
||||
auto selection = m_filterModel->mapSelectionToSource(ui->treeView->selectionModel()->selection());
|
||||
if (response != QMessageBox::Yes)
|
||||
return;
|
||||
}
|
||||
m_model->deleteMods(selection.indexes());
|
||||
}
|
||||
|
||||
void ModFolderPage::installMods()
|
||||
{
|
||||
if (!m_controlsEnabled)
|
||||
return;
|
||||
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) {
|
||||
if (!profile->getModLoaders().has_value()) {
|
||||
QMessageBox::critical(this, tr("Error"), tr("Please install a mod loader first!"));
|
||||
return;
|
||||
}
|
||||
|
||||
ModDownloadDialog mdownload(m_model, this, m_instance);
|
||||
ResourceDownload::ModDownloadDialog mdownload(this, m_model, m_instance);
|
||||
if (mdownload.exec()) {
|
||||
ConcurrentTask* tasks = new ConcurrentTask(this);
|
||||
connect(tasks, &Task::failed, [this, tasks](QString reason) {
|
||||
@ -218,8 +220,7 @@ void ModFolderPage::updateMods()
|
||||
message = tr("All selected mods are up-to-date! :)");
|
||||
}
|
||||
}
|
||||
CustomMessageBox::selectable(this, tr("Update checker"), message)
|
||||
->exec();
|
||||
CustomMessageBox::selectable(this, tr("Update checker"), message)->exec();
|
||||
return;
|
||||
}
|
||||
|
||||
@ -277,3 +278,22 @@ bool CoreModFolderPage::shouldDisplay() const
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
NilModFolderPage::NilModFolderPage(BaseInstance* inst, std::shared_ptr<ModFolderModel> mods, QWidget* parent)
|
||||
: ModFolderPage(inst, mods, parent)
|
||||
{}
|
||||
|
||||
bool NilModFolderPage::shouldDisplay() const
|
||||
{
|
||||
return m_model->dir().exists();
|
||||
}
|
||||
|
||||
void ModFolderPage::visitModPages()
|
||||
{
|
||||
auto selection = m_filterModel->mapSelectionToSource(ui->treeView->selectionModel()->selection()).indexes();
|
||||
for (auto mod : m_model->selectedMods(selection)) {
|
||||
auto url = mod->metaurl();
|
||||
if (!url.isEmpty())
|
||||
DesktopServices::openUrl(url);
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,10 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Prism Launcher - Minecraft Launcher
|
||||
* Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||
* Copyright (C) 2022 TheKodeToad <TheKodeToad@proton.me>
|
||||
* Copyright (c) 2023 Trial97 <alexandru.tripon97@gmail.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@ -53,16 +55,16 @@ class ModFolderPage : public ExternalResourcesPage {
|
||||
virtual QString helpPage() const override { return "Loader-mods"; }
|
||||
|
||||
virtual bool shouldDisplay() const override;
|
||||
void runningStateChanged(bool running) override;
|
||||
|
||||
public slots:
|
||||
bool onSelectionChanged(const QModelIndex& current, const QModelIndex& previous) override;
|
||||
|
||||
private slots:
|
||||
void removeItem() override;
|
||||
void removeItems(const QItemSelection& selection) override;
|
||||
|
||||
void installMods();
|
||||
void updateMods();
|
||||
void visitModPages();
|
||||
|
||||
protected:
|
||||
std::shared_ptr<ModFolderModel> m_model;
|
||||
@ -80,3 +82,16 @@ class CoreModFolderPage : public ModFolderPage {
|
||||
|
||||
virtual bool shouldDisplay() const override;
|
||||
};
|
||||
|
||||
class NilModFolderPage : public ModFolderPage {
|
||||
public:
|
||||
explicit NilModFolderPage(BaseInstance* inst, std::shared_ptr<ModFolderModel> mods, QWidget* parent = 0);
|
||||
virtual ~NilModFolderPage() = default;
|
||||
|
||||
virtual QString displayName() const override { return tr("Nilmods"); }
|
||||
virtual QIcon icon() const override { return APPLICATION->getThemedIcon("coremods"); }
|
||||
virtual QString id() const override { return "nilmods"; }
|
||||
virtual QString helpPage() const override { return "Nilmods"; }
|
||||
|
||||
virtual bool shouldDisplay() const override;
|
||||
};
|
||||
|
@ -17,17 +17,11 @@
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QTextEdit" name="noteEditor">
|
||||
<property name="verticalScrollBarPolicy">
|
||||
<enum>Qt::ScrollBarAlwaysOn</enum>
|
||||
</property>
|
||||
<property name="tabChangesFocus">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
|
@ -1,7 +1,8 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Prism Launcher - Minecraft Launcher
|
||||
* Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
|
||||
* Copyright (C) 2022 TheKodeToad <TheKodeToad@proton.me>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@ -204,7 +205,7 @@ void OtherLogsPage::on_btnReload_clicked()
|
||||
|
||||
void OtherLogsPage::on_btnPaste_clicked()
|
||||
{
|
||||
GuiUtil::uploadPaste(ui->text->toPlainText(), this);
|
||||
GuiUtil::uploadPaste(m_currentFile, ui->text->toPlainText(), this);
|
||||
}
|
||||
|
||||
void OtherLogsPage::on_btnCopy_clicked()
|
||||
@ -219,13 +220,21 @@ void OtherLogsPage::on_btnDelete_clicked()
|
||||
setControlsEnabled(false);
|
||||
return;
|
||||
}
|
||||
if (QMessageBox::question(this, tr("Delete"),
|
||||
tr("Do you really want to delete %1?").arg(m_currentFile),
|
||||
QMessageBox::Yes, QMessageBox::No) == QMessageBox::No)
|
||||
{
|
||||
if (QMessageBox::question(this, tr("Confirm Deletion"),
|
||||
tr("You are about to delete \"%1\".\n"
|
||||
"This may be permanent and it will be gone from the logs folder.\n\n"
|
||||
"Are you sure?")
|
||||
.arg(m_currentFile),
|
||||
QMessageBox::Yes, QMessageBox::No) == QMessageBox::No) {
|
||||
return;
|
||||
}
|
||||
QFile file(FS::PathCombine(m_path, m_currentFile));
|
||||
|
||||
if (FS::trash(file.fileName()))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!file.remove())
|
||||
{
|
||||
QMessageBox::critical(this, tr("Error"), tr("Unable to delete %1: %2")
|
||||
@ -243,15 +252,15 @@ void OtherLogsPage::on_btnClean_clicked()
|
||||
return;
|
||||
}
|
||||
QMessageBox *messageBox = new QMessageBox(this);
|
||||
messageBox->setWindowTitle(tr("Clean up"));
|
||||
messageBox->setWindowTitle(tr("Confirm Cleanup"));
|
||||
if(toDelete.size() > 5)
|
||||
{
|
||||
messageBox->setText(tr("Do you really want to delete all log files?"));
|
||||
messageBox->setText(tr("Are you sure you want to delete all log files?"));
|
||||
messageBox->setDetailedText(toDelete.join('\n'));
|
||||
}
|
||||
else
|
||||
{
|
||||
messageBox->setText(tr("Do you really want to delete these files?\n%1").arg(toDelete.join('\n')));
|
||||
messageBox->setText(tr("Are you sure you want to delete all these files?\n%1").arg(toDelete.join('\n')));
|
||||
}
|
||||
messageBox->setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);
|
||||
messageBox->setDefaultButton(QMessageBox::Ok);
|
||||
@ -267,6 +276,10 @@ void OtherLogsPage::on_btnClean_clicked()
|
||||
for(auto item: toDelete)
|
||||
{
|
||||
QFile file(FS::PathCombine(m_path, item));
|
||||
if (FS::trash(file.fileName()))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (!file.remove())
|
||||
{
|
||||
failed.push_back(item);
|
||||
|
@ -48,9 +48,6 @@
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="verticalScrollBarPolicy">
|
||||
<enum>Qt::ScrollBarAlwaysOn</enum>
|
||||
</property>
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
|
102
launcher/ui/pages/instance/ResourcePackPage.cpp
Normal file
102
launcher/ui/pages/instance/ResourcePackPage.cpp
Normal file
@ -0,0 +1,102 @@
|
||||
// SPDX-FileCopyrightText: 2023 flowln <flowlnlnln@gmail.com>
|
||||
//
|
||||
// SPDX-License-Identifier: GPL-3.0-only AND Apache-2.0
|
||||
/*
|
||||
* Prism Launcher - Minecraft Launcher
|
||||
* Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* This file incorporates work covered by the following copyright and
|
||||
* permission notice:
|
||||
*
|
||||
* Copyright 2013-2021 MultiMC Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "ResourcePackPage.h"
|
||||
|
||||
#include "ResourceDownloadTask.h"
|
||||
|
||||
#include "ui/dialogs/CustomMessageBox.h"
|
||||
#include "ui/dialogs/ProgressDialog.h"
|
||||
#include "ui/dialogs/ResourceDownloadDialog.h"
|
||||
|
||||
ResourcePackPage::ResourcePackPage(MinecraftInstance* instance, std::shared_ptr<ResourcePackFolderModel> model, QWidget* parent)
|
||||
: ExternalResourcesPage(instance, model, parent)
|
||||
{
|
||||
ui->actionDownloadItem->setText(tr("Download packs"));
|
||||
ui->actionDownloadItem->setToolTip(tr("Download resource packs from online platforms"));
|
||||
ui->actionDownloadItem->setEnabled(true);
|
||||
connect(ui->actionDownloadItem, &QAction::triggered, this, &ResourcePackPage::downloadRPs);
|
||||
ui->actionsToolbar->insertActionBefore(ui->actionAddItem, ui->actionDownloadItem);
|
||||
|
||||
ui->actionViewConfigs->setVisible(false);
|
||||
}
|
||||
|
||||
bool ResourcePackPage::onSelectionChanged(const QModelIndex& current, const QModelIndex& previous)
|
||||
{
|
||||
auto sourceCurrent = m_filterModel->mapToSource(current);
|
||||
int row = sourceCurrent.row();
|
||||
auto& rp = static_cast<ResourcePack&>(m_model->at(row));
|
||||
ui->frame->updateWithResourcePack(rp);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ResourcePackPage::downloadRPs()
|
||||
{
|
||||
if (m_instance->typeName() != "Minecraft")
|
||||
return; // this is a null instance or a legacy instance
|
||||
|
||||
ResourceDownload::ResourcePackDownloadDialog mdownload(this, std::static_pointer_cast<ResourcePackFolderModel>(m_model), m_instance);
|
||||
if (mdownload.exec()) {
|
||||
auto tasks = new ConcurrentTask(this);
|
||||
connect(tasks, &Task::failed, [this, tasks](QString reason) {
|
||||
CustomMessageBox::selectable(this, tr("Error"), reason, QMessageBox::Critical)->show();
|
||||
tasks->deleteLater();
|
||||
});
|
||||
connect(tasks, &Task::aborted, [this, tasks]() {
|
||||
CustomMessageBox::selectable(this, tr("Aborted"), tr("Download stopped by user."), QMessageBox::Information)->show();
|
||||
tasks->deleteLater();
|
||||
});
|
||||
connect(tasks, &Task::succeeded, [this, tasks]() {
|
||||
QStringList warnings = tasks->warnings();
|
||||
if (warnings.count())
|
||||
CustomMessageBox::selectable(this, tr("Warnings"), warnings.join('\n'), QMessageBox::Warning)->show();
|
||||
|
||||
tasks->deleteLater();
|
||||
});
|
||||
|
||||
for (auto& task : mdownload.getTasks()) {
|
||||
tasks->addTask(task);
|
||||
}
|
||||
|
||||
ProgressDialog loadDialog(this);
|
||||
loadDialog.setSkipButton(true, tr("Abort"));
|
||||
loadDialog.execWithTask(tasks);
|
||||
|
||||
m_model->update();
|
||||
}
|
||||
}
|
@ -1,6 +1,8 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
// SPDX-FileCopyrightText: 2023 flowln <flowlnlnln@gmail.com>
|
||||
//
|
||||
// SPDX-License-Identifier: GPL-3.0-only AND Apache-2.0
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Prism Launcher - Minecraft Launcher
|
||||
* Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
@ -44,12 +46,7 @@ class ResourcePackPage : public ExternalResourcesPage
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ResourcePackPage(MinecraftInstance *instance, std::shared_ptr<ResourcePackFolderModel> model, QWidget *parent = 0)
|
||||
: ExternalResourcesPage(instance, model, parent)
|
||||
{
|
||||
ui->actionViewConfigs->setVisible(false);
|
||||
}
|
||||
virtual ~ResourcePackPage() {}
|
||||
explicit ResourcePackPage(MinecraftInstance *instance, std::shared_ptr<ResourcePackFolderModel> model, QWidget *parent = 0);
|
||||
|
||||
QString displayName() const override { return tr("Resource packs"); }
|
||||
QIcon icon() const override { return APPLICATION->getThemedIcon("resourcepacks"); }
|
||||
@ -63,13 +60,7 @@ public:
|
||||
}
|
||||
|
||||
public slots:
|
||||
bool onSelectionChanged(const QModelIndex& current, const QModelIndex& previous) override
|
||||
{
|
||||
auto sourceCurrent = m_filterModel->mapToSource(current);
|
||||
int row = sourceCurrent.row();
|
||||
auto& rp = static_cast<ResourcePack&>(m_model->at(row));
|
||||
ui->frame->updateWithResourcePack(rp);
|
||||
|
||||
return true;
|
||||
}
|
||||
bool onSelectionChanged(const QModelIndex& current, const QModelIndex& previous) override;
|
||||
void downloadRPs();
|
||||
};
|
||||
|
||||
|
@ -1,8 +1,9 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Prism Launcher - Minecraft Launcher
|
||||
* Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||
* Copyright (C) 2022 TheKodeToad <TheKodeToad@proton.me>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@ -35,6 +36,7 @@
|
||||
*/
|
||||
|
||||
#include "ScreenshotsPage.h"
|
||||
#include "BuildConfig.h"
|
||||
#include "ui_ScreenshotsPage.h"
|
||||
|
||||
#include <QModelIndex>
|
||||
@ -95,37 +97,30 @@ public:
|
||||
return;
|
||||
if ((info.suffix().compare("png", Qt::CaseInsensitive) != 0))
|
||||
return;
|
||||
int tries = 5;
|
||||
while (tries)
|
||||
{
|
||||
if (!m_cache->stale(m_path))
|
||||
return;
|
||||
QImage image(m_path);
|
||||
if (image.isNull())
|
||||
{
|
||||
QThread::msleep(500);
|
||||
tries--;
|
||||
continue;
|
||||
}
|
||||
QImage small;
|
||||
if (image.width() > image.height())
|
||||
small = image.scaledToWidth(512).scaledToWidth(256, Qt::SmoothTransformation);
|
||||
else
|
||||
small = image.scaledToHeight(512).scaledToHeight(256, Qt::SmoothTransformation);
|
||||
QPoint offset((256 - small.width()) / 2, (256 - small.height()) / 2);
|
||||
QImage square(QSize(256, 256), QImage::Format_ARGB32);
|
||||
square.fill(Qt::transparent);
|
||||
|
||||
QPainter painter(&square);
|
||||
painter.drawImage(offset, small);
|
||||
painter.end();
|
||||
|
||||
QIcon icon(QPixmap::fromImage(square));
|
||||
m_cache->add(m_path, icon);
|
||||
m_resultEmitter.emitResultsReady(m_path);
|
||||
if (!m_cache->stale(m_path))
|
||||
return;
|
||||
QImage image(m_path);
|
||||
if (image.isNull()) {
|
||||
m_resultEmitter.emitResultsFailed(m_path);
|
||||
qDebug() << "Error loading screenshot: " + m_path + ". Perhaps too large?";
|
||||
return;
|
||||
}
|
||||
m_resultEmitter.emitResultsFailed(m_path);
|
||||
QImage small;
|
||||
if (image.width() > image.height())
|
||||
small = image.scaledToWidth(512).scaledToWidth(256, Qt::SmoothTransformation);
|
||||
else
|
||||
small = image.scaledToHeight(512).scaledToHeight(256, Qt::SmoothTransformation);
|
||||
QPoint offset((256 - small.width()) / 2, (256 - small.height()) / 2);
|
||||
QImage square(QSize(256, 256), QImage::Format_ARGB32);
|
||||
square.fill(Qt::transparent);
|
||||
|
||||
QPainter painter(&square);
|
||||
painter.drawImage(offset, small);
|
||||
painter.end();
|
||||
|
||||
QIcon icon(QPixmap::fromImage(square));
|
||||
m_cache->add(m_path, icon);
|
||||
m_resultEmitter.emitResultsReady(m_path);
|
||||
}
|
||||
QString m_path;
|
||||
SharedIconCachePtr m_cache;
|
||||
@ -144,9 +139,12 @@ public:
|
||||
m_thumbnailCache = std::make_shared<SharedIconCache>();
|
||||
m_thumbnailCache->add("placeholder", APPLICATION->getThemedIcon("screenshot-placeholder"));
|
||||
connect(&watcher, SIGNAL(fileChanged(QString)), SLOT(fileChanged(QString)));
|
||||
// FIXME: the watched file set is not updated when files are removed
|
||||
}
|
||||
virtual ~FilterModel() { m_thumbnailingPool.waitForDone(500); }
|
||||
virtual ~FilterModel() {
|
||||
m_thumbnailingPool.clear();
|
||||
if (!m_thumbnailingPool.waitForDone(500))
|
||||
qDebug() << "Thumbnail pool took longer than 500ms to finish";
|
||||
}
|
||||
virtual QVariant data(const QModelIndex &proxyIndex, int role = Qt::DisplayRole) const
|
||||
{
|
||||
auto model = sourceModel();
|
||||
@ -213,10 +211,12 @@ private slots:
|
||||
void fileChanged(QString filepath)
|
||||
{
|
||||
m_thumbnailCache->setStale(filepath);
|
||||
thumbnailImage(filepath);
|
||||
// reinsert the path...
|
||||
watcher.removePath(filepath);
|
||||
watcher.addPath(filepath);
|
||||
if (QFile::exists(filepath)) {
|
||||
watcher.addPath(filepath);
|
||||
thumbnailImage(filepath);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
@ -379,6 +379,26 @@ void ScreenshotsPage::on_actionUpload_triggered()
|
||||
if (selection.isEmpty())
|
||||
return;
|
||||
|
||||
QString text;
|
||||
QUrl baseUrl(BuildConfig.IMGUR_BASE_URL);
|
||||
if (selection.size() > 1)
|
||||
text = tr("You are about to upload %1 screenshots to %2.\n"
|
||||
"You should double-check for personal information.\n\n"
|
||||
"Are you sure?")
|
||||
.arg(QString::number(selection.size()), baseUrl.host());
|
||||
else
|
||||
text = tr("You are about to upload the selected screenshot to %1.\n"
|
||||
"You should double-check for personal information.\n\n"
|
||||
"Are you sure?")
|
||||
.arg(baseUrl.host());
|
||||
|
||||
auto response = CustomMessageBox::selectable(this, "Confirm Upload", text, QMessageBox::Warning, QMessageBox::Yes | QMessageBox::No,
|
||||
QMessageBox::No)
|
||||
->exec();
|
||||
|
||||
if (response != QMessageBox::Yes)
|
||||
return;
|
||||
|
||||
QList<ScreenShot::Ptr> uploaded;
|
||||
auto job = NetJob::Ptr(new NetJob("Screenshot Upload", APPLICATION->network()));
|
||||
if(selection.size() < 2)
|
||||
@ -491,17 +511,32 @@ void ScreenshotsPage::on_actionCopy_File_s_triggered()
|
||||
|
||||
void ScreenshotsPage::on_actionDelete_triggered()
|
||||
{
|
||||
auto mbox = CustomMessageBox::selectable(
|
||||
this, tr("Are you sure?"), tr("This will delete all selected screenshots."),
|
||||
QMessageBox::Warning, QMessageBox::Yes | QMessageBox::No);
|
||||
std::unique_ptr<QMessageBox> box(mbox);
|
||||
auto selected = ui->listView->selectionModel()->selectedIndexes();
|
||||
|
||||
if (box->exec() != QMessageBox::Yes)
|
||||
int count = ui->listView->selectionModel()->selectedRows().size();
|
||||
QString text;
|
||||
if (count > 1)
|
||||
text = tr("You are about to delete %1 screenshots.\n"
|
||||
"This may be permanent and they will be gone from the folder.\n\n"
|
||||
"Are you sure?")
|
||||
.arg(count);
|
||||
else
|
||||
text = tr("You are about to delete the selected screenshot.\n"
|
||||
"This may be permanent and it will be gone from the folder.\n\n"
|
||||
"Are you sure?")
|
||||
.arg(count);
|
||||
|
||||
auto response =
|
||||
CustomMessageBox::selectable(this, tr("Confirm Deletion"), text, QMessageBox::Warning, QMessageBox::Yes | QMessageBox::No)->exec();
|
||||
|
||||
if (response != QMessageBox::Yes)
|
||||
return;
|
||||
|
||||
auto selected = ui->listView->selectionModel()->selectedIndexes();
|
||||
for (auto item : selected)
|
||||
{
|
||||
if (FS::trash(m_model->filePath(item)))
|
||||
continue;
|
||||
|
||||
m_model->remove(item);
|
||||
}
|
||||
}
|
||||
@ -537,6 +572,19 @@ void ScreenshotsPage::openedImpl()
|
||||
ui->listView->setModel(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
auto const setting_name = QString("WideBarVisibility_%1").arg(id());
|
||||
if (!APPLICATION->settings()->contains(setting_name))
|
||||
m_wide_bar_setting = APPLICATION->settings()->registerSetting(setting_name);
|
||||
else
|
||||
m_wide_bar_setting = APPLICATION->settings()->getSetting(setting_name);
|
||||
|
||||
ui->toolBar->setVisibilityState(m_wide_bar_setting->get().toByteArray());
|
||||
}
|
||||
|
||||
void ScreenshotsPage::closedImpl()
|
||||
{
|
||||
m_wide_bar_setting->set(ui->toolBar->getVisibilityState());
|
||||
}
|
||||
|
||||
#include "ScreenshotsPage.moc"
|
||||
|
@ -40,8 +40,11 @@
|
||||
#include "ui/pages/BasePage.h"
|
||||
#include <Application.h>
|
||||
|
||||
#include "settings/Setting.h"
|
||||
|
||||
class QFileSystemModel;
|
||||
class QIdentityProxyModel;
|
||||
class QItemSelection;
|
||||
namespace Ui
|
||||
{
|
||||
class ScreenshotsPage;
|
||||
@ -59,7 +62,8 @@ public:
|
||||
explicit ScreenshotsPage(QString path, QWidget *parent = 0);
|
||||
virtual ~ScreenshotsPage();
|
||||
|
||||
virtual void openedImpl() override;
|
||||
void openedImpl() override;
|
||||
void closedImpl() override;
|
||||
|
||||
enum
|
||||
{
|
||||
@ -110,4 +114,6 @@ private:
|
||||
QString m_folder;
|
||||
bool m_valid = false;
|
||||
bool m_uploadActive = false;
|
||||
|
||||
std::shared_ptr<Setting> m_wide_bar_setting = nullptr;
|
||||
};
|
||||
|
@ -1,8 +1,9 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Prism Launcher - Minecraft Launcher
|
||||
* Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||
* Copyright (C) 2022 TheKodeToad <TheKodeToad@proton.me>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@ -35,6 +36,7 @@
|
||||
*/
|
||||
|
||||
#include "ServersPage.h"
|
||||
#include "ui/dialogs/CustomMessageBox.h"
|
||||
#include "ui_ServersPage.h"
|
||||
|
||||
#include <FileSystem.h>
|
||||
@ -48,6 +50,7 @@
|
||||
|
||||
#include <QFileSystemWatcher>
|
||||
#include <QMenu>
|
||||
#include <QTimer>
|
||||
|
||||
static const int COLUMN_COUNT = 2; // 3 , TBD: latency and other nice things.
|
||||
|
||||
@ -400,11 +403,11 @@ public:
|
||||
|
||||
virtual int rowCount(const QModelIndex &parent = QModelIndex()) const override
|
||||
{
|
||||
return m_servers.size();
|
||||
return parent.isValid() ? 0 : m_servers.size();
|
||||
}
|
||||
int columnCount(const QModelIndex & parent) const override
|
||||
{
|
||||
return COLUMN_COUNT;
|
||||
return parent.isValid() ? 0 : COLUMN_COUNT;
|
||||
}
|
||||
|
||||
Server * at(int index)
|
||||
@ -765,11 +768,21 @@ void ServersPage::updateState()
|
||||
void ServersPage::openedImpl()
|
||||
{
|
||||
m_model->observe();
|
||||
|
||||
auto const setting_name = QString("WideBarVisibility_%1").arg(id());
|
||||
if (!APPLICATION->settings()->contains(setting_name))
|
||||
m_wide_bar_setting = APPLICATION->settings()->registerSetting(setting_name);
|
||||
else
|
||||
m_wide_bar_setting = APPLICATION->settings()->getSetting(setting_name);
|
||||
|
||||
ui->toolBar->setVisibilityState(m_wide_bar_setting->get().toByteArray());
|
||||
}
|
||||
|
||||
void ServersPage::closedImpl()
|
||||
{
|
||||
m_model->unobserve();
|
||||
|
||||
m_wide_bar_setting->set(ui->toolBar->getVisibilityState());
|
||||
}
|
||||
|
||||
void ServersPage::on_actionAdd_triggered()
|
||||
@ -789,6 +802,17 @@ void ServersPage::on_actionAdd_triggered()
|
||||
|
||||
void ServersPage::on_actionRemove_triggered()
|
||||
{
|
||||
auto response = CustomMessageBox::selectable(this, tr("Confirm Removal"),
|
||||
tr("You are about to remove \"%1\".\n"
|
||||
"This is permanent and the server will be gone from your list forever (A LONG TIME).\n\n"
|
||||
"Are you sure?")
|
||||
.arg(m_model->at(currentServer)->m_name),
|
||||
QMessageBox::Warning, QMessageBox::Yes | QMessageBox::No, QMessageBox::No)
|
||||
->exec();
|
||||
|
||||
if (response != QMessageBox::Yes)
|
||||
return;
|
||||
|
||||
m_model->removeRow(currentServer);
|
||||
}
|
||||
|
||||
|
@ -42,6 +42,8 @@
|
||||
#include "ui/pages/BasePage.h"
|
||||
#include <Application.h>
|
||||
|
||||
#include "settings/Setting.h"
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class ServersPage;
|
||||
@ -68,7 +70,7 @@ public:
|
||||
}
|
||||
virtual QIcon icon() const override
|
||||
{
|
||||
return APPLICATION->getThemedIcon("unknown_server");
|
||||
return APPLICATION->getThemedIcon("server");
|
||||
}
|
||||
virtual QString id() const override
|
||||
{
|
||||
@ -112,5 +114,7 @@ private: // data
|
||||
Ui::ServersPage *ui = nullptr;
|
||||
ServersModel * m_model = nullptr;
|
||||
InstancePtr m_inst = nullptr;
|
||||
|
||||
std::shared_ptr<Setting> m_wide_bar_setting = nullptr;
|
||||
};
|
||||
|
||||
|
95
launcher/ui/pages/instance/ShaderPackPage.cpp
Normal file
95
launcher/ui/pages/instance/ShaderPackPage.cpp
Normal file
@ -0,0 +1,95 @@
|
||||
// SPDX-FileCopyrightText: 2023 flowln <flowlnlnln@gmail.com>
|
||||
//
|
||||
// SPDX-License-Identifier: GPL-3.0-only AND Apache-2.0
|
||||
/*
|
||||
* Prism Launcher - Minecraft Launcher
|
||||
* Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* This file incorporates work covered by the following copyright and
|
||||
* permission notice:
|
||||
*
|
||||
* Copyright 2013-2021 MultiMC Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "ShaderPackPage.h"
|
||||
#include "ui_ExternalResourcesPage.h"
|
||||
|
||||
#include "ResourceDownloadTask.h"
|
||||
|
||||
#include "minecraft/mod/ShaderPackFolderModel.h"
|
||||
|
||||
#include "ui/dialogs/CustomMessageBox.h"
|
||||
#include "ui/dialogs/ProgressDialog.h"
|
||||
#include "ui/dialogs/ResourceDownloadDialog.h"
|
||||
|
||||
ShaderPackPage::ShaderPackPage(MinecraftInstance* instance, std::shared_ptr<ShaderPackFolderModel> model, QWidget* parent)
|
||||
: ExternalResourcesPage(instance, model, parent)
|
||||
{
|
||||
ui->actionDownloadItem->setText(tr("Download shaders"));
|
||||
ui->actionDownloadItem->setToolTip(tr("Download shaders from online platforms"));
|
||||
ui->actionDownloadItem->setEnabled(true);
|
||||
connect(ui->actionDownloadItem, &QAction::triggered, this, &ShaderPackPage::downloadShaders);
|
||||
ui->actionsToolbar->insertActionBefore(ui->actionAddItem, ui->actionDownloadItem);
|
||||
|
||||
ui->actionViewConfigs->setVisible(false);
|
||||
}
|
||||
|
||||
void ShaderPackPage::downloadShaders()
|
||||
{
|
||||
if (m_instance->typeName() != "Minecraft")
|
||||
return; // this is a null instance or a legacy instance
|
||||
|
||||
ResourceDownload::ShaderPackDownloadDialog mdownload(this, std::static_pointer_cast<ShaderPackFolderModel>(m_model), m_instance);
|
||||
if (mdownload.exec()) {
|
||||
auto tasks = new ConcurrentTask(this);
|
||||
connect(tasks, &Task::failed, [this, tasks](QString reason) {
|
||||
CustomMessageBox::selectable(this, tr("Error"), reason, QMessageBox::Critical)->show();
|
||||
tasks->deleteLater();
|
||||
});
|
||||
connect(tasks, &Task::aborted, [this, tasks]() {
|
||||
CustomMessageBox::selectable(this, tr("Aborted"), tr("Download stopped by user."), QMessageBox::Information)->show();
|
||||
tasks->deleteLater();
|
||||
});
|
||||
connect(tasks, &Task::succeeded, [this, tasks]() {
|
||||
QStringList warnings = tasks->warnings();
|
||||
if (warnings.count())
|
||||
CustomMessageBox::selectable(this, tr("Warnings"), warnings.join('\n'), QMessageBox::Warning)->show();
|
||||
|
||||
tasks->deleteLater();
|
||||
});
|
||||
|
||||
for (auto& task : mdownload.getTasks()) {
|
||||
tasks->addTask(task);
|
||||
}
|
||||
|
||||
ProgressDialog loadDialog(this);
|
||||
loadDialog.setSkipButton(true, tr("Abort"));
|
||||
loadDialog.execWithTask(tasks);
|
||||
|
||||
m_model->update();
|
||||
}
|
||||
}
|
@ -1,6 +1,8 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
// SPDX-FileCopyrightText: 2023 flowln <flowlnlnln@gmail.com>
|
||||
//
|
||||
// SPDX-License-Identifier: GPL-3.0-only AND Apache-2.0
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Prism Launcher - Minecraft Launcher
|
||||
* Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
@ -36,28 +38,21 @@
|
||||
#pragma once
|
||||
|
||||
#include "ExternalResourcesPage.h"
|
||||
#include "ui_ExternalResourcesPage.h"
|
||||
|
||||
#include "minecraft/mod/ShaderPackFolderModel.h"
|
||||
|
||||
class ShaderPackPage : public ExternalResourcesPage
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ShaderPackPage(MinecraftInstance *instance, std::shared_ptr<ShaderPackFolderModel> model, QWidget *parent = 0)
|
||||
: ExternalResourcesPage(instance, model, parent)
|
||||
{
|
||||
ui->actionViewConfigs->setVisible(false);
|
||||
}
|
||||
virtual ~ShaderPackPage() {}
|
||||
explicit ShaderPackPage(MinecraftInstance *instance, std::shared_ptr<ShaderPackFolderModel> model, QWidget *parent = nullptr);
|
||||
~ShaderPackPage() override = default;
|
||||
|
||||
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;
|
||||
}
|
||||
bool shouldDisplay() const override { return true; }
|
||||
|
||||
public slots:
|
||||
void downloadShaders();
|
||||
};
|
||||
|
104
launcher/ui/pages/instance/TexturePackPage.cpp
Normal file
104
launcher/ui/pages/instance/TexturePackPage.cpp
Normal file
@ -0,0 +1,104 @@
|
||||
// SPDX-FileCopyrightText: 2023 flowln <flowlnlnln@gmail.com>
|
||||
//
|
||||
// SPDX-License-Identifier: GPL-3.0-only AND Apache-2.0
|
||||
/*
|
||||
* Prism Launcher - Minecraft Launcher
|
||||
* Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* This file incorporates work covered by the following copyright and
|
||||
* permission notice:
|
||||
*
|
||||
* Copyright 2013-2021 MultiMC Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "TexturePackPage.h"
|
||||
|
||||
#include "ResourceDownloadTask.h"
|
||||
|
||||
#include "minecraft/mod/TexturePack.h"
|
||||
|
||||
#include "ui/dialogs/CustomMessageBox.h"
|
||||
#include "ui/dialogs/ProgressDialog.h"
|
||||
#include "ui/dialogs/ResourceDownloadDialog.h"
|
||||
|
||||
TexturePackPage::TexturePackPage(MinecraftInstance* instance, std::shared_ptr<TexturePackFolderModel> model, QWidget* parent)
|
||||
: ExternalResourcesPage(instance, model, parent)
|
||||
{
|
||||
ui->actionDownloadItem->setText(tr("Download packs"));
|
||||
ui->actionDownloadItem->setToolTip(tr("Download texture packs from online platforms"));
|
||||
ui->actionDownloadItem->setEnabled(true);
|
||||
connect(ui->actionDownloadItem, &QAction::triggered, this, &TexturePackPage::downloadTPs);
|
||||
ui->actionsToolbar->insertActionBefore(ui->actionAddItem, ui->actionDownloadItem);
|
||||
|
||||
ui->actionViewConfigs->setVisible(false);
|
||||
}
|
||||
|
||||
bool TexturePackPage::onSelectionChanged(const QModelIndex& current, const QModelIndex& previous)
|
||||
{
|
||||
auto sourceCurrent = m_filterModel->mapToSource(current);
|
||||
int row = sourceCurrent.row();
|
||||
auto& rp = static_cast<TexturePack&>(m_model->at(row));
|
||||
ui->frame->updateWithTexturePack(rp);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void TexturePackPage::downloadTPs()
|
||||
{
|
||||
if (m_instance->typeName() != "Minecraft")
|
||||
return; // this is a null instance or a legacy instance
|
||||
|
||||
ResourceDownload::TexturePackDownloadDialog mdownload(this, std::static_pointer_cast<TexturePackFolderModel>(m_model), m_instance);
|
||||
if (mdownload.exec()) {
|
||||
auto tasks = new ConcurrentTask(this);
|
||||
connect(tasks, &Task::failed, [this, tasks](QString reason) {
|
||||
CustomMessageBox::selectable(this, tr("Error"), reason, QMessageBox::Critical)->show();
|
||||
tasks->deleteLater();
|
||||
});
|
||||
connect(tasks, &Task::aborted, [this, tasks]() {
|
||||
CustomMessageBox::selectable(this, tr("Aborted"), tr("Download stopped by user."), QMessageBox::Information)->show();
|
||||
tasks->deleteLater();
|
||||
});
|
||||
connect(tasks, &Task::succeeded, [this, tasks]() {
|
||||
QStringList warnings = tasks->warnings();
|
||||
if (warnings.count())
|
||||
CustomMessageBox::selectable(this, tr("Warnings"), warnings.join('\n'), QMessageBox::Warning)->show();
|
||||
|
||||
tasks->deleteLater();
|
||||
});
|
||||
|
||||
for (auto& task : mdownload.getTasks()) {
|
||||
tasks->addTask(task);
|
||||
}
|
||||
|
||||
ProgressDialog loadDialog(this);
|
||||
loadDialog.setSkipButton(true, tr("Abort"));
|
||||
loadDialog.execWithTask(tasks);
|
||||
|
||||
m_model->update();
|
||||
}
|
||||
}
|
@ -1,6 +1,8 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
// SPDX-FileCopyrightText: 2023 flowln <flowlnlnln@gmail.com>
|
||||
//
|
||||
// SPDX-License-Identifier: GPL-3.0-only AND Apache-2.0
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Prism Launcher - Minecraft Launcher
|
||||
* Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
@ -39,18 +41,12 @@
|
||||
#include "ui_ExternalResourcesPage.h"
|
||||
|
||||
#include "minecraft/mod/TexturePackFolderModel.h"
|
||||
#include "minecraft/mod/TexturePack.h"
|
||||
|
||||
class TexturePackPage : public ExternalResourcesPage
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit TexturePackPage(MinecraftInstance *instance, std::shared_ptr<TexturePackFolderModel> model, QWidget *parent = 0)
|
||||
: ExternalResourcesPage(instance, model, parent)
|
||||
{
|
||||
ui->actionViewConfigs->setVisible(false);
|
||||
}
|
||||
virtual ~TexturePackPage() {}
|
||||
explicit TexturePackPage(MinecraftInstance *instance, std::shared_ptr<TexturePackFolderModel> model, QWidget* parent = nullptr);
|
||||
|
||||
QString displayName() const override { return tr("Texture packs"); }
|
||||
QIcon icon() const override { return APPLICATION->getThemedIcon("resourcepacks"); }
|
||||
@ -63,13 +59,6 @@ public:
|
||||
}
|
||||
|
||||
public slots:
|
||||
bool onSelectionChanged(const QModelIndex& current, const QModelIndex& previous) override
|
||||
{
|
||||
auto sourceCurrent = m_filterModel->mapToSource(current);
|
||||
int row = sourceCurrent.row();
|
||||
auto& rp = static_cast<TexturePack&>(m_model->at(row));
|
||||
ui->frame->updateWithTexturePack(rp);
|
||||
|
||||
return true;
|
||||
}
|
||||
bool onSelectionChanged(const QModelIndex& current, const QModelIndex& previous) override;
|
||||
void downloadTPs();
|
||||
};
|
||||
|
@ -1,8 +1,12 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
// SPDX-FileCopyrightText: 2022-2023 Sefa Eyeoglu <contact@scrumplex.net>
|
||||
//
|
||||
// SPDX-License-Identifier: GPL-3.0-only AND Apache-2.0
|
||||
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Prism Launcher - Minecraft Launcher
|
||||
* Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||
* Copyright (C) 2022-2023 Sefa Eyeoglu <contact@scrumplex.net>
|
||||
* Copyright (C) 2022 TheKodeToad <TheKodeToad@proton.me>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@ -36,14 +40,13 @@
|
||||
|
||||
#include "Application.h"
|
||||
|
||||
#include <QMessageBox>
|
||||
#include <QLabel>
|
||||
#include <QAbstractItemModel>
|
||||
#include <QEvent>
|
||||
#include <QKeyEvent>
|
||||
#include <QMenu>
|
||||
#include <QAbstractItemModel>
|
||||
#include <QMessageBox>
|
||||
#include <QLabel>
|
||||
#include <QListView>
|
||||
#include <QMenu>
|
||||
#include <QMessageBox>
|
||||
#include <QString>
|
||||
#include <QUrl>
|
||||
|
||||
@ -51,49 +54,42 @@
|
||||
#include "ui_VersionPage.h"
|
||||
|
||||
#include "ui/dialogs/CustomMessageBox.h"
|
||||
#include "ui/dialogs/VersionSelectDialog.h"
|
||||
#include "ui/dialogs/NewComponentDialog.h"
|
||||
#include "ui/dialogs/ProgressDialog.h"
|
||||
#include "ui/dialogs/VersionSelectDialog.h"
|
||||
|
||||
#include "ui/GuiUtil.h"
|
||||
|
||||
#include "DesktopServices.h"
|
||||
#include "Exception.h"
|
||||
#include "Version.h"
|
||||
#include "icons/IconList.h"
|
||||
#include "minecraft/PackProfile.h"
|
||||
#include "minecraft/auth/AccountList.h"
|
||||
#include "minecraft/mod/Mod.h"
|
||||
#include "icons/IconList.h"
|
||||
#include "Exception.h"
|
||||
#include "Version.h"
|
||||
#include "DesktopServices.h"
|
||||
|
||||
#include "meta/Index.h"
|
||||
#include "meta/VersionList.h"
|
||||
|
||||
class IconProxy : public QIdentityProxyModel
|
||||
{
|
||||
class IconProxy : public QIdentityProxyModel {
|
||||
Q_OBJECT
|
||||
public:
|
||||
|
||||
IconProxy(QWidget *parentWidget) : QIdentityProxyModel(parentWidget)
|
||||
public:
|
||||
IconProxy(QWidget* parentWidget) : QIdentityProxyModel(parentWidget)
|
||||
{
|
||||
connect(parentWidget, &QObject::destroyed, this, &IconProxy::widgetGone);
|
||||
m_parentWidget = parentWidget;
|
||||
}
|
||||
|
||||
virtual QVariant data(const QModelIndex &proxyIndex, int role = Qt::DisplayRole) const override
|
||||
virtual QVariant data(const QModelIndex& proxyIndex, int role = Qt::DisplayRole) const override
|
||||
{
|
||||
QVariant var = QIdentityProxyModel::data(proxyIndex, role);
|
||||
int column = proxyIndex.column();
|
||||
if(column == 0 && role == Qt::DecorationRole && m_parentWidget)
|
||||
{
|
||||
if(!var.isNull())
|
||||
{
|
||||
if (column == 0 && role == Qt::DecorationRole && m_parentWidget) {
|
||||
if (!var.isNull()) {
|
||||
auto string = var.toString();
|
||||
if(string == "warning")
|
||||
{
|
||||
if (string == "warning") {
|
||||
return APPLICATION->getThemedIcon("status-yellow");
|
||||
}
|
||||
else if(string == "error")
|
||||
{
|
||||
} else if (string == "error") {
|
||||
return APPLICATION->getThemedIcon("status-bad");
|
||||
}
|
||||
}
|
||||
@ -101,14 +97,11 @@ public:
|
||||
}
|
||||
return var;
|
||||
}
|
||||
private slots:
|
||||
void widgetGone()
|
||||
{
|
||||
m_parentWidget = nullptr;
|
||||
}
|
||||
private slots:
|
||||
void widgetGone() { m_parentWidget = nullptr; }
|
||||
|
||||
private:
|
||||
QWidget *m_parentWidget = nullptr;
|
||||
private:
|
||||
QWidget* m_parentWidget = nullptr;
|
||||
};
|
||||
|
||||
QIcon VersionPage::icon() const
|
||||
@ -125,15 +118,29 @@ void VersionPage::retranslate()
|
||||
ui->retranslateUi(this);
|
||||
}
|
||||
|
||||
QMenu * VersionPage::createPopupMenu()
|
||||
void VersionPage::openedImpl()
|
||||
{
|
||||
auto const setting_name = QString("WideBarVisibility_%1").arg(id());
|
||||
if (!APPLICATION->settings()->contains(setting_name))
|
||||
m_wide_bar_setting = APPLICATION->settings()->registerSetting(setting_name);
|
||||
else
|
||||
m_wide_bar_setting = APPLICATION->settings()->getSetting(setting_name);
|
||||
|
||||
ui->toolBar->setVisibilityState(m_wide_bar_setting->get().toByteArray());
|
||||
}
|
||||
void VersionPage::closedImpl()
|
||||
{
|
||||
m_wide_bar_setting->set(ui->toolBar->getVisibilityState());
|
||||
}
|
||||
|
||||
QMenu* VersionPage::createPopupMenu()
|
||||
{
|
||||
QMenu* filteredMenu = QMainWindow::createPopupMenu();
|
||||
filteredMenu->removeAction( ui->toolBar->toggleViewAction() );
|
||||
filteredMenu->removeAction(ui->toolBar->toggleViewAction());
|
||||
return filteredMenu;
|
||||
}
|
||||
|
||||
VersionPage::VersionPage(MinecraftInstance *inst, QWidget *parent)
|
||||
: QMainWindow(parent), ui(new Ui::VersionPage), m_inst(inst)
|
||||
VersionPage::VersionPage(MinecraftInstance* inst, QWidget* parent) : QMainWindow(parent), ui(new Ui::VersionPage), m_inst(inst)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
@ -146,7 +153,7 @@ VersionPage::VersionPage(MinecraftInstance *inst, QWidget *parent)
|
||||
auto proxy = new IconProxy(ui->packageView);
|
||||
proxy->setSourceModel(m_profile.get());
|
||||
|
||||
m_filterModel = new QSortFilterProxyModel();
|
||||
m_filterModel = new QSortFilterProxyModel(this);
|
||||
m_filterModel->setDynamicSortFilter(true);
|
||||
m_filterModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
|
||||
m_filterModel->setSortCaseSensitivity(Qt::CaseInsensitive);
|
||||
@ -163,10 +170,8 @@ VersionPage::VersionPage(MinecraftInstance *inst, QWidget *parent)
|
||||
connect(smodel, &QItemSelectionModel::currentChanged, this, &VersionPage::packageCurrent);
|
||||
|
||||
connect(m_profile.get(), &PackProfile::minecraftChanged, this, &VersionPage::updateVersionControls);
|
||||
controlsEnabled = !m_inst->isRunning();
|
||||
updateVersionControls();
|
||||
preselect(0);
|
||||
connect(m_inst, &BaseInstance::runningStatusChanged, this, &VersionPage::updateRunningStatus);
|
||||
connect(ui->packageView, &ModListView::customContextMenuRequested, this, &VersionPage::showContextMenu);
|
||||
connect(ui->filterEdit, &QLineEdit::textChanged, this, &VersionPage::onFilterTextChanged);
|
||||
}
|
||||
@ -183,18 +188,16 @@ void VersionPage::showContextMenu(const QPoint& pos)
|
||||
delete menu;
|
||||
}
|
||||
|
||||
void VersionPage::packageCurrent(const QModelIndex ¤t, const QModelIndex &previous)
|
||||
void VersionPage::packageCurrent(const QModelIndex& current, const QModelIndex& previous)
|
||||
{
|
||||
if (!current.isValid())
|
||||
{
|
||||
if (!current.isValid()) {
|
||||
ui->frame->clear();
|
||||
return;
|
||||
}
|
||||
int row = current.row();
|
||||
auto patch = m_profile->getComponent(row);
|
||||
auto severity = patch->getProblemSeverity();
|
||||
switch(severity)
|
||||
{
|
||||
switch (severity) {
|
||||
case ProblemSeverity::Warning:
|
||||
ui->frame->setName(tr("%1 possibly has issues.").arg(patch->getName()));
|
||||
break;
|
||||
@ -207,16 +210,12 @@ void VersionPage::packageCurrent(const QModelIndex ¤t, const QModelIndex &
|
||||
return;
|
||||
}
|
||||
|
||||
auto &problems = patch->getProblems();
|
||||
auto& problems = patch->getProblems();
|
||||
QString problemOut;
|
||||
for (auto &problem: problems)
|
||||
{
|
||||
if(problem.m_severity == ProblemSeverity::Error)
|
||||
{
|
||||
for (auto& problem : problems) {
|
||||
if (problem.m_severity == ProblemSeverity::Error) {
|
||||
problemOut += tr("Error: ");
|
||||
}
|
||||
else if(problem.m_severity == ProblemSeverity::Warning)
|
||||
{
|
||||
} else if (problem.m_severity == ProblemSeverity::Warning) {
|
||||
problemOut += tr("Warning: ");
|
||||
}
|
||||
problemOut += problem.m_description;
|
||||
@ -225,70 +224,47 @@ void VersionPage::packageCurrent(const QModelIndex ¤t, const QModelIndex &
|
||||
ui->frame->setDescription(problemOut);
|
||||
}
|
||||
|
||||
void VersionPage::updateRunningStatus(bool running)
|
||||
{
|
||||
if(controlsEnabled == running) {
|
||||
controlsEnabled = !running;
|
||||
updateVersionControls();
|
||||
}
|
||||
}
|
||||
|
||||
void VersionPage::updateVersionControls()
|
||||
{
|
||||
// FIXME: this is a dirty hack
|
||||
auto minecraftVersion = Version(m_profile->getComponentVersion("net.minecraft"));
|
||||
|
||||
ui->actionInstall_Forge->setEnabled(controlsEnabled);
|
||||
|
||||
bool supportsFabric = minecraftVersion >= Version("1.14");
|
||||
ui->actionInstall_Fabric->setEnabled(controlsEnabled && supportsFabric);
|
||||
ui->actionInstall_Fabric->setEnabled(supportsFabric);
|
||||
|
||||
bool supportsQuilt = minecraftVersion >= Version("1.14");
|
||||
ui->actionInstall_Quilt->setEnabled(controlsEnabled && supportsQuilt);
|
||||
ui->actionInstall_Quilt->setEnabled(supportsQuilt);
|
||||
|
||||
bool supportsLiteLoader = minecraftVersion <= Version("1.12.2");
|
||||
ui->actionInstall_LiteLoader->setEnabled(controlsEnabled && supportsLiteLoader);
|
||||
ui->actionInstall_LiteLoader->setEnabled(supportsLiteLoader);
|
||||
|
||||
updateButtons();
|
||||
}
|
||||
|
||||
void VersionPage::updateButtons(int row)
|
||||
{
|
||||
if(row == -1)
|
||||
if (row == -1)
|
||||
row = currentRow();
|
||||
auto patch = m_profile->getComponent(row);
|
||||
ui->actionRemove->setEnabled(controlsEnabled && patch && patch->isRemovable());
|
||||
ui->actionMove_down->setEnabled(controlsEnabled && patch && patch->isMoveable());
|
||||
ui->actionMove_up->setEnabled(controlsEnabled && patch && patch->isMoveable());
|
||||
ui->actionChange_version->setEnabled(controlsEnabled && patch && patch->isVersionChangeable());
|
||||
ui->actionEdit->setEnabled(controlsEnabled && patch && patch->isCustom());
|
||||
ui->actionCustomize->setEnabled(controlsEnabled && patch && patch->isCustomizable());
|
||||
ui->actionRevert->setEnabled(controlsEnabled && patch && patch->isRevertible());
|
||||
ui->actionDownload_All->setEnabled(controlsEnabled);
|
||||
ui->actionAdd_Empty->setEnabled(controlsEnabled);
|
||||
ui->actionReload->setEnabled(controlsEnabled);
|
||||
ui->actionInstall_mods->setEnabled(controlsEnabled);
|
||||
ui->actionReplace_Minecraft_jar->setEnabled(controlsEnabled);
|
||||
ui->actionAdd_to_Minecraft_jar->setEnabled(controlsEnabled);
|
||||
ui->actionRemove->setEnabled(patch && patch->isRemovable());
|
||||
ui->actionMove_down->setEnabled(patch && patch->isMoveable());
|
||||
ui->actionMove_up->setEnabled(patch && patch->isMoveable());
|
||||
ui->actionChange_version->setEnabled(patch && patch->isVersionChangeable());
|
||||
ui->actionEdit->setEnabled(patch && patch->isCustom());
|
||||
ui->actionCustomize->setEnabled(patch && patch->isCustomizable());
|
||||
ui->actionRevert->setEnabled(patch && patch->isRevertible());
|
||||
}
|
||||
|
||||
bool VersionPage::reloadPackProfile()
|
||||
{
|
||||
try
|
||||
{
|
||||
try {
|
||||
m_profile->reload(Net::Mode::Online);
|
||||
return true;
|
||||
}
|
||||
catch (const Exception &e)
|
||||
{
|
||||
} catch (const Exception& e) {
|
||||
QMessageBox::critical(this, tr("Error"), e.cause());
|
||||
return false;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
QMessageBox::critical(
|
||||
this, tr("Error"),
|
||||
tr("Couldn't load the instance profile."));
|
||||
} catch (...) {
|
||||
QMessageBox::critical(this, tr("Error"), tr("Couldn't load the instance profile."));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -301,13 +277,26 @@ void VersionPage::on_actionReload_triggered()
|
||||
|
||||
void VersionPage::on_actionRemove_triggered()
|
||||
{
|
||||
if (ui->packageView->currentIndex().isValid())
|
||||
{
|
||||
// FIXME: use actual model, not reloading.
|
||||
if (!m_profile->remove(ui->packageView->currentIndex().row()))
|
||||
{
|
||||
QMessageBox::critical(this, tr("Error"), tr("Couldn't remove file"));
|
||||
}
|
||||
if (!ui->packageView->currentIndex().isValid()) {
|
||||
return;
|
||||
}
|
||||
int index = ui->packageView->currentIndex().row();
|
||||
auto component = m_profile->getComponent(index);
|
||||
if (component->isCustom()) {
|
||||
auto response = CustomMessageBox::selectable(this, tr("Confirm Removal"),
|
||||
tr("You are about to remove \"%1\".\n"
|
||||
"This is permanent and will completely remove the custom component.\n\n"
|
||||
"Are you sure?")
|
||||
.arg(component->getName()),
|
||||
QMessageBox::Warning, QMessageBox::Yes | QMessageBox::No, QMessageBox::No)
|
||||
->exec();
|
||||
|
||||
if (response != QMessageBox::Yes)
|
||||
return;
|
||||
}
|
||||
// FIXME: use actual model, not reloading.
|
||||
if (!m_profile->remove(index)) {
|
||||
QMessageBox::critical(this, tr("Error"), tr("Couldn't remove file"));
|
||||
}
|
||||
updateButtons();
|
||||
reloadPackProfile();
|
||||
@ -316,17 +305,16 @@ void VersionPage::on_actionRemove_triggered()
|
||||
|
||||
void VersionPage::on_actionInstall_mods_triggered()
|
||||
{
|
||||
if(m_container)
|
||||
{
|
||||
if (m_container) {
|
||||
m_container->selectPage("mods");
|
||||
}
|
||||
}
|
||||
|
||||
void VersionPage::on_actionAdd_to_Minecraft_jar_triggered()
|
||||
{
|
||||
auto list = GuiUtil::BrowseForFiles("jarmod", tr("Select jar mods"), tr("Minecraft.jar mods (*.zip *.jar)"), APPLICATION->settings()->get("CentralModsDir").toString(), this->parentWidget());
|
||||
if(!list.empty())
|
||||
{
|
||||
auto list = GuiUtil::BrowseForFiles("jarmod", tr("Select jar mods"), tr("Minecraft.jar mods (*.zip *.jar)"),
|
||||
APPLICATION->settings()->get("CentralModsDir").toString(), this->parentWidget());
|
||||
if (!list.empty()) {
|
||||
m_profile->installJarMods(list);
|
||||
}
|
||||
updateButtons();
|
||||
@ -334,22 +322,45 @@ void VersionPage::on_actionAdd_to_Minecraft_jar_triggered()
|
||||
|
||||
void VersionPage::on_actionReplace_Minecraft_jar_triggered()
|
||||
{
|
||||
auto jarPath = GuiUtil::BrowseForFile("jar", tr("Select jar"), tr("Minecraft.jar replacement (*.jar)"), APPLICATION->settings()->get("CentralModsDir").toString(), this->parentWidget());
|
||||
if(!jarPath.isEmpty())
|
||||
{
|
||||
auto jarPath = GuiUtil::BrowseForFile("jar", tr("Select jar"), tr("Minecraft.jar replacement (*.jar)"),
|
||||
APPLICATION->settings()->get("CentralModsDir").toString(), this->parentWidget());
|
||||
if (!jarPath.isEmpty()) {
|
||||
m_profile->installCustomJar(jarPath);
|
||||
}
|
||||
updateButtons();
|
||||
}
|
||||
|
||||
void VersionPage::on_actionImport_Components_triggered()
|
||||
{
|
||||
QStringList list = GuiUtil::BrowseForFiles("component", tr("Select components"), tr("Components (*.json)"),
|
||||
APPLICATION->settings()->get("CentralModsDir").toString(), this->parentWidget());
|
||||
|
||||
if (!list.isEmpty()) {
|
||||
if (!m_profile->installComponents(list)) {
|
||||
QMessageBox::warning(this, tr("Failed to import components"),
|
||||
tr("Some components could not be imported. Check logs for details"));
|
||||
}
|
||||
}
|
||||
|
||||
updateButtons();
|
||||
}
|
||||
|
||||
void VersionPage::on_actionAdd_Agents_triggered()
|
||||
{
|
||||
QStringList list = GuiUtil::BrowseForFiles("agent", tr("Select agents"), tr("Java agents (*.jar)"),
|
||||
APPLICATION->settings()->get("CentralModsDir").toString(), this->parentWidget());
|
||||
|
||||
if (!list.isEmpty())
|
||||
m_profile->installAgents(list);
|
||||
|
||||
updateButtons();
|
||||
}
|
||||
|
||||
void VersionPage::on_actionMove_up_triggered()
|
||||
{
|
||||
try
|
||||
{
|
||||
try {
|
||||
m_profile->move(currentRow(), PackProfile::MoveUp);
|
||||
}
|
||||
catch (const Exception &e)
|
||||
{
|
||||
} catch (const Exception& e) {
|
||||
QMessageBox::critical(this, tr("Error"), e.cause());
|
||||
}
|
||||
updateButtons();
|
||||
@ -357,12 +368,9 @@ void VersionPage::on_actionMove_up_triggered()
|
||||
|
||||
void VersionPage::on_actionMove_down_triggered()
|
||||
{
|
||||
try
|
||||
{
|
||||
try {
|
||||
m_profile->move(currentRow(), PackProfile::MoveDown);
|
||||
}
|
||||
catch (const Exception &e)
|
||||
{
|
||||
} catch (const Exception& e) {
|
||||
QMessageBox::critical(this, tr("Error"), e.cause());
|
||||
}
|
||||
updateButtons();
|
||||
@ -371,39 +379,32 @@ void VersionPage::on_actionMove_down_triggered()
|
||||
void VersionPage::on_actionChange_version_triggered()
|
||||
{
|
||||
auto versionRow = currentRow();
|
||||
if(versionRow == -1)
|
||||
{
|
||||
if (versionRow == -1) {
|
||||
return;
|
||||
}
|
||||
auto patch = m_profile->getComponent(versionRow);
|
||||
auto name = patch->getName();
|
||||
auto list = patch->getVersionList();
|
||||
if(!list)
|
||||
{
|
||||
if (!list) {
|
||||
return;
|
||||
}
|
||||
auto uid = list->uid();
|
||||
// FIXME: this is a horrible HACK. Get version filtering information from the actual metadata...
|
||||
if(uid == "net.minecraftforge")
|
||||
{
|
||||
if (uid == "net.minecraftforge") {
|
||||
on_actionInstall_Forge_triggered();
|
||||
return;
|
||||
}
|
||||
else if (uid == "com.mumfrey.liteloader")
|
||||
{
|
||||
} else if (uid == "com.mumfrey.liteloader") {
|
||||
on_actionInstall_LiteLoader_triggered();
|
||||
return;
|
||||
}
|
||||
VersionSelectDialog vselect(list.get(), tr("Change %1 version").arg(name), this);
|
||||
if (uid == "net.fabricmc.intermediary" || uid == "org.quiltmc.hashed")
|
||||
{
|
||||
if (uid == "net.fabricmc.intermediary" || uid == "org.quiltmc.hashed") {
|
||||
vselect.setEmptyString(tr("No intermediary mappings versions are currently available."));
|
||||
vselect.setEmptyErrorString(tr("Couldn't load or download the intermediary mappings version lists!"));
|
||||
vselect.setExactFilter(BaseVersionList::ParentVersionRole, m_profile->getComponentVersion("net.minecraft"));
|
||||
}
|
||||
auto currentVersion = patch->getVersion();
|
||||
if(!currentVersion.isEmpty())
|
||||
{
|
||||
if (!currentVersion.isEmpty()) {
|
||||
vselect.setCurrentVersion(currentVersion);
|
||||
}
|
||||
if (!vselect.exec() || !vselect.selectedVersion())
|
||||
@ -411,8 +412,7 @@ void VersionPage::on_actionChange_version_triggered()
|
||||
|
||||
qDebug() << "Change" << uid << "to" << vselect.selectedVersion()->descriptor();
|
||||
bool important = false;
|
||||
if(uid == "net.minecraft")
|
||||
{
|
||||
if (uid == "net.minecraft") {
|
||||
important = true;
|
||||
}
|
||||
m_profile->setComponentVersion(uid, vselect.selectedVersion()->descriptor(), important);
|
||||
@ -422,23 +422,21 @@ void VersionPage::on_actionChange_version_triggered()
|
||||
|
||||
void VersionPage::on_actionDownload_All_triggered()
|
||||
{
|
||||
if (!APPLICATION->accounts()->anyAccountIsValid())
|
||||
{
|
||||
CustomMessageBox::selectable(
|
||||
this, tr("Error"),
|
||||
tr("Cannot download Minecraft or update instances unless you have at least "
|
||||
"one account added.\nPlease add your Mojang or Minecraft account."),
|
||||
QMessageBox::Warning)->show();
|
||||
if (!APPLICATION->accounts()->anyAccountIsValid()) {
|
||||
CustomMessageBox::selectable(this, tr("Error"),
|
||||
tr("Cannot download Minecraft or update instances unless you have at least "
|
||||
"one account added.\nPlease add your Mojang or Minecraft account."),
|
||||
QMessageBox::Warning)
|
||||
->show();
|
||||
return;
|
||||
}
|
||||
|
||||
auto updateTask = m_inst->createUpdateTask(Net::Mode::Online);
|
||||
if (!updateTask)
|
||||
{
|
||||
if (!updateTask) {
|
||||
return;
|
||||
}
|
||||
ProgressDialog tDialog(this);
|
||||
connect(updateTask.get(), SIGNAL(failed(QString)), SLOT(onGameUpdateError(QString)));
|
||||
connect(updateTask.get(), &Task::failed, this, &VersionPage::onGameUpdateError);
|
||||
// FIXME: unused return value
|
||||
tDialog.execWithTask(updateTask.get());
|
||||
updateButtons();
|
||||
@ -448,28 +446,26 @@ void VersionPage::on_actionDownload_All_triggered()
|
||||
void VersionPage::on_actionInstall_Forge_triggered()
|
||||
{
|
||||
auto vlist = APPLICATION->metadataIndex()->get("net.minecraftforge");
|
||||
if(!vlist)
|
||||
{
|
||||
if (!vlist) {
|
||||
return;
|
||||
}
|
||||
VersionSelectDialog vselect(vlist.get(), tr("Select Forge version"), this);
|
||||
vselect.setExactFilter(BaseVersionList::ParentVersionRole, m_profile->getComponentVersion("net.minecraft"));
|
||||
vselect.setEmptyString(tr("No Forge versions are currently available for Minecraft ") + m_profile->getComponentVersion("net.minecraft"));
|
||||
vselect.setEmptyString(tr("No Forge versions are currently available for Minecraft ") +
|
||||
m_profile->getComponentVersion("net.minecraft"));
|
||||
vselect.setEmptyErrorString(tr("Couldn't load or download the Forge version lists!"));
|
||||
|
||||
auto currentVersion = m_profile->getComponentVersion("net.minecraftforge");
|
||||
if(!currentVersion.isEmpty())
|
||||
{
|
||||
if (!currentVersion.isEmpty()) {
|
||||
vselect.setCurrentVersion(currentVersion);
|
||||
}
|
||||
|
||||
if (vselect.exec() && vselect.selectedVersion())
|
||||
{
|
||||
if (vselect.exec() && vselect.selectedVersion()) {
|
||||
auto vsn = vselect.selectedVersion();
|
||||
m_profile->setComponentVersion("net.minecraftforge", vsn->descriptor());
|
||||
m_profile->resolve(Net::Mode::Online);
|
||||
// m_profile->installVersion();
|
||||
preselect(m_profile->rowCount(QModelIndex())-1);
|
||||
preselect(m_profile->rowCount(QModelIndex()) - 1);
|
||||
m_container->refreshContainer();
|
||||
}
|
||||
}
|
||||
@ -477,8 +473,7 @@ void VersionPage::on_actionInstall_Forge_triggered()
|
||||
void VersionPage::on_actionInstall_Fabric_triggered()
|
||||
{
|
||||
auto vlist = APPLICATION->metadataIndex()->get("net.fabricmc.fabric-loader");
|
||||
if(!vlist)
|
||||
{
|
||||
if (!vlist) {
|
||||
return;
|
||||
}
|
||||
VersionSelectDialog vselect(vlist.get(), tr("Select Fabric Loader version"), this);
|
||||
@ -486,17 +481,15 @@ void VersionPage::on_actionInstall_Fabric_triggered()
|
||||
vselect.setEmptyErrorString(tr("Couldn't load or download the Fabric Loader version lists!"));
|
||||
|
||||
auto currentVersion = m_profile->getComponentVersion("net.fabricmc.fabric-loader");
|
||||
if(!currentVersion.isEmpty())
|
||||
{
|
||||
if (!currentVersion.isEmpty()) {
|
||||
vselect.setCurrentVersion(currentVersion);
|
||||
}
|
||||
|
||||
if (vselect.exec() && vselect.selectedVersion())
|
||||
{
|
||||
if (vselect.exec() && vselect.selectedVersion()) {
|
||||
auto vsn = vselect.selectedVersion();
|
||||
m_profile->setComponentVersion("net.fabricmc.fabric-loader", vsn->descriptor());
|
||||
m_profile->resolve(Net::Mode::Online);
|
||||
preselect(m_profile->rowCount(QModelIndex())-1);
|
||||
preselect(m_profile->rowCount(QModelIndex()) - 1);
|
||||
m_container->refreshContainer();
|
||||
}
|
||||
}
|
||||
@ -504,8 +497,7 @@ void VersionPage::on_actionInstall_Fabric_triggered()
|
||||
void VersionPage::on_actionInstall_Quilt_triggered()
|
||||
{
|
||||
auto vlist = APPLICATION->metadataIndex()->get("org.quiltmc.quilt-loader");
|
||||
if(!vlist)
|
||||
{
|
||||
if (!vlist) {
|
||||
return;
|
||||
}
|
||||
VersionSelectDialog vselect(vlist.get(), tr("Select Quilt Loader version"), this);
|
||||
@ -513,17 +505,15 @@ void VersionPage::on_actionInstall_Quilt_triggered()
|
||||
vselect.setEmptyErrorString(tr("Couldn't load or download the Quilt Loader version lists!"));
|
||||
|
||||
auto currentVersion = m_profile->getComponentVersion("org.quiltmc.quilt-loader");
|
||||
if(!currentVersion.isEmpty())
|
||||
{
|
||||
if (!currentVersion.isEmpty()) {
|
||||
vselect.setCurrentVersion(currentVersion);
|
||||
}
|
||||
|
||||
if (vselect.exec() && vselect.selectedVersion())
|
||||
{
|
||||
if (vselect.exec() && vselect.selectedVersion()) {
|
||||
auto vsn = vselect.selectedVersion();
|
||||
m_profile->setComponentVersion("org.quiltmc.quilt-loader", vsn->descriptor());
|
||||
m_profile->resolve(Net::Mode::Online);
|
||||
preselect(m_profile->rowCount(QModelIndex())-1);
|
||||
preselect(m_profile->rowCount(QModelIndex()) - 1);
|
||||
m_container->refreshContainer();
|
||||
}
|
||||
}
|
||||
@ -532,14 +522,12 @@ void VersionPage::on_actionAdd_Empty_triggered()
|
||||
{
|
||||
NewComponentDialog compdialog(QString(), QString(), this);
|
||||
QStringList blacklist;
|
||||
for(int i = 0; i < m_profile->rowCount(); i++)
|
||||
{
|
||||
for (int i = 0; i < m_profile->rowCount(); i++) {
|
||||
auto comp = m_profile->getComponent(i);
|
||||
blacklist.push_back(comp->getID());
|
||||
}
|
||||
compdialog.setBlacklist(blacklist);
|
||||
if (compdialog.exec())
|
||||
{
|
||||
if (compdialog.exec()) {
|
||||
qDebug() << "name:" << compdialog.name();
|
||||
qDebug() << "uid:" << compdialog.uid();
|
||||
m_profile->installEmpty(compdialog.uid(), compdialog.name());
|
||||
@ -549,28 +537,26 @@ void VersionPage::on_actionAdd_Empty_triggered()
|
||||
void VersionPage::on_actionInstall_LiteLoader_triggered()
|
||||
{
|
||||
auto vlist = APPLICATION->metadataIndex()->get("com.mumfrey.liteloader");
|
||||
if(!vlist)
|
||||
{
|
||||
if (!vlist) {
|
||||
return;
|
||||
}
|
||||
VersionSelectDialog vselect(vlist.get(), tr("Select LiteLoader version"), this);
|
||||
vselect.setExactFilter(BaseVersionList::ParentVersionRole, m_profile->getComponentVersion("net.minecraft"));
|
||||
vselect.setEmptyString(tr("No LiteLoader versions are currently available for Minecraft ") + m_profile->getComponentVersion("net.minecraft"));
|
||||
vselect.setEmptyString(tr("No LiteLoader versions are currently available for Minecraft ") +
|
||||
m_profile->getComponentVersion("net.minecraft"));
|
||||
vselect.setEmptyErrorString(tr("Couldn't load or download the LiteLoader version lists!"));
|
||||
|
||||
auto currentVersion = m_profile->getComponentVersion("com.mumfrey.liteloader");
|
||||
if(!currentVersion.isEmpty())
|
||||
{
|
||||
if (!currentVersion.isEmpty()) {
|
||||
vselect.setCurrentVersion(currentVersion);
|
||||
}
|
||||
|
||||
if (vselect.exec() && vselect.selectedVersion())
|
||||
{
|
||||
if (vselect.exec() && vselect.selectedVersion()) {
|
||||
auto vsn = vselect.selectedVersion();
|
||||
m_profile->setComponentVersion("com.mumfrey.liteloader", vsn->descriptor());
|
||||
m_profile->resolve(Net::Mode::Online);
|
||||
// m_profile->installVersion(vselect.selectedVersion());
|
||||
preselect(m_profile->rowCount(QModelIndex())-1);
|
||||
preselect(m_profile->rowCount(QModelIndex()) - 1);
|
||||
m_container->refreshContainer();
|
||||
}
|
||||
}
|
||||
@ -585,7 +571,7 @@ void VersionPage::on_actionMinecraftFolder_triggered()
|
||||
DesktopServices::openDirectory(m_inst->gameRoot(), true);
|
||||
}
|
||||
|
||||
void VersionPage::versionCurrent(const QModelIndex ¤t, const QModelIndex &previous)
|
||||
void VersionPage::versionCurrent(const QModelIndex& current, const QModelIndex& previous)
|
||||
{
|
||||
currentIdx = current.row();
|
||||
updateButtons(currentIdx);
|
||||
@ -593,16 +579,13 @@ void VersionPage::versionCurrent(const QModelIndex ¤t, const QModelIndex &
|
||||
|
||||
void VersionPage::preselect(int row)
|
||||
{
|
||||
if(row < 0)
|
||||
{
|
||||
if (row < 0) {
|
||||
row = 0;
|
||||
}
|
||||
if(row >= m_profile->rowCount(QModelIndex()))
|
||||
{
|
||||
if (row >= m_profile->rowCount(QModelIndex())) {
|
||||
row = m_profile->rowCount(QModelIndex()) - 1;
|
||||
}
|
||||
if(row < 0)
|
||||
{
|
||||
if (row < 0) {
|
||||
return;
|
||||
}
|
||||
auto model_index = m_profile->index(row);
|
||||
@ -615,11 +598,10 @@ void VersionPage::onGameUpdateError(QString error)
|
||||
CustomMessageBox::selectable(this, tr("Error updating instance"), error, QMessageBox::Warning)->show();
|
||||
}
|
||||
|
||||
Component * VersionPage::current()
|
||||
ComponentPtr VersionPage::current()
|
||||
{
|
||||
auto row = currentRow();
|
||||
if(row < 0)
|
||||
{
|
||||
if (row < 0) {
|
||||
return nullptr;
|
||||
}
|
||||
return m_profile->getComponent(row);
|
||||
@ -627,8 +609,7 @@ Component * VersionPage::current()
|
||||
|
||||
int VersionPage::currentRow()
|
||||
{
|
||||
if (ui->packageView->selectionModel()->selectedRows().isEmpty())
|
||||
{
|
||||
if (ui->packageView->selectionModel()->selectedRows().isEmpty()) {
|
||||
return -1;
|
||||
}
|
||||
return ui->packageView->selectionModel()->selectedRows().first().row();
|
||||
@ -637,18 +618,15 @@ int VersionPage::currentRow()
|
||||
void VersionPage::on_actionCustomize_triggered()
|
||||
{
|
||||
auto version = currentRow();
|
||||
if(version == -1)
|
||||
{
|
||||
if (version == -1) {
|
||||
return;
|
||||
}
|
||||
auto patch = m_profile->getComponent(version);
|
||||
if(!patch->getVersionFile())
|
||||
{
|
||||
if (!patch->getVersionFile()) {
|
||||
// TODO: wait for the update task to finish here...
|
||||
return;
|
||||
}
|
||||
if(!m_profile->customize(version))
|
||||
{
|
||||
if (!m_profile->customize(version)) {
|
||||
// TODO: some error box here
|
||||
}
|
||||
updateButtons();
|
||||
@ -658,13 +636,11 @@ void VersionPage::on_actionCustomize_triggered()
|
||||
void VersionPage::on_actionEdit_triggered()
|
||||
{
|
||||
auto version = current();
|
||||
if(!version)
|
||||
{
|
||||
if (!version) {
|
||||
return;
|
||||
}
|
||||
auto filename = version->getFilename();
|
||||
if(!QFileInfo::exists(filename))
|
||||
{
|
||||
if (!QFileInfo::exists(filename)) {
|
||||
qWarning() << "file" << filename << "can't be opened for editing, doesn't exist!";
|
||||
return;
|
||||
}
|
||||
@ -674,12 +650,23 @@ void VersionPage::on_actionEdit_triggered()
|
||||
void VersionPage::on_actionRevert_triggered()
|
||||
{
|
||||
auto version = currentRow();
|
||||
if(version == -1)
|
||||
{
|
||||
if (version == -1) {
|
||||
return;
|
||||
}
|
||||
if(!m_profile->revertToBase(version))
|
||||
{
|
||||
auto component = m_profile->getComponent(version);
|
||||
|
||||
auto response = CustomMessageBox::selectable(this, tr("Confirm Reversion"),
|
||||
tr("You are about to revert \"%1\".\n"
|
||||
"This is permanent and will completely revert your customizations.\n\n"
|
||||
"Are you sure?")
|
||||
.arg(component->getName()),
|
||||
QMessageBox::Warning, QMessageBox::Yes | QMessageBox::No, QMessageBox::No)
|
||||
->exec();
|
||||
|
||||
if (response != QMessageBox::Yes)
|
||||
return;
|
||||
|
||||
if (!m_profile->revertToBase(version)) {
|
||||
// TODO: some error box here
|
||||
}
|
||||
updateButtons();
|
||||
@ -687,7 +674,7 @@ void VersionPage::on_actionRevert_triggered()
|
||||
m_container->refreshContainer();
|
||||
}
|
||||
|
||||
void VersionPage::onFilterTextChanged(const QString &newContents)
|
||||
void VersionPage::onFilterTextChanged(const QString& newContents)
|
||||
{
|
||||
m_filterModel->setFilterFixedString(newContents);
|
||||
}
|
||||
|
@ -1,7 +1,12 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
// SPDX-FileCopyrightText: 2022-2023 Sefa Eyeoglu <contact@scrumplex.net>
|
||||
//
|
||||
// SPDX-License-Identifier: GPL-3.0-only AND Apache-2.0
|
||||
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Prism Launcher - Minecraft Launcher
|
||||
* Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
|
||||
* Copyright (C) 2022-2023 Sefa Eyeoglu <contact@scrumplex.net>
|
||||
* Copyright (C) 2022 TheKodeToad <TheKodeToad@proton.me>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@ -41,35 +46,27 @@
|
||||
#include "minecraft/PackProfile.h"
|
||||
#include "ui/pages/BasePage.h"
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
namespace Ui {
|
||||
class VersionPage;
|
||||
}
|
||||
|
||||
class VersionPage : public QMainWindow, public BasePage
|
||||
{
|
||||
class VersionPage : public QMainWindow, public BasePage {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit VersionPage(MinecraftInstance *inst, QWidget *parent = 0);
|
||||
public:
|
||||
explicit VersionPage(MinecraftInstance* inst, QWidget* parent = 0);
|
||||
virtual ~VersionPage();
|
||||
virtual QString displayName() const override
|
||||
{
|
||||
return tr("Version");
|
||||
}
|
||||
virtual QString displayName() const override { return tr("Version"); }
|
||||
virtual QIcon icon() const override;
|
||||
virtual QString id() const override
|
||||
{
|
||||
return "version";
|
||||
}
|
||||
virtual QString helpPage() const override
|
||||
{
|
||||
return "Instance-Version";
|
||||
}
|
||||
virtual QString id() const override { return "version"; }
|
||||
virtual QString helpPage() const override { return "Instance-Version"; }
|
||||
virtual bool shouldDisplay() const override;
|
||||
void retranslate() override;
|
||||
|
||||
private slots:
|
||||
void openedImpl() override;
|
||||
void closedImpl() override;
|
||||
|
||||
private slots:
|
||||
void on_actionChange_version_triggered();
|
||||
void on_actionInstall_Forge_triggered();
|
||||
void on_actionInstall_Fabric_triggered();
|
||||
@ -82,6 +79,8 @@ private slots:
|
||||
void on_actionMove_down_triggered();
|
||||
void on_actionAdd_to_Minecraft_jar_triggered();
|
||||
void on_actionReplace_Minecraft_jar_triggered();
|
||||
void on_actionImport_Components_triggered();
|
||||
void on_actionAdd_Agents_triggered();
|
||||
void on_actionRevert_triggered();
|
||||
void on_actionEdit_triggered();
|
||||
void on_actionInstall_mods_triggered();
|
||||
@ -93,34 +92,34 @@ private slots:
|
||||
|
||||
void updateVersionControls();
|
||||
|
||||
private:
|
||||
Component * current();
|
||||
private:
|
||||
ComponentPtr current();
|
||||
int currentRow();
|
||||
void updateButtons(int row = -1);
|
||||
void preselect(int row = 0);
|
||||
int doUpdate();
|
||||
|
||||
protected:
|
||||
QMenu * createPopupMenu() override;
|
||||
protected:
|
||||
QMenu* createPopupMenu() override;
|
||||
|
||||
/// FIXME: this shouldn't be necessary!
|
||||
bool reloadPackProfile();
|
||||
|
||||
private:
|
||||
Ui::VersionPage *ui;
|
||||
QSortFilterProxyModel *m_filterModel;
|
||||
private:
|
||||
Ui::VersionPage* ui;
|
||||
QSortFilterProxyModel* m_filterModel;
|
||||
std::shared_ptr<PackProfile> m_profile;
|
||||
MinecraftInstance *m_inst;
|
||||
MinecraftInstance* m_inst;
|
||||
int currentIdx = 0;
|
||||
bool controlsEnabled = false;
|
||||
|
||||
public slots:
|
||||
void versionCurrent(const QModelIndex ¤t, const QModelIndex &previous);
|
||||
std::shared_ptr<Setting> m_wide_bar_setting = nullptr;
|
||||
|
||||
private slots:
|
||||
void updateRunningStatus(bool running);
|
||||
public slots:
|
||||
void versionCurrent(const QModelIndex& current, const QModelIndex& previous);
|
||||
|
||||
private slots:
|
||||
void onGameUpdateError(QString error);
|
||||
void packageCurrent(const QModelIndex ¤t, const QModelIndex &previous);
|
||||
void showContextMenu(const QPoint &pos);
|
||||
void onFilterTextChanged(const QString & newContents);
|
||||
void packageCurrent(const QModelIndex& current, const QModelIndex& previous);
|
||||
void showContextMenu(const QPoint& pos);
|
||||
void onFilterTextChanged(const QString& newContents);
|
||||
};
|
||||
|
@ -28,9 +28,6 @@
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="ModListView" name="packageView">
|
||||
<property name="verticalScrollBarPolicy">
|
||||
<enum>Qt::ScrollBarAlwaysOn</enum>
|
||||
</property>
|
||||
<property name="horizontalScrollBarPolicy">
|
||||
<enum>Qt::ScrollBarAlwaysOff</enum>
|
||||
</property>
|
||||
@ -48,11 +45,7 @@
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="filterEdit">
|
||||
<property name="clearButtonEnabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLineEdit" name="filterEdit"/>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="filterLabel">
|
||||
@ -109,15 +102,15 @@
|
||||
<addaction name="actionInstall_Fabric"/>
|
||||
<addaction name="actionInstall_Quilt"/>
|
||||
<addaction name="actionInstall_LiteLoader"/>
|
||||
<addaction name="actionInstall_mods"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionAdd_to_Minecraft_jar"/>
|
||||
<addaction name="actionReplace_Minecraft_jar"/>
|
||||
<addaction name="actionAdd_Agents"/>
|
||||
<addaction name="actionAdd_Empty"/>
|
||||
<addaction name="actionImport_Components"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionMinecraftFolder"/>
|
||||
<addaction name="actionLibrariesFolder"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionReload"/>
|
||||
<addaction name="actionDownload_All"/>
|
||||
</widget>
|
||||
@ -209,14 +202,6 @@
|
||||
<string>Install the LiteLoader package.</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionInstall_mods">
|
||||
<property name="text">
|
||||
<string>Install mods</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Install normal mods.</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionAdd_to_Minecraft_jar">
|
||||
<property name="text">
|
||||
<string>Add to Minecraft.jar</string>
|
||||
@ -230,6 +215,14 @@
|
||||
<string>Replace Minecraft.jar</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionAdd_Agents">
|
||||
<property name="text">
|
||||
<string>Add Agents</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Add Java agents.</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionAdd_Empty">
|
||||
<property name="text">
|
||||
<string>Add Empty</string>
|
||||
@ -270,6 +263,14 @@
|
||||
<string>Open the instance's local libraries folder.</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionImport_Components">
|
||||
<property name="text">
|
||||
<string>Import Components</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Import existing component JSON files.</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
|
@ -1,8 +1,9 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Prism Launcher - Minecraft Launcher
|
||||
* Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||
* Copyright (C) 2022 TheKodeToad <TheKodeToad@proton.me>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@ -35,6 +36,7 @@
|
||||
*/
|
||||
|
||||
#include "WorldListPage.h"
|
||||
#include "ui/dialogs/CustomMessageBox.h"
|
||||
#include "ui_WorldListPage.h"
|
||||
#include "minecraft/WorldList.h"
|
||||
|
||||
@ -43,9 +45,9 @@
|
||||
#include <QKeyEvent>
|
||||
#include <QClipboard>
|
||||
#include <QMessageBox>
|
||||
#include <QSortFilterProxyModel>
|
||||
#include <QTreeView>
|
||||
#include <QInputDialog>
|
||||
#include <QProcess>
|
||||
#include <Qt>
|
||||
|
||||
#include "tools/MCEditTool.h"
|
||||
@ -105,6 +107,7 @@ WorldListPage::WorldListPage(BaseInstance *inst, std::shared_ptr<WorldList> worl
|
||||
auto head = ui->worldTreeView->header();
|
||||
head->setSectionResizeMode(0, QHeaderView::Stretch);
|
||||
head->setSectionResizeMode(1, QHeaderView::ResizeToContents);
|
||||
head->setSectionResizeMode(4, QHeaderView::ResizeToContents);
|
||||
|
||||
connect(ui->worldTreeView->selectionModel(), &QItemSelectionModel::currentChanged, this, &WorldListPage::worldChanged);
|
||||
worldChanged(QModelIndex(), QModelIndex());
|
||||
@ -113,11 +116,21 @@ WorldListPage::WorldListPage(BaseInstance *inst, std::shared_ptr<WorldList> worl
|
||||
void WorldListPage::openedImpl()
|
||||
{
|
||||
m_worlds->startWatching();
|
||||
|
||||
auto const setting_name = QString("WideBarVisibility_%1").arg(id());
|
||||
if (!APPLICATION->settings()->contains(setting_name))
|
||||
m_wide_bar_setting = APPLICATION->settings()->registerSetting(setting_name);
|
||||
else
|
||||
m_wide_bar_setting = APPLICATION->settings()->getSetting(setting_name);
|
||||
|
||||
ui->toolBar->setVisibilityState(m_wide_bar_setting->get().toByteArray());
|
||||
}
|
||||
|
||||
void WorldListPage::closedImpl()
|
||||
{
|
||||
m_worlds->stopWatching();
|
||||
|
||||
m_wide_bar_setting->set(ui->toolBar->getVisibilityState());
|
||||
}
|
||||
|
||||
WorldListPage::~WorldListPage()
|
||||
@ -182,12 +195,14 @@ void WorldListPage::on_actionRemove_triggered()
|
||||
if(!proxiedIndex.isValid())
|
||||
return;
|
||||
|
||||
auto result = QMessageBox::question(this,
|
||||
tr("Are you sure?"),
|
||||
tr("This will remove the selected world permenantly.\n"
|
||||
"The world will be gone forever (A LONG TIME).\n"
|
||||
"\n"
|
||||
"Do you want to continue?"));
|
||||
auto result = CustomMessageBox::selectable(this, tr("Confirm Deletion"),
|
||||
tr("You are about to delete \"%1\".\n"
|
||||
"The world may be gone forever (A LONG TIME).\n\n"
|
||||
"Are you sure?")
|
||||
.arg(m_worlds->allWorlds().at(proxiedIndex.row()).name()),
|
||||
QMessageBox::Warning, QMessageBox::Yes | QMessageBox::No, QMessageBox::No)
|
||||
->exec();
|
||||
|
||||
if(result != QMessageBox::Yes)
|
||||
{
|
||||
return;
|
||||
@ -324,6 +339,7 @@ void WorldListPage::mceditState(LoggedProcess::State state)
|
||||
{
|
||||
failed = true;
|
||||
}
|
||||
/* fallthrough */
|
||||
case LoggedProcess::Running:
|
||||
case LoggedProcess::Finished:
|
||||
{
|
||||
|
@ -42,6 +42,8 @@
|
||||
#include <Application.h>
|
||||
#include <LoggedProcess.h>
|
||||
|
||||
#include "settings/Setting.h"
|
||||
|
||||
class WorldList;
|
||||
namespace Ui
|
||||
{
|
||||
@ -102,6 +104,8 @@ private:
|
||||
unique_qobject_ptr<LoggedProcess> m_mceditProcess;
|
||||
bool m_mceditStarting = false;
|
||||
|
||||
std::shared_ptr<Setting> m_wide_bar_setting = nullptr;
|
||||
|
||||
private slots:
|
||||
void on_actionCopy_Seed_triggered();
|
||||
void on_actionMCEdit_triggered();
|
||||
|
@ -109,7 +109,7 @@
|
||||
</action>
|
||||
<action name="actionRemove">
|
||||
<property name="text">
|
||||
<string>Remove</string>
|
||||
<string>Delete</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionMCEdit">
|
||||
|
Reference in New Issue
Block a user