mirror of
https://github.com/PrismLauncher/PrismLauncher.git
synced 2025-06-13 13:47:46 +02:00
Merge remote-tracking branch 'upstream/develop' into data-packs
Signed-off-by: TheKodeToad <TheKodeToad@proton.me>
This commit is contained in:
@ -34,14 +34,12 @@ DataPackPage::DataPackPage(MinecraftInstance* instance, std::shared_ptr<DataPack
|
||||
ui->actionViewConfigs->setVisible(false);
|
||||
}
|
||||
|
||||
bool DataPackPage::onSelectionChanged(const QModelIndex& current, [[maybe_unused]] const QModelIndex& previous)
|
||||
void DataPackPage::updateFrame(const QModelIndex& current, [[maybe_unused]] const QModelIndex& previous)
|
||||
{
|
||||
auto sourceCurrent = m_filterModel->mapToSource(current);
|
||||
int row = sourceCurrent.row();
|
||||
auto& dp = static_cast<DataPack&>(m_model->at(row));
|
||||
ui->frame->updateWithDataPack(dp);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void DataPackPage::downloadDataPacks()
|
||||
@ -52,7 +50,7 @@ void DataPackPage::downloadDataPacks()
|
||||
ResourceDownload::DataPackDownloadDialog mdownload(this, std::static_pointer_cast<DataPackFolderModel>(m_model), m_instance);
|
||||
if (mdownload.exec()) {
|
||||
auto tasks =
|
||||
new ConcurrentTask(this, "Download Data Pack", APPLICATION->settings()->get("NumberOfConcurrentDownloads").toInt());
|
||||
new ConcurrentTask("Download Data Pack", APPLICATION->settings()->get("NumberOfConcurrentDownloads").toInt());
|
||||
connect(tasks, &Task::failed, [this, tasks](QString reason) {
|
||||
CustomMessageBox::selectable(this, tr("Error"), reason, QMessageBox::Critical)->show();
|
||||
tasks->deleteLater();
|
||||
|
@ -34,6 +34,6 @@ class DataPackPage : public ExternalResourcesPage {
|
||||
bool shouldDisplay() const override { return true; }
|
||||
|
||||
public slots:
|
||||
bool onSelectionChanged(const QModelIndex& current, const QModelIndex& previous) override;
|
||||
void updateFrame(const QModelIndex& current, const QModelIndex& previous) override;
|
||||
void downloadDataPacks();
|
||||
};
|
||||
|
@ -74,6 +74,7 @@ ExternalResourcesPage::ExternalResourcesPage(BaseInstance* instance, std::shared
|
||||
connect(ui->actionRemoveItem, &QAction::triggered, this, &ExternalResourcesPage::removeItem);
|
||||
connect(ui->actionEnableItem, &QAction::triggered, this, &ExternalResourcesPage::enableItem);
|
||||
connect(ui->actionDisableItem, &QAction::triggered, this, &ExternalResourcesPage::disableItem);
|
||||
connect(ui->actionViewHomepage, &QAction::triggered, this, &ExternalResourcesPage::viewHomepage);
|
||||
connect(ui->actionViewConfigs, &QAction::triggered, this, &ExternalResourcesPage::viewConfigs);
|
||||
connect(ui->actionViewFolder, &QAction::triggered, this, &ExternalResourcesPage::viewFolder);
|
||||
|
||||
@ -81,16 +82,28 @@ ExternalResourcesPage::ExternalResourcesPage(BaseInstance* instance, std::shared
|
||||
connect(ui->treeView, &ModListView::activated, this, &ExternalResourcesPage::itemActivated);
|
||||
|
||||
auto selection_model = ui->treeView->selectionModel();
|
||||
connect(selection_model, &QItemSelectionModel::currentChanged, this, &ExternalResourcesPage::current);
|
||||
|
||||
connect(selection_model, &QItemSelectionModel::currentChanged, this, [this](const QModelIndex& current, const QModelIndex& previous) {
|
||||
if (!current.isValid()) {
|
||||
ui->frame->clear();
|
||||
return;
|
||||
}
|
||||
|
||||
updateFrame(current, previous);
|
||||
});
|
||||
|
||||
auto updateExtra = [this]() {
|
||||
if (updateExtraInfo)
|
||||
updateExtraInfo(id(), extraHeaderInfoString());
|
||||
};
|
||||
|
||||
connect(selection_model, &QItemSelectionModel::selectionChanged, this, updateExtra);
|
||||
connect(model.get(), &ResourceFolderModel::updateFinished, this, updateExtra);
|
||||
connect(model.get(), &ResourceFolderModel::parseFinished, this, updateExtra);
|
||||
|
||||
connect(ui->filterEdit, &QLineEdit::textChanged, this, &ExternalResourcesPage::filterTextChanged);
|
||||
connect(selection_model, &QItemSelectionModel::selectionChanged, this, [this] { updateActions(); });
|
||||
connect(m_model.get(), &ResourceFolderModel::rowsInserted, this, [this] { updateActions(); });
|
||||
connect(m_model.get(), &ResourceFolderModel::rowsRemoved, this, [this] { updateActions(); });
|
||||
|
||||
auto viewHeader = ui->treeView->header();
|
||||
viewHeader->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
@ -99,6 +112,7 @@ ExternalResourcesPage::ExternalResourcesPage(BaseInstance* instance, std::shared
|
||||
|
||||
m_model->loadColumns(ui->treeView);
|
||||
connect(ui->treeView->header(), &QHeaderView::sectionResized, this, [this] { m_model->saveColumns(ui->treeView); });
|
||||
connect(ui->filterEdit, &QLineEdit::textChanged, this, &ExternalResourcesPage::filterTextChanged);
|
||||
}
|
||||
|
||||
ExternalResourcesPage::~ExternalResourcesPage()
|
||||
@ -289,6 +303,16 @@ void ExternalResourcesPage::disableItem()
|
||||
m_model->setResourceEnabled(selection.indexes(), EnableAction::DISABLE);
|
||||
}
|
||||
|
||||
void ExternalResourcesPage::viewHomepage()
|
||||
{
|
||||
auto selection = m_filterModel->mapSelectionToSource(ui->treeView->selectionModel()->selection()).indexes();
|
||||
for (auto resource : m_model->selectedResources(selection)) {
|
||||
auto url = resource->homepage();
|
||||
if (!url.isEmpty())
|
||||
DesktopServices::openUrl(url);
|
||||
}
|
||||
}
|
||||
|
||||
void ExternalResourcesPage::viewConfigs()
|
||||
{
|
||||
DesktopServices::openPath(m_instance->instanceConfigFolder(), true);
|
||||
@ -299,23 +323,32 @@ void ExternalResourcesPage::viewFolder()
|
||||
DesktopServices::openPath(m_model->dir().absolutePath(), true);
|
||||
}
|
||||
|
||||
bool ExternalResourcesPage::current(const QModelIndex& current, const QModelIndex& previous)
|
||||
void ExternalResourcesPage::updateActions()
|
||||
{
|
||||
if (!current.isValid()) {
|
||||
ui->frame->clear();
|
||||
return false;
|
||||
}
|
||||
const bool hasSelection = ui->treeView->selectionModel()->hasSelection();
|
||||
const QModelIndexList selection = m_filterModel->mapSelectionToSource(ui->treeView->selectionModel()->selection()).indexes();
|
||||
const QList<Resource*> selectedResources = m_model->selectedResources(selection);
|
||||
|
||||
return onSelectionChanged(current, previous);
|
||||
ui->actionUpdateItem->setEnabled(!m_model->empty());
|
||||
ui->actionResetItemMetadata->setEnabled(hasSelection);
|
||||
|
||||
ui->actionChangeVersion->setEnabled(selectedResources.size() == 1 && selectedResources[0]->metadata() != nullptr);
|
||||
|
||||
ui->actionRemoveItem->setEnabled(hasSelection);
|
||||
ui->actionEnableItem->setEnabled(hasSelection);
|
||||
ui->actionDisableItem->setEnabled(hasSelection);
|
||||
|
||||
ui->actionViewHomepage->setEnabled(hasSelection && std::any_of(selectedResources.begin(), selectedResources.end(),
|
||||
[](Resource* resource) { return !resource->homepage().isEmpty(); }));
|
||||
ui->actionExportMetadata->setEnabled(!m_model->empty());
|
||||
}
|
||||
|
||||
bool ExternalResourcesPage::onSelectionChanged(const QModelIndex& current, [[maybe_unused]] const QModelIndex& previous)
|
||||
void ExternalResourcesPage::updateFrame(const QModelIndex& current, [[maybe_unused]] const QModelIndex& previous)
|
||||
{
|
||||
auto sourceCurrent = m_filterModel->mapToSource(current);
|
||||
int row = sourceCurrent.row();
|
||||
Resource const& resource = m_model->at(row);
|
||||
ui->frame->updateWithResource(resource);
|
||||
return true;
|
||||
}
|
||||
|
||||
QString ExternalResourcesPage::extraHeaderInfoString()
|
||||
|
@ -43,9 +43,8 @@ class ExternalResourcesPage : public QMainWindow, public BasePage {
|
||||
QMenu* createPopupMenu() override;
|
||||
|
||||
public slots:
|
||||
bool current(const QModelIndex& current, const QModelIndex& previous);
|
||||
|
||||
virtual bool onSelectionChanged(const QModelIndex& current, const QModelIndex& previous);
|
||||
virtual void updateActions();
|
||||
virtual void updateFrame(const QModelIndex& current, const QModelIndex& previous);
|
||||
|
||||
protected slots:
|
||||
void itemActivated(const QModelIndex& index);
|
||||
@ -58,6 +57,8 @@ class ExternalResourcesPage : public QMainWindow, public BasePage {
|
||||
virtual void enableItem();
|
||||
virtual void disableItem();
|
||||
|
||||
virtual void viewHomepage();
|
||||
|
||||
virtual void viewFolder();
|
||||
virtual void viewConfigs();
|
||||
|
||||
|
@ -74,7 +74,7 @@
|
||||
<string>Actions</string>
|
||||
</property>
|
||||
<property name="toolButtonStyle">
|
||||
<enum>Qt::ToolButtonTextOnly</enum>
|
||||
<enum>Qt::ToolButtonIconOnly</enum>
|
||||
</property>
|
||||
<property name="useDefaultAction" stdset="0">
|
||||
<bool>true</bool>
|
||||
@ -90,39 +90,50 @@
|
||||
<addaction name="actionRemoveItem"/>
|
||||
<addaction name="actionEnableItem"/>
|
||||
<addaction name="actionDisableItem"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionViewHomepage"/>
|
||||
<addaction name="actionViewConfigs"/>
|
||||
<addaction name="actionViewFolder"/>
|
||||
</widget>
|
||||
<action name="actionAddItem">
|
||||
<property name="text">
|
||||
<string>&Add</string>
|
||||
<string>&Add File</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Add</string>
|
||||
<string>Add a locally downloaded file.</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionRemoveItem">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Remove</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Remove selected item</string>
|
||||
<string>Remove all selected items.</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionEnableItem">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Enable</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Enable selected item</string>
|
||||
<string>Enable all selected items.</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionDisableItem">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Disable</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Disable selected item</string>
|
||||
<string>Disable all selected items.</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionViewConfigs">
|
||||
@ -137,6 +148,9 @@
|
||||
<property name="text">
|
||||
<string>View &Folder</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Open the folder in the system file manager.</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionDownloadItem">
|
||||
<property name="enabled">
|
||||
@ -146,40 +160,70 @@
|
||||
<string>&Download</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Download a new resource</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>
|
||||
<string>Download resources from online mod platforms.</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionUpdateItem">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Check for &Updates</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Try to check or update all selected resources (all resources if none are selected)</string>
|
||||
<string>Try to check or update all selected resources (all resources if none are selected).</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionResetItemMetadata">
|
||||
<property name="text">
|
||||
<string>Reset Update Metadata</string>
|
||||
</property>
|
||||
<property name="menuRole">
|
||||
<enum>QAction::NoRole</enum>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionVerifyItemDependencies">
|
||||
<property name="text">
|
||||
<string>Verify Dependencies</string>
|
||||
</property>
|
||||
<property name="menuRole">
|
||||
<enum>QAction::NoRole</enum>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionExportMetadata">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Export modlist</string>
|
||||
<string>Export List</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Export mod's metadata to text</string>
|
||||
<string>Export resource's metadata to text.</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionChangeVersion">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Change Version</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Change a resource's version.</string>
|
||||
</property>
|
||||
<property name="menuRole">
|
||||
<enum>QAction::NoRole</enum>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionViewHomepage">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>View Homepage</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>View the homepages of all selected items.</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
|
@ -1,589 +0,0 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* 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
|
||||
* 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 "InstanceSettingsPage.h"
|
||||
#include "minecraft/MinecraftInstance.h"
|
||||
#include "minecraft/WorldList.h"
|
||||
#include "ui_InstanceSettingsPage.h"
|
||||
|
||||
#include <QDialog>
|
||||
#include <QFileDialog>
|
||||
#include <QMessageBox>
|
||||
|
||||
#include <sys.h>
|
||||
|
||||
#include "ui/dialogs/VersionSelectDialog.h"
|
||||
#include "ui/widgets/CustomCommands.h"
|
||||
|
||||
#include "Application.h"
|
||||
#include "BuildConfig.h"
|
||||
#include "JavaCommon.h"
|
||||
#include "minecraft/auth/AccountList.h"
|
||||
|
||||
#include "FileSystem.h"
|
||||
#include "java/JavaInstallList.h"
|
||||
#include "java/JavaUtils.h"
|
||||
|
||||
InstanceSettingsPage::InstanceSettingsPage(BaseInstance* inst, QWidget* parent)
|
||||
: QWidget(parent), ui(new Ui::InstanceSettingsPage), m_instance(inst)
|
||||
{
|
||||
m_settings = inst->settings();
|
||||
ui->setupUi(this);
|
||||
|
||||
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);
|
||||
|
||||
connect(ui->useNativeGLFWCheck, &QAbstractButton::toggled, this, &InstanceSettingsPage::onUseNativeGLFWChanged);
|
||||
connect(ui->useNativeOpenALCheck, &QAbstractButton::toggled, this, &InstanceSettingsPage::onUseNativeOpenALChanged);
|
||||
|
||||
auto mInst = dynamic_cast<MinecraftInstance*>(inst);
|
||||
m_world_quickplay_supported = mInst && mInst->traits().contains("feature:is_quick_play_singleplayer");
|
||||
if (m_world_quickplay_supported) {
|
||||
auto worlds = mInst->worldList();
|
||||
worlds->update();
|
||||
for (const auto& world : worlds->allWorlds()) {
|
||||
ui->worldsCb->addItem(world.folderName());
|
||||
}
|
||||
} else {
|
||||
ui->worldsCb->hide();
|
||||
ui->worldJoinButton->hide();
|
||||
ui->serverJoinAddressButton->setChecked(true);
|
||||
ui->serverJoinAddress->setEnabled(true);
|
||||
ui->serverJoinAddressButton->setStyleSheet("QRadioButton::indicator { width: 0px; height: 0px; }");
|
||||
}
|
||||
|
||||
loadSettings();
|
||||
|
||||
updateThresholds();
|
||||
}
|
||||
|
||||
InstanceSettingsPage::~InstanceSettingsPage()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void InstanceSettingsPage::globalSettingsButtonClicked(bool)
|
||||
{
|
||||
switch (ui->settingsTabs->currentIndex()) {
|
||||
case 0:
|
||||
APPLICATION->ShowGlobalSettings(this, "java-settings");
|
||||
return;
|
||||
case 2:
|
||||
APPLICATION->ShowGlobalSettings(this, "custom-commands");
|
||||
return;
|
||||
case 3:
|
||||
APPLICATION->ShowGlobalSettings(this, "environment-variables");
|
||||
return;
|
||||
default:
|
||||
APPLICATION->ShowGlobalSettings(this, "minecraft-settings");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
bool InstanceSettingsPage::apply()
|
||||
{
|
||||
applySettings();
|
||||
return true;
|
||||
}
|
||||
|
||||
void InstanceSettingsPage::applySettings()
|
||||
{
|
||||
SettingsObject::Lock lock(m_settings);
|
||||
|
||||
// Miscellaneous
|
||||
bool miscellaneous = ui->miscellaneousSettingsBox->isChecked();
|
||||
m_settings->set("OverrideMiscellaneous", miscellaneous);
|
||||
if (miscellaneous) {
|
||||
m_settings->set("CloseAfterLaunch", ui->closeAfterLaunchCheck->isChecked());
|
||||
m_settings->set("QuitAfterGameStop", ui->quitAfterGameStopCheck->isChecked());
|
||||
} else {
|
||||
m_settings->reset("CloseAfterLaunch");
|
||||
m_settings->reset("QuitAfterGameStop");
|
||||
}
|
||||
|
||||
// Console
|
||||
bool console = ui->consoleSettingsBox->isChecked();
|
||||
m_settings->set("OverrideConsole", console);
|
||||
if (console) {
|
||||
m_settings->set("ShowConsole", ui->showConsoleCheck->isChecked());
|
||||
m_settings->set("AutoCloseConsole", ui->autoCloseConsoleCheck->isChecked());
|
||||
m_settings->set("ShowConsoleOnError", ui->showConsoleErrorCheck->isChecked());
|
||||
} else {
|
||||
m_settings->reset("ShowConsole");
|
||||
m_settings->reset("AutoCloseConsole");
|
||||
m_settings->reset("ShowConsoleOnError");
|
||||
}
|
||||
|
||||
// Window Size
|
||||
bool window = ui->windowSizeGroupBox->isChecked();
|
||||
m_settings->set("OverrideWindow", window);
|
||||
if (window) {
|
||||
m_settings->set("LaunchMaximized", ui->maximizedCheckBox->isChecked());
|
||||
m_settings->set("MinecraftWinWidth", ui->windowWidthSpinBox->value());
|
||||
m_settings->set("MinecraftWinHeight", ui->windowHeightSpinBox->value());
|
||||
} else {
|
||||
m_settings->reset("LaunchMaximized");
|
||||
m_settings->reset("MinecraftWinWidth");
|
||||
m_settings->reset("MinecraftWinHeight");
|
||||
}
|
||||
|
||||
// Memory
|
||||
bool memory = ui->memoryGroupBox->isChecked();
|
||||
m_settings->set("OverrideMemory", memory);
|
||||
if (memory) {
|
||||
int min = ui->minMemSpinBox->value();
|
||||
int max = ui->maxMemSpinBox->value();
|
||||
if (min < max) {
|
||||
m_settings->set("MinMemAlloc", min);
|
||||
m_settings->set("MaxMemAlloc", max);
|
||||
} else {
|
||||
m_settings->set("MinMemAlloc", max);
|
||||
m_settings->set("MaxMemAlloc", min);
|
||||
}
|
||||
m_settings->set("PermGen", ui->permGenSpinBox->value());
|
||||
} else {
|
||||
m_settings->reset("MinMemAlloc");
|
||||
m_settings->reset("MaxMemAlloc");
|
||||
m_settings->reset("PermGen");
|
||||
}
|
||||
|
||||
// Java Install Settings
|
||||
bool javaInstall = ui->javaSettingsGroupBox->isChecked();
|
||||
m_settings->set("OverrideJavaLocation", javaInstall);
|
||||
if (javaInstall) {
|
||||
m_settings->set("JavaPath", ui->javaPathTextBox->text());
|
||||
m_settings->set("IgnoreJavaCompatibility", ui->skipCompatibilityCheckbox->isChecked());
|
||||
} else {
|
||||
m_settings->reset("JavaPath");
|
||||
m_settings->reset("IgnoreJavaCompatibility");
|
||||
}
|
||||
|
||||
// Java arguments
|
||||
bool javaArgs = ui->javaArgumentsGroupBox->isChecked();
|
||||
m_settings->set("OverrideJavaArgs", javaArgs);
|
||||
if (javaArgs) {
|
||||
m_settings->set("JvmArgs", ui->jvmArgsTextBox->toPlainText().replace("\n", " "));
|
||||
} else {
|
||||
m_settings->reset("JvmArgs");
|
||||
}
|
||||
|
||||
// old generic 'override both' is removed.
|
||||
m_settings->reset("OverrideJava");
|
||||
|
||||
// Custom Commands
|
||||
bool custcmd = ui->customCommands->checked();
|
||||
m_settings->set("OverrideCommands", custcmd);
|
||||
if (custcmd) {
|
||||
m_settings->set("PreLaunchCommand", ui->customCommands->prelaunchCommand());
|
||||
m_settings->set("WrapperCommand", ui->customCommands->wrapperCommand());
|
||||
m_settings->set("PostExitCommand", ui->customCommands->postexitCommand());
|
||||
} else {
|
||||
m_settings->reset("PreLaunchCommand");
|
||||
m_settings->reset("WrapperCommand");
|
||||
m_settings->reset("PostExitCommand");
|
||||
}
|
||||
|
||||
// Environment Variables
|
||||
auto env = ui->environmentVariables->override();
|
||||
m_settings->set("OverrideEnv", env);
|
||||
if (env)
|
||||
m_settings->set("Env", ui->environmentVariables->value());
|
||||
else
|
||||
m_settings->reset("Env");
|
||||
|
||||
// Workarounds
|
||||
bool workarounds = ui->nativeWorkaroundsGroupBox->isChecked();
|
||||
m_settings->set("OverrideNativeWorkarounds", workarounds);
|
||||
if (workarounds) {
|
||||
m_settings->set("UseNativeGLFW", ui->useNativeGLFWCheck->isChecked());
|
||||
m_settings->set("CustomGLFWPath", ui->lineEditGLFWPath->text());
|
||||
m_settings->set("UseNativeOpenAL", ui->useNativeOpenALCheck->isChecked());
|
||||
m_settings->set("CustomOpenALPath", ui->lineEditOpenALPath->text());
|
||||
} else {
|
||||
m_settings->reset("UseNativeGLFW");
|
||||
m_settings->reset("CustomGLFWPath");
|
||||
m_settings->reset("UseNativeOpenAL");
|
||||
m_settings->reset("CustomOpenALPath");
|
||||
}
|
||||
|
||||
// Performance
|
||||
bool performance = ui->perfomanceGroupBox->isChecked();
|
||||
m_settings->set("OverridePerformance", performance);
|
||||
if (performance) {
|
||||
m_settings->set("EnableFeralGamemode", ui->enableFeralGamemodeCheck->isChecked());
|
||||
m_settings->set("EnableMangoHud", ui->enableMangoHud->isChecked());
|
||||
m_settings->set("UseDiscreteGpu", ui->useDiscreteGpuCheck->isChecked());
|
||||
m_settings->set("UseZink", ui->useZink->isChecked());
|
||||
|
||||
} else {
|
||||
m_settings->reset("EnableFeralGamemode");
|
||||
m_settings->reset("EnableMangoHud");
|
||||
m_settings->reset("UseDiscreteGpu");
|
||||
m_settings->reset("UseZink");
|
||||
}
|
||||
|
||||
// Game time
|
||||
bool gameTime = ui->gameTimeGroupBox->isChecked();
|
||||
m_settings->set("OverrideGameTime", gameTime);
|
||||
if (gameTime) {
|
||||
m_settings->set("ShowGameTime", ui->showGameTime->isChecked());
|
||||
m_settings->set("RecordGameTime", ui->recordGameTime->isChecked());
|
||||
} else {
|
||||
m_settings->reset("ShowGameTime");
|
||||
m_settings->reset("RecordGameTime");
|
||||
}
|
||||
|
||||
// Join server on launch
|
||||
bool joinServerOnLaunch = ui->serverJoinGroupBox->isChecked();
|
||||
m_settings->set("JoinServerOnLaunch", joinServerOnLaunch);
|
||||
if (joinServerOnLaunch) {
|
||||
if (ui->serverJoinAddressButton->isChecked() || !m_world_quickplay_supported) {
|
||||
m_settings->set("JoinServerOnLaunchAddress", ui->serverJoinAddress->text());
|
||||
m_settings->reset("JoinWorldOnLaunch");
|
||||
} else {
|
||||
m_settings->set("JoinWorldOnLaunch", ui->worldsCb->currentText());
|
||||
m_settings->reset("JoinServerOnLaunchAddress");
|
||||
}
|
||||
} else {
|
||||
m_settings->reset("JoinServerOnLaunchAddress");
|
||||
m_settings->reset("JoinWorldOnLaunch");
|
||||
}
|
||||
|
||||
// Use an account for this instance
|
||||
bool useAccountForInstance = ui->instanceAccountGroupBox->isChecked();
|
||||
m_settings->set("UseAccountForInstance", useAccountForInstance);
|
||||
if (!useAccountForInstance) {
|
||||
m_settings->reset("InstanceAccountId");
|
||||
}
|
||||
|
||||
bool overrideLegacySettings = ui->legacySettingsGroupBox->isChecked();
|
||||
m_settings->set("OverrideLegacySettings", overrideLegacySettings);
|
||||
if (overrideLegacySettings) {
|
||||
m_settings->set("OnlineFixes", ui->onlineFixes->isChecked());
|
||||
} else {
|
||||
m_settings->reset("OnlineFixes");
|
||||
}
|
||||
|
||||
// FIXME: This should probably be called by a signal instead
|
||||
m_instance->updateRuntimeContext();
|
||||
}
|
||||
|
||||
void InstanceSettingsPage::loadSettings()
|
||||
{
|
||||
// Miscellaneous
|
||||
ui->miscellaneousSettingsBox->setChecked(m_settings->get("OverrideMiscellaneous").toBool());
|
||||
ui->closeAfterLaunchCheck->setChecked(m_settings->get("CloseAfterLaunch").toBool());
|
||||
ui->quitAfterGameStopCheck->setChecked(m_settings->get("QuitAfterGameStop").toBool());
|
||||
|
||||
// Console
|
||||
ui->consoleSettingsBox->setChecked(m_settings->get("OverrideConsole").toBool());
|
||||
ui->showConsoleCheck->setChecked(m_settings->get("ShowConsole").toBool());
|
||||
ui->autoCloseConsoleCheck->setChecked(m_settings->get("AutoCloseConsole").toBool());
|
||||
ui->showConsoleErrorCheck->setChecked(m_settings->get("ShowConsoleOnError").toBool());
|
||||
|
||||
// Window Size
|
||||
ui->windowSizeGroupBox->setChecked(m_settings->get("OverrideWindow").toBool());
|
||||
ui->maximizedCheckBox->setChecked(m_settings->get("LaunchMaximized").toBool());
|
||||
ui->windowWidthSpinBox->setValue(m_settings->get("MinecraftWinWidth").toInt());
|
||||
ui->windowHeightSpinBox->setValue(m_settings->get("MinecraftWinHeight").toInt());
|
||||
|
||||
// Memory
|
||||
ui->memoryGroupBox->setChecked(m_settings->get("OverrideMemory").toBool());
|
||||
int min = m_settings->get("MinMemAlloc").toInt();
|
||||
int max = m_settings->get("MaxMemAlloc").toInt();
|
||||
if (min < max) {
|
||||
ui->minMemSpinBox->setValue(min);
|
||||
ui->maxMemSpinBox->setValue(max);
|
||||
} else {
|
||||
ui->minMemSpinBox->setValue(max);
|
||||
ui->maxMemSpinBox->setValue(min);
|
||||
}
|
||||
ui->permGenSpinBox->setValue(m_settings->get("PermGen").toInt());
|
||||
bool permGenVisible = m_settings->get("PermGenVisible").toBool();
|
||||
ui->permGenSpinBox->setVisible(permGenVisible);
|
||||
ui->labelPermGen->setVisible(permGenVisible);
|
||||
ui->labelPermgenNote->setVisible(permGenVisible);
|
||||
|
||||
// Java Settings
|
||||
bool overrideJava = m_settings->get("OverrideJava").toBool();
|
||||
bool overrideLocation = m_settings->get("OverrideJavaLocation").toBool() || overrideJava;
|
||||
bool overrideArgs = m_settings->get("OverrideJavaArgs").toBool() || overrideJava;
|
||||
|
||||
ui->javaSettingsGroupBox->setChecked(overrideLocation);
|
||||
ui->javaPathTextBox->setText(m_settings->get("JavaPath").toString());
|
||||
ui->skipCompatibilityCheckbox->setChecked(m_settings->get("IgnoreJavaCompatibility").toBool());
|
||||
|
||||
ui->javaArgumentsGroupBox->setChecked(overrideArgs);
|
||||
ui->jvmArgsTextBox->setPlainText(m_settings->get("JvmArgs").toString());
|
||||
|
||||
// Custom commands
|
||||
ui->customCommands->initialize(true, m_settings->get("OverrideCommands").toBool(), m_settings->get("PreLaunchCommand").toString(),
|
||||
m_settings->get("WrapperCommand").toString(), m_settings->get("PostExitCommand").toString());
|
||||
|
||||
// Environment variables
|
||||
ui->environmentVariables->initialize(true, m_settings->get("OverrideEnv").toBool(), m_settings->get("Env").toMap());
|
||||
|
||||
// Workarounds
|
||||
ui->nativeWorkaroundsGroupBox->setChecked(m_settings->get("OverrideNativeWorkarounds").toBool());
|
||||
ui->useNativeGLFWCheck->setChecked(m_settings->get("UseNativeGLFW").toBool());
|
||||
ui->lineEditGLFWPath->setText(m_settings->get("CustomGLFWPath").toString());
|
||||
#ifdef Q_OS_LINUX
|
||||
ui->lineEditGLFWPath->setPlaceholderText(APPLICATION->m_detectedGLFWPath);
|
||||
#else
|
||||
ui->lineEditGLFWPath->setPlaceholderText(tr("Path to %1 library file").arg(BuildConfig.GLFW_LIBRARY_NAME));
|
||||
#endif
|
||||
ui->useNativeOpenALCheck->setChecked(m_settings->get("UseNativeOpenAL").toBool());
|
||||
ui->lineEditOpenALPath->setText(m_settings->get("CustomOpenALPath").toString());
|
||||
#ifdef Q_OS_LINUX
|
||||
ui->lineEditOpenALPath->setPlaceholderText(APPLICATION->m_detectedOpenALPath);
|
||||
#else
|
||||
ui->lineEditOpenALPath->setPlaceholderText(tr("Path to %1 library file").arg(BuildConfig.OPENAL_LIBRARY_NAME));
|
||||
#endif
|
||||
|
||||
// Performance
|
||||
ui->perfomanceGroupBox->setChecked(m_settings->get("OverridePerformance").toBool());
|
||||
ui->enableFeralGamemodeCheck->setChecked(m_settings->get("EnableFeralGamemode").toBool());
|
||||
ui->enableMangoHud->setChecked(m_settings->get("EnableMangoHud").toBool());
|
||||
ui->useDiscreteGpuCheck->setChecked(m_settings->get("UseDiscreteGpu").toBool());
|
||||
ui->useZink->setChecked(m_settings->get("UseZink").toBool());
|
||||
|
||||
#if !defined(Q_OS_LINUX)
|
||||
ui->settingsTabs->setTabVisible(ui->settingsTabs->indexOf(ui->performancePage), false);
|
||||
#endif
|
||||
|
||||
if (!(APPLICATION->capabilities() & Application::SupportsGameMode)) {
|
||||
ui->enableFeralGamemodeCheck->setDisabled(true);
|
||||
ui->enableFeralGamemodeCheck->setToolTip(tr("Feral Interactive's GameMode could not be found on your system."));
|
||||
}
|
||||
|
||||
if (!(APPLICATION->capabilities() & Application::SupportsMangoHud)) {
|
||||
ui->enableMangoHud->setDisabled(true);
|
||||
ui->enableMangoHud->setToolTip(tr("MangoHud could not be found on your system."));
|
||||
}
|
||||
|
||||
// Miscellanous
|
||||
ui->gameTimeGroupBox->setChecked(m_settings->get("OverrideGameTime").toBool());
|
||||
ui->showGameTime->setChecked(m_settings->get("ShowGameTime").toBool());
|
||||
ui->recordGameTime->setChecked(m_settings->get("RecordGameTime").toBool());
|
||||
|
||||
ui->serverJoinGroupBox->setChecked(m_settings->get("JoinServerOnLaunch").toBool());
|
||||
|
||||
if (auto server = m_settings->get("JoinServerOnLaunchAddress").toString(); !server.isEmpty()) {
|
||||
ui->serverJoinAddress->setText(server);
|
||||
ui->serverJoinAddressButton->setChecked(true);
|
||||
ui->worldJoinButton->setChecked(false);
|
||||
ui->serverJoinAddress->setEnabled(true);
|
||||
ui->worldsCb->setEnabled(false);
|
||||
} else if (auto world = m_settings->get("JoinWorldOnLaunch").toString(); !world.isEmpty() && m_world_quickplay_supported) {
|
||||
ui->worldsCb->setCurrentText(world);
|
||||
ui->serverJoinAddressButton->setChecked(false);
|
||||
ui->worldJoinButton->setChecked(true);
|
||||
ui->serverJoinAddress->setEnabled(false);
|
||||
ui->worldsCb->setEnabled(true);
|
||||
} else {
|
||||
ui->serverJoinAddressButton->setChecked(true);
|
||||
ui->worldJoinButton->setChecked(false);
|
||||
ui->serverJoinAddress->setEnabled(true);
|
||||
ui->worldsCb->setEnabled(false);
|
||||
}
|
||||
|
||||
ui->instanceAccountGroupBox->setChecked(m_settings->get("UseAccountForInstance").toBool());
|
||||
updateAccountsMenu();
|
||||
|
||||
ui->legacySettingsGroupBox->setChecked(m_settings->get("OverrideLegacySettings").toBool());
|
||||
ui->onlineFixes->setChecked(m_settings->get("OnlineFixes").toBool());
|
||||
}
|
||||
|
||||
void InstanceSettingsPage::on_javaDetectBtn_clicked()
|
||||
{
|
||||
if (JavaUtils::getJavaCheckPath().isEmpty()) {
|
||||
JavaCommon::javaCheckNotFound(this);
|
||||
return;
|
||||
}
|
||||
|
||||
JavaInstallPtr java;
|
||||
|
||||
VersionSelectDialog vselect(APPLICATION->javalist().get(), tr("Select a Java version"), this, true);
|
||||
vselect.setResizeOn(2);
|
||||
vselect.exec();
|
||||
|
||||
if (vselect.result() == QDialog::Accepted && vselect.selectedVersion()) {
|
||||
java = std::dynamic_pointer_cast<JavaInstall>(vselect.selectedVersion());
|
||||
ui->javaPathTextBox->setText(java->path);
|
||||
bool visible = java->id.requiresPermGen() && m_settings->get("OverrideMemory").toBool();
|
||||
ui->permGenSpinBox->setVisible(visible);
|
||||
ui->labelPermGen->setVisible(visible);
|
||||
ui->labelPermgenNote->setVisible(visible);
|
||||
m_settings->set("PermGenVisible", visible);
|
||||
}
|
||||
}
|
||||
|
||||
void InstanceSettingsPage::on_javaBrowseBtn_clicked()
|
||||
{
|
||||
QString raw_path = QFileDialog::getOpenFileName(this, tr("Find Java executable"));
|
||||
|
||||
// do not allow current dir - it's dirty. Do not allow dirs that don't exist
|
||||
if (raw_path.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
QString cooked_path = FS::NormalizePath(raw_path);
|
||||
|
||||
QFileInfo javaInfo(cooked_path);
|
||||
if (!javaInfo.exists() || !javaInfo.isExecutable()) {
|
||||
return;
|
||||
}
|
||||
ui->javaPathTextBox->setText(cooked_path);
|
||||
|
||||
// custom Java could be anything... enable perm gen option
|
||||
ui->permGenSpinBox->setVisible(true);
|
||||
ui->labelPermGen->setVisible(true);
|
||||
ui->labelPermgenNote->setVisible(true);
|
||||
m_settings->set("PermGenVisible", true);
|
||||
}
|
||||
|
||||
void InstanceSettingsPage::on_javaTestBtn_clicked()
|
||||
{
|
||||
if (checker) {
|
||||
return;
|
||||
}
|
||||
checker.reset(new JavaCommon::TestCheck(this, ui->javaPathTextBox->text(), ui->jvmArgsTextBox->toPlainText().replace("\n", " "),
|
||||
ui->minMemSpinBox->value(), ui->maxMemSpinBox->value(), ui->permGenSpinBox->value()));
|
||||
connect(checker.get(), SIGNAL(finished()), SLOT(checkerFinished()));
|
||||
checker->run();
|
||||
}
|
||||
|
||||
void InstanceSettingsPage::onUseNativeGLFWChanged(bool checked)
|
||||
{
|
||||
ui->lineEditGLFWPath->setEnabled(checked);
|
||||
}
|
||||
|
||||
void InstanceSettingsPage::onUseNativeOpenALChanged(bool checked)
|
||||
{
|
||||
ui->lineEditOpenALPath->setEnabled(checked);
|
||||
}
|
||||
|
||||
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([[maybe_unused]] int i)
|
||||
{
|
||||
updateThresholds();
|
||||
}
|
||||
|
||||
void InstanceSettingsPage::checkerFinished()
|
||||
{
|
||||
checker.reset();
|
||||
}
|
||||
|
||||
void InstanceSettingsPage::retranslate()
|
||||
{
|
||||
ui->retranslateUi(this);
|
||||
ui->customCommands->retranslate(); // TODO: why is this seperate from the others?
|
||||
ui->environmentVariables->retranslate();
|
||||
}
|
||||
|
||||
void InstanceSettingsPage::updateThresholds()
|
||||
{
|
||||
auto sysMiB = Sys::getSystemRam() / Sys::mebibyte;
|
||||
unsigned int maxMem = ui->maxMemSpinBox->value();
|
||||
unsigned int minMem = ui->minMemSpinBox->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 if (maxMem < minMem) {
|
||||
iconName = "status-yellow";
|
||||
ui->labelMaxMemIcon->setToolTip(tr("Your maximum memory allocation is smaller than the minimum value"));
|
||||
} 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);
|
||||
}
|
||||
}
|
||||
|
||||
void InstanceSettingsPage::on_serverJoinAddressButton_toggled(bool checked)
|
||||
{
|
||||
ui->serverJoinAddress->setEnabled(checked);
|
||||
}
|
||||
|
||||
void InstanceSettingsPage::on_worldJoinButton_toggled(bool checked)
|
||||
{
|
||||
ui->worldsCb->setEnabled(checked);
|
||||
}
|
@ -35,62 +35,29 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QWidget>
|
||||
|
||||
#include <QObjectPtr.h>
|
||||
#include <QMenu>
|
||||
#include "Application.h"
|
||||
#include "BaseInstance.h"
|
||||
#include "JavaCommon.h"
|
||||
#include "java/JavaChecker.h"
|
||||
#include "ui/pages/BasePage.h"
|
||||
#include "ui/widgets/MinecraftSettingsWidget.h"
|
||||
#include <QWidget>
|
||||
|
||||
class JavaChecker;
|
||||
namespace Ui {
|
||||
class InstanceSettingsPage;
|
||||
}
|
||||
|
||||
class InstanceSettingsPage : public QWidget, public BasePage {
|
||||
class InstanceSettingsPage : public MinecraftSettingsWidget, public BasePage {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit InstanceSettingsPage(BaseInstance* inst, QWidget* parent = 0);
|
||||
virtual ~InstanceSettingsPage();
|
||||
virtual QString displayName() const override { return tr("Settings"); }
|
||||
virtual QIcon icon() const override { return APPLICATION->getThemedIcon("instance-settings"); }
|
||||
virtual QString id() const override { return "settings"; }
|
||||
virtual bool apply() override;
|
||||
virtual QString helpPage() const override { return "Instance-settings"; }
|
||||
void retranslate() override;
|
||||
|
||||
void updateThresholds();
|
||||
|
||||
private slots:
|
||||
void on_javaDetectBtn_clicked();
|
||||
void on_javaTestBtn_clicked();
|
||||
void on_javaBrowseBtn_clicked();
|
||||
void on_maxMemSpinBox_valueChanged(int i);
|
||||
void on_serverJoinAddressButton_toggled(bool checked);
|
||||
void on_worldJoinButton_toggled(bool checked);
|
||||
|
||||
void onUseNativeGLFWChanged(bool checked);
|
||||
void onUseNativeOpenALChanged(bool checked);
|
||||
|
||||
void applySettings();
|
||||
void loadSettings();
|
||||
|
||||
void checkerFinished();
|
||||
|
||||
void globalSettingsButtonClicked(bool checked);
|
||||
|
||||
void updateAccountsMenu();
|
||||
QIcon getFaceForAccount(MinecraftAccountPtr account);
|
||||
void changeInstanceAccount(int index);
|
||||
|
||||
private:
|
||||
Ui::InstanceSettingsPage* ui;
|
||||
BaseInstance* m_instance;
|
||||
SettingsObjectPtr m_settings;
|
||||
unique_qobject_ptr<JavaCommon::TestCheck> checker;
|
||||
bool m_world_quickplay_supported;
|
||||
explicit InstanceSettingsPage(MinecraftInstancePtr instance, QWidget* parent = nullptr) : MinecraftSettingsWidget(std::move(instance), parent)
|
||||
{
|
||||
connect(APPLICATION, &Application::globalSettingsAboutToOpen, this, &InstanceSettingsPage::saveSettings);
|
||||
connect(APPLICATION, &Application::globalSettingsClosed, this, &InstanceSettingsPage::loadSettings);
|
||||
}
|
||||
~InstanceSettingsPage() override {}
|
||||
QString displayName() const override { return tr("Settings"); }
|
||||
QIcon icon() const override { return APPLICATION->getThemedIcon("instance-settings"); }
|
||||
QString id() const override { return "settings"; }
|
||||
bool apply() override
|
||||
{
|
||||
saveSettings();
|
||||
return true;
|
||||
}
|
||||
QString helpPage() const override { return "Instance-settings"; }
|
||||
};
|
||||
|
@ -1,789 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>InstanceSettingsPage</class>
|
||||
<widget class="QWidget" name="InstanceSettingsPage">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>691</width>
|
||||
<height>581</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QCommandLinkButton" name="openGlobalJavaSettingsButton">
|
||||
<property name="text">
|
||||
<string>Open Global Settings</string>
|
||||
</property>
|
||||
<property name="description">
|
||||
<string>The settings here are overrides for global settings.</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QTabWidget" name="settingsTabs">
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="minecraftPage">
|
||||
<attribute name="title">
|
||||
<string notr="true">Java</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_5">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="javaSettingsGroupBox">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Java insta&llation</string>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="4" column="0">
|
||||
<widget class="QCheckBox" name="skipCompatibilityCheckbox">
|
||||
<property name="toolTip">
|
||||
<string>If enabled, the launcher will not check if an instance is compatible with the selected Java version.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Skip Java compatibility checks</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QLineEdit" name="javaPathTextBox"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="javaBrowseBtn">
|
||||
<property name="text">
|
||||
<string>Browse</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QPushButton" name="javaDetectBtn">
|
||||
<property name="text">
|
||||
<string>Auto-detect...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="javaTestBtn">
|
||||
<property name="text">
|
||||
<string>Test</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="memoryGroupBox">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Memor&y</string>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<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>PermGen:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="labelMinMem">
|
||||
<property name="text">
|
||||
<string>Minimum memory allocation:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="labelMaxMem">
|
||||
<property name="text">
|
||||
<string>Maximum memory allocation:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<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>
|
||||
</property>
|
||||
<property name="suffix">
|
||||
<string notr="true"> MiB</string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>8</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>1048576</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<number>128</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>256</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<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>8</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>
|
||||
</property>
|
||||
<property name="suffix">
|
||||
<string notr="true"> MiB</string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>999999999</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<number>8</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>64</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="3">
|
||||
<widget class="QLabel" name="labelMaxMemIcon">
|
||||
<property name="text">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>maxMemSpinBox</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="javaArgumentsGroupBox">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Java argumen&ts</string>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_5">
|
||||
<item row="1" column="1">
|
||||
<widget class="QPlainTextEdit" name="jvmArgsTextBox"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="javaPage">
|
||||
<attribute name="title">
|
||||
<string>Game windows</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="windowSizeGroupBox">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Game Window</string>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="maximizedCheckBox">
|
||||
<property name="text">
|
||||
<string>Start Minecraft maximized</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayoutWindowSize">
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="labelWindowHeight">
|
||||
<property name="text">
|
||||
<string>Window height:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="labelWindowWidth">
|
||||
<property name="text">
|
||||
<string>Window width:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QSpinBox" name="windowWidthSpinBox">
|
||||
<property name="minimum">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>65536</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>854</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QSpinBox" name="windowHeightSpinBox">
|
||||
<property name="minimum">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>65536</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>480</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="consoleSettingsBox">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Conso&le Settings</string>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="showConsoleCheck">
|
||||
<property name="text">
|
||||
<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>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="showConsoleErrorCheck">
|
||||
<property name="text">
|
||||
<string>Show console when the game crashes</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="miscellaneousSettingsBox">
|
||||
<property name="title">
|
||||
<string>Miscellaneous</string>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_12">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="closeAfterLaunchCheck">
|
||||
<property name="text">
|
||||
<string>Close the launcher after game window opens</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="quitAfterGameStopCheck">
|
||||
<property name="text">
|
||||
<string>Quit the launcher after game window closes</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacerMinecraft_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>88</width>
|
||||
<height>125</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="customCommandsPage">
|
||||
<attribute name="title">
|
||||
<string>Custom commands</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_6">
|
||||
<item>
|
||||
<widget class="CustomCommands" name="customCommands" native="true"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="environmentVariablesPage">
|
||||
<attribute name="title">
|
||||
<string>Environment variables</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_16">
|
||||
<item>
|
||||
<widget class="EnvironmentVariables" name="environmentVariables" native="true"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="workaroundsPage">
|
||||
<attribute name="title">
|
||||
<string>Workarounds</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_8">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="nativeWorkaroundsGroupBox">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Native libraries</string>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_3">
|
||||
<item row="2" column="0">
|
||||
<widget class="QCheckBox" name="useNativeOpenALCheck">
|
||||
<property name="text">
|
||||
<string>Use system installation of OpenAL</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="labelGLFWPath">
|
||||
<property name="text">
|
||||
<string>&GLFW library path</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>lineEditGLFWPath</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QCheckBox" name="useNativeGLFWCheck">
|
||||
<property name="text">
|
||||
<string>Use system installation of GLFW</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLineEdit" name="lineEditGLFWPath">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="labelOpenALPath">
|
||||
<property name="text">
|
||||
<string>&OpenAL library path</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>lineEditOpenALPath</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QLineEdit" name="lineEditOpenALPath">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="performancePage">
|
||||
<attribute name="title">
|
||||
<string>Performance</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_14">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="perfomanceGroupBox">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Performance</string>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_13">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="enableFeralGamemodeCheck">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Enable Feral Interactive's GameMode, to potentially improve gaming performance.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Enable Feral GameMode</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="enableMangoHud">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Enable MangoHud's advanced performance overlay.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Enable MangoHud</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="useDiscreteGpuCheck">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Use the discrete GPU instead of the primary GPU.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Use discrete GPU</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="useZink">
|
||||
<property name="toolTip">
|
||||
<string>Use Zink, a Mesa OpenGL driver that implements OpenGL on top of Vulkan. Performance may vary depending on the situation. Note: If no suitable Vulkan driver is found, software rendering will be used.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Use Zink</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="miscellaneousPage">
|
||||
<attribute name="title">
|
||||
<string>Miscellaneous</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_9">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="legacySettingsGroupBox">
|
||||
<property name="title">
|
||||
<string>Legacy settings</string>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_17">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="onlineFixes">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Emulates usages of old online services which are no longer operating.</p><p>Current fixes include: skin and online mode support.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Enable online fixes (experimental)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="gameTimeGroupBox">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Override global game time settings</string>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_10">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="showGameTime">
|
||||
<property name="text">
|
||||
<string>Show time spent playing this instance</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="recordGameTime">
|
||||
<property name="text">
|
||||
<string>Record time spent playing this instance</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="serverJoinGroupBox">
|
||||
<property name="title">
|
||||
<string>Set a target to join on launch</string>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_4">
|
||||
<item row="0" column="0">
|
||||
<widget class="QRadioButton" name="serverJoinAddressButton">
|
||||
<property name="text">
|
||||
<string>Server address:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QLineEdit" name="serverJoinAddress"/>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QRadioButton" name="worldJoinButton">
|
||||
<property name="text">
|
||||
<string>Singleplayer world</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QComboBox" name="worldsCb"/>
|
||||
</item>
|
||||
</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">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>CustomCommands</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>ui/widgets/CustomCommands.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>EnvironmentVariables</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>ui/widgets/EnvironmentVariables.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<tabstops>
|
||||
<tabstop>openGlobalJavaSettingsButton</tabstop>
|
||||
<tabstop>settingsTabs</tabstop>
|
||||
<tabstop>javaSettingsGroupBox</tabstop>
|
||||
<tabstop>memoryGroupBox</tabstop>
|
||||
<tabstop>minMemSpinBox</tabstop>
|
||||
<tabstop>maxMemSpinBox</tabstop>
|
||||
<tabstop>permGenSpinBox</tabstop>
|
||||
<tabstop>javaArgumentsGroupBox</tabstop>
|
||||
<tabstop>jvmArgsTextBox</tabstop>
|
||||
<tabstop>windowSizeGroupBox</tabstop>
|
||||
<tabstop>maximizedCheckBox</tabstop>
|
||||
<tabstop>windowWidthSpinBox</tabstop>
|
||||
<tabstop>windowHeightSpinBox</tabstop>
|
||||
<tabstop>consoleSettingsBox</tabstop>
|
||||
<tabstop>showConsoleCheck</tabstop>
|
||||
<tabstop>autoCloseConsoleCheck</tabstop>
|
||||
<tabstop>showConsoleErrorCheck</tabstop>
|
||||
<tabstop>nativeWorkaroundsGroupBox</tabstop>
|
||||
<tabstop>useNativeGLFWCheck</tabstop>
|
||||
<tabstop>useNativeOpenALCheck</tabstop>
|
||||
<tabstop>showGameTime</tabstop>
|
||||
<tabstop>recordGameTime</tabstop>
|
||||
</tabstops>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
@ -3,7 +3,7 @@
|
||||
* 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) 2024 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
|
||||
@ -47,8 +47,8 @@
|
||||
#include "launch/LaunchTask.h"
|
||||
#include "settings/Setting.h"
|
||||
|
||||
#include "ui/ColorCache.h"
|
||||
#include "ui/GuiUtil.h"
|
||||
#include "ui/themes/ThemeManager.h"
|
||||
|
||||
#include <BuildConfig.h>
|
||||
|
||||
@ -57,30 +57,40 @@ class LogFormatProxyModel : public QIdentityProxyModel {
|
||||
LogFormatProxyModel(QObject* parent = nullptr) : QIdentityProxyModel(parent) {}
|
||||
QVariant data(const QModelIndex& index, int role) const override
|
||||
{
|
||||
const LogColors& colors = APPLICATION->themeManager()->getLogColors();
|
||||
|
||||
switch (role) {
|
||||
case Qt::FontRole:
|
||||
return m_font;
|
||||
case Qt::ForegroundRole: {
|
||||
MessageLevel::Enum level = (MessageLevel::Enum)QIdentityProxyModel::data(index, LogModel::LevelRole).toInt();
|
||||
return m_colors->getFront(level);
|
||||
auto level = static_cast<MessageLevel::Enum>(QIdentityProxyModel::data(index, LogModel::LevelRole).toInt());
|
||||
QColor result = colors.foreground.value(level);
|
||||
|
||||
if (result.isValid())
|
||||
return result;
|
||||
|
||||
break;
|
||||
}
|
||||
case Qt::BackgroundRole: {
|
||||
MessageLevel::Enum level = (MessageLevel::Enum)QIdentityProxyModel::data(index, LogModel::LevelRole).toInt();
|
||||
return m_colors->getBack(level);
|
||||
auto level = static_cast<MessageLevel::Enum>(QIdentityProxyModel::data(index, LogModel::LevelRole).toInt());
|
||||
QColor result = colors.background.value(level);
|
||||
|
||||
if (result.isValid())
|
||||
return result;
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return QIdentityProxyModel::data(index, role);
|
||||
}
|
||||
|
||||
return QIdentityProxyModel::data(index, role);
|
||||
}
|
||||
|
||||
void setFont(QFont font) { m_font = font; }
|
||||
|
||||
void setColors(LogColorCache* colors) { m_colors.reset(colors); }
|
||||
|
||||
QModelIndex find(const QModelIndex& start, const QString& value, bool reverse) const
|
||||
{
|
||||
QModelIndex parentIndex = parent(start);
|
||||
auto compare = [&](int r) -> QModelIndex {
|
||||
auto compare = [this, start, parentIndex, value](int r) -> QModelIndex {
|
||||
QModelIndex idx = index(r, start.column(), parentIndex);
|
||||
if (!idx.isValid() || idx == start) {
|
||||
return QModelIndex();
|
||||
@ -125,7 +135,6 @@ class LogFormatProxyModel : public QIdentityProxyModel {
|
||||
|
||||
private:
|
||||
QFont m_font;
|
||||
std::unique_ptr<LogColorCache> m_colors;
|
||||
};
|
||||
|
||||
LogPage::LogPage(InstancePtr instance, QWidget* parent) : QWidget(parent), ui(new Ui::LogPage), m_instance(instance)
|
||||
@ -134,12 +143,6 @@ LogPage::LogPage(InstancePtr instance, QWidget* parent) : QWidget(parent), ui(ne
|
||||
ui->tabWidget->tabBar()->hide();
|
||||
|
||||
m_proxy = new LogFormatProxyModel(this);
|
||||
// set up text colors in the log proxy and adapt them to the current theme foreground and background
|
||||
{
|
||||
auto origForeground = ui->text->palette().color(ui->text->foregroundRole());
|
||||
auto origBackground = ui->text->palette().color(ui->text->backgroundRole());
|
||||
m_proxy->setColors(new LogColorCache(origForeground, origBackground));
|
||||
}
|
||||
|
||||
// set up fonts in the log proxy
|
||||
{
|
||||
@ -231,7 +234,7 @@ bool LogPage::apply()
|
||||
|
||||
bool LogPage::shouldDisplay() const
|
||||
{
|
||||
return m_instance->isRunning() || m_proxy->rowCount() > 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
void LogPage::on_btnPaste_clicked()
|
||||
|
164
launcher/ui/pages/instance/McClient.cpp
Normal file
164
launcher/ui/pages/instance/McClient.cpp
Normal file
@ -0,0 +1,164 @@
|
||||
#include <QObject>
|
||||
#include <QTcpSocket>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <qtconcurrentrun.h>
|
||||
|
||||
#include <Exception.h>
|
||||
#include "McClient.h"
|
||||
#include "Json.h"
|
||||
|
||||
// 7 first bits
|
||||
#define SEGMENT_BITS 0x7F
|
||||
// last bit
|
||||
#define CONTINUE_BIT 0x80
|
||||
|
||||
McClient::McClient(QObject *parent, QString domain, QString ip, short port): QObject(parent), m_domain(domain), m_ip(ip), m_port(port) {}
|
||||
|
||||
void McClient::getStatusData() {
|
||||
qDebug() << "Connecting to socket..";
|
||||
|
||||
connect(&m_socket, &QTcpSocket::connected, this, [this]() {
|
||||
qDebug() << "Connected to socket successfully";
|
||||
sendRequest();
|
||||
|
||||
connect(&m_socket, &QTcpSocket::readyRead, this, &McClient::readRawResponse);
|
||||
});
|
||||
|
||||
connect(&m_socket, &QTcpSocket::errorOccurred, this, [this]() {
|
||||
emitFail("Socket disconnected: " + m_socket.errorString());
|
||||
});
|
||||
|
||||
m_socket.connectToHost(m_ip, m_port);
|
||||
}
|
||||
|
||||
void McClient::sendRequest() {
|
||||
QByteArray data;
|
||||
writeVarInt(data, 0x00); // packet ID
|
||||
writeVarInt(data, 763); // hardcoded protocol version (763 = 1.20.1)
|
||||
writeVarInt(data, m_domain.size()); // server address length
|
||||
writeString(data, m_domain.toStdString()); // server address
|
||||
writeFixedInt(data, m_port, 2); // server port
|
||||
writeVarInt(data, 0x01); // next state
|
||||
writePacketToSocket(data); // send handshake packet
|
||||
|
||||
writeVarInt(data, 0x00); // packet ID
|
||||
writePacketToSocket(data); // send status packet
|
||||
}
|
||||
|
||||
void McClient::readRawResponse() {
|
||||
if (m_responseReadState == 2) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_resp.append(m_socket.readAll());
|
||||
if (m_responseReadState == 0 && m_resp.size() >= 5) {
|
||||
m_wantedRespLength = readVarInt(m_resp);
|
||||
m_responseReadState = 1;
|
||||
}
|
||||
|
||||
if (m_responseReadState == 1 && m_resp.size() >= m_wantedRespLength) {
|
||||
if (m_resp.size() > m_wantedRespLength) {
|
||||
qDebug() << "Warning: Packet length doesn't match actual packet size (" << m_wantedRespLength << " expected vs " << m_resp.size() << " received)";
|
||||
}
|
||||
parseResponse();
|
||||
m_responseReadState = 2;
|
||||
}
|
||||
}
|
||||
|
||||
void McClient::parseResponse() {
|
||||
qDebug() << "Received response successfully";
|
||||
|
||||
int packetID = readVarInt(m_resp);
|
||||
if (packetID != 0x00) {
|
||||
throw Exception(
|
||||
QString("Packet ID doesn't match expected value (0x00 vs 0x%1)")
|
||||
.arg(packetID, 0, 16)
|
||||
);
|
||||
}
|
||||
|
||||
Q_UNUSED(readVarInt(m_resp)); // json length
|
||||
|
||||
// 'resp' should now be the JSON string
|
||||
QJsonDocument doc = QJsonDocument::fromJson(m_resp);
|
||||
emitSucceed(doc.object());
|
||||
}
|
||||
|
||||
// From https://wiki.vg/Protocol#VarInt_and_VarLong
|
||||
void McClient::writeVarInt(QByteArray &data, int value) {
|
||||
while ((value & ~SEGMENT_BITS)) { // check if the value is too big to fit in 7 bits
|
||||
// Write 7 bits
|
||||
data.append((value & SEGMENT_BITS) | CONTINUE_BIT);
|
||||
|
||||
// Erase theses 7 bits from the value to write
|
||||
// Note: >>> means that the sign bit is shifted with the rest of the number rather than being left alone
|
||||
value >>= 7;
|
||||
}
|
||||
data.append(value);
|
||||
}
|
||||
|
||||
// From https://wiki.vg/Protocol#VarInt_and_VarLong
|
||||
int McClient::readVarInt(QByteArray &data) {
|
||||
int value = 0;
|
||||
int position = 0;
|
||||
char currentByte;
|
||||
|
||||
while (position < 32) {
|
||||
currentByte = readByte(data);
|
||||
value |= (currentByte & SEGMENT_BITS) << position;
|
||||
|
||||
if ((currentByte & CONTINUE_BIT) == 0) break;
|
||||
|
||||
position += 7;
|
||||
}
|
||||
|
||||
if (position >= 32) throw Exception("VarInt is too big");
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
char McClient::readByte(QByteArray &data) {
|
||||
if (data.isEmpty()) {
|
||||
throw Exception("No more bytes to read");
|
||||
}
|
||||
|
||||
char byte = data.at(0);
|
||||
data.remove(0, 1);
|
||||
return byte;
|
||||
}
|
||||
|
||||
// write number with specified size in big endian format
|
||||
void McClient::writeFixedInt(QByteArray &data, int value, int size) {
|
||||
for (int i = size - 1; i >= 0; i--) {
|
||||
data.append((value >> (i * 8)) & 0xFF);
|
||||
}
|
||||
}
|
||||
|
||||
void McClient::writeString(QByteArray &data, const std::string &value) {
|
||||
data.append(value.c_str());
|
||||
}
|
||||
|
||||
void McClient::writePacketToSocket(QByteArray &data) {
|
||||
// we prefix the packet with its length
|
||||
QByteArray dataWithSize;
|
||||
writeVarInt(dataWithSize, data.size());
|
||||
dataWithSize.append(data);
|
||||
|
||||
// write it to the socket
|
||||
m_socket.write(dataWithSize);
|
||||
m_socket.flush();
|
||||
|
||||
data.clear();
|
||||
}
|
||||
|
||||
|
||||
void McClient::emitFail(QString error) {
|
||||
qDebug() << "Minecraft server ping for status error:" << error;
|
||||
emit failed(error);
|
||||
emit finished();
|
||||
}
|
||||
|
||||
void McClient::emitSucceed(QJsonObject data) {
|
||||
emit succeeded(data);
|
||||
emit finished();
|
||||
}
|
51
launcher/ui/pages/instance/McClient.h
Normal file
51
launcher/ui/pages/instance/McClient.h
Normal file
@ -0,0 +1,51 @@
|
||||
#include <QObject>
|
||||
#include <QTcpSocket>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QFuture>
|
||||
|
||||
#include <Exception.h>
|
||||
|
||||
// Client for the Minecraft protocol
|
||||
class McClient : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
QString m_domain;
|
||||
QString m_ip;
|
||||
short m_port;
|
||||
QTcpSocket m_socket;
|
||||
|
||||
// 0: did not start reading the response yet
|
||||
// 1: read the response length, still reading the response
|
||||
// 2: finished reading the response
|
||||
unsigned m_responseReadState = 0;
|
||||
unsigned m_wantedRespLength = 0;
|
||||
QByteArray m_resp;
|
||||
|
||||
public:
|
||||
explicit McClient(QObject *parent, QString domain, QString ip, short port);
|
||||
//! Read status data of the server, and calls the succeeded() signal with the parsed JSON data
|
||||
void getStatusData();
|
||||
private:
|
||||
void sendRequest();
|
||||
//! Accumulate data until we have a full response, then call parseResponse() once
|
||||
void readRawResponse();
|
||||
void parseResponse();
|
||||
|
||||
void writeVarInt(QByteArray &data, int value);
|
||||
int readVarInt(QByteArray &data);
|
||||
char readByte(QByteArray &data);
|
||||
//! write number with specified size in big endian format
|
||||
void writeFixedInt(QByteArray &data, int value, int size);
|
||||
void writeString(QByteArray &data, const std::string &value);
|
||||
|
||||
void writePacketToSocket(QByteArray &data);
|
||||
|
||||
void emitFail(QString error);
|
||||
void emitSucceed(QJsonObject data);
|
||||
|
||||
signals:
|
||||
void succeeded(QJsonObject data);
|
||||
void failed(QString error);
|
||||
void finished();
|
||||
};
|
73
launcher/ui/pages/instance/McResolver.cpp
Normal file
73
launcher/ui/pages/instance/McResolver.cpp
Normal file
@ -0,0 +1,73 @@
|
||||
#include <QObject>
|
||||
#include <QDnsLookup>
|
||||
#include <QtNetwork/qtcpsocket.h>
|
||||
#include <QHostInfo>
|
||||
|
||||
#include "McResolver.h"
|
||||
|
||||
McResolver::McResolver(QObject *parent, QString domain, int port): QObject(parent), m_constrDomain(domain), m_constrPort(port) {}
|
||||
|
||||
void McResolver::ping() {
|
||||
pingWithDomainSRV(m_constrDomain, m_constrPort);
|
||||
}
|
||||
|
||||
void McResolver::pingWithDomainSRV(QString domain, int port) {
|
||||
QDnsLookup *lookup = new QDnsLookup(this);
|
||||
lookup->setName(QString("_minecraft._tcp.%1").arg(domain));
|
||||
lookup->setType(QDnsLookup::SRV);
|
||||
|
||||
connect(lookup, &QDnsLookup::finished, this, [this, domain, port]() {
|
||||
QDnsLookup *lookup = qobject_cast<QDnsLookup *>(sender());
|
||||
|
||||
lookup->deleteLater();
|
||||
|
||||
if (lookup->error() != QDnsLookup::NoError) {
|
||||
qDebug() << QString("Warning: SRV record lookup failed (%1), trying A record lookup").arg(lookup->errorString());
|
||||
pingWithDomainA(domain, port);
|
||||
return;
|
||||
}
|
||||
|
||||
auto records = lookup->serviceRecords();
|
||||
if (records.isEmpty()) {
|
||||
qDebug() << "Warning: no SRV entries found for domain, trying A record lookup";
|
||||
pingWithDomainA(domain, port);
|
||||
return;
|
||||
}
|
||||
|
||||
const auto& firstRecord = records.at(0);
|
||||
QString domain = firstRecord.target();
|
||||
int port = firstRecord.port();
|
||||
pingWithDomainA(domain, port);
|
||||
});
|
||||
|
||||
lookup->lookup();
|
||||
}
|
||||
|
||||
void McResolver::pingWithDomainA(QString domain, int port) {
|
||||
QHostInfo::lookupHost(domain, this, [this, port](const QHostInfo &hostInfo){
|
||||
if (hostInfo.error() != QHostInfo::NoError) {
|
||||
emitFail("A record lookup failed");
|
||||
return;
|
||||
}
|
||||
|
||||
auto records = hostInfo.addresses();
|
||||
if (records.isEmpty()) {
|
||||
emitFail("No A entries found for domain");
|
||||
return;
|
||||
}
|
||||
|
||||
const auto& firstRecord = records.at(0);
|
||||
emitSucceed(firstRecord.toString(), port);
|
||||
});
|
||||
}
|
||||
|
||||
void McResolver::emitFail(QString error) {
|
||||
qDebug() << "DNS resolver error:" << error;
|
||||
emit failed(error);
|
||||
emit finished();
|
||||
}
|
||||
|
||||
void McResolver::emitSucceed(QString ip, int port) {
|
||||
emit succeeded(ip, port);
|
||||
emit finished();
|
||||
}
|
28
launcher/ui/pages/instance/McResolver.h
Normal file
28
launcher/ui/pages/instance/McResolver.h
Normal file
@ -0,0 +1,28 @@
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <QDnsLookup>
|
||||
#include <QtNetwork/qtcpsocket.h>
|
||||
#include <QHostInfo>
|
||||
|
||||
// resolve the IP and port of a Minecraft server
|
||||
class McResolver : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
QString m_constrDomain;
|
||||
int m_constrPort;
|
||||
|
||||
public:
|
||||
explicit McResolver(QObject *parent, QString domain, int port);
|
||||
void ping();
|
||||
|
||||
private:
|
||||
void pingWithDomainSRV(QString domain, int port);
|
||||
void pingWithDomainA(QString domain, int port);
|
||||
void emitFail(QString error);
|
||||
void emitSucceed(QString ip, int port);
|
||||
|
||||
signals:
|
||||
void succeeded(QString ip, int port);
|
||||
void failed(QString error);
|
||||
void finished();
|
||||
};
|
@ -51,117 +51,60 @@
|
||||
|
||||
#include "Application.h"
|
||||
|
||||
#include "ui/GuiUtil.h"
|
||||
#include "ui/dialogs/CustomMessageBox.h"
|
||||
#include "ui/dialogs/ModUpdateDialog.h"
|
||||
#include "ui/dialogs/ResourceDownloadDialog.h"
|
||||
|
||||
#include "DesktopServices.h"
|
||||
#include "ui/dialogs/ResourceUpdateDialog.h"
|
||||
|
||||
#include "minecraft/PackProfile.h"
|
||||
#include "minecraft/VersionFilterData.h"
|
||||
#include "minecraft/mod/Mod.h"
|
||||
#include "minecraft/mod/ModFolderModel.h"
|
||||
|
||||
#include "modplatform/ModIndex.h"
|
||||
#include "modplatform/ResourceAPI.h"
|
||||
|
||||
#include "Version.h"
|
||||
#include "tasks/ConcurrentTask.h"
|
||||
#include "tasks/Task.h"
|
||||
#include "ui/dialogs/ProgressDialog.h"
|
||||
|
||||
ModFolderPage::ModFolderPage(BaseInstance* inst, std::shared_ptr<ModFolderModel> mods, QWidget* parent)
|
||||
: ExternalResourcesPage(inst, mods, parent), m_model(mods)
|
||||
ModFolderPage::ModFolderPage(BaseInstance* inst, std::shared_ptr<ModFolderModel> model, QWidget* parent)
|
||||
: ExternalResourcesPage(inst, model, parent), m_model(model)
|
||||
{
|
||||
// This is structured like that so that these changes
|
||||
// do not affect the Resource pack and Shader pack tabs
|
||||
{
|
||||
ui->actionDownloadItem->setText(tr("Download mods"));
|
||||
ui->actionDownloadItem->setToolTip(tr("Download mods from online mod platforms"));
|
||||
ui->actionDownloadItem->setEnabled(true);
|
||||
ui->actionAddItem->setText(tr("Add file"));
|
||||
ui->actionAddItem->setToolTip(tr("Add a locally downloaded file"));
|
||||
ui->actionDownloadItem->setText(tr("Download Mods"));
|
||||
ui->actionDownloadItem->setToolTip(tr("Download mods from online mod platforms"));
|
||||
ui->actionDownloadItem->setEnabled(true);
|
||||
ui->actionsToolbar->insertActionBefore(ui->actionAddItem, ui->actionDownloadItem);
|
||||
|
||||
ui->actionsToolbar->insertActionBefore(ui->actionAddItem, ui->actionDownloadItem);
|
||||
connect(ui->actionDownloadItem, &QAction::triggered, this, &ModFolderPage::downloadMods);
|
||||
|
||||
connect(ui->actionDownloadItem, &QAction::triggered, this, &ModFolderPage::installMods);
|
||||
ui->actionUpdateItem->setToolTip(tr("Try to check or update all selected mods (all mods if none are selected)"));
|
||||
connect(ui->actionUpdateItem, &QAction::triggered, this, &ModFolderPage::updateMods);
|
||||
ui->actionsToolbar->insertActionBefore(ui->actionAddItem, ui->actionUpdateItem);
|
||||
|
||||
// update menu
|
||||
auto updateMenu = ui->actionUpdateItem->menu();
|
||||
if (updateMenu) {
|
||||
updateMenu->clear();
|
||||
} else {
|
||||
updateMenu = new QMenu(this);
|
||||
}
|
||||
auto updateMenu = new QMenu(this);
|
||||
|
||||
auto update = updateMenu->addAction(tr("Check for Updates"));
|
||||
update->setToolTip(tr("Try to check or update all selected mods (all mods if none are selected)"));
|
||||
connect(update, &QAction::triggered, this, &ModFolderPage::updateMods);
|
||||
auto update = updateMenu->addAction(tr("Check for Updates"));
|
||||
connect(update, &QAction::triggered, this, &ModFolderPage::updateMods);
|
||||
|
||||
auto updateWithDeps = updateMenu->addAction(tr("Verify Dependencies"));
|
||||
updateWithDeps->setToolTip(
|
||||
tr("Try to update and check for missing dependencies all selected mods (all mods if none are selected)"));
|
||||
connect(updateWithDeps, &QAction::triggered, this, [this] { updateMods(true); });
|
||||
updateMenu->addAction(ui->actionVerifyItemDependencies);
|
||||
connect(ui->actionVerifyItemDependencies, &QAction::triggered, this, [this] { updateMods(true); });
|
||||
|
||||
auto depsDisabled = APPLICATION->settings()->getSetting("ModDependenciesDisabled");
|
||||
updateWithDeps->setVisible(!depsDisabled->get().toBool());
|
||||
connect(depsDisabled.get(), &Setting::SettingChanged, this,
|
||||
[updateWithDeps](const Setting& setting, QVariant value) { updateWithDeps->setVisible(!value.toBool()); });
|
||||
auto depsDisabled = APPLICATION->settings()->getSetting("ModDependenciesDisabled");
|
||||
ui->actionVerifyItemDependencies->setVisible(!depsDisabled->get().toBool());
|
||||
connect(depsDisabled.get(), &Setting::SettingChanged, this,
|
||||
[this](const Setting& setting, const QVariant& value) { ui->actionVerifyItemDependencies->setVisible(!value.toBool()); });
|
||||
|
||||
auto actionRemoveItemMetadata = updateMenu->addAction(tr("Reset update metadata"));
|
||||
actionRemoveItemMetadata->setToolTip(tr("Remove mod's metadata"));
|
||||
connect(actionRemoveItemMetadata, &QAction::triggered, this, &ModFolderPage::deleteModMetadata);
|
||||
actionRemoveItemMetadata->setEnabled(false);
|
||||
updateMenu->addAction(ui->actionResetItemMetadata);
|
||||
connect(ui->actionResetItemMetadata, &QAction::triggered, this, &ModFolderPage::deleteModMetadata);
|
||||
|
||||
ui->actionUpdateItem->setMenu(updateMenu);
|
||||
ui->actionUpdateItem->setMenu(updateMenu);
|
||||
|
||||
ui->actionUpdateItem->setToolTip(tr("Try to check or update all selected mods (all mods if none are selected)"));
|
||||
connect(ui->actionUpdateItem, &QAction::triggered, this, &ModFolderPage::updateMods);
|
||||
ui->actionsToolbar->insertActionBefore(ui->actionAddItem, ui->actionUpdateItem);
|
||||
ui->actionChangeVersion->setToolTip(tr("Change a mod's version."));
|
||||
connect(ui->actionChangeVersion, &QAction::triggered, this, &ModFolderPage::changeModVersion);
|
||||
ui->actionsToolbar->insertActionAfter(ui->actionUpdateItem, ui->actionChangeVersion);
|
||||
|
||||
ui->actionVisitItemPage->setToolTip(tr("Go to mod's home page"));
|
||||
ui->actionsToolbar->addAction(ui->actionVisitItemPage);
|
||||
connect(ui->actionVisitItemPage, &QAction::triggered, this, &ModFolderPage::visitModPages);
|
||||
ui->actionViewHomepage->setToolTip(tr("View the homepages of all selected mods."));
|
||||
|
||||
auto changeVersion = new QAction(tr("Change Version"));
|
||||
changeVersion->setToolTip(tr("Change mod version"));
|
||||
changeVersion->setEnabled(false);
|
||||
ui->actionsToolbar->insertActionAfter(ui->actionUpdateItem, changeVersion);
|
||||
connect(changeVersion, &QAction::triggered, this, &ModFolderPage::changeModVersion);
|
||||
|
||||
ui->actionsToolbar->insertActionAfter(ui->actionVisitItemPage, ui->actionExportMetadata);
|
||||
connect(ui->actionExportMetadata, &QAction::triggered, this, &ModFolderPage::exportModMetadata);
|
||||
|
||||
auto check_allow_update = [this] { return ui->treeView->selectionModel()->hasSelection() || !m_model->empty(); };
|
||||
|
||||
connect(ui->treeView->selectionModel(), &QItemSelectionModel::selectionChanged, this,
|
||||
[this, check_allow_update, actionRemoveItemMetadata, changeVersion] {
|
||||
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"));
|
||||
}
|
||||
|
||||
changeVersion->setEnabled(mods_list.length() == 1 && mods_list[0]->metadata() != nullptr);
|
||||
ui->actionVisitItemPage->setEnabled(selected != 0);
|
||||
actionRemoveItemMetadata->setEnabled(selected != 0);
|
||||
});
|
||||
|
||||
auto updateButtons = [this, check_allow_update] { ui->actionUpdateItem->setEnabled(check_allow_update()); };
|
||||
connect(mods.get(), &ModFolderModel::rowsInserted, this, updateButtons);
|
||||
|
||||
connect(mods.get(), &ModFolderModel::rowsRemoved, this, updateButtons);
|
||||
|
||||
connect(mods.get(), &ModFolderModel::updateFinished, this, updateButtons);
|
||||
}
|
||||
ui->actionExportMetadata->setToolTip(tr("Export mod's metadata to text."));
|
||||
connect(ui->actionExportMetadata, &QAction::triggered, this, &ModFolderPage::exportModMetadata);
|
||||
ui->actionsToolbar->insertActionAfter(ui->actionViewHomepage, ui->actionExportMetadata);
|
||||
}
|
||||
|
||||
bool ModFolderPage::shouldDisplay() const
|
||||
@ -169,15 +112,12 @@ bool ModFolderPage::shouldDisplay() const
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ModFolderPage::onSelectionChanged(const QModelIndex& current, [[maybe_unused]] const QModelIndex& previous)
|
||||
void ModFolderPage::updateFrame(const QModelIndex& current, [[maybe_unused]] const QModelIndex& previous)
|
||||
{
|
||||
auto sourceCurrent = m_filterModel->mapToSource(current);
|
||||
int row = sourceCurrent.row();
|
||||
Mod const* m = m_model->at(row);
|
||||
if (m)
|
||||
ui->frame->updateWithMod(*m);
|
||||
|
||||
return true;
|
||||
const Mod& mod = m_model->at(row);
|
||||
ui->frame->updateWithMod(mod);
|
||||
}
|
||||
|
||||
void ModFolderPage::removeItems(const QItemSelection& selection)
|
||||
@ -192,10 +132,10 @@ void ModFolderPage::removeItems(const QItemSelection& selection)
|
||||
if (response != QMessageBox::Yes)
|
||||
return;
|
||||
}
|
||||
m_model->deleteMods(selection.indexes());
|
||||
m_model->deleteResources(selection.indexes());
|
||||
}
|
||||
|
||||
void ModFolderPage::installMods()
|
||||
void ModFolderPage::downloadMods()
|
||||
{
|
||||
if (m_instance->typeName() != "Minecraft")
|
||||
return; // this is a null instance or a legacy instance
|
||||
@ -208,7 +148,7 @@ void ModFolderPage::installMods()
|
||||
|
||||
ResourceDownload::ModDownloadDialog mdownload(this, m_model, m_instance);
|
||||
if (mdownload.exec()) {
|
||||
auto tasks = new ConcurrentTask(this, "Download Mods", APPLICATION->settings()->get("NumberOfConcurrentDownloads").toInt());
|
||||
auto tasks = new ConcurrentTask(tr("Download Mods"), APPLICATION->settings()->get("NumberOfConcurrentDownloads").toInt());
|
||||
connect(tasks, &Task::failed, [this, tasks](QString reason) {
|
||||
CustomMessageBox::selectable(this, tr("Error"), reason, QMessageBox::Critical)->show();
|
||||
tasks->deleteLater();
|
||||
@ -265,12 +205,12 @@ void ModFolderPage::updateMods(bool includeDeps)
|
||||
}
|
||||
auto selection = m_filterModel->mapSelectionToSource(ui->treeView->selectionModel()->selection()).indexes();
|
||||
|
||||
auto mods_list = m_model->selectedMods(selection);
|
||||
auto mods_list = m_model->selectedResources(selection);
|
||||
bool use_all = mods_list.empty();
|
||||
if (use_all)
|
||||
mods_list = m_model->allMods();
|
||||
mods_list = m_model->allResources();
|
||||
|
||||
ModUpdateDialog update_dialog(this, m_instance, m_model, mods_list, includeDeps);
|
||||
ResourceUpdateDialog update_dialog(this, m_instance, m_model, mods_list, includeDeps, true);
|
||||
update_dialog.checkCandidates();
|
||||
|
||||
if (update_dialog.aborted()) {
|
||||
@ -291,7 +231,7 @@ void ModFolderPage::updateMods(bool includeDeps)
|
||||
}
|
||||
|
||||
if (update_dialog.exec()) {
|
||||
auto tasks = new ConcurrentTask(this, "Download Mods", APPLICATION->settings()->get("NumberOfConcurrentDownloads").toInt());
|
||||
auto tasks = new ConcurrentTask("Download Mods", APPLICATION->settings()->get("NumberOfConcurrentDownloads").toInt());
|
||||
connect(tasks, &Task::failed, [this, tasks](QString reason) {
|
||||
CustomMessageBox::selectable(this, tr("Error"), reason, QMessageBox::Critical)->show();
|
||||
tasks->deleteLater();
|
||||
@ -320,50 +260,6 @@ void ModFolderPage::updateMods(bool includeDeps)
|
||||
}
|
||||
}
|
||||
|
||||
CoreModFolderPage::CoreModFolderPage(BaseInstance* inst, std::shared_ptr<ModFolderModel> mods, QWidget* parent)
|
||||
: ModFolderPage(inst, mods, parent)
|
||||
{}
|
||||
|
||||
bool CoreModFolderPage::shouldDisplay() const
|
||||
{
|
||||
if (ModFolderPage::shouldDisplay()) {
|
||||
auto inst = dynamic_cast<MinecraftInstance*>(m_instance);
|
||||
if (!inst)
|
||||
return true;
|
||||
|
||||
auto version = inst->getPackProfile();
|
||||
|
||||
if (!version)
|
||||
return true;
|
||||
if (!version->getComponent("net.minecraftforge"))
|
||||
return false;
|
||||
if (!version->getComponent("net.minecraft"))
|
||||
return false;
|
||||
if (version->getComponent("net.minecraft")->getReleaseDateTime() < g_VersionFilterData.legacyCutoffDate)
|
||||
return true;
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
void ModFolderPage::deleteModMetadata()
|
||||
{
|
||||
auto selection = m_filterModel->mapSelectionToSource(ui->treeView->selectionModel()->selection()).indexes();
|
||||
@ -382,7 +278,7 @@ void ModFolderPage::deleteModMetadata()
|
||||
return;
|
||||
}
|
||||
|
||||
m_model->deleteModsMetadata(selection);
|
||||
m_model->deleteMetadata(selection);
|
||||
}
|
||||
|
||||
void ModFolderPage::changeModVersion()
|
||||
@ -405,9 +301,9 @@ void ModFolderPage::changeModVersion()
|
||||
return;
|
||||
|
||||
ResourceDownload::ModDownloadDialog mdownload(this, m_model, m_instance);
|
||||
mdownload.setModMetadata((*mods_list.begin())->metadata());
|
||||
mdownload.setResourceMetadata((*mods_list.begin())->metadata());
|
||||
if (mdownload.exec()) {
|
||||
auto tasks = new ConcurrentTask(this, "Download Mods", APPLICATION->settings()->get("NumberOfConcurrentDownloads").toInt());
|
||||
auto tasks = new ConcurrentTask("Download Mods", APPLICATION->settings()->get("NumberOfConcurrentDownloads").toInt());
|
||||
connect(tasks, &Task::failed, [this, tasks](QString reason) {
|
||||
CustomMessageBox::selectable(this, tr("Error"), reason, QMessageBox::Critical)->show();
|
||||
tasks->deleteLater();
|
||||
@ -447,3 +343,52 @@ void ModFolderPage::exportModMetadata()
|
||||
ExportToModListDialog dlg(m_instance->name(), selectedMods, this);
|
||||
dlg.exec();
|
||||
}
|
||||
|
||||
CoreModFolderPage::CoreModFolderPage(BaseInstance* inst, std::shared_ptr<ModFolderModel> mods, QWidget* parent)
|
||||
: ModFolderPage(inst, mods, parent)
|
||||
{
|
||||
auto mcInst = dynamic_cast<MinecraftInstance*>(m_instance);
|
||||
if (mcInst) {
|
||||
auto version = mcInst->getPackProfile();
|
||||
if (version && version->getComponent("net.minecraftforge") && version->getComponent("net.minecraft")) {
|
||||
auto minecraftCmp = version->getComponent("net.minecraft");
|
||||
if (!minecraftCmp->m_loaded) {
|
||||
version->reload(Net::Mode::Offline);
|
||||
auto update = version->getCurrentTask();
|
||||
if (update) {
|
||||
connect(update.get(), &Task::finished, this, [this] {
|
||||
if (m_container) {
|
||||
m_container->refreshContainer();
|
||||
}
|
||||
});
|
||||
update->start();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool CoreModFolderPage::shouldDisplay() const
|
||||
{
|
||||
if (ModFolderPage::shouldDisplay()) {
|
||||
auto inst = dynamic_cast<MinecraftInstance*>(m_instance);
|
||||
if (!inst)
|
||||
return true;
|
||||
|
||||
auto version = inst->getPackProfile();
|
||||
if (!version || !version->getComponent("net.minecraftforge") || !version->getComponent("net.minecraft"))
|
||||
return false;
|
||||
auto minecraftCmp = version->getComponent("net.minecraft");
|
||||
return minecraftCmp->m_loaded && minecraftCmp->getReleaseDateTime() < g_VersionFilterData.legacyCutoffDate;
|
||||
}
|
||||
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();
|
||||
}
|
||||
|
@ -44,7 +44,7 @@ class ModFolderPage : public ExternalResourcesPage {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ModFolderPage(BaseInstance* inst, std::shared_ptr<ModFolderModel> mods, QWidget* parent = nullptr);
|
||||
explicit ModFolderPage(BaseInstance* inst, std::shared_ptr<ModFolderModel> model, QWidget* parent = nullptr);
|
||||
virtual ~ModFolderPage() = default;
|
||||
|
||||
void setFilter(const QString& filter) { m_fileSelectionFilter = filter; }
|
||||
@ -57,16 +57,15 @@ class ModFolderPage : public ExternalResourcesPage {
|
||||
virtual bool shouldDisplay() const override;
|
||||
|
||||
public slots:
|
||||
bool onSelectionChanged(const QModelIndex& current, const QModelIndex& previous) override;
|
||||
void updateFrame(const QModelIndex& current, const QModelIndex& previous) override;
|
||||
|
||||
private slots:
|
||||
void removeItems(const QItemSelection& selection) override;
|
||||
|
||||
void downloadMods();
|
||||
void updateMods(bool includeDeps = false);
|
||||
void deleteModMetadata();
|
||||
void exportModMetadata();
|
||||
|
||||
void installMods();
|
||||
void updateMods(bool includeDeps = false);
|
||||
void visitModPages();
|
||||
void changeModVersion();
|
||||
|
||||
protected:
|
||||
@ -74,6 +73,7 @@ class ModFolderPage : public ExternalResourcesPage {
|
||||
};
|
||||
|
||||
class CoreModFolderPage : public ModFolderPage {
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit CoreModFolderPage(BaseInstance* inst, std::shared_ptr<ModFolderModel> mods, QWidget* parent = 0);
|
||||
virtual ~CoreModFolderPage() = default;
|
||||
@ -87,6 +87,7 @@ class CoreModFolderPage : public ModFolderPage {
|
||||
};
|
||||
|
||||
class NilModFolderPage : public ModFolderPage {
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit NilModFolderPage(BaseInstance* inst, std::shared_ptr<ModFolderModel> mods, QWidget* parent = 0);
|
||||
virtual ~NilModFolderPage() = default;
|
||||
|
@ -138,7 +138,7 @@ void OtherLogsPage::on_btnReload_clicked()
|
||||
m_currentFile = QString();
|
||||
QMessageBox::critical(this, tr("Error"), tr("Unable to open %1 for reading: %2").arg(m_currentFile, file.errorString()));
|
||||
} else {
|
||||
auto setPlainText = [&](const QString& text) {
|
||||
auto setPlainText = [this](const QString& text) {
|
||||
QString fontFamily = APPLICATION->settings()->get("ConsoleFont").toString();
|
||||
bool conversionOk = false;
|
||||
int fontSize = APPLICATION->settings()->get("ConsoleFontSize").toInt(&conversionOk);
|
||||
@ -149,7 +149,7 @@ void OtherLogsPage::on_btnReload_clicked()
|
||||
doc->setDefaultFont(QFont(fontFamily, fontSize));
|
||||
ui->text->setPlainText(text);
|
||||
};
|
||||
auto showTooBig = [&]() {
|
||||
auto showTooBig = [setPlainText, &file]() {
|
||||
setPlainText(tr("The file (%1) is too big. You may want to open it in a viewer optimized "
|
||||
"for large files.")
|
||||
.arg(file.fileName()));
|
||||
|
@ -37,43 +37,56 @@
|
||||
|
||||
#include "ResourcePackPage.h"
|
||||
|
||||
#include "ResourceDownloadTask.h"
|
||||
|
||||
#include "ui/dialogs/CustomMessageBox.h"
|
||||
#include "ui/dialogs/ProgressDialog.h"
|
||||
#include "ui/dialogs/ResourceDownloadDialog.h"
|
||||
#include "ui/dialogs/ResourceUpdateDialog.h"
|
||||
|
||||
ResourcePackPage::ResourcePackPage(MinecraftInstance* instance, std::shared_ptr<ResourcePackFolderModel> model, QWidget* parent)
|
||||
: ExternalResourcesPage(instance, model, parent)
|
||||
: ExternalResourcesPage(instance, model, parent), m_model(model)
|
||||
{
|
||||
ui->actionDownloadItem->setText(tr("Download packs"));
|
||||
ui->actionDownloadItem->setToolTip(tr("Download resource packs from online platforms"));
|
||||
ui->actionDownloadItem->setText(tr("Download Packs"));
|
||||
ui->actionDownloadItem->setToolTip(tr("Download resource packs from online mod platforms"));
|
||||
ui->actionDownloadItem->setEnabled(true);
|
||||
connect(ui->actionDownloadItem, &QAction::triggered, this, &ResourcePackPage::downloadRPs);
|
||||
ui->actionsToolbar->insertActionBefore(ui->actionAddItem, ui->actionDownloadItem);
|
||||
|
||||
ui->actionViewConfigs->setVisible(false);
|
||||
connect(ui->actionDownloadItem, &QAction::triggered, this, &ResourcePackPage::downloadResourcePacks);
|
||||
|
||||
ui->actionUpdateItem->setToolTip(tr("Try to check or update all selected resource packs (all resource packs if none are selected)"));
|
||||
connect(ui->actionUpdateItem, &QAction::triggered, this, &ResourcePackPage::updateResourcePacks);
|
||||
ui->actionsToolbar->insertActionBefore(ui->actionAddItem, ui->actionUpdateItem);
|
||||
|
||||
auto updateMenu = new QMenu(this);
|
||||
|
||||
auto update = updateMenu->addAction(ui->actionUpdateItem->text());
|
||||
connect(update, &QAction::triggered, this, &ResourcePackPage::updateResourcePacks);
|
||||
|
||||
updateMenu->addAction(ui->actionResetItemMetadata);
|
||||
connect(ui->actionResetItemMetadata, &QAction::triggered, this, &ResourcePackPage::deleteResourcePackMetadata);
|
||||
|
||||
ui->actionUpdateItem->setMenu(updateMenu);
|
||||
|
||||
ui->actionChangeVersion->setToolTip(tr("Change a mod's version."));
|
||||
connect(ui->actionChangeVersion, &QAction::triggered, this, &ResourcePackPage::changeResourcePackVersion);
|
||||
ui->actionsToolbar->insertActionAfter(ui->actionUpdateItem, ui->actionChangeVersion);
|
||||
}
|
||||
|
||||
bool ResourcePackPage::onSelectionChanged(const QModelIndex& current, [[maybe_unused]] const QModelIndex& previous)
|
||||
void ResourcePackPage::updateFrame(const QModelIndex& current, [[maybe_unused]] 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()
|
||||
void ResourcePackPage::downloadResourcePacks()
|
||||
{
|
||||
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);
|
||||
ResourceDownload::ResourcePackDownloadDialog mdownload(this, m_model, m_instance);
|
||||
if (mdownload.exec()) {
|
||||
auto tasks =
|
||||
new ConcurrentTask(this, "Download Resource Pack", APPLICATION->settings()->get("NumberOfConcurrentDownloads").toInt());
|
||||
auto tasks = new ConcurrentTask("Download Resource Pack", APPLICATION->settings()->get("NumberOfConcurrentDownloads").toInt());
|
||||
connect(tasks, &Task::failed, [this, tasks](QString reason) {
|
||||
CustomMessageBox::selectable(this, tr("Error"), reason, QMessageBox::Critical)->show();
|
||||
tasks->deleteLater();
|
||||
@ -101,3 +114,155 @@ void ResourcePackPage::downloadRPs()
|
||||
m_model->update();
|
||||
}
|
||||
}
|
||||
|
||||
void ResourcePackPage::updateResourcePacks()
|
||||
{
|
||||
if (m_instance->typeName() != "Minecraft")
|
||||
return; // this is a null instance or a legacy instance
|
||||
|
||||
auto profile = static_cast<MinecraftInstance*>(m_instance)->getPackProfile();
|
||||
if (APPLICATION->settings()->get("ModMetadataDisabled").toBool()) {
|
||||
QMessageBox::critical(this, tr("Error"), tr("Resource pack updates are unavailable when metadata is disabled!"));
|
||||
return;
|
||||
}
|
||||
if (m_instance != nullptr && m_instance->isRunning()) {
|
||||
auto response = CustomMessageBox::selectable(
|
||||
this, tr("Confirm Update"),
|
||||
tr("Updating resource packs while the game is running may cause pack duplication and game crashes.\n"
|
||||
"The old files may not be deleted as they are in use.\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()).indexes();
|
||||
|
||||
auto mods_list = m_model->selectedResources(selection);
|
||||
bool use_all = mods_list.empty();
|
||||
if (use_all)
|
||||
mods_list = m_model->allResources();
|
||||
|
||||
ResourceUpdateDialog update_dialog(this, m_instance, m_model, mods_list, false, false);
|
||||
update_dialog.checkCandidates();
|
||||
|
||||
if (update_dialog.aborted()) {
|
||||
CustomMessageBox::selectable(this, tr("Aborted"), tr("The resource pack updater was aborted!"), QMessageBox::Warning)->show();
|
||||
return;
|
||||
}
|
||||
if (update_dialog.noUpdates()) {
|
||||
QString message{ tr("'%1' is up-to-date! :)").arg(mods_list.front()->name()) };
|
||||
if (mods_list.size() > 1) {
|
||||
if (use_all) {
|
||||
message = tr("All resource packs are up-to-date! :)");
|
||||
} else {
|
||||
message = tr("All selected resource packs are up-to-date! :)");
|
||||
}
|
||||
}
|
||||
CustomMessageBox::selectable(this, tr("Update checker"), message)->exec();
|
||||
return;
|
||||
}
|
||||
|
||||
if (update_dialog.exec()) {
|
||||
auto tasks = new ConcurrentTask("Download Resource Packs", APPLICATION->settings()->get("NumberOfConcurrentDownloads").toInt());
|
||||
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 : update_dialog.getTasks()) {
|
||||
tasks->addTask(task);
|
||||
}
|
||||
|
||||
ProgressDialog loadDialog(this);
|
||||
loadDialog.setSkipButton(true, tr("Abort"));
|
||||
loadDialog.execWithTask(tasks);
|
||||
|
||||
m_model->update();
|
||||
}
|
||||
}
|
||||
|
||||
void ResourcePackPage::deleteResourcePackMetadata()
|
||||
{
|
||||
auto selection = m_filterModel->mapSelectionToSource(ui->treeView->selectionModel()->selection()).indexes();
|
||||
auto selectionCount = m_model->selectedResourcePacks(selection).length();
|
||||
if (selectionCount == 0)
|
||||
return;
|
||||
if (selectionCount > 1) {
|
||||
auto response = CustomMessageBox::selectable(this, tr("Confirm Removal"),
|
||||
tr("You are about to remove the metadata for %1 resource packs.\n"
|
||||
"Are you sure?")
|
||||
.arg(selectionCount),
|
||||
QMessageBox::Warning, QMessageBox::Yes | QMessageBox::No, QMessageBox::No)
|
||||
->exec();
|
||||
|
||||
if (response != QMessageBox::Yes)
|
||||
return;
|
||||
}
|
||||
|
||||
m_model->deleteMetadata(selection);
|
||||
}
|
||||
|
||||
void ResourcePackPage::changeResourcePackVersion()
|
||||
{
|
||||
if (m_instance->typeName() != "Minecraft")
|
||||
return; // this is a null instance or a legacy instance
|
||||
|
||||
if (APPLICATION->settings()->get("ModMetadataDisabled").toBool()) {
|
||||
QMessageBox::critical(this, tr("Error"), tr("Resource pack updates are unavailable when metadata is disabled!"));
|
||||
return;
|
||||
}
|
||||
|
||||
const QModelIndexList rows = ui->treeView->selectionModel()->selectedRows();
|
||||
|
||||
if (rows.count() != 1)
|
||||
return;
|
||||
|
||||
Resource& resource = m_model->at(m_filterModel->mapToSource(rows[0]).row());
|
||||
|
||||
if (resource.metadata() == nullptr)
|
||||
return;
|
||||
|
||||
ResourceDownload::ResourcePackDownloadDialog mdownload(this, m_model, m_instance);
|
||||
mdownload.setResourceMetadata(resource.metadata());
|
||||
if (mdownload.exec()) {
|
||||
auto tasks = new ConcurrentTask("Download Resource Packs", APPLICATION->settings()->get("NumberOfConcurrentDownloads").toInt());
|
||||
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();
|
||||
}
|
||||
}
|
@ -58,6 +58,14 @@ class ResourcePackPage : public ExternalResourcesPage {
|
||||
}
|
||||
|
||||
public slots:
|
||||
bool onSelectionChanged(const QModelIndex& current, const QModelIndex& previous) override;
|
||||
void downloadRPs();
|
||||
void updateFrame(const QModelIndex& current, const QModelIndex& previous) override;
|
||||
|
||||
private slots:
|
||||
void downloadResourcePacks();
|
||||
void updateResourcePacks();
|
||||
void deleteResourcePackMetadata();
|
||||
void changeResourcePackVersion();
|
||||
|
||||
protected:
|
||||
std::shared_ptr<ResourcePackFolderModel> m_model;
|
||||
};
|
||||
|
@ -242,6 +242,11 @@ ScreenshotsPage::ScreenshotsPage(QString path, QWidget* parent) : QMainWindow(pa
|
||||
m_model->setReadOnly(false);
|
||||
m_model->setNameFilters({ "*.png" });
|
||||
m_model->setNameFilterDisables(false);
|
||||
// Sorts by modified date instead of creation date because that column is not available and would require subclassing, this should work
|
||||
// considering screenshots aren't modified after creation.
|
||||
constexpr int file_modified_column_index = 3;
|
||||
m_model->sort(file_modified_column_index, Qt::DescendingOrder);
|
||||
|
||||
m_folder = path;
|
||||
m_valid = FS::ensureFolderPathExists(m_folder);
|
||||
|
||||
|
47
launcher/ui/pages/instance/ServerPingTask.cpp
Normal file
47
launcher/ui/pages/instance/ServerPingTask.cpp
Normal file
@ -0,0 +1,47 @@
|
||||
#include <QFutureWatcher>
|
||||
|
||||
#include "ServerPingTask.h"
|
||||
#include "McResolver.h"
|
||||
#include "McClient.h"
|
||||
#include <Json.h>
|
||||
|
||||
unsigned getOnlinePlayers(QJsonObject data) {
|
||||
return Json::requireInteger(Json::requireObject(data, "players"), "online");
|
||||
}
|
||||
|
||||
void ServerPingTask::executeTask() {
|
||||
qDebug() << "Querying status of " << QString("%1:%2").arg(m_domain).arg(m_port);
|
||||
|
||||
// Resolve the actual IP and port for the server
|
||||
McResolver *resolver = new McResolver(nullptr, m_domain, m_port);
|
||||
QObject::connect(resolver, &McResolver::succeeded, this, [this, resolver](QString ip, int port) {
|
||||
qDebug() << "Resolved Address for" << m_domain << ": " << ip << ":" << port;
|
||||
|
||||
// Now that we have the IP and port, query the server
|
||||
McClient *client = new McClient(nullptr, m_domain, ip, port);
|
||||
|
||||
QObject::connect(client, &McClient::succeeded, this, [this](QJsonObject data) {
|
||||
m_outputOnlinePlayers = getOnlinePlayers(data);
|
||||
qDebug() << "Online players: " << m_outputOnlinePlayers;
|
||||
emitSucceeded();
|
||||
});
|
||||
QObject::connect(client, &McClient::failed, this, [this](QString error) {
|
||||
emitFailed(error);
|
||||
});
|
||||
|
||||
// Delete McClient object when done
|
||||
QObject::connect(client, &McClient::finished, this, [this, client]() {
|
||||
client->deleteLater();
|
||||
});
|
||||
client->getStatusData();
|
||||
});
|
||||
QObject::connect(resolver, &McResolver::failed, this, [this](QString error) {
|
||||
emitFailed(error);
|
||||
});
|
||||
|
||||
// Delete McResolver object when done
|
||||
QObject::connect(resolver, &McResolver::finished, [resolver]() {
|
||||
resolver->deleteLater();
|
||||
});
|
||||
resolver->ping();
|
||||
}
|
22
launcher/ui/pages/instance/ServerPingTask.h
Normal file
22
launcher/ui/pages/instance/ServerPingTask.h
Normal file
@ -0,0 +1,22 @@
|
||||
#pragma once
|
||||
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
|
||||
#include <tasks/Task.h>
|
||||
|
||||
|
||||
class ServerPingTask : public Task {
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ServerPingTask(QString domain, int port) : Task(), m_domain(domain), m_port(port) {}
|
||||
~ServerPingTask() override = default;
|
||||
int m_outputOnlinePlayers = -1;
|
||||
|
||||
private:
|
||||
QString m_domain;
|
||||
int m_port;
|
||||
|
||||
protected:
|
||||
virtual void executeTask() override;
|
||||
};
|
@ -38,6 +38,7 @@
|
||||
#include "ServersPage.h"
|
||||
#include "ui/dialogs/CustomMessageBox.h"
|
||||
#include "ui_ServersPage.h"
|
||||
#include "ServerPingTask.h"
|
||||
|
||||
#include <FileSystem.h>
|
||||
#include <io/stream_reader.h>
|
||||
@ -51,8 +52,9 @@
|
||||
#include <QFileSystemWatcher>
|
||||
#include <QMenu>
|
||||
#include <QTimer>
|
||||
#include <tasks/ConcurrentTask.h>
|
||||
|
||||
static const int COLUMN_COUNT = 2; // 3 , TBD: latency and other nice things.
|
||||
static const int COLUMN_COUNT = 3; // 3 , TBD: latency and other nice things.
|
||||
|
||||
struct Server {
|
||||
// Types
|
||||
@ -112,8 +114,7 @@ struct Server {
|
||||
bool m_checked = false;
|
||||
bool m_up = false;
|
||||
QString m_motd; // https://mctools.org/motd-creator
|
||||
int m_ping = 0;
|
||||
int m_currentPlayers = 0;
|
||||
std::optional<int> m_currentPlayers; // nullopt if not calculated/calculating
|
||||
int m_maxPlayers = 0;
|
||||
};
|
||||
|
||||
@ -296,7 +297,7 @@ class ServersModel : public QAbstractListModel {
|
||||
case 1:
|
||||
return tr("Address");
|
||||
case 2:
|
||||
return tr("Latency");
|
||||
return tr("Online");
|
||||
}
|
||||
}
|
||||
|
||||
@ -345,7 +346,11 @@ class ServersModel : public QAbstractListModel {
|
||||
case 2:
|
||||
switch (role) {
|
||||
case Qt::DisplayRole:
|
||||
return m_servers[row].m_ping;
|
||||
if (m_servers[row].m_currentPlayers) {
|
||||
return *m_servers[row].m_currentPlayers;
|
||||
} else {
|
||||
return "...";
|
||||
}
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
@ -433,6 +438,40 @@ class ServersModel : public QAbstractListModel {
|
||||
}
|
||||
}
|
||||
|
||||
void queryServersStatus()
|
||||
{
|
||||
// Abort the currently running task if present
|
||||
if (m_currentQueryTask != nullptr) {
|
||||
m_currentQueryTask->abort();
|
||||
qDebug() << "Aborted previous server query task";
|
||||
}
|
||||
|
||||
m_currentQueryTask = ConcurrentTask::Ptr(
|
||||
new ConcurrentTask("Query servers status", APPLICATION->settings()->get("NumberOfConcurrentTasks").toInt())
|
||||
);
|
||||
int row = 0;
|
||||
for (Server &server : m_servers) {
|
||||
// reset current players
|
||||
server.m_currentPlayers = {};
|
||||
emit dataChanged(index(row, 0), index(row, COLUMN_COUNT - 1));
|
||||
|
||||
// Start task to query server status
|
||||
auto target = MinecraftTarget::parse(server.m_address, false);
|
||||
auto *task = new ServerPingTask(target.address, target.port);
|
||||
m_currentQueryTask->addTask(Task::Ptr(task));
|
||||
|
||||
// Update the model when the task is done
|
||||
connect(task, &Task::finished, this, [this, task, row]() {
|
||||
if (m_servers.size() < row) return;
|
||||
m_servers[row].m_currentPlayers = task->m_outputOnlinePlayers;
|
||||
emit dataChanged(index(row, 0), index(row, COLUMN_COUNT - 1));
|
||||
});
|
||||
row++;
|
||||
}
|
||||
|
||||
m_currentQueryTask->start();
|
||||
}
|
||||
|
||||
public slots:
|
||||
void dirChanged(const QString& path)
|
||||
{
|
||||
@ -520,6 +559,7 @@ class ServersModel : public QAbstractListModel {
|
||||
QList<Server> m_servers;
|
||||
QFileSystemWatcher* m_watcher = nullptr;
|
||||
QTimer m_saveTimer;
|
||||
ConcurrentTask::Ptr m_currentQueryTask = nullptr;
|
||||
};
|
||||
|
||||
ServersPage::ServersPage(InstancePtr inst, QWidget* parent) : QMainWindow(parent), ui(new Ui::ServersPage)
|
||||
@ -676,6 +716,9 @@ void ServersPage::openedImpl()
|
||||
m_wide_bar_setting = APPLICATION->settings()->getSetting(setting_name);
|
||||
|
||||
ui->toolBar->setVisibilityState(m_wide_bar_setting->get().toByteArray());
|
||||
|
||||
// ping servers
|
||||
m_model->queryServersStatus();
|
||||
}
|
||||
|
||||
void ServersPage::closedImpl()
|
||||
@ -734,4 +777,9 @@ void ServersPage::on_actionJoin_triggered()
|
||||
APPLICATION->launch(m_inst, true, false, std::make_shared<MinecraftTarget>(MinecraftTarget::parse(address, false)));
|
||||
}
|
||||
|
||||
void ServersPage::on_actionRefresh_triggered()
|
||||
{
|
||||
m_model->queryServersStatus();
|
||||
}
|
||||
|
||||
#include "ServersPage.moc"
|
||||
|
@ -85,6 +85,7 @@ class ServersPage : public QMainWindow, public BasePage {
|
||||
void on_actionMove_Up_triggered();
|
||||
void on_actionMove_Down_triggered();
|
||||
void on_actionJoin_triggered();
|
||||
void on_actionRefresh_triggered();
|
||||
|
||||
void runningStateChanged(bool running);
|
||||
|
||||
|
@ -149,6 +149,8 @@
|
||||
<addaction name="actionMove_Up"/>
|
||||
<addaction name="actionMove_Down"/>
|
||||
<addaction name="actionJoin"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionRefresh"/>
|
||||
</widget>
|
||||
<action name="actionAdd">
|
||||
<property name="text">
|
||||
@ -175,6 +177,11 @@
|
||||
<string>Join</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionRefresh">
|
||||
<property name="text">
|
||||
<string>Refresh</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
|
@ -45,27 +45,197 @@
|
||||
#include "ui/dialogs/CustomMessageBox.h"
|
||||
#include "ui/dialogs/ProgressDialog.h"
|
||||
#include "ui/dialogs/ResourceDownloadDialog.h"
|
||||
#include "ui/dialogs/ResourceUpdateDialog.h"
|
||||
|
||||
ShaderPackPage::ShaderPackPage(MinecraftInstance* instance, std::shared_ptr<ShaderPackFolderModel> model, QWidget* parent)
|
||||
: ExternalResourcesPage(instance, model, parent)
|
||||
: ExternalResourcesPage(instance, model, parent), m_model(model)
|
||||
{
|
||||
ui->actionDownloadItem->setText(tr("Download shaders"));
|
||||
ui->actionDownloadItem->setToolTip(tr("Download shaders from online platforms"));
|
||||
ui->actionDownloadItem->setText(tr("Download Packs"));
|
||||
ui->actionDownloadItem->setToolTip(tr("Download shader packs from online mod platforms"));
|
||||
ui->actionDownloadItem->setEnabled(true);
|
||||
connect(ui->actionDownloadItem, &QAction::triggered, this, &ShaderPackPage::downloadShaders);
|
||||
ui->actionsToolbar->insertActionBefore(ui->actionAddItem, ui->actionDownloadItem);
|
||||
|
||||
ui->actionViewConfigs->setVisible(false);
|
||||
connect(ui->actionDownloadItem, &QAction::triggered, this, &ShaderPackPage::downloadShaderPack);
|
||||
|
||||
ui->actionUpdateItem->setToolTip(tr("Try to check or update all selected shader packs (all shader packs if none are selected)"));
|
||||
connect(ui->actionUpdateItem, &QAction::triggered, this, &ShaderPackPage::updateShaderPacks);
|
||||
ui->actionsToolbar->insertActionBefore(ui->actionAddItem, ui->actionUpdateItem);
|
||||
|
||||
auto updateMenu = new QMenu(this);
|
||||
|
||||
auto update = updateMenu->addAction(ui->actionUpdateItem->text());
|
||||
connect(update, &QAction::triggered, this, &ShaderPackPage::updateShaderPacks);
|
||||
|
||||
updateMenu->addAction(ui->actionResetItemMetadata);
|
||||
connect(ui->actionResetItemMetadata, &QAction::triggered, this, &ShaderPackPage::deleteShaderPackMetadata);
|
||||
|
||||
ui->actionUpdateItem->setMenu(updateMenu);
|
||||
|
||||
ui->actionChangeVersion->setToolTip(tr("Change a shader pack's version."));
|
||||
connect(ui->actionChangeVersion, &QAction::triggered, this, &ShaderPackPage::changeShaderPackVersion);
|
||||
ui->actionsToolbar->insertActionAfter(ui->actionUpdateItem, ui->actionChangeVersion);
|
||||
}
|
||||
|
||||
void ShaderPackPage::downloadShaders()
|
||||
void ShaderPackPage::downloadShaderPack()
|
||||
{
|
||||
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);
|
||||
ResourceDownload::ShaderPackDownloadDialog mdownload(this, m_model, m_instance);
|
||||
if (mdownload.exec()) {
|
||||
auto tasks = new ConcurrentTask(this, "Download Shaders", APPLICATION->settings()->get("NumberOfConcurrentDownloads").toInt());
|
||||
auto tasks = new ConcurrentTask("Download Shader Packs", APPLICATION->settings()->get("NumberOfConcurrentDownloads").toInt());
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
void ShaderPackPage::updateShaderPacks()
|
||||
{
|
||||
if (m_instance->typeName() != "Minecraft")
|
||||
return; // this is a null instance or a legacy instance
|
||||
|
||||
auto profile = static_cast<MinecraftInstance*>(m_instance)->getPackProfile();
|
||||
if (APPLICATION->settings()->get("ModMetadataDisabled").toBool()) {
|
||||
QMessageBox::critical(this, tr("Error"), tr("Shader pack updates are unavailable when metadata is disabled!"));
|
||||
return;
|
||||
}
|
||||
if (m_instance != nullptr && m_instance->isRunning()) {
|
||||
auto response =
|
||||
CustomMessageBox::selectable(this, tr("Confirm Update"),
|
||||
tr("Updating shader packs while the game is running may pack duplication and game crashes.\n"
|
||||
"The old files may not be deleted as they are in use.\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()).indexes();
|
||||
|
||||
auto mods_list = m_model->selectedResources(selection);
|
||||
bool use_all = mods_list.empty();
|
||||
if (use_all)
|
||||
mods_list = m_model->allResources();
|
||||
|
||||
ResourceUpdateDialog update_dialog(this, m_instance, m_model, mods_list, false, false);
|
||||
update_dialog.checkCandidates();
|
||||
|
||||
if (update_dialog.aborted()) {
|
||||
CustomMessageBox::selectable(this, tr("Aborted"), tr("The shader pack updater was aborted!"), QMessageBox::Warning)->show();
|
||||
return;
|
||||
}
|
||||
if (update_dialog.noUpdates()) {
|
||||
QString message{ tr("'%1' is up-to-date! :)").arg(mods_list.front()->name()) };
|
||||
if (mods_list.size() > 1) {
|
||||
if (use_all) {
|
||||
message = tr("All shader packs are up-to-date! :)");
|
||||
} else {
|
||||
message = tr("All selected shader packs are up-to-date! :)");
|
||||
}
|
||||
}
|
||||
CustomMessageBox::selectable(this, tr("Update checker"), message)->exec();
|
||||
return;
|
||||
}
|
||||
|
||||
if (update_dialog.exec()) {
|
||||
auto tasks = new ConcurrentTask("Download Shader Packs", APPLICATION->settings()->get("NumberOfConcurrentDownloads").toInt());
|
||||
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 : update_dialog.getTasks()) {
|
||||
tasks->addTask(task);
|
||||
}
|
||||
|
||||
ProgressDialog loadDialog(this);
|
||||
loadDialog.setSkipButton(true, tr("Abort"));
|
||||
loadDialog.execWithTask(tasks);
|
||||
|
||||
m_model->update();
|
||||
}
|
||||
}
|
||||
|
||||
void ShaderPackPage::deleteShaderPackMetadata()
|
||||
{
|
||||
auto selection = m_filterModel->mapSelectionToSource(ui->treeView->selectionModel()->selection()).indexes();
|
||||
auto selectionCount = m_model->selectedShaderPacks(selection).length();
|
||||
if (selectionCount == 0)
|
||||
return;
|
||||
if (selectionCount > 1) {
|
||||
auto response = CustomMessageBox::selectable(this, tr("Confirm Removal"),
|
||||
tr("You are about to remove the metadata for %1 shader packs.\n"
|
||||
"Are you sure?")
|
||||
.arg(selectionCount),
|
||||
QMessageBox::Warning, QMessageBox::Yes | QMessageBox::No, QMessageBox::No)
|
||||
->exec();
|
||||
|
||||
if (response != QMessageBox::Yes)
|
||||
return;
|
||||
}
|
||||
|
||||
m_model->deleteMetadata(selection);
|
||||
}
|
||||
|
||||
void ShaderPackPage::changeShaderPackVersion()
|
||||
{
|
||||
if (m_instance->typeName() != "Minecraft")
|
||||
return; // this is a null instance or a legacy instance
|
||||
|
||||
if (APPLICATION->settings()->get("ModMetadataDisabled").toBool()) {
|
||||
QMessageBox::critical(this, tr("Error"), tr("Shader pack updates are unavailable when metadata is disabled!"));
|
||||
return;
|
||||
}
|
||||
|
||||
const QModelIndexList rows = ui->treeView->selectionModel()->selectedRows();
|
||||
|
||||
if (rows.count() != 1)
|
||||
return;
|
||||
|
||||
Resource& resource = m_model->at(m_filterModel->mapToSource(rows[0]).row());
|
||||
|
||||
if (resource.metadata() == nullptr)
|
||||
return;
|
||||
|
||||
ResourceDownload::ShaderPackDownloadDialog mdownload(this, m_model, m_instance);
|
||||
mdownload.setResourceMetadata(resource.metadata());
|
||||
if (mdownload.exec()) {
|
||||
auto tasks = new ConcurrentTask("Download Shader Packs", APPLICATION->settings()->get("NumberOfConcurrentDownloads").toInt());
|
||||
connect(tasks, &Task::failed, [this, tasks](QString reason) {
|
||||
CustomMessageBox::selectable(this, tr("Error"), reason, QMessageBox::Critical)->show();
|
||||
tasks->deleteLater();
|
||||
|
@ -53,5 +53,11 @@ class ShaderPackPage : public ExternalResourcesPage {
|
||||
bool shouldDisplay() const override { return true; }
|
||||
|
||||
public slots:
|
||||
void downloadShaders();
|
||||
void downloadShaderPack();
|
||||
void updateShaderPacks();
|
||||
void deleteShaderPackMetadata();
|
||||
void changeShaderPackVersion();
|
||||
|
||||
private:
|
||||
std::shared_ptr<ShaderPackFolderModel> m_model;
|
||||
};
|
||||
|
@ -44,38 +44,207 @@
|
||||
#include "ui/dialogs/CustomMessageBox.h"
|
||||
#include "ui/dialogs/ProgressDialog.h"
|
||||
#include "ui/dialogs/ResourceDownloadDialog.h"
|
||||
#include "ui/dialogs/ResourceUpdateDialog.h"
|
||||
|
||||
TexturePackPage::TexturePackPage(MinecraftInstance* instance, std::shared_ptr<TexturePackFolderModel> model, QWidget* parent)
|
||||
: ExternalResourcesPage(instance, model, parent)
|
||||
: ExternalResourcesPage(instance, model, parent), m_model(model)
|
||||
{
|
||||
ui->actionDownloadItem->setText(tr("Download packs"));
|
||||
ui->actionDownloadItem->setToolTip(tr("Download texture packs from online platforms"));
|
||||
ui->actionDownloadItem->setText(tr("Download Packs"));
|
||||
ui->actionDownloadItem->setToolTip(tr("Download texture packs from online mod platforms"));
|
||||
ui->actionDownloadItem->setEnabled(true);
|
||||
connect(ui->actionDownloadItem, &QAction::triggered, this, &TexturePackPage::downloadTPs);
|
||||
ui->actionsToolbar->insertActionBefore(ui->actionAddItem, ui->actionDownloadItem);
|
||||
|
||||
ui->actionViewConfigs->setVisible(false);
|
||||
connect(ui->actionDownloadItem, &QAction::triggered, this, &TexturePackPage::downloadTexturePacks);
|
||||
|
||||
ui->actionUpdateItem->setToolTip(tr("Try to check or update all selected texture packs (all texture packs if none are selected)"));
|
||||
connect(ui->actionUpdateItem, &QAction::triggered, this, &TexturePackPage::updateTexturePacks);
|
||||
ui->actionsToolbar->insertActionBefore(ui->actionAddItem, ui->actionUpdateItem);
|
||||
|
||||
auto updateMenu = new QMenu(this);
|
||||
|
||||
auto update = updateMenu->addAction(ui->actionUpdateItem->text());
|
||||
connect(update, &QAction::triggered, this, &TexturePackPage::updateTexturePacks);
|
||||
|
||||
updateMenu->addAction(ui->actionResetItemMetadata);
|
||||
connect(ui->actionResetItemMetadata, &QAction::triggered, this, &TexturePackPage::deleteTexturePackMetadata);
|
||||
|
||||
ui->actionUpdateItem->setMenu(updateMenu);
|
||||
|
||||
ui->actionChangeVersion->setToolTip(tr("Change a texture pack's version."));
|
||||
connect(ui->actionChangeVersion, &QAction::triggered, this, &TexturePackPage::changeTexturePackVersion);
|
||||
ui->actionsToolbar->insertActionAfter(ui->actionUpdateItem, ui->actionChangeVersion);
|
||||
|
||||
ui->actionViewHomepage->setToolTip(tr("View the homepages of all selected texture packs."));
|
||||
}
|
||||
|
||||
bool TexturePackPage::onSelectionChanged(const QModelIndex& current, [[maybe_unused]] const QModelIndex& previous)
|
||||
void TexturePackPage::updateFrame(const QModelIndex& current, [[maybe_unused]] 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()
|
||||
void TexturePackPage::downloadTexturePacks()
|
||||
{
|
||||
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);
|
||||
ResourceDownload::TexturePackDownloadDialog mdownload(this, m_model, m_instance);
|
||||
if (mdownload.exec()) {
|
||||
auto tasks =
|
||||
new ConcurrentTask(this, "Download Texture Packs", APPLICATION->settings()->get("NumberOfConcurrentDownloads").toInt());
|
||||
auto tasks = new ConcurrentTask("Download Texture Packs", APPLICATION->settings()->get("NumberOfConcurrentDownloads").toInt());
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
void TexturePackPage::updateTexturePacks()
|
||||
{
|
||||
if (m_instance->typeName() != "Minecraft")
|
||||
return; // this is a null instance or a legacy instance
|
||||
|
||||
auto profile = static_cast<MinecraftInstance*>(m_instance)->getPackProfile();
|
||||
if (APPLICATION->settings()->get("ModMetadataDisabled").toBool()) {
|
||||
QMessageBox::critical(this, tr("Error"), tr("Texture pack updates are unavailable when metadata is disabled!"));
|
||||
return;
|
||||
}
|
||||
if (m_instance != nullptr && m_instance->isRunning()) {
|
||||
auto response = CustomMessageBox::selectable(
|
||||
this, tr("Confirm Update"),
|
||||
tr("Updating texture packs while the game is running may cause pack duplication and game crashes.\n"
|
||||
"The old files may not be deleted as they are in use.\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()).indexes();
|
||||
|
||||
auto mods_list = m_model->selectedResources(selection);
|
||||
bool use_all = mods_list.empty();
|
||||
if (use_all)
|
||||
mods_list = m_model->allResources();
|
||||
|
||||
ResourceUpdateDialog update_dialog(this, m_instance, m_model, mods_list, false, false);
|
||||
update_dialog.checkCandidates();
|
||||
|
||||
if (update_dialog.aborted()) {
|
||||
CustomMessageBox::selectable(this, tr("Aborted"), tr("The texture pack updater was aborted!"), QMessageBox::Warning)->show();
|
||||
return;
|
||||
}
|
||||
if (update_dialog.noUpdates()) {
|
||||
QString message{ tr("'%1' is up-to-date! :)").arg(mods_list.front()->name()) };
|
||||
if (mods_list.size() > 1) {
|
||||
if (use_all) {
|
||||
message = tr("All texture packs are up-to-date! :)");
|
||||
} else {
|
||||
message = tr("All selected texture packs are up-to-date! :)");
|
||||
}
|
||||
}
|
||||
CustomMessageBox::selectable(this, tr("Update checker"), message)->exec();
|
||||
return;
|
||||
}
|
||||
|
||||
if (update_dialog.exec()) {
|
||||
auto tasks = new ConcurrentTask("Download Texture Packs", APPLICATION->settings()->get("NumberOfConcurrentDownloads").toInt());
|
||||
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 : update_dialog.getTasks()) {
|
||||
tasks->addTask(task);
|
||||
}
|
||||
|
||||
ProgressDialog loadDialog(this);
|
||||
loadDialog.setSkipButton(true, tr("Abort"));
|
||||
loadDialog.execWithTask(tasks);
|
||||
|
||||
m_model->update();
|
||||
}
|
||||
}
|
||||
|
||||
void TexturePackPage::deleteTexturePackMetadata()
|
||||
{
|
||||
auto selection = m_filterModel->mapSelectionToSource(ui->treeView->selectionModel()->selection()).indexes();
|
||||
auto selectionCount = m_model->selectedTexturePacks(selection).length();
|
||||
if (selectionCount == 0)
|
||||
return;
|
||||
if (selectionCount > 1) {
|
||||
auto response = CustomMessageBox::selectable(this, tr("Confirm Removal"),
|
||||
tr("You are about to remove the metadata for %1 texture packs.\n"
|
||||
"Are you sure?")
|
||||
.arg(selectionCount),
|
||||
QMessageBox::Warning, QMessageBox::Yes | QMessageBox::No, QMessageBox::No)
|
||||
->exec();
|
||||
|
||||
if (response != QMessageBox::Yes)
|
||||
return;
|
||||
}
|
||||
|
||||
m_model->deleteMetadata(selection);
|
||||
}
|
||||
|
||||
void TexturePackPage::changeTexturePackVersion()
|
||||
{
|
||||
if (m_instance->typeName() != "Minecraft")
|
||||
return; // this is a null instance or a legacy instance
|
||||
|
||||
if (APPLICATION->settings()->get("ModMetadataDisabled").toBool()) {
|
||||
QMessageBox::critical(this, tr("Error"), tr("Texture pack updates are unavailable when metadata is disabled!"));
|
||||
return;
|
||||
}
|
||||
|
||||
const QModelIndexList rows = ui->treeView->selectionModel()->selectedRows();
|
||||
|
||||
if (rows.count() != 1)
|
||||
return;
|
||||
|
||||
Resource& resource = m_model->at(m_filterModel->mapToSource(rows[0]).row());
|
||||
|
||||
if (resource.metadata() == nullptr)
|
||||
return;
|
||||
|
||||
ResourceDownload::TexturePackDownloadDialog mdownload(this, m_model, m_instance);
|
||||
mdownload.setResourceMetadata(resource.metadata());
|
||||
if (mdownload.exec()) {
|
||||
auto tasks = new ConcurrentTask("Download Texture Packs", APPLICATION->settings()->get("NumberOfConcurrentDownloads").toInt());
|
||||
connect(tasks, &Task::failed, [this, tasks](QString reason) {
|
||||
CustomMessageBox::selectable(this, tr("Error"), reason, QMessageBox::Critical)->show();
|
||||
tasks->deleteLater();
|
||||
|
@ -55,6 +55,12 @@ class TexturePackPage : public ExternalResourcesPage {
|
||||
virtual bool shouldDisplay() const override { return m_instance->traits().contains("texturepacks"); }
|
||||
|
||||
public slots:
|
||||
bool onSelectionChanged(const QModelIndex& current, const QModelIndex& previous) override;
|
||||
void downloadTPs();
|
||||
void updateFrame(const QModelIndex& current, const QModelIndex& previous) override;
|
||||
void downloadTexturePacks();
|
||||
void updateTexturePacks();
|
||||
void deleteTexturePackMetadata();
|
||||
void changeTexturePackVersion();
|
||||
|
||||
private:
|
||||
std::shared_ptr<TexturePackFolderModel> m_model;
|
||||
};
|
||||
|
@ -49,8 +49,12 @@
|
||||
#include <QMessageBox>
|
||||
#include <QString>
|
||||
#include <QUrl>
|
||||
#include <algorithm>
|
||||
|
||||
#include "QObjectPtr.h"
|
||||
#include "VersionPage.h"
|
||||
#include "meta/JsonFormat.h"
|
||||
#include "tasks/SequentialTask.h"
|
||||
#include "ui/dialogs/InstallLoaderDialog.h"
|
||||
#include "ui_VersionPage.h"
|
||||
|
||||
@ -63,11 +67,9 @@
|
||||
|
||||
#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 "meta/Index.h"
|
||||
#include "meta/VersionList.h"
|
||||
@ -241,7 +243,7 @@ void VersionPage::updateButtons(int row)
|
||||
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->actionChange_version->setEnabled(patch && patch->isVersionChangeable(false));
|
||||
ui->actionEdit->setEnabled(patch && patch->isCustom());
|
||||
ui->actionCustomize->setEnabled(patch && patch->isCustomizable());
|
||||
ui->actionRevert->setEnabled(patch && patch->isRevertible());
|
||||
@ -250,8 +252,11 @@ void VersionPage::updateButtons(int row)
|
||||
bool VersionPage::reloadPackProfile()
|
||||
{
|
||||
try {
|
||||
m_profile->reload(Net::Mode::Online);
|
||||
return true;
|
||||
auto result = m_profile->reload(Net::Mode::Online);
|
||||
if (!result) {
|
||||
QMessageBox::critical(this, tr("Error"), result.error);
|
||||
}
|
||||
return result;
|
||||
} catch (const Exception& e) {
|
||||
QMessageBox::critical(this, tr("Error"), e.cause());
|
||||
return false;
|
||||
@ -370,11 +375,25 @@ void VersionPage::on_actionChange_version_triggered()
|
||||
auto patch = m_profile->getComponent(versionRow);
|
||||
auto name = patch->getName();
|
||||
auto list = patch->getVersionList();
|
||||
list->clearExternalRecommends();
|
||||
if (!list) {
|
||||
return;
|
||||
}
|
||||
auto uid = list->uid();
|
||||
|
||||
// recommend the correct lwjgl version for the current minecraft version
|
||||
if (uid == "org.lwjgl" || uid == "org.lwjgl3") {
|
||||
auto minecraft = m_profile->getComponent("net.minecraft");
|
||||
auto lwjglReq = std::find_if(minecraft->m_cachedRequires.cbegin(), minecraft->m_cachedRequires.cend(),
|
||||
[uid](const Meta::Require& req) -> bool { return req.uid == uid; });
|
||||
if (lwjglReq != minecraft->m_cachedRequires.cend()) {
|
||||
auto lwjglVersion = !lwjglReq->equalsVersion.isEmpty() ? lwjglReq->equalsVersion : lwjglReq->suggests;
|
||||
if (!lwjglVersion.isEmpty()) {
|
||||
list->addExternalRecommends({ lwjglVersion });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VersionSelectDialog vselect(list.get(), tr("Change %1 version").arg(name), this);
|
||||
if (uid == "net.fabricmc.intermediary" || uid == "org.quiltmc.hashed") {
|
||||
vselect.setEmptyString(tr("No intermediary mappings versions are currently available."));
|
||||
@ -393,6 +412,11 @@ void VersionPage::on_actionChange_version_triggered()
|
||||
bool important = false;
|
||||
if (uid == "net.minecraft") {
|
||||
important = true;
|
||||
if (APPLICATION->settings()->get("AutomaticJavaSwitch").toBool() && m_inst->settings()->get("AutomaticJava").toBool() &&
|
||||
m_inst->settings()->get("OverrideJavaLocation").toBool()) {
|
||||
m_inst->settings()->set("OverrideJavaLocation", false);
|
||||
m_inst->settings()->set("JavaPath", "");
|
||||
}
|
||||
}
|
||||
m_profile->setComponentVersion(uid, vselect.selectedVersion()->descriptor(), important);
|
||||
m_profile->resolve(Net::Mode::Online);
|
||||
@ -410,14 +434,18 @@ void VersionPage::on_actionDownload_All_triggered()
|
||||
return;
|
||||
}
|
||||
|
||||
auto updateTask = m_inst->createUpdateTask(Net::Mode::Online);
|
||||
if (!updateTask) {
|
||||
auto updateTasks = m_inst->createUpdateTask();
|
||||
if (updateTasks.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
auto task = makeShared<SequentialTask>();
|
||||
for (auto t : updateTasks) {
|
||||
task->addTask(t);
|
||||
}
|
||||
ProgressDialog tDialog(this);
|
||||
connect(updateTask.get(), &Task::failed, this, &VersionPage::onGameUpdateError);
|
||||
connect(task.get(), &Task::failed, this, &VersionPage::onGameUpdateError);
|
||||
// FIXME: unused return value
|
||||
tDialog.execWithTask(updateTask.get());
|
||||
tDialog.execWithTask(task.get());
|
||||
updateButtons();
|
||||
m_container->refreshContainer();
|
||||
}
|
||||
|
@ -239,7 +239,7 @@ void WorldListPage::on_actionData_Packs_triggered()
|
||||
dialog->restoreGeometry(QByteArray::fromBase64(APPLICATION->settings()->get("DataPackDownloadGeometry").toByteArray()));
|
||||
|
||||
auto layout = new QHBoxLayout(dialog);
|
||||
auto page = new DataPackPage(m_inst, std::make_shared<DataPackFolderModel>(folder, m_inst));
|
||||
auto page = new DataPackPage(m_inst.get(), std::make_shared<DataPackFolderModel>(folder, m_inst.get(), true, true));
|
||||
page->setParent(dialog); // HACK: many pages extend QMainWindow; setting the parent manually prevents them from creating a window.
|
||||
layout->addWidget(page);
|
||||
dialog->setLayout(layout);
|
||||
|
Reference in New Issue
Block a user