Merge remote-tracking branch 'upstream/develop' into data-packs

Signed-off-by: TheKodeToad <TheKodeToad@proton.me>
This commit is contained in:
TheKodeToad
2025-03-24 21:11:46 +00:00
686 changed files with 15261 additions and 9719 deletions

View File

@ -40,7 +40,7 @@ class CheckComboModel : public QIdentityProxyModel {
{
if (role == Qt::CheckStateRole) {
auto txt = QIdentityProxyModel::data(index, Qt::DisplayRole).toString();
return checked.contains(txt) ? Qt::Checked : Qt::Unchecked;
return m_checked.contains(txt) ? Qt::Checked : Qt::Unchecked;
}
if (role == Qt::DisplayRole)
return QIdentityProxyModel::data(index, Qt::DisplayRole);
@ -50,10 +50,10 @@ class CheckComboModel : public QIdentityProxyModel {
{
if (role == Qt::CheckStateRole) {
auto txt = QIdentityProxyModel::data(index, Qt::DisplayRole).toString();
if (checked.contains(txt)) {
checked.removeOne(txt);
if (m_checked.contains(txt)) {
m_checked.removeOne(txt);
} else {
checked.push_back(txt);
m_checked.push_back(txt);
}
emit dataChanged(index, index);
emit checkStateChanged();
@ -61,13 +61,13 @@ class CheckComboModel : public QIdentityProxyModel {
}
return QIdentityProxyModel::setData(index, value, role);
}
QStringList getChecked() { return checked; }
QStringList getChecked() { return m_checked; }
signals:
void checkStateChanged();
private:
QStringList checked;
QStringList m_checked;
};
CheckComboBox::CheckComboBox(QWidget* parent) : QComboBox(parent), m_separator(", ")
@ -92,7 +92,7 @@ void CheckComboBox::setSourceModel(QAbstractItemModel* new_model)
void CheckComboBox::hidePopup()
{
if (!containerMousePress)
if (!m_containerMousePress)
QComboBox::hidePopup();
}
@ -138,7 +138,7 @@ bool CheckComboBox::eventFilter(QObject* receiver, QEvent* event)
}
case QEvent::MouseButtonPress: {
auto ev = static_cast<QMouseEvent*>(event);
containerMousePress = ev && view()->indexAt(ev->pos()).isValid();
m_containerMousePress = ev && view()->indexAt(ev->pos()).isValid();
break;
}
case QEvent::Wheel:

View File

@ -60,5 +60,5 @@ class CheckComboBox : public QComboBox {
private:
QString m_default_text;
QString m_separator;
bool containerMousePress;
bool m_containerMousePress = false;
};

View File

@ -38,19 +38,6 @@
<bool>false</bool>
</property>
<layout class="QGridLayout" name="gridLayout_4">
<item row="2" column="0">
<widget class="QLabel" name="labelPostExitCmd">
<property name="text">
<string>P&amp;ost-exit command:</string>
</property>
<property name="buddy">
<cstring>postExitCmdTextBox</cstring>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="preLaunchCmdTextBox"/>
</item>
<item row="0" column="0">
<widget class="QLabel" name="labelPreLaunchCmd">
<property name="text">
@ -61,8 +48,8 @@
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="postExitCmdTextBox"/>
<item row="0" column="1">
<widget class="QLineEdit" name="preLaunchCmdTextBox"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="labelWrapperCmd">
@ -77,6 +64,19 @@
<item row="1" column="1">
<widget class="QLineEdit" name="wrapperCmdTextBox"/>
</item>
<item row="2" column="0">
<widget class="QLabel" name="labelPostExitCmd">
<property name="text">
<string>P&amp;ost-exit command:</string>
</property>
<property name="buddy">
<cstring>postExitCmdTextBox</cstring>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="postExitCmdTextBox"/>
</item>
</layout>
</widget>
</item>

View File

@ -1,40 +0,0 @@
#include "DropLabel.h"
#include <QDropEvent>
#include <QMimeData>
DropLabel::DropLabel(QWidget* parent) : QLabel(parent)
{
setAcceptDrops(true);
}
void DropLabel::dragEnterEvent(QDragEnterEvent* event)
{
event->acceptProposedAction();
}
void DropLabel::dragMoveEvent(QDragMoveEvent* event)
{
event->acceptProposedAction();
}
void DropLabel::dragLeaveEvent(QDragLeaveEvent* event)
{
event->accept();
}
void DropLabel::dropEvent(QDropEvent* event)
{
const QMimeData* mimeData = event->mimeData();
if (!mimeData) {
return;
}
if (mimeData->hasUrls()) {
auto urls = mimeData->urls();
emit droppedURLs(urls);
}
event->acceptProposedAction();
}

View File

@ -1,19 +0,0 @@
#pragma once
#include <QLabel>
class DropLabel : public QLabel {
Q_OBJECT
public:
explicit DropLabel(QWidget* parent = nullptr);
signals:
void droppedURLs(QList<QUrl> urls);
protected:
void dropEvent(QDropEvent* event) override;
void dragEnterEvent(QDragEnterEvent* event) override;
void dragMoveEvent(QDragMoveEvent* event) override;
void dragLeaveEvent(QDragLeaveEvent* event) override;
};

View File

@ -84,7 +84,7 @@ void InfoFrame::updateWithMod(Mod const& m)
QString text = "";
QString name = "";
QString link = m.metaurl();
QString link = m.homepage();
if (m.name().isEmpty())
name = m.internal_id();
else
@ -93,7 +93,7 @@ void InfoFrame::updateWithMod(Mod const& m)
if (link.isEmpty())
text = name;
else {
text = "<a href=\"" + link + "\">" + name + "</a>";
text = "<a href=\"" + QUrl(link).toEncoded() + "\">" + name + "</a>";
}
if (!m.authors().isEmpty())
text += " by " + m.authors().join(", ");
@ -145,7 +145,13 @@ void InfoFrame::updateWithMod(Mod const& m)
void InfoFrame::updateWithResource(const Resource& resource)
{
setName(resource.name());
const QString homepage = resource.homepage();
if (!homepage.isEmpty())
setName("<a href=\"" + homepage + "\">" + resource.name() + "</a>");
else
setName(resource.name());
setImage();
}
@ -209,7 +215,14 @@ QString InfoFrame::renderColorCodes(QString input)
void InfoFrame::updateWithResourcePack(ResourcePack& resource_pack)
{
setName(renderColorCodes(resource_pack.name()));
QString name = renderColorCodes(resource_pack.name());
const QString homepage = resource_pack.homepage();
if (!homepage.isEmpty()) {
name = "<a href=\"" + homepage + "\">" + name + "</a>";
}
setName(name);
setDescription(renderColorCodes(resource_pack.description()));
setImage(resource_pack.image({ 64, 64 }));
}
@ -222,7 +235,14 @@ void InfoFrame::updateWithDataPack(DataPack& data_pack) {
void InfoFrame::updateWithTexturePack(TexturePack& texture_pack)
{
setName(renderColorCodes(texture_pack.name()));
QString name = renderColorCodes(texture_pack.name());
const QString homepage = texture_pack.homepage();
if (!homepage.isEmpty()) {
name = "<a href=\"" + homepage + "\">" + name + "</a>";
}
setName(name);
setDescription(renderColorCodes(texture_pack.description()));
setImage(texture_pack.image({ 64, 64 }));
}

View File

@ -1,432 +1,314 @@
// 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) 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
* 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 "JavaSettingsWidget.h"
#include <QFileDialog>
#include <QGroupBox>
#include <QLabel>
#include <QLineEdit>
#include <QPushButton>
#include <QSpinBox>
#include <QToolButton>
#include <QVBoxLayout>
#include <sys.h>
#include "FileSystem.h"
#include "JavaCommon.h"
#include "java/JavaInstall.h"
#include "java/JavaUtils.h"
#include "ui/dialogs/CustomMessageBox.h"
#include "ui/widgets/VersionSelectWidget.h"
#include <QFileInfo>
#include "Application.h"
#include "BuildConfig.h"
#include "FileSystem.h"
#include "JavaCommon.h"
#include "java/JavaInstallList.h"
#include "java/JavaUtils.h"
#include "settings/Setting.h"
#include "sys.h"
#include "ui/dialogs/CustomMessageBox.h"
#include "ui/dialogs/VersionSelectDialog.h"
#include "ui/java/InstallJavaDialog.h"
JavaSettingsWidget::JavaSettingsWidget(QWidget* parent) : QWidget(parent)
#include "ui_JavaSettingsWidget.h"
JavaSettingsWidget::JavaSettingsWidget(InstancePtr instance, QWidget* parent)
: QWidget(parent), m_instance(std::move(instance)), m_ui(new Ui::JavaSettingsWidget)
{
m_availableMemory = Sys::getSystemRam() / Sys::mebibyte;
m_ui->setupUi(this);
goodIcon = APPLICATION->getThemedIcon("status-good");
yellowIcon = APPLICATION->getThemedIcon("status-yellow");
badIcon = APPLICATION->getThemedIcon("status-bad");
setupUi();
if (m_instance == nullptr) {
m_ui->javaDownloadBtn->hide();
if (BuildConfig.JAVA_DOWNLOADER_ENABLED) {
connect(m_ui->autodetectJavaCheckBox, &QCheckBox::stateChanged, this, [this](bool state) {
m_ui->autodownloadJavaCheckBox->setEnabled(state);
if (!state)
m_ui->autodownloadJavaCheckBox->setChecked(false);
});
} else {
m_ui->autodownloadJavaCheckBox->hide();
}
} else {
m_ui->javaDownloadBtn->setVisible(BuildConfig.JAVA_DOWNLOADER_ENABLED);
m_ui->skipWizardCheckBox->hide();
m_ui->autodetectJavaCheckBox->hide();
m_ui->autodownloadJavaCheckBox->hide();
connect(m_minMemSpinBox, SIGNAL(valueChanged(int)), this, SLOT(memoryValueChanged(int)));
connect(m_maxMemSpinBox, SIGNAL(valueChanged(int)), this, SLOT(memoryValueChanged(int)));
connect(m_permGenSpinBox, SIGNAL(valueChanged(int)), this, SLOT(memoryValueChanged(int)));
connect(m_versionWidget, &VersionSelectWidget::selectedVersionChanged, this, &JavaSettingsWidget::javaVersionSelected);
connect(m_javaBrowseBtn, &QPushButton::clicked, this, &JavaSettingsWidget::on_javaBrowseBtn_clicked);
connect(m_javaPathTextBox, &QLineEdit::textEdited, this, &JavaSettingsWidget::javaPathEdited);
connect(m_javaStatusBtn, &QToolButton::clicked, this, &JavaSettingsWidget::on_javaStatusBtn_clicked);
}
m_ui->javaInstallationGroupBox->setCheckable(true);
m_ui->memoryGroupBox->setCheckable(true);
m_ui->javaArgumentsGroupBox->setCheckable(true);
void JavaSettingsWidget::setupUi()
{
setObjectName(QStringLiteral("javaSettingsWidget"));
m_verticalLayout = new QVBoxLayout(this);
m_verticalLayout->setObjectName(QStringLiteral("verticalLayout"));
SettingsObjectPtr settings = m_instance->settings();
m_versionWidget = new VersionSelectWidget(this);
m_verticalLayout->addWidget(m_versionWidget);
connect(settings->getSetting("OverrideJavaLocation").get(), &Setting::SettingChanged, m_ui->javaInstallationGroupBox,
[this, settings] { m_ui->javaInstallationGroupBox->setChecked(settings->get("OverrideJavaLocation").toBool()); });
connect(settings->getSetting("JavaPath").get(), &Setting::SettingChanged, m_ui->javaInstallationGroupBox,
[this, settings] { m_ui->javaPathTextBox->setText(settings->get("JavaPath").toString()); });
m_horizontalLayout = new QHBoxLayout();
m_horizontalLayout->setObjectName(QStringLiteral("horizontalLayout"));
m_javaPathTextBox = new QLineEdit(this);
m_javaPathTextBox->setObjectName(QStringLiteral("javaPathTextBox"));
connect(m_ui->javaDownloadBtn, &QPushButton::clicked, this, [this] {
auto javaDialog = new Java::InstallDialog({}, m_instance.get(), this);
javaDialog->exec();
});
connect(m_ui->javaPathTextBox, &QLineEdit::textChanged, [this](QString newValue) {
if (m_instance->settings()->get("JavaPath").toString() != newValue) {
m_instance->settings()->set("AutomaticJava", false);
}
});
}
m_horizontalLayout->addWidget(m_javaPathTextBox);
connect(m_ui->javaTestBtn, &QPushButton::clicked, this, &JavaSettingsWidget::onJavaTest);
connect(m_ui->javaDetectBtn, &QPushButton::clicked, this, &JavaSettingsWidget::onJavaAutodetect);
connect(m_ui->javaBrowseBtn, &QPushButton::clicked, this, &JavaSettingsWidget::onJavaBrowse);
m_javaBrowseBtn = new QPushButton(this);
m_javaBrowseBtn->setObjectName(QStringLiteral("javaBrowseBtn"));
connect(m_ui->maxMemSpinBox, QOverload<int>::of(&QSpinBox::valueChanged), this, &JavaSettingsWidget::updateThresholds);
connect(m_ui->minMemSpinBox, QOverload<int>::of(&QSpinBox::valueChanged), this, &JavaSettingsWidget::updateThresholds);
m_horizontalLayout->addWidget(m_javaBrowseBtn);
m_javaStatusBtn = new QToolButton(this);
m_javaStatusBtn->setIcon(yellowIcon);
m_horizontalLayout->addWidget(m_javaStatusBtn);
m_verticalLayout->addLayout(m_horizontalLayout);
m_memoryGroupBox = new QGroupBox(this);
m_memoryGroupBox->setObjectName(QStringLiteral("memoryGroupBox"));
m_gridLayout_2 = new QGridLayout(m_memoryGroupBox);
m_gridLayout_2->setObjectName(QStringLiteral("gridLayout_2"));
m_gridLayout_2->setColumnStretch(0, 1);
m_labelMinMem = new QLabel(m_memoryGroupBox);
m_labelMinMem->setObjectName(QStringLiteral("labelMinMem"));
m_gridLayout_2->addWidget(m_labelMinMem, 0, 0, 1, 1);
m_minMemSpinBox = new QSpinBox(m_memoryGroupBox);
m_minMemSpinBox->setObjectName(QStringLiteral("minMemSpinBox"));
m_minMemSpinBox->setSuffix(QStringLiteral(" MiB"));
m_minMemSpinBox->setMinimum(8);
m_minMemSpinBox->setMaximum(1048576);
m_minMemSpinBox->setSingleStep(128);
m_labelMinMem->setBuddy(m_minMemSpinBox);
m_gridLayout_2->addWidget(m_minMemSpinBox, 0, 1, 1, 1);
m_labelMaxMem = new QLabel(m_memoryGroupBox);
m_labelMaxMem->setObjectName(QStringLiteral("labelMaxMem"));
m_gridLayout_2->addWidget(m_labelMaxMem, 1, 0, 1, 1);
m_maxMemSpinBox = new QSpinBox(m_memoryGroupBox);
m_maxMemSpinBox->setObjectName(QStringLiteral("maxMemSpinBox"));
m_maxMemSpinBox->setSuffix(QStringLiteral(" MiB"));
m_maxMemSpinBox->setMinimum(8);
m_maxMemSpinBox->setMaximum(1048576);
m_maxMemSpinBox->setSingleStep(128);
m_labelMaxMem->setBuddy(m_maxMemSpinBox);
m_gridLayout_2->addWidget(m_maxMemSpinBox, 1, 1, 1, 1);
m_labelMaxMemIcon = new QLabel(m_memoryGroupBox);
m_labelMaxMemIcon->setObjectName(QStringLiteral("labelMaxMemIcon"));
m_gridLayout_2->addWidget(m_labelMaxMemIcon, 1, 2, 1, 1);
m_labelPermGen = new QLabel(m_memoryGroupBox);
m_labelPermGen->setObjectName(QStringLiteral("labelPermGen"));
m_labelPermGen->setText(QStringLiteral("PermGen:"));
m_gridLayout_2->addWidget(m_labelPermGen, 2, 0, 1, 1);
m_labelPermGen->setVisible(false);
m_permGenSpinBox = new QSpinBox(m_memoryGroupBox);
m_permGenSpinBox->setObjectName(QStringLiteral("permGenSpinBox"));
m_permGenSpinBox->setSuffix(QStringLiteral(" MiB"));
m_permGenSpinBox->setMinimum(4);
m_permGenSpinBox->setMaximum(1048576);
m_permGenSpinBox->setSingleStep(8);
m_gridLayout_2->addWidget(m_permGenSpinBox, 2, 1, 1, 1);
m_permGenSpinBox->setVisible(false);
m_verticalLayout->addWidget(m_memoryGroupBox);
retranslate();
}
void JavaSettingsWidget::initialize()
{
m_versionWidget->initialize(APPLICATION->javalist().get());
m_versionWidget->selectSearch();
m_versionWidget->setResizeOn(2);
auto s = APPLICATION->settings();
// Memory
observedMinMemory = s->get("MinMemAlloc").toInt();
observedMaxMemory = s->get("MaxMemAlloc").toInt();
observedPermGenMemory = s->get("PermGen").toInt();
m_minMemSpinBox->setValue(observedMinMemory);
m_maxMemSpinBox->setValue(observedMaxMemory);
m_permGenSpinBox->setValue(observedPermGenMemory);
loadSettings();
updateThresholds();
}
void JavaSettingsWidget::refresh()
JavaSettingsWidget::~JavaSettingsWidget()
{
delete m_ui;
}
void JavaSettingsWidget::loadSettings()
{
SettingsObjectPtr settings;
if (m_instance != nullptr)
settings = m_instance->settings();
else
settings = APPLICATION->settings();
// Java Settings
m_ui->javaInstallationGroupBox->setChecked(settings->get("OverrideJavaLocation").toBool());
m_ui->javaPathTextBox->setText(settings->get("JavaPath").toString());
m_ui->skipCompatibilityCheckBox->setChecked(settings->get("IgnoreJavaCompatibility").toBool());
m_ui->javaArgumentsGroupBox->setChecked(m_instance == nullptr || settings->get("OverrideJavaArgs").toBool());
m_ui->jvmArgsTextBox->setPlainText(settings->get("JvmArgs").toString());
if (m_instance == nullptr) {
m_ui->skipWizardCheckBox->setChecked(settings->get("IgnoreJavaWizard").toBool());
m_ui->autodetectJavaCheckBox->setChecked(settings->get("AutomaticJavaSwitch").toBool());
m_ui->autodetectJavaCheckBox->stateChanged(m_ui->autodetectJavaCheckBox->isChecked());
m_ui->autodownloadJavaCheckBox->setChecked(settings->get("AutomaticJavaDownload").toBool());
}
// Memory
m_ui->memoryGroupBox->setChecked(m_instance == nullptr || settings->get("OverrideMemory").toBool());
int min = settings->get("MinMemAlloc").toInt();
int max = settings->get("MaxMemAlloc").toInt();
if (min < max) {
m_ui->minMemSpinBox->setValue(min);
m_ui->maxMemSpinBox->setValue(max);
} else {
m_ui->minMemSpinBox->setValue(max);
m_ui->maxMemSpinBox->setValue(min);
}
m_ui->permGenSpinBox->setValue(settings->get("PermGen").toInt());
// Java arguments
m_ui->javaArgumentsGroupBox->setChecked(m_instance == nullptr || settings->get("OverrideJavaArgs").toBool());
m_ui->jvmArgsTextBox->setPlainText(settings->get("JvmArgs").toString());
}
void JavaSettingsWidget::saveSettings()
{
SettingsObjectPtr settings;
if (m_instance != nullptr)
settings = m_instance->settings();
else
settings = APPLICATION->settings();
SettingsObject::Lock lock(settings);
// Java Install Settings
bool javaInstall = m_instance == nullptr || m_ui->javaInstallationGroupBox->isChecked();
if (m_instance != nullptr)
settings->set("OverrideJavaLocation", javaInstall);
if (javaInstall) {
settings->set("JavaPath", m_ui->javaPathTextBox->text());
settings->set("IgnoreJavaCompatibility", m_ui->skipCompatibilityCheckBox->isChecked());
} else {
settings->reset("JavaPath");
settings->reset("IgnoreJavaCompatibility");
}
if (m_instance == nullptr) {
settings->set("IgnoreJavaWizard", m_ui->skipWizardCheckBox->isChecked());
settings->set("AutomaticJavaSwitch", m_ui->autodetectJavaCheckBox->isChecked());
settings->set("AutomaticJavaDownload", m_ui->autodownloadJavaCheckBox->isChecked());
}
// Memory
bool memory = m_instance == nullptr || m_ui->memoryGroupBox->isChecked();
if (m_instance != nullptr)
settings->set("OverrideMemory", memory);
if (memory) {
int min = m_ui->minMemSpinBox->value();
int max = m_ui->maxMemSpinBox->value();
if (min < max) {
settings->set("MinMemAlloc", min);
settings->set("MaxMemAlloc", max);
} else {
settings->set("MinMemAlloc", max);
settings->set("MaxMemAlloc", min);
}
settings->set("PermGen", m_ui->permGenSpinBox->value());
} else {
settings->reset("MinMemAlloc");
settings->reset("MaxMemAlloc");
settings->reset("PermGen");
}
// Java arguments
bool javaArgs = m_instance == nullptr || m_ui->javaArgumentsGroupBox->isChecked();
if (m_instance != nullptr)
settings->set("OverrideJavaArgs", javaArgs);
if (javaArgs) {
settings->set("JvmArgs", m_ui->jvmArgsTextBox->toPlainText().replace("\n", " "));
} else {
settings->reset("JvmArgs");
}
}
void JavaSettingsWidget::onJavaBrowse()
{
QString rawPath = QFileDialog::getOpenFileName(this, tr("Find Java executable"));
// do not allow current dir - it's dirty. Do not allow dirs that don't exist
if (rawPath.isEmpty()) {
return;
}
QString cookedPath = FS::NormalizePath(rawPath);
QFileInfo javaInfo(cookedPath);
if (!javaInfo.exists() || !javaInfo.isExecutable()) {
return;
}
m_ui->javaPathTextBox->setText(cookedPath);
}
void JavaSettingsWidget::onJavaTest()
{
if (m_checker != nullptr)
return;
QString jvmArgs;
if (m_instance == nullptr || m_ui->javaArgumentsGroupBox->isChecked())
jvmArgs = m_ui->jvmArgsTextBox->toPlainText().replace("\n", " ");
else
jvmArgs = APPLICATION->settings()->get("JvmArgs").toString();
m_checker.reset(new JavaCommon::TestCheck(this, m_ui->javaPathTextBox->text(), jvmArgs, m_ui->minMemSpinBox->value(),
m_ui->maxMemSpinBox->value(), m_ui->permGenSpinBox->value()));
connect(m_checker.get(), &JavaCommon::TestCheck::finished, this, [this] { m_checker.reset(); });
m_checker->run();
}
void JavaSettingsWidget::onJavaAutodetect()
{
if (JavaUtils::getJavaCheckPath().isEmpty()) {
JavaCommon::javaCheckNotFound(this);
return;
}
m_versionWidget->loadList();
}
JavaSettingsWidget::ValidationStatus JavaSettingsWidget::validate()
{
switch (javaStatus) {
default:
case JavaStatus::NotSet:
case JavaStatus::DoesNotExist:
case JavaStatus::DoesNotStart:
case JavaStatus::ReturnedInvalidData: {
int button = CustomMessageBox::selectable(this, tr("No Java version selected"),
tr("You didn't select a Java version or selected something that doesn't work.\n"
"%1 will not be able to start Minecraft.\n"
"Do you wish to proceed without any Java?"
"\n\n"
"You can change the Java version in the settings later.\n")
.arg(BuildConfig.LAUNCHER_DISPLAYNAME),
QMessageBox::Warning, QMessageBox::Yes | QMessageBox::No, QMessageBox::NoButton)
->exec();
if (button == QMessageBox::No) {
return ValidationStatus::Bad;
}
return ValidationStatus::JavaBad;
} break;
case JavaStatus::Pending: {
return ValidationStatus::Bad;
}
case JavaStatus::Good: {
return ValidationStatus::AllOK;
VersionSelectDialog versionDialog(APPLICATION->javalist().get(), tr("Select a Java version"), this, true);
versionDialog.setResizeOn(2);
versionDialog.exec();
if (versionDialog.result() == QDialog::Accepted && versionDialog.selectedVersion()) {
JavaInstallPtr java = std::dynamic_pointer_cast<JavaInstall>(versionDialog.selectedVersion());
m_ui->javaPathTextBox->setText(java->path);
if (!java->is_64bit && m_ui->maxMemSpinBox->value() > 2048) {
CustomMessageBox::selectable(this, tr("Confirm Selection"),
tr("You selected a 32-bit version of Java.\n"
"This installation does not support more than 2048MiB of RAM.\n"
"Please make sure that the maximum memory value is lower."),
QMessageBox::Warning, QMessageBox::Ok, QMessageBox::Ok)
->exec();
}
}
}
QString JavaSettingsWidget::javaPath() const
{
return m_javaPathTextBox->text();
}
int JavaSettingsWidget::maxHeapSize() const
{
auto min = m_minMemSpinBox->value();
auto max = m_maxMemSpinBox->value();
if (max < min)
max = min;
return max;
}
int JavaSettingsWidget::minHeapSize() const
{
auto min = m_minMemSpinBox->value();
auto max = m_maxMemSpinBox->value();
if (min > max)
min = max;
return min;
}
bool JavaSettingsWidget::permGenEnabled() const
{
return m_permGenSpinBox->isVisible();
}
int JavaSettingsWidget::permGenSize() const
{
return m_permGenSpinBox->value();
}
void JavaSettingsWidget::memoryValueChanged(int)
{
bool actuallyChanged = false;
unsigned int min = m_minMemSpinBox->value();
unsigned int max = m_maxMemSpinBox->value();
unsigned int permgen = m_permGenSpinBox->value();
QObject* obj = sender();
if (obj == m_minMemSpinBox && min != observedMinMemory) {
observedMinMemory = min;
actuallyChanged = true;
} else if (obj == m_maxMemSpinBox && max != observedMaxMemory) {
observedMaxMemory = max;
actuallyChanged = true;
} else if (obj == m_permGenSpinBox && permgen != observedPermGenMemory) {
observedPermGenMemory = permgen;
actuallyChanged = true;
}
if (actuallyChanged) {
checkJavaPathOnEdit(m_javaPathTextBox->text());
updateThresholds();
}
}
void JavaSettingsWidget::javaVersionSelected(BaseVersion::Ptr version)
{
auto java = std::dynamic_pointer_cast<JavaInstall>(version);
if (!java) {
return;
}
auto visible = java->id.requiresPermGen();
m_labelPermGen->setVisible(visible);
m_permGenSpinBox->setVisible(visible);
m_javaPathTextBox->setText(java->path);
checkJavaPath(java->path);
}
void JavaSettingsWidget::on_javaBrowseBtn_clicked()
{
QString filter;
#if defined Q_OS_WIN32
filter = "Java (javaw.exe)";
#else
filter = "Java (java)";
#endif
QString raw_path = QFileDialog::getOpenFileName(this, tr("Find Java executable"), QString(), filter);
if (raw_path.isEmpty()) {
return;
}
QString cooked_path = FS::NormalizePath(raw_path);
m_javaPathTextBox->setText(cooked_path);
checkJavaPath(cooked_path);
}
void JavaSettingsWidget::on_javaStatusBtn_clicked()
{
QString text;
bool failed = false;
switch (javaStatus) {
case JavaStatus::NotSet:
checkJavaPath(m_javaPathTextBox->text());
return;
case JavaStatus::DoesNotExist:
text += QObject::tr("The specified file either doesn't exist or is not a proper executable.");
failed = true;
break;
case JavaStatus::DoesNotStart: {
text += QObject::tr("The specified Java binary didn't start properly.<br />");
auto htmlError = m_result.errorLog;
if (!htmlError.isEmpty()) {
htmlError.replace('\n', "<br />");
text += QString("<font color=\"red\">%1</font>").arg(htmlError);
}
failed = true;
break;
}
case JavaStatus::ReturnedInvalidData: {
text += QObject::tr("The specified Java binary returned unexpected results:<br />");
auto htmlOut = m_result.outLog;
if (!htmlOut.isEmpty()) {
htmlOut.replace('\n', "<br />");
text += QString("<font color=\"red\">%1</font>").arg(htmlOut);
}
failed = true;
break;
}
case JavaStatus::Good:
text += QObject::tr(
"Java test succeeded!<br />Platform reported: %1<br />Java version "
"reported: %2<br />")
.arg(m_result.realPlatform, m_result.javaVersion.toString());
break;
case JavaStatus::Pending:
// TODO: abort here?
return;
}
CustomMessageBox::selectable(this, failed ? QObject::tr("Java test failure") : QObject::tr("Java test success"), text,
failed ? QMessageBox::Critical : QMessageBox::Information)
->show();
}
void JavaSettingsWidget::setJavaStatus(JavaSettingsWidget::JavaStatus status)
{
javaStatus = status;
switch (javaStatus) {
case JavaStatus::Good:
m_javaStatusBtn->setIcon(goodIcon);
break;
case JavaStatus::NotSet:
case JavaStatus::Pending:
m_javaStatusBtn->setIcon(yellowIcon);
break;
default:
m_javaStatusBtn->setIcon(badIcon);
break;
}
}
void JavaSettingsWidget::javaPathEdited(const QString& path)
{
checkJavaPathOnEdit(path);
}
void JavaSettingsWidget::checkJavaPathOnEdit(const QString& path)
{
auto realPath = FS::ResolveExecutable(path);
QFileInfo pathInfo(realPath);
if (pathInfo.baseName().toLower().contains("java")) {
checkJavaPath(path);
} else {
if (!m_checker) {
setJavaStatus(JavaStatus::NotSet);
}
}
}
void JavaSettingsWidget::checkJavaPath(const QString& path)
{
if (m_checker) {
queuedCheck = path;
return;
}
auto realPath = FS::ResolveExecutable(path);
if (realPath.isNull()) {
setJavaStatus(JavaStatus::DoesNotExist);
return;
}
setJavaStatus(JavaStatus::Pending);
m_checker.reset(new JavaChecker());
m_checker->m_path = path;
m_checker->m_minMem = minHeapSize();
m_checker->m_maxMem = maxHeapSize();
if (m_permGenSpinBox->isVisible()) {
m_checker->m_permGen = m_permGenSpinBox->value();
}
connect(m_checker.get(), &JavaChecker::checkFinished, this, &JavaSettingsWidget::checkFinished);
m_checker->performCheck();
}
void JavaSettingsWidget::checkFinished(JavaCheckResult result)
{
m_result = result;
switch (result.validity) {
case JavaCheckResult::Validity::Valid: {
setJavaStatus(JavaStatus::Good);
break;
}
case JavaCheckResult::Validity::ReturnedInvalidData: {
setJavaStatus(JavaStatus::ReturnedInvalidData);
break;
}
case JavaCheckResult::Validity::Errored: {
setJavaStatus(JavaStatus::DoesNotStart);
break;
}
}
m_checker.reset();
if (!queuedCheck.isNull()) {
checkJavaPath(queuedCheck);
queuedCheck.clear();
}
}
void JavaSettingsWidget::retranslate()
{
m_memoryGroupBox->setTitle(tr("Memory"));
m_maxMemSpinBox->setToolTip(tr("The maximum amount of memory Minecraft is allowed to use."));
m_labelMinMem->setText(tr("Minimum memory allocation:"));
m_labelMaxMem->setText(tr("Maximum memory allocation:"));
m_minMemSpinBox->setToolTip(tr("The amount of memory Minecraft is started with."));
m_permGenSpinBox->setToolTip(tr("The amount of memory available to store loaded Java classes."));
m_javaBrowseBtn->setText(tr("Browse"));
}
void JavaSettingsWidget::updateThresholds()
{
auto sysMiB = Sys::getSystemRam() / Sys::mebibyte;
unsigned int maxMem = m_ui->maxMemSpinBox->value();
unsigned int minMem = m_ui->minMemSpinBox->value();
QString iconName;
if (observedMaxMemory >= m_availableMemory) {
if (maxMem >= sysMiB) {
iconName = "status-bad";
m_labelMaxMemIcon->setToolTip(tr("Your maximum memory allocation exceeds your system memory capacity."));
} else if (observedMaxMemory > (m_availableMemory * 0.9)) {
m_ui->labelMaxMemIcon->setToolTip(tr("Your maximum memory allocation exceeds your system memory capacity."));
} else if (maxMem > (sysMiB * 0.9)) {
iconName = "status-yellow";
m_labelMaxMemIcon->setToolTip(tr("Your maximum memory allocation approaches your system memory capacity."));
} else if (observedMaxMemory < observedMinMemory) {
m_ui->labelMaxMemIcon->setToolTip(tr("Your maximum memory allocation approaches your system memory capacity."));
} else if (maxMem < minMem) {
iconName = "status-yellow";
m_labelMaxMemIcon->setToolTip(tr("Your maximum memory allocation is smaller than the minimum value"));
m_ui->labelMaxMemIcon->setToolTip(tr("Your maximum memory allocation is smaller than the minimum value"));
} else {
iconName = "status-good";
m_labelMaxMemIcon->setToolTip("");
m_ui->labelMaxMemIcon->setToolTip("");
}
{
auto height = m_labelMaxMemIcon->fontInfo().pixelSize();
auto height = m_ui->labelMaxMemIcon->fontInfo().pixelSize();
QIcon icon = APPLICATION->getThemedIcon(iconName);
QPixmap pix = icon.pixmap(height, height);
m_labelMaxMemIcon->setPixmap(pix);
m_ui->labelMaxMemIcon->setPixmap(pix);
}
}

View File

@ -1,90 +1,68 @@
#pragma once
#include <QWidget>
#include <BaseVersion.h>
#include <QObjectPtr.h>
#include <java/JavaChecker.h>
#include <QIcon>
class QLineEdit;
class VersionSelectWidget;
class QSpinBox;
class QPushButton;
class QVBoxLayout;
class QHBoxLayout;
class QGroupBox;
class QGridLayout;
class QLabel;
class QToolButton;
/**
* This is a widget for all the Java settings dialogs and pages.
// SPDX-License-Identifier: GPL-3.0-only
/*
* Prism Launcher - Minecraft Launcher
* Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
* 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
* 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.
*/
#pragma once
#include <QWidget>
#include "BaseInstance.h"
#include "JavaCommon.h"
namespace Ui {
class JavaSettingsWidget;
}
class JavaSettingsWidget : public QWidget {
Q_OBJECT
public:
explicit JavaSettingsWidget(QWidget* parent);
virtual ~JavaSettingsWidget() {};
explicit JavaSettingsWidget(QWidget* parent = nullptr) : JavaSettingsWidget(nullptr, nullptr) {}
explicit JavaSettingsWidget(InstancePtr instance, QWidget* parent = nullptr);
~JavaSettingsWidget() override;
enum class JavaStatus { NotSet, Pending, Good, DoesNotExist, DoesNotStart, ReturnedInvalidData } javaStatus = JavaStatus::NotSet;
enum class ValidationStatus { Bad, JavaBad, AllOK };
void refresh();
void initialize();
ValidationStatus validate();
void retranslate();
bool permGenEnabled() const;
int permGenSize() const;
int minHeapSize() const;
int maxHeapSize() const;
QString javaPath() const;
void loadSettings();
void saveSettings();
private slots:
void onJavaBrowse();
void onJavaAutodetect();
void onJavaTest();
void updateThresholds();
protected slots:
void memoryValueChanged(int);
void javaPathEdited(const QString& path);
void javaVersionSelected(BaseVersion::Ptr version);
void on_javaBrowseBtn_clicked();
void on_javaStatusBtn_clicked();
void checkFinished(JavaCheckResult result);
protected: /* methods */
void checkJavaPathOnEdit(const QString& path);
void checkJavaPath(const QString& path);
void setJavaStatus(JavaStatus status);
void setupUi();
private: /* data */
VersionSelectWidget* m_versionWidget = nullptr;
QVBoxLayout* m_verticalLayout = nullptr;
QLineEdit* m_javaPathTextBox = nullptr;
QPushButton* m_javaBrowseBtn = nullptr;
QToolButton* m_javaStatusBtn = nullptr;
QHBoxLayout* m_horizontalLayout = nullptr;
QGroupBox* m_memoryGroupBox = nullptr;
QGridLayout* m_gridLayout_2 = nullptr;
QSpinBox* m_maxMemSpinBox = nullptr;
QLabel* m_labelMinMem = nullptr;
QLabel* m_labelMaxMem = nullptr;
QLabel* m_labelMaxMemIcon = nullptr;
QSpinBox* m_minMemSpinBox = nullptr;
QLabel* m_labelPermGen = nullptr;
QSpinBox* m_permGenSpinBox = nullptr;
QIcon goodIcon;
QIcon yellowIcon;
QIcon badIcon;
unsigned int observedMinMemory = 0;
unsigned int observedMaxMemory = 0;
unsigned int observedPermGenMemory = 0;
QString queuedCheck;
uint64_t m_availableMemory = 0ull;
shared_qobject_ptr<JavaChecker> m_checker;
JavaCheckResult m_result;
private:
InstancePtr m_instance;
Ui::JavaSettingsWidget* m_ui;
unique_qobject_ptr<JavaCommon::TestCheck> m_checker;
};

View File

@ -0,0 +1,269 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>JavaSettingsWidget</class>
<widget class="QWidget" name="JavaSettingsWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>500</width>
<height>600</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QGroupBox" name="javaInstallationGroupBox">
<property name="enabled">
<bool>true</bool>
</property>
<property name="title">
<string>Java Insta&amp;llation</string>
</property>
<property name="checkable">
<bool>false</bool>
</property>
<property name="checked">
<bool>false</bool>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="6" column="0">
<widget class="QCheckBox" name="autodetectJavaCheckBox">
<property name="text">
<string>Auto-&amp;detect Java version</string>
</property>
</widget>
</item>
<item row="1" column="0">
<layout class="QHBoxLayout" name="horizontalLayout_3">
<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_4">
<item>
<widget class="QPushButton" name="javaDownloadBtn">
<property name="text">
<string>Download Java</string>
</property>
</widget>
</item>
<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>
<item row="7" column="0">
<widget class="QCheckBox" name="autodownloadJavaCheckBox">
<property name="toolTip">
<string>Automatically downloads and selects the Java build recommended by Mojang.</string>
</property>
<property name="text">
<string>Auto-download &amp;Mojang Java</string>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QCheckBox" name="skipWizardCheckBox">
<property name="toolTip">
<string>If enabled, the launcher won't prompt you to choose a Java version if one is not found on startup.</string>
</property>
<property name="text">
<string>Skip Java setup prompt on startup</string>
</property>
</widget>
</item>
<item row="3" 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>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="memoryGroupBox">
<property name="enabled">
<bool>true</bool>
</property>
<property name="title">
<string>Memor&amp;y</string>
</property>
<property name="checkable">
<bool>false</bool>
</property>
<property name="checked">
<bool>false</bool>
</property>
<layout class="QGridLayout" name="gridLayout_5" columnstretch="1,0,0">
<item row="2" column="0">
<widget class="QLabel" name="labelPermGen">
<property name="text">
<string>PermGen (Java 7 and earlier):</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="2" column="1">
<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="0">
<widget class="QLabel" name="labelMaxMem">
<property name="text">
<string>Maximum memory allocation:</string>
</property>
</widget>
</item>
<item row="1" column="2">
<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>
<item row="1" column="1">
<widget class="QSpinBox" name="maxMemSpinBox">
<property name="toolTip">
<string>The maximum amount of memory Minecraft is allowed to use.</string>
</property>
<property name="suffix">
<string notr="true"> MiB</string>
</property>
<property name="minimum">
<number>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="0" column="1">
<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>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="javaArgumentsGroupBox">
<property name="enabled">
<bool>true</bool>
</property>
<property name="title">
<string>Java Argumen&amp;ts</string>
</property>
<property name="checkable">
<bool>false</bool>
</property>
<property name="checked">
<bool>false</bool>
</property>
<layout class="QGridLayout" name="gridLayout_6">
<item row="1" column="1">
<widget class="QPlainTextEdit" name="jvmArgsTextBox"/>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<tabstops>
<tabstop>javaPathTextBox</tabstop>
<tabstop>javaBrowseBtn</tabstop>
<tabstop>javaDownloadBtn</tabstop>
<tabstop>javaDetectBtn</tabstop>
<tabstop>javaTestBtn</tabstop>
<tabstop>skipCompatibilityCheckBox</tabstop>
<tabstop>skipWizardCheckBox</tabstop>
<tabstop>autodetectJavaCheckBox</tabstop>
<tabstop>autodownloadJavaCheckBox</tabstop>
<tabstop>minMemSpinBox</tabstop>
<tabstop>maxMemSpinBox</tabstop>
<tabstop>permGenSpinBox</tabstop>
<tabstop>jvmArgsTextBox</tabstop>
</tabstops>
<resources/>
<connections/>
</ui>

View File

@ -0,0 +1,559 @@
#include "JavaWizardWidget.h"
#include <QFileDialog>
#include <QGroupBox>
#include <QLabel>
#include <QLayoutItem>
#include <QLineEdit>
#include <QMessageBox>
#include <QPushButton>
#include <QSizePolicy>
#include <QSpinBox>
#include <QToolButton>
#include <QVBoxLayout>
#include <sys.h>
#include "DesktopServices.h"
#include "FileSystem.h"
#include "JavaCommon.h"
#include "java/JavaChecker.h"
#include "java/JavaInstall.h"
#include "java/JavaInstallList.h"
#include "java/JavaUtils.h"
#include "ui/dialogs/CustomMessageBox.h"
#include "ui/java/InstallJavaDialog.h"
#include "ui/widgets/VersionSelectWidget.h"
#include "Application.h"
#include "BuildConfig.h"
JavaWizardWidget::JavaWizardWidget(QWidget* parent) : QWidget(parent)
{
m_availableMemory = Sys::getSystemRam() / Sys::mebibyte;
goodIcon = APPLICATION->getThemedIcon("status-good");
yellowIcon = APPLICATION->getThemedIcon("status-yellow");
badIcon = APPLICATION->getThemedIcon("status-bad");
m_memoryTimer = new QTimer(this);
setupUi();
connect(m_minMemSpinBox, SIGNAL(valueChanged(int)), this, SLOT(onSpinBoxValueChanged(int)));
connect(m_maxMemSpinBox, SIGNAL(valueChanged(int)), this, SLOT(onSpinBoxValueChanged(int)));
connect(m_permGenSpinBox, SIGNAL(valueChanged(int)), this, SLOT(onSpinBoxValueChanged(int)));
connect(m_memoryTimer, &QTimer::timeout, this, &JavaWizardWidget::memoryValueChanged);
connect(m_versionWidget, &VersionSelectWidget::selectedVersionChanged, this, &JavaWizardWidget::javaVersionSelected);
connect(m_javaBrowseBtn, &QPushButton::clicked, this, &JavaWizardWidget::on_javaBrowseBtn_clicked);
connect(m_javaPathTextBox, &QLineEdit::textEdited, this, &JavaWizardWidget::javaPathEdited);
connect(m_javaStatusBtn, &QToolButton::clicked, this, &JavaWizardWidget::on_javaStatusBtn_clicked);
if (BuildConfig.JAVA_DOWNLOADER_ENABLED) {
connect(m_javaDownloadBtn, &QPushButton::clicked, this, &JavaWizardWidget::javaDownloadBtn_clicked);
}
}
void JavaWizardWidget::setupUi()
{
setObjectName(QStringLiteral("javaSettingsWidget"));
m_verticalLayout = new QVBoxLayout(this);
m_verticalLayout->setObjectName(QStringLiteral("verticalLayout"));
m_versionWidget = new VersionSelectWidget(this);
m_horizontalLayout = new QHBoxLayout();
m_horizontalLayout->setObjectName(QStringLiteral("horizontalLayout"));
m_javaPathTextBox = new QLineEdit(this);
m_javaPathTextBox->setObjectName(QStringLiteral("javaPathTextBox"));
m_horizontalLayout->addWidget(m_javaPathTextBox);
m_javaBrowseBtn = new QPushButton(this);
m_javaBrowseBtn->setObjectName(QStringLiteral("javaBrowseBtn"));
m_horizontalLayout->addWidget(m_javaBrowseBtn);
m_javaStatusBtn = new QToolButton(this);
m_javaStatusBtn->setIcon(yellowIcon);
m_horizontalLayout->addWidget(m_javaStatusBtn);
m_memoryGroupBox = new QGroupBox(this);
m_memoryGroupBox->setObjectName(QStringLiteral("memoryGroupBox"));
m_gridLayout_2 = new QGridLayout(m_memoryGroupBox);
m_gridLayout_2->setObjectName(QStringLiteral("gridLayout_2"));
m_gridLayout_2->setColumnStretch(0, 1);
m_labelMinMem = new QLabel(m_memoryGroupBox);
m_labelMinMem->setObjectName(QStringLiteral("labelMinMem"));
m_gridLayout_2->addWidget(m_labelMinMem, 0, 0, 1, 1);
m_minMemSpinBox = new QSpinBox(m_memoryGroupBox);
m_minMemSpinBox->setObjectName(QStringLiteral("minMemSpinBox"));
m_minMemSpinBox->setSuffix(QStringLiteral(" MiB"));
m_minMemSpinBox->setMinimum(8);
m_minMemSpinBox->setMaximum(1048576);
m_minMemSpinBox->setSingleStep(128);
m_labelMinMem->setBuddy(m_minMemSpinBox);
m_gridLayout_2->addWidget(m_minMemSpinBox, 0, 1, 1, 1);
m_labelMaxMem = new QLabel(m_memoryGroupBox);
m_labelMaxMem->setObjectName(QStringLiteral("labelMaxMem"));
m_gridLayout_2->addWidget(m_labelMaxMem, 1, 0, 1, 1);
m_maxMemSpinBox = new QSpinBox(m_memoryGroupBox);
m_maxMemSpinBox->setObjectName(QStringLiteral("maxMemSpinBox"));
m_maxMemSpinBox->setSuffix(QStringLiteral(" MiB"));
m_maxMemSpinBox->setMinimum(8);
m_maxMemSpinBox->setMaximum(1048576);
m_maxMemSpinBox->setSingleStep(128);
m_labelMaxMem->setBuddy(m_maxMemSpinBox);
m_gridLayout_2->addWidget(m_maxMemSpinBox, 1, 1, 1, 1);
m_labelMaxMemIcon = new QLabel(m_memoryGroupBox);
m_labelMaxMemIcon->setObjectName(QStringLiteral("labelMaxMemIcon"));
m_gridLayout_2->addWidget(m_labelMaxMemIcon, 1, 2, 1, 1);
m_labelPermGen = new QLabel(m_memoryGroupBox);
m_labelPermGen->setObjectName(QStringLiteral("labelPermGen"));
m_labelPermGen->setText(QStringLiteral("PermGen:"));
m_gridLayout_2->addWidget(m_labelPermGen, 2, 0, 1, 1);
m_labelPermGen->setVisible(false);
m_permGenSpinBox = new QSpinBox(m_memoryGroupBox);
m_permGenSpinBox->setObjectName(QStringLiteral("permGenSpinBox"));
m_permGenSpinBox->setSuffix(QStringLiteral(" MiB"));
m_permGenSpinBox->setMinimum(4);
m_permGenSpinBox->setMaximum(1048576);
m_permGenSpinBox->setSingleStep(8);
m_gridLayout_2->addWidget(m_permGenSpinBox, 2, 1, 1, 1);
m_permGenSpinBox->setVisible(false);
m_verticalLayout->addWidget(m_memoryGroupBox);
m_horizontalBtnLayout = new QHBoxLayout();
m_horizontalBtnLayout->setObjectName(QStringLiteral("horizontalBtnLayout"));
if (BuildConfig.JAVA_DOWNLOADER_ENABLED) {
m_javaDownloadBtn = new QPushButton(tr("Download Java"), this);
m_horizontalBtnLayout->addWidget(m_javaDownloadBtn);
}
m_autoJavaGroupBox = new QGroupBox(this);
m_autoJavaGroupBox->setObjectName(QStringLiteral("autoJavaGroupBox"));
m_veriticalJavaLayout = new QVBoxLayout(m_autoJavaGroupBox);
m_veriticalJavaLayout->setObjectName(QStringLiteral("veriticalJavaLayout"));
m_autodetectJavaCheckBox = new QCheckBox(m_autoJavaGroupBox);
m_autodetectJavaCheckBox->setObjectName("autodetectJavaCheckBox");
m_autodetectJavaCheckBox->setChecked(true);
m_veriticalJavaLayout->addWidget(m_autodetectJavaCheckBox);
if (BuildConfig.JAVA_DOWNLOADER_ENABLED) {
m_autodownloadCheckBox = new QCheckBox(m_autoJavaGroupBox);
m_autodownloadCheckBox->setObjectName("autodownloadCheckBox");
m_autodownloadCheckBox->setEnabled(m_autodetectJavaCheckBox->isChecked());
m_veriticalJavaLayout->addWidget(m_autodownloadCheckBox);
connect(m_autodetectJavaCheckBox, &QCheckBox::stateChanged, this, [this] {
m_autodownloadCheckBox->setEnabled(m_autodetectJavaCheckBox->isChecked());
if (!m_autodetectJavaCheckBox->isChecked())
m_autodownloadCheckBox->setChecked(false);
});
connect(m_autodownloadCheckBox, &QCheckBox::stateChanged, this, [this] {
auto isChecked = m_autodownloadCheckBox->isChecked();
m_versionWidget->setVisible(!isChecked);
m_javaStatusBtn->setVisible(!isChecked);
m_javaBrowseBtn->setVisible(!isChecked);
m_javaPathTextBox->setVisible(!isChecked);
m_javaDownloadBtn->setVisible(!isChecked);
if (!isChecked) {
m_verticalLayout->removeItem(m_verticalSpacer);
} else {
m_verticalLayout->addSpacerItem(m_verticalSpacer);
}
});
}
m_verticalLayout->addWidget(m_autoJavaGroupBox);
m_verticalLayout->addLayout(m_horizontalBtnLayout);
m_verticalLayout->addWidget(m_versionWidget);
m_verticalLayout->addLayout(m_horizontalLayout);
m_verticalSpacer = new QSpacerItem(20, 40, QSizePolicy::Minimum, QSizePolicy::Expanding);
retranslate();
}
void JavaWizardWidget::initialize()
{
m_versionWidget->initialize(APPLICATION->javalist().get());
m_versionWidget->selectSearch();
m_versionWidget->setResizeOn(2);
auto s = APPLICATION->settings();
// Memory
observedMinMemory = s->get("MinMemAlloc").toInt();
observedMaxMemory = s->get("MaxMemAlloc").toInt();
observedPermGenMemory = s->get("PermGen").toInt();
m_minMemSpinBox->setValue(observedMinMemory);
m_maxMemSpinBox->setValue(observedMaxMemory);
m_permGenSpinBox->setValue(observedPermGenMemory);
updateThresholds();
if (BuildConfig.JAVA_DOWNLOADER_ENABLED) {
m_autodownloadCheckBox->setChecked(true);
}
}
void JavaWizardWidget::refresh()
{
if (BuildConfig.JAVA_DOWNLOADER_ENABLED && m_autodownloadCheckBox->isChecked()) {
return;
}
if (JavaUtils::getJavaCheckPath().isEmpty()) {
JavaCommon::javaCheckNotFound(this);
return;
}
m_versionWidget->loadList();
}
JavaWizardWidget::ValidationStatus JavaWizardWidget::validate()
{
switch (javaStatus) {
default:
case JavaStatus::NotSet:
/* fallthrough */
case JavaStatus::DoesNotExist:
/* fallthrough */
case JavaStatus::DoesNotStart:
/* fallthrough */
case JavaStatus::ReturnedInvalidData: {
if (!(BuildConfig.JAVA_DOWNLOADER_ENABLED && m_autodownloadCheckBox->isChecked())) { // the java will not be autodownloaded
int button = QMessageBox::No;
if (m_result.mojangPlatform == "32" && maxHeapSize() > 2048) {
button = CustomMessageBox::selectable(
this, tr("32-bit Java detected"),
tr("You selected a 32-bit installation of Java, but allocated more than 2048MiB as maximum memory.\n"
"%1 will not be able to start Minecraft.\n"
"Do you wish to proceed?"
"\n\n"
"You can change the Java version in the settings later.\n")
.arg(BuildConfig.LAUNCHER_DISPLAYNAME),
QMessageBox::Warning, QMessageBox::Yes | QMessageBox::No | QMessageBox::Help, QMessageBox::NoButton)
->exec();
} else {
button = CustomMessageBox::selectable(this, tr("No Java version selected"),
tr("You either didn't select a Java version or selected one that does not work.\n"
"%1 will not be able to start Minecraft.\n"
"Do you wish to proceed without a functional version of Java?"
"\n\n"
"You can change the Java version in the settings later.\n")
.arg(BuildConfig.LAUNCHER_DISPLAYNAME),
QMessageBox::Warning, QMessageBox::Yes | QMessageBox::No | QMessageBox::Help,
QMessageBox::NoButton)
->exec();
}
switch (button) {
case QMessageBox::Yes:
return ValidationStatus::JavaBad;
case QMessageBox::Help:
DesktopServices::openUrl(QUrl(BuildConfig.HELP_URL.arg("java-wizard")));
/* fallthrough */
case QMessageBox::No:
/* fallthrough */
default:
return ValidationStatus::Bad;
}
if (button == QMessageBox::No) {
return ValidationStatus::Bad;
}
}
return ValidationStatus::JavaBad;
} break;
case JavaStatus::Pending: {
return ValidationStatus::Bad;
}
case JavaStatus::Good: {
return ValidationStatus::AllOK;
}
}
}
QString JavaWizardWidget::javaPath() const
{
return m_javaPathTextBox->text();
}
int JavaWizardWidget::maxHeapSize() const
{
auto min = m_minMemSpinBox->value();
auto max = m_maxMemSpinBox->value();
if (max < min)
max = min;
return max;
}
int JavaWizardWidget::minHeapSize() const
{
auto min = m_minMemSpinBox->value();
auto max = m_maxMemSpinBox->value();
if (min > max)
min = max;
return min;
}
bool JavaWizardWidget::permGenEnabled() const
{
return m_permGenSpinBox->isVisible();
}
int JavaWizardWidget::permGenSize() const
{
return m_permGenSpinBox->value();
}
void JavaWizardWidget::memoryValueChanged()
{
bool actuallyChanged = false;
unsigned int min = m_minMemSpinBox->value();
unsigned int max = m_maxMemSpinBox->value();
unsigned int permgen = m_permGenSpinBox->value();
if (min != observedMinMemory) {
observedMinMemory = min;
actuallyChanged = true;
}
if (max != observedMaxMemory) {
observedMaxMemory = max;
actuallyChanged = true;
}
if (permgen != observedPermGenMemory) {
observedPermGenMemory = permgen;
actuallyChanged = true;
}
if (actuallyChanged) {
checkJavaPathOnEdit(m_javaPathTextBox->text());
updateThresholds();
}
}
void JavaWizardWidget::javaVersionSelected(BaseVersion::Ptr version)
{
auto java = std::dynamic_pointer_cast<JavaInstall>(version);
if (!java) {
return;
}
auto visible = java->id.requiresPermGen();
m_labelPermGen->setVisible(visible);
m_permGenSpinBox->setVisible(visible);
m_javaPathTextBox->setText(java->path);
checkJavaPath(java->path);
}
void JavaWizardWidget::on_javaBrowseBtn_clicked()
{
auto filter = QString("Java (%1)").arg(JavaUtils::javaExecutable);
auto raw_path = QFileDialog::getOpenFileName(this, tr("Find Java executable"), QString(), filter);
if (raw_path.isEmpty()) {
return;
}
auto cooked_path = FS::NormalizePath(raw_path);
m_javaPathTextBox->setText(cooked_path);
checkJavaPath(cooked_path);
}
void JavaWizardWidget::javaDownloadBtn_clicked()
{
auto jdialog = new Java::InstallDialog({}, nullptr, this);
jdialog->exec();
}
void JavaWizardWidget::on_javaStatusBtn_clicked()
{
QString text;
bool failed = false;
switch (javaStatus) {
case JavaStatus::NotSet:
checkJavaPath(m_javaPathTextBox->text());
return;
case JavaStatus::DoesNotExist:
text += QObject::tr("The specified file either doesn't exist or is not a proper executable.");
failed = true;
break;
case JavaStatus::DoesNotStart: {
text += QObject::tr("The specified Java binary didn't start properly.<br />");
auto htmlError = m_result.errorLog;
if (!htmlError.isEmpty()) {
htmlError.replace('\n', "<br />");
text += QString("<font color=\"red\">%1</font>").arg(htmlError);
}
failed = true;
break;
}
case JavaStatus::ReturnedInvalidData: {
text += QObject::tr("The specified Java binary returned unexpected results:<br />");
auto htmlOut = m_result.outLog;
if (!htmlOut.isEmpty()) {
htmlOut.replace('\n', "<br />");
text += QString("<font color=\"red\">%1</font>").arg(htmlOut);
}
failed = true;
break;
}
case JavaStatus::Good:
text += QObject::tr(
"Java test succeeded!<br />Platform reported: %1<br />Java version "
"reported: %2<br />")
.arg(m_result.realPlatform, m_result.javaVersion.toString());
break;
case JavaStatus::Pending:
// TODO: abort here?
return;
}
CustomMessageBox::selectable(this, failed ? QObject::tr("Java test failure") : QObject::tr("Java test success"), text,
failed ? QMessageBox::Critical : QMessageBox::Information)
->show();
}
void JavaWizardWidget::setJavaStatus(JavaWizardWidget::JavaStatus status)
{
javaStatus = status;
switch (javaStatus) {
case JavaStatus::Good:
m_javaStatusBtn->setIcon(goodIcon);
break;
case JavaStatus::NotSet:
case JavaStatus::Pending:
m_javaStatusBtn->setIcon(yellowIcon);
break;
default:
m_javaStatusBtn->setIcon(badIcon);
break;
}
}
void JavaWizardWidget::javaPathEdited(const QString& path)
{
checkJavaPathOnEdit(path);
}
void JavaWizardWidget::checkJavaPathOnEdit(const QString& path)
{
auto realPath = FS::ResolveExecutable(path);
QFileInfo pathInfo(realPath);
if (pathInfo.baseName().toLower().contains("java")) {
checkJavaPath(path);
} else {
if (!m_checker) {
setJavaStatus(JavaStatus::NotSet);
}
}
}
void JavaWizardWidget::checkJavaPath(const QString& path)
{
if (m_checker) {
queuedCheck = path;
return;
}
auto realPath = FS::ResolveExecutable(path);
if (realPath.isNull()) {
setJavaStatus(JavaStatus::DoesNotExist);
return;
}
setJavaStatus(JavaStatus::Pending);
m_checker.reset(
new JavaChecker(path, "", minHeapSize(), maxHeapSize(), m_permGenSpinBox->isVisible() ? m_permGenSpinBox->value() : 0, 0));
connect(m_checker.get(), &JavaChecker::checkFinished, this, &JavaWizardWidget::checkFinished);
m_checker->start();
}
void JavaWizardWidget::checkFinished(const JavaChecker::Result& result)
{
m_result = result;
switch (result.validity) {
case JavaChecker::Result::Validity::Valid: {
setJavaStatus(JavaStatus::Good);
break;
}
case JavaChecker::Result::Validity::ReturnedInvalidData: {
setJavaStatus(JavaStatus::ReturnedInvalidData);
break;
}
case JavaChecker::Result::Validity::Errored: {
setJavaStatus(JavaStatus::DoesNotStart);
break;
}
}
updateThresholds();
m_checker.reset();
if (!queuedCheck.isNull()) {
checkJavaPath(queuedCheck);
queuedCheck.clear();
}
}
void JavaWizardWidget::retranslate()
{
m_memoryGroupBox->setTitle(tr("Memory"));
m_maxMemSpinBox->setToolTip(tr("The maximum amount of memory Minecraft is allowed to use."));
m_labelMinMem->setText(tr("Minimum memory allocation:"));
m_labelMaxMem->setText(tr("Maximum memory allocation:"));
m_minMemSpinBox->setToolTip(tr("The amount of memory Minecraft is started with."));
m_permGenSpinBox->setToolTip(tr("The amount of memory available to store loaded Java classes."));
m_javaBrowseBtn->setText(tr("Browse"));
if (BuildConfig.JAVA_DOWNLOADER_ENABLED) {
m_autodownloadCheckBox->setText(tr("Auto-download Mojang Java"));
}
m_autodetectJavaCheckBox->setText(tr("Auto-detect Java version"));
m_autoJavaGroupBox->setTitle(tr("Autodetect Java"));
}
void JavaWizardWidget::updateThresholds()
{
QString iconName;
if (observedMaxMemory >= m_availableMemory) {
iconName = "status-bad";
m_labelMaxMemIcon->setToolTip(tr("Your maximum memory allocation exceeds your system memory capacity."));
} else if (observedMaxMemory > (m_availableMemory * 0.9)) {
iconName = "status-yellow";
m_labelMaxMemIcon->setToolTip(tr("Your maximum memory allocation approaches your system memory capacity."));
} else if (observedMaxMemory < observedMinMemory) {
iconName = "status-yellow";
m_labelMaxMemIcon->setToolTip(tr("Your maximum memory allocation is smaller than the minimum value"));
} else if (BuildConfig.JAVA_DOWNLOADER_ENABLED && m_autodownloadCheckBox->isChecked()) {
iconName = "status-good";
m_labelMaxMemIcon->setToolTip("");
} else if (observedMaxMemory > 2048 && !m_result.is_64bit) {
iconName = "status-bad";
m_labelMaxMemIcon->setToolTip(tr("You are exceeding the maximum allocation supported by 32-bit installations of Java."));
} else {
iconName = "status-good";
m_labelMaxMemIcon->setToolTip("");
}
{
auto height = m_labelMaxMemIcon->fontInfo().pixelSize();
QIcon icon = APPLICATION->getThemedIcon(iconName);
QPixmap pix = icon.pixmap(height, height);
m_labelMaxMemIcon->setPixmap(pix);
}
}
bool JavaWizardWidget::autoDownloadJava() const
{
return m_autodownloadCheckBox && m_autodownloadCheckBox->isChecked();
}
bool JavaWizardWidget::autoDetectJava() const
{
return m_autodetectJavaCheckBox->isChecked();
}
void JavaWizardWidget::onSpinBoxValueChanged(int)
{
m_memoryTimer->start(500);
}
JavaWizardWidget::~JavaWizardWidget()
{
delete m_verticalSpacer;
};

View File

@ -0,0 +1,103 @@
#pragma once
#include <QWidget>
#include <BaseVersion.h>
#include <QObjectPtr.h>
#include <java/JavaChecker.h>
#include <qcheckbox.h>
#include <QIcon>
class QLineEdit;
class VersionSelectWidget;
class QSpinBox;
class QPushButton;
class QVBoxLayout;
class QHBoxLayout;
class QGroupBox;
class QGridLayout;
class QLabel;
class QToolButton;
class QSpacerItem;
class JavaWizardWidget : public QWidget {
Q_OBJECT
public:
explicit JavaWizardWidget(QWidget* parent);
virtual ~JavaWizardWidget();
enum class JavaStatus { NotSet, Pending, Good, DoesNotExist, DoesNotStart, ReturnedInvalidData } javaStatus = JavaStatus::NotSet;
enum class ValidationStatus { Bad, JavaBad, AllOK };
void refresh();
void initialize();
ValidationStatus validate();
void retranslate();
bool permGenEnabled() const;
int permGenSize() const;
int minHeapSize() const;
int maxHeapSize() const;
QString javaPath() const;
bool autoDetectJava() const;
bool autoDownloadJava() const;
void updateThresholds();
protected slots:
void onSpinBoxValueChanged(int);
void memoryValueChanged();
void javaPathEdited(const QString& path);
void javaVersionSelected(BaseVersion::Ptr version);
void on_javaBrowseBtn_clicked();
void on_javaStatusBtn_clicked();
void javaDownloadBtn_clicked();
void checkFinished(const JavaChecker::Result& result);
protected: /* methods */
void checkJavaPathOnEdit(const QString& path);
void checkJavaPath(const QString& path);
void setJavaStatus(JavaStatus status);
void setupUi();
private: /* data */
VersionSelectWidget* m_versionWidget = nullptr;
QVBoxLayout* m_verticalLayout = nullptr;
QSpacerItem* m_verticalSpacer = nullptr;
QLineEdit* m_javaPathTextBox = nullptr;
QPushButton* m_javaBrowseBtn = nullptr;
QToolButton* m_javaStatusBtn = nullptr;
QHBoxLayout* m_horizontalLayout = nullptr;
QGroupBox* m_memoryGroupBox = nullptr;
QGridLayout* m_gridLayout_2 = nullptr;
QSpinBox* m_maxMemSpinBox = nullptr;
QLabel* m_labelMinMem = nullptr;
QLabel* m_labelMaxMem = nullptr;
QLabel* m_labelMaxMemIcon = nullptr;
QSpinBox* m_minMemSpinBox = nullptr;
QLabel* m_labelPermGen = nullptr;
QSpinBox* m_permGenSpinBox = nullptr;
QHBoxLayout* m_horizontalBtnLayout = nullptr;
QPushButton* m_javaDownloadBtn = nullptr;
QIcon goodIcon;
QIcon yellowIcon;
QIcon badIcon;
QGroupBox* m_autoJavaGroupBox = nullptr;
QVBoxLayout* m_veriticalJavaLayout = nullptr;
QCheckBox* m_autodetectJavaCheckBox = nullptr;
QCheckBox* m_autodownloadCheckBox = nullptr;
unsigned int observedMinMemory = 0;
unsigned int observedMaxMemory = 0;
unsigned int observedPermGenMemory = 0;
QString queuedCheck;
uint64_t m_availableMemory = 0ull;
shared_qobject_ptr<JavaChecker> m_checker;
JavaChecker::Result m_result;
QTimer* m_memoryTimer;
};

View File

@ -0,0 +1,460 @@
// 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) 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
* 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 "MinecraftSettingsWidget.h"
#include "Application.h"
#include "BuildConfig.h"
#include "minecraft/WorldList.h"
#include "minecraft/auth/AccountList.h"
#include "settings/Setting.h"
#include "ui_MinecraftSettingsWidget.h"
MinecraftSettingsWidget::MinecraftSettingsWidget(MinecraftInstancePtr instance, QWidget* parent)
: QWidget(parent), m_instance(std::move(instance)), m_ui(new Ui::MinecraftSettingsWidget)
{
m_ui->setupUi(this);
if (m_instance == nullptr) {
for (int i = m_ui->settingsTabs->count() - 1; i >= 0; --i) {
const QString name = m_ui->settingsTabs->widget(i)->objectName();
if (name == "javaPage" || name == "launchPage")
m_ui->settingsTabs->removeTab(i);
}
m_ui->openGlobalSettingsButton->setVisible(false);
} else {
m_javaSettings = new JavaSettingsWidget(m_instance, this);
m_ui->javaScrollArea->setWidget(m_javaSettings);
m_ui->showGameTime->setText(tr("Show time &playing this instance"));
m_ui->recordGameTime->setText(tr("&Record time playing this instance"));
m_ui->showGlobalGameTime->hide();
m_ui->showGameTimeWithoutDays->hide();
m_ui->maximizedWarning->setText(
tr("<span style=\" font-weight:600; color:#f5c211;\">Warning</span><span style=\" color:#f5c211;\">: The maximized option is "
"not fully supported on this Minecraft version.</span>"));
m_ui->miscellaneousSettingsBox->setCheckable(true);
m_ui->consoleSettingsBox->setCheckable(true);
m_ui->windowSizeGroupBox->setCheckable(true);
m_ui->nativeWorkaroundsGroupBox->setCheckable(true);
m_ui->perfomanceGroupBox->setCheckable(true);
m_ui->gameTimeGroupBox->setCheckable(true);
m_ui->legacySettingsGroupBox->setCheckable(true);
m_quickPlaySingleplayer = m_instance->traits().contains("feature:is_quick_play_singleplayer");
if (m_quickPlaySingleplayer) {
auto worlds = m_instance->worldList();
worlds->update();
for (const auto& world : worlds->allWorlds()) {
m_ui->worldsCb->addItem(world.folderName());
}
} else {
m_ui->worldsCb->hide();
m_ui->worldJoinButton->hide();
m_ui->serverJoinAddressButton->setChecked(true);
m_ui->serverJoinAddress->setEnabled(true);
m_ui->serverJoinAddressButton->setStyleSheet("QRadioButton::indicator { width: 0px; height: 0px; }");
}
connect(m_ui->openGlobalSettingsButton, &QCommandLinkButton::clicked, this, &MinecraftSettingsWidget::openGlobalSettings);
connect(m_ui->serverJoinAddressButton, &QAbstractButton::toggled, m_ui->serverJoinAddress, &QWidget::setEnabled);
connect(m_ui->worldJoinButton, &QAbstractButton::toggled, m_ui->worldsCb, &QWidget::setEnabled);
}
m_ui->maximizedWarning->hide();
connect(m_ui->maximizedCheckBox, &QCheckBox::toggled, this,
[this](const bool value) { m_ui->maximizedWarning->setVisible(value && (m_instance == nullptr || !m_instance->isLegacy())); });
#if !defined(Q_OS_LINUX)
m_ui->perfomanceGroupBox->hide();
#endif
if (!(APPLICATION->capabilities() & Application::SupportsGameMode)) {
m_ui->enableFeralGamemodeCheck->setDisabled(true);
m_ui->enableFeralGamemodeCheck->setToolTip(tr("Feral Interactive's GameMode could not be found on your system."));
}
if (!(APPLICATION->capabilities() & Application::SupportsMangoHud)) {
m_ui->enableMangoHud->setEnabled(false);
m_ui->enableMangoHud->setToolTip(tr("MangoHud could not be found on your system."));
}
connect(m_ui->useNativeOpenALCheck, &QAbstractButton::toggled, m_ui->lineEditOpenALPath, &QWidget::setEnabled);
connect(m_ui->useNativeGLFWCheck, &QAbstractButton::toggled, m_ui->lineEditGLFWPath, &QWidget::setEnabled);
loadSettings();
}
MinecraftSettingsWidget::~MinecraftSettingsWidget()
{
delete m_ui;
}
void MinecraftSettingsWidget::loadSettings()
{
SettingsObjectPtr settings;
if (m_instance != nullptr)
settings = m_instance->settings();
else
settings = APPLICATION->settings();
// Game Window
m_ui->windowSizeGroupBox->setChecked(m_instance == nullptr || settings->get("OverrideWindow").toBool());
m_ui->windowSizeGroupBox->setChecked(settings->get("OverrideWindow").toBool());
m_ui->maximizedCheckBox->setChecked(settings->get("LaunchMaximized").toBool());
m_ui->windowWidthSpinBox->setValue(settings->get("MinecraftWinWidth").toInt());
m_ui->windowHeightSpinBox->setValue(settings->get("MinecraftWinHeight").toInt());
// Game Time
m_ui->gameTimeGroupBox->setChecked(m_instance == nullptr || settings->get("OverrideGameTime").toBool());
m_ui->showGameTime->setChecked(settings->get("ShowGameTime").toBool());
m_ui->recordGameTime->setChecked(settings->get("RecordGameTime").toBool());
m_ui->showGlobalGameTime->setChecked(m_instance == nullptr && settings->get("ShowGlobalGameTime").toBool());
m_ui->showGameTimeWithoutDays->setChecked(m_instance == nullptr && settings->get("ShowGameTimeWithoutDays").toBool());
// Console
m_ui->consoleSettingsBox->setChecked(m_instance == nullptr || settings->get("OverrideConsole").toBool());
m_ui->showConsoleCheck->setChecked(settings->get("ShowConsole").toBool());
m_ui->autoCloseConsoleCheck->setChecked(settings->get("AutoCloseConsole").toBool());
m_ui->showConsoleErrorCheck->setChecked(settings->get("ShowConsoleOnError").toBool());
// Miscellaneous
m_ui->miscellaneousSettingsBox->setChecked(settings->get("OverrideMiscellaneous").toBool());
m_ui->closeAfterLaunchCheck->setChecked(settings->get("CloseAfterLaunch").toBool());
m_ui->quitAfterGameStopCheck->setChecked(settings->get("QuitAfterGameStop").toBool());
if (m_javaSettings != nullptr)
m_javaSettings->loadSettings();
// Custom commands
m_ui->customCommands->initialize(m_instance != nullptr, m_instance == nullptr || settings->get("OverrideCommands").toBool(),
settings->get("PreLaunchCommand").toString(), settings->get("WrapperCommand").toString(),
settings->get("PostExitCommand").toString());
// Environment variables
m_ui->environmentVariables->initialize(m_instance != nullptr, m_instance == nullptr || settings->get("OverrideEnv").toBool(),
settings->get("Env").toMap());
// Legacy Tweaks
m_ui->legacySettingsGroupBox->setChecked(m_instance == nullptr || settings->get("OverrideLegacySettings").toBool());
m_ui->onlineFixes->setChecked(settings->get("OnlineFixes").toBool());
// Native Libraries
m_ui->nativeWorkaroundsGroupBox->setChecked(m_instance == nullptr || settings->get("OverrideNativeWorkarounds").toBool());
m_ui->useNativeGLFWCheck->setChecked(settings->get("UseNativeGLFW").toBool());
m_ui->lineEditGLFWPath->setText(settings->get("CustomGLFWPath").toString());
#ifdef Q_OS_LINUX
m_ui->lineEditGLFWPath->setPlaceholderText(APPLICATION->m_detectedGLFWPath);
#else
m_ui->lineEditGLFWPath->setPlaceholderText(tr("Path to %1 library file").arg(BuildConfig.GLFW_LIBRARY_NAME));
#endif
m_ui->useNativeOpenALCheck->setChecked(settings->get("UseNativeOpenAL").toBool());
m_ui->lineEditOpenALPath->setText(settings->get("CustomOpenALPath").toString());
#ifdef Q_OS_LINUX
m_ui->lineEditOpenALPath->setPlaceholderText(APPLICATION->m_detectedOpenALPath);
#else
m_ui->lineEditOpenALPath->setPlaceholderText(tr("Path to %1 library file").arg(BuildConfig.OPENAL_LIBRARY_NAME));
#endif
// Performance
m_ui->perfomanceGroupBox->setChecked(m_instance == nullptr || settings->get("OverridePerformance").toBool());
m_ui->enableFeralGamemodeCheck->setChecked(settings->get("EnableFeralGamemode").toBool());
m_ui->enableMangoHud->setChecked(settings->get("EnableMangoHud").toBool());
m_ui->useDiscreteGpuCheck->setChecked(settings->get("UseDiscreteGpu").toBool());
m_ui->useZink->setChecked(settings->get("UseZink").toBool());
m_ui->serverJoinGroupBox->setChecked(settings->get("JoinServerOnLaunch").toBool());
if (m_instance != nullptr) {
if (auto server = settings->get("JoinServerOnLaunchAddress").toString(); !server.isEmpty()) {
m_ui->serverJoinAddress->setText(server);
m_ui->serverJoinAddressButton->setChecked(true);
m_ui->worldJoinButton->setChecked(false);
m_ui->serverJoinAddress->setEnabled(true);
m_ui->worldsCb->setEnabled(false);
} else if (auto world = settings->get("JoinWorldOnLaunch").toString(); !world.isEmpty() && m_quickPlaySingleplayer) {
m_ui->worldsCb->setCurrentText(world);
m_ui->serverJoinAddressButton->setChecked(false);
m_ui->worldJoinButton->setChecked(true);
m_ui->serverJoinAddress->setEnabled(false);
m_ui->worldsCb->setEnabled(true);
} else {
m_ui->serverJoinAddressButton->setChecked(true);
m_ui->worldJoinButton->setChecked(false);
m_ui->serverJoinAddress->setEnabled(true);
m_ui->worldsCb->setEnabled(false);
}
m_ui->instanceAccountGroupBox->setChecked(settings->get("UseAccountForInstance").toBool());
updateAccountsMenu(*settings);
}
m_ui->legacySettingsGroupBox->setChecked(settings->get("OverrideLegacySettings").toBool());
m_ui->onlineFixes->setChecked(settings->get("OnlineFixes").toBool());
}
void MinecraftSettingsWidget::saveSettings()
{
SettingsObjectPtr settings;
if (m_instance != nullptr)
settings = m_instance->settings();
else
settings = APPLICATION->settings();
{
SettingsObject::Lock lock(settings);
// Miscellaneous
bool miscellaneous = m_instance == nullptr || m_ui->miscellaneousSettingsBox->isChecked();
if (m_instance != nullptr)
settings->set("OverrideMiscellaneous", miscellaneous);
if (miscellaneous) {
settings->set("CloseAfterLaunch", m_ui->closeAfterLaunchCheck->isChecked());
settings->set("QuitAfterGameStop", m_ui->quitAfterGameStopCheck->isChecked());
} else {
settings->reset("CloseAfterLaunch");
settings->reset("QuitAfterGameStop");
}
// Console
bool console = m_instance == nullptr || m_ui->consoleSettingsBox->isChecked();
if (m_instance != nullptr)
settings->set("OverrideConsole", console);
if (console) {
settings->set("ShowConsole", m_ui->showConsoleCheck->isChecked());
settings->set("AutoCloseConsole", m_ui->autoCloseConsoleCheck->isChecked());
settings->set("ShowConsoleOnError", m_ui->showConsoleErrorCheck->isChecked());
} else {
settings->reset("ShowConsole");
settings->reset("AutoCloseConsole");
settings->reset("ShowConsoleOnError");
}
// Window Size
bool window = m_instance == nullptr || m_ui->windowSizeGroupBox->isChecked();
if (m_instance != nullptr)
settings->set("OverrideWindow", window);
if (window) {
settings->set("LaunchMaximized", m_ui->maximizedCheckBox->isChecked());
settings->set("MinecraftWinWidth", m_ui->windowWidthSpinBox->value());
settings->set("MinecraftWinHeight", m_ui->windowHeightSpinBox->value());
} else {
settings->reset("LaunchMaximized");
settings->reset("MinecraftWinWidth");
settings->reset("MinecraftWinHeight");
}
// Custom Commands
bool custcmd = m_instance == nullptr || m_ui->customCommands->checked();
if (m_instance != nullptr)
settings->set("OverrideCommands", custcmd);
if (custcmd) {
settings->set("PreLaunchCommand", m_ui->customCommands->prelaunchCommand());
settings->set("WrapperCommand", m_ui->customCommands->wrapperCommand());
settings->set("PostExitCommand", m_ui->customCommands->postexitCommand());
} else {
settings->reset("PreLaunchCommand");
settings->reset("WrapperCommand");
settings->reset("PostExitCommand");
}
// Environment Variables
auto env = m_instance == nullptr || m_ui->environmentVariables->override();
if (m_instance != nullptr)
settings->set("OverrideEnv", env);
if (env)
settings->set("Env", m_ui->environmentVariables->value());
else
settings->reset("Env");
// Workarounds
bool workarounds = m_instance == nullptr || m_ui->nativeWorkaroundsGroupBox->isChecked();
if (m_instance != nullptr)
settings->set("OverrideNativeWorkarounds", workarounds);
if (workarounds) {
settings->set("UseNativeGLFW", m_ui->useNativeGLFWCheck->isChecked());
settings->set("CustomGLFWPath", m_ui->lineEditGLFWPath->text());
settings->set("UseNativeOpenAL", m_ui->useNativeOpenALCheck->isChecked());
settings->set("CustomOpenALPath", m_ui->lineEditOpenALPath->text());
} else {
settings->reset("UseNativeGLFW");
settings->reset("CustomGLFWPath");
settings->reset("UseNativeOpenAL");
settings->reset("CustomOpenALPath");
}
// Performance
bool performance = m_instance == nullptr || m_ui->perfomanceGroupBox->isChecked();
if (m_instance != nullptr)
settings->set("OverridePerformance", performance);
if (performance) {
settings->set("EnableFeralGamemode", m_ui->enableFeralGamemodeCheck->isChecked());
settings->set("EnableMangoHud", m_ui->enableMangoHud->isChecked());
settings->set("UseDiscreteGpu", m_ui->useDiscreteGpuCheck->isChecked());
settings->set("UseZink", m_ui->useZink->isChecked());
} else {
settings->reset("EnableFeralGamemode");
settings->reset("EnableMangoHud");
settings->reset("UseDiscreteGpu");
settings->reset("UseZink");
}
// Game time
bool gameTime = m_instance == nullptr || m_ui->gameTimeGroupBox->isChecked();
if (m_instance != nullptr)
settings->set("OverrideGameTime", gameTime);
if (gameTime) {
settings->set("ShowGameTime", m_ui->showGameTime->isChecked());
settings->set("RecordGameTime", m_ui->recordGameTime->isChecked());
} else {
settings->reset("ShowGameTime");
settings->reset("RecordGameTime");
}
if (m_instance == nullptr) {
settings->set("ShowGlobalGameTime", m_ui->showGlobalGameTime->isChecked());
settings->set("ShowGameTimeWithoutDays", m_ui->showGameTimeWithoutDays->isChecked());
}
if (m_instance != nullptr) {
// Join server on launch
bool joinServerOnLaunch = m_ui->serverJoinGroupBox->isChecked();
settings->set("JoinServerOnLaunch", joinServerOnLaunch);
if (joinServerOnLaunch) {
if (m_ui->serverJoinAddressButton->isChecked() || !m_quickPlaySingleplayer) {
settings->set("JoinServerOnLaunchAddress", m_ui->serverJoinAddress->text());
settings->reset("JoinWorldOnLaunch");
} else {
settings->set("JoinWorldOnLaunch", m_ui->worldsCb->currentText());
settings->reset("JoinServerOnLaunchAddress");
}
} else {
settings->reset("JoinServerOnLaunchAddress");
settings->reset("JoinWorldOnLaunch");
}
// Use an account for this instance
bool useAccountForInstance = m_ui->instanceAccountGroupBox->isChecked();
settings->set("UseAccountForInstance", useAccountForInstance);
if (useAccountForInstance) {
int accountIndex = m_ui->instanceAccountSelector->currentIndex();
if (accountIndex != -1) {
const MinecraftAccountPtr account = APPLICATION->accounts()->at(accountIndex);
if (account != nullptr)
settings->set("InstanceAccountId", account->profileId());
}
} else {
settings->reset("InstanceAccountId");
}
}
bool overrideLegacySettings = m_instance == nullptr || m_ui->legacySettingsGroupBox->isChecked();
if (m_instance != nullptr)
settings->set("OverrideLegacySettings", overrideLegacySettings);
if (overrideLegacySettings) {
settings->set("OnlineFixes", m_ui->onlineFixes->isChecked());
} else {
settings->reset("OnlineFixes");
}
}
if (m_javaSettings != nullptr)
m_javaSettings->saveSettings();
}
void MinecraftSettingsWidget::openGlobalSettings()
{
const QString id = m_ui->settingsTabs->currentWidget()->objectName();
qDebug() << id;
if (id == "javaPage")
APPLICATION->ShowGlobalSettings(this, "java-settings");
else // TODO select tab
APPLICATION->ShowGlobalSettings(this, "minecraft-settings");
}
void MinecraftSettingsWidget::updateAccountsMenu(const SettingsObject& settings)
{
m_ui->instanceAccountSelector->clear();
auto accounts = APPLICATION->accounts();
int accountIndex = accounts->findAccountByProfileId(settings.get("InstanceAccountId").toString());
for (int i = 0; i < accounts->count(); i++) {
MinecraftAccountPtr account = accounts->at(i);
QIcon face = account->getFace();
if (face.isNull())
face = APPLICATION->getThemedIcon("noaccount");
m_ui->instanceAccountSelector->addItem(face, account->profileName(), i);
if (i == accountIndex)
m_ui->instanceAccountSelector->setCurrentIndex(i);
}
}
bool MinecraftSettingsWidget::isQuickPlaySupported()
{
return m_instance->traits().contains("feature:is_quick_play_singleplayer");
}

View File

@ -0,0 +1,64 @@
// SPDX-License-Identifier: GPL-3.0-only
/*
* Prism Launcher - Minecraft Launcher
* Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
* 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
* 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.
*/
#pragma once
#include <QWidget>
#include "JavaSettingsWidget.h"
#include "minecraft/MinecraftInstance.h"
namespace Ui {
class MinecraftSettingsWidget;
}
class MinecraftSettingsWidget : public QWidget {
public:
MinecraftSettingsWidget(MinecraftInstancePtr instance, QWidget* parent = nullptr);
~MinecraftSettingsWidget() override;
void loadSettings();
void saveSettings();
private:
void openGlobalSettings();
void updateAccountsMenu(const SettingsObject& settings);
bool isQuickPlaySupported();
MinecraftInstancePtr m_instance;
Ui::MinecraftSettingsWidget* m_ui;
JavaSettingsWidget* m_javaSettings = nullptr;
bool m_quickPlaySingleplayer = false;
};

View File

@ -0,0 +1,686 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MinecraftSettingsWidget</class>
<widget class="QWidget" name="MinecraftSettingsWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>648</width>
<height>400</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="openGlobalSettingsButton">
<property name="text">
<string>Open &amp;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="generalPage">
<attribute name="title">
<string>General</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QScrollArea" name="scrollArea">
<property name="sizePolicy">
<sizepolicy hsizetype="Minimum" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="horizontalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
<property name="widgetResizable">
<bool>true</bool>
</property>
<widget class="QWidget" name="scrollAreaWidgetContents">
<property name="geometry">
<rect>
<x>0</x>
<y>-253</y>
<width>610</width>
<height>550</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_5">
<item>
<widget class="QGroupBox" name="windowSizeGroupBox">
<property name="enabled">
<bool>true</bool>
</property>
<property name="title">
<string>Game &amp;Window</string>
</property>
<property name="checkable">
<bool>false</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>
<widget class="QLabel" name="maximizedWarning">
<property name="toolTip">
<string>The base game only supports resolution. In order to simulate the maximized behaviour the current implementation approximates the maximum display size.</string>
</property>
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;&lt;span style=&quot; font-weight:600; color:#f5c211;&quot;&gt;Warning&lt;/span&gt;&lt;span style=&quot; color:#f5c211;&quot;&gt;: The maximized option may not be fully supported on all Minecraft versions.&lt;/span&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</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="gameTimeGroupBox">
<property name="enabled">
<bool>true</bool>
</property>
<property name="title">
<string>Game &amp;Time</string>
</property>
<property name="checkable">
<bool>false</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 &amp;playing instances</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="recordGameTime">
<property name="text">
<string>&amp;Record time spent playing instances</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="showGlobalGameTime">
<property name="text">
<string>Show the &amp;total time played across instances</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="showGameTimeWithoutDays">
<property name="text">
<string>Always show durations in &amp;hours</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="consoleSettingsBox">
<property name="enabled">
<bool>true</bool>
</property>
<property name="title">
<string>&amp;Console</string>
</property>
<property name="checkable">
<bool>false</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>&amp;Miscellaneous</string>
</property>
<property name="checkable">
<bool>false</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="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>
</item>
</layout>
</widget>
<widget class="QWidget" name="javaPage">
<attribute name="title">
<string>Java</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_11">
<item>
<widget class="QScrollArea" name="javaScrollArea">
<property name="widgetResizable">
<bool>true</bool>
</property>
<widget class="QWidget" name="scrollAreaWidgetContents_3">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>624</width>
<height>297</height>
</rect>
</property>
</widget>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="tweaksPage">
<attribute name="title">
<string>Tweaks</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_8">
<item>
<widget class="QScrollArea" name="scrollArea_2">
<property name="horizontalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
<property name="widgetResizable">
<bool>true</bool>
</property>
<widget class="QWidget" name="scrollAreaWidgetContents_2">
<property name="geometry">
<rect>
<x>0</x>
<y>-101</y>
<width>610</width>
<height>398</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_7">
<item>
<widget class="QGroupBox" name="legacySettingsGroupBox">
<property name="title">
<string>&amp;Legacy Tweaks</string>
</property>
<property name="checkable">
<bool>false</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>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Emulates usages of old online services which are no longer operating.&lt;/p&gt;&lt;p&gt;Current fixes include: skin and online mode support.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Enable online fixes (experimental)</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="nativeWorkaroundsGroupBox">
<property name="enabled">
<bool>true</bool>
</property>
<property name="title">
<string>&amp;Native Libraries</string>
</property>
<property name="checkable">
<bool>false</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>&amp;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>&amp;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>
<widget class="QGroupBox" name="perfomanceGroupBox">
<property name="enabled">
<bool>true</bool>
</property>
<property name="title">
<string>&amp;Performance</string>
</property>
<property name="checkable">
<bool>false</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>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Enable Feral Interactive's GameMode, to potentially improve gaming performance.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Enable Feral GameMode</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="enableMangoHud">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Enable MangoHud's advanced performance overlay.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="text">
<string>Enable MangoHud</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="useDiscreteGpuCheck">
<property name="toolTip">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Use the discrete GPU instead of the primary GPU.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</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">
<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>
<widget class="QWidget" name="launchPage">
<attribute name="title">
<string>Launch</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_9">
<item>
<widget class="QScrollArea" name="scrollArea_3">
<property name="widgetResizable">
<bool>true</bool>
</property>
<widget class="QWidget" name="scrollAreaWidgetContents_5">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>624</width>
<height>297</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout_14">
<item>
<widget class="QGroupBox" name="instanceAccountGroupBox">
<property name="title">
<string>Override default &amp;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>
<widget class="QGroupBox" name="serverJoinGroupBox">
<property name="title">
<string>Set a &amp;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>
<spacer name="verticalSpacer_3">
<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>
<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>
</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>openGlobalSettingsButton</tabstop>
<tabstop>settingsTabs</tabstop>
<tabstop>scrollArea</tabstop>
<tabstop>maximizedCheckBox</tabstop>
<tabstop>windowWidthSpinBox</tabstop>
<tabstop>windowHeightSpinBox</tabstop>
<tabstop>showGameTime</tabstop>
<tabstop>recordGameTime</tabstop>
<tabstop>showGlobalGameTime</tabstop>
<tabstop>showGameTimeWithoutDays</tabstop>
<tabstop>showConsoleCheck</tabstop>
<tabstop>autoCloseConsoleCheck</tabstop>
<tabstop>showConsoleErrorCheck</tabstop>
<tabstop>closeAfterLaunchCheck</tabstop>
<tabstop>quitAfterGameStopCheck</tabstop>
<tabstop>javaScrollArea</tabstop>
<tabstop>scrollArea_2</tabstop>
<tabstop>onlineFixes</tabstop>
<tabstop>useNativeGLFWCheck</tabstop>
<tabstop>lineEditGLFWPath</tabstop>
<tabstop>useNativeOpenALCheck</tabstop>
<tabstop>lineEditOpenALPath</tabstop>
<tabstop>perfomanceGroupBox</tabstop>
<tabstop>enableFeralGamemodeCheck</tabstop>
<tabstop>enableMangoHud</tabstop>
<tabstop>useDiscreteGpuCheck</tabstop>
<tabstop>useZink</tabstop>
<tabstop>scrollArea_3</tabstop>
<tabstop>instanceAccountGroupBox</tabstop>
<tabstop>instanceAccountSelector</tabstop>
<tabstop>serverJoinGroupBox</tabstop>
<tabstop>serverJoinAddressButton</tabstop>
<tabstop>serverJoinAddress</tabstop>
<tabstop>worldJoinButton</tabstop>
<tabstop>worldsCb</tabstop>
</tabstops>
<resources/>
<connections/>
</ui>

View File

@ -64,10 +64,49 @@ class VersionBasicModel : public QIdentityProxyModel {
{
if (role == Qt::DisplayRole)
return QIdentityProxyModel::data(index, BaseVersionList::VersionIdRole);
if (role == Qt::UserRole)
return QIdentityProxyModel::data(index, BaseVersionList::VersionIdRole);
return {};
}
};
class AllVersionProxyModel : public QSortFilterProxyModel {
Q_OBJECT
public:
AllVersionProxyModel(QObject* parent = nullptr) : QSortFilterProxyModel(parent) {}
int rowCount(const QModelIndex& parent = QModelIndex()) const override { return QSortFilterProxyModel::rowCount(parent) + 1; }
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override
{
if (!index.isValid()) {
return {};
}
if (index.row() == 0) {
if (role == Qt::DisplayRole) {
return tr("All Versions");
}
if (role == Qt::UserRole) {
return "all";
}
return {};
}
QModelIndex newIndex = QSortFilterProxyModel::index(index.row() - 1, index.column());
return QSortFilterProxyModel::data(newIndex, role);
}
Qt::ItemFlags flags(const QModelIndex& index) const override
{
if (index.row() == 0) {
return Qt::ItemIsSelectable | Qt::ItemIsEnabled;
}
return QSortFilterProxyModel::flags(index);
}
};
ModFilterWidget::ModFilterWidget(MinecraftInstance* instance, bool extended, QWidget* parent)
: QTabWidget(parent), ui(new Ui::ModFilterWidget), m_instance(instance), m_filter(new Filter())
{
@ -76,18 +115,26 @@ ModFilterWidget::ModFilterWidget(MinecraftInstance* instance, bool extended, QWi
m_versions_proxy = new VersionProxyModel(this);
m_versions_proxy->setFilter(BaseVersionList::TypeRole, new ExactFilter("release"));
auto proxy = new VersionBasicModel(this);
QAbstractProxyModel* proxy = new VersionBasicModel(this);
proxy->setSourceModel(m_versions_proxy);
if (extended) {
if (!m_instance) {
ui->environmentGroup->hide();
}
ui->versions->setSourceModel(proxy);
ui->versions->setSeparator(", ");
ui->versions->setDefaultText(tr("All Versions"));
ui->version->hide();
} else {
auto allVersions = new AllVersionProxyModel(this);
allVersions->setSourceModel(proxy);
proxy = allVersions;
ui->version->setModel(proxy);
ui->versions->hide();
ui->showAllVersions->hide();
ui->environmentGroup->hide();
ui->openSource->hide();
}
ui->versions->setStyleSheet("combobox-popup: 0;");
@ -113,6 +160,12 @@ ModFilterWidget::ModFilterWidget(MinecraftInstance* instance, bool extended, QWi
}
connect(ui->hideInstalled, &QCheckBox::stateChanged, this, &ModFilterWidget::onHideInstalledFilterChanged);
connect(ui->openSource, &QCheckBox::stateChanged, this, &ModFilterWidget::onOpenSourceFilterChanged);
connect(ui->releaseCb, &QCheckBox::stateChanged, this, &ModFilterWidget::onReleaseFilterChanged);
connect(ui->betaCb, &QCheckBox::stateChanged, this, &ModFilterWidget::onReleaseFilterChanged);
connect(ui->alphaCb, &QCheckBox::stateChanged, this, &ModFilterWidget::onReleaseFilterChanged);
connect(ui->unknownCb, &QCheckBox::stateChanged, this, &ModFilterWidget::onReleaseFilterChanged);
setHidden(true);
loadVersionList();
@ -162,18 +215,23 @@ void ModFilterWidget::loadVersionList()
void ModFilterWidget::prepareBasicFilter()
{
m_filter->hideInstalled = false;
m_filter->side = ""; // or "both"
auto loaders = m_instance->getPackProfile()->getSupportedModLoaders().value();
ui->neoForge->setChecked(loaders & ModPlatform::NeoForge);
ui->forge->setChecked(loaders & ModPlatform::Forge);
ui->fabric->setChecked(loaders & ModPlatform::Fabric);
ui->quilt->setChecked(loaders & ModPlatform::Quilt);
m_filter->loaders = loaders;
auto def = m_instance->getPackProfile()->getComponentVersion("net.minecraft");
m_filter->versions.emplace_front(def);
ui->versions->setCheckedItems({ def });
ui->version->setCurrentIndex(ui->version->findText(def));
m_filter->openSource = false;
if (m_instance) {
m_filter->hideInstalled = false;
m_filter->side = ""; // or "both"
auto loaders = m_instance->getPackProfile()->getSupportedModLoaders().value();
ui->neoForge->setChecked(loaders & ModPlatform::NeoForge);
ui->forge->setChecked(loaders & ModPlatform::Forge);
ui->fabric->setChecked(loaders & ModPlatform::Fabric);
ui->quilt->setChecked(loaders & ModPlatform::Quilt);
m_filter->loaders = loaders;
auto def = m_instance->getPackProfile()->getComponentVersion("net.minecraft");
m_filter->versions.emplace_front(def);
ui->versions->setCheckedItems({ def });
ui->version->setCurrentIndex(ui->version->findText(def));
} else {
ui->hideInstalled->hide();
}
}
void ModFilterWidget::onShowAllVersionsChanged()
@ -221,16 +279,17 @@ void ModFilterWidget::onSideFilterChanged()
{
QString side;
if (ui->clientSide->isChecked() != ui->serverSide->isChecked()) {
if (ui->clientSide->isChecked())
side = "client";
else
side = "server";
if (ui->clientSide->isChecked() && !ui->serverSide->isChecked()) {
side = "client";
} else if (!ui->clientSide->isChecked() && ui->serverSide->isChecked()) {
side = "server";
} else if (ui->clientSide->isChecked() && ui->serverSide->isChecked()) {
side = "both";
} else {
// both are checked or none are checked; in either case no filtering will happen
side = "";
}
m_filter_changed = side != m_filter->side;
m_filter->side = side;
if (m_filter_changed)
@ -249,7 +308,9 @@ void ModFilterWidget::onHideInstalledFilterChanged()
void ModFilterWidget::onVersionFilterTextChanged(const QString& version)
{
m_filter->versions.clear();
m_filter->versions.emplace_back(version);
if (ui->version->currentData(Qt::UserRole) != "all") {
m_filter->versions.emplace_back(version);
}
m_filter_changed = true;
emit filterChanged();
}
@ -285,4 +346,30 @@ void ModFilterWidget::setCategories(const QList<ModPlatform::Category>& categori
}
}
#include "ModFilterWidget.moc"
void ModFilterWidget::onOpenSourceFilterChanged()
{
auto open = ui->openSource->isChecked();
m_filter_changed = open != m_filter->openSource;
m_filter->openSource = open;
if (m_filter_changed)
emit filterChanged();
}
void ModFilterWidget::onReleaseFilterChanged()
{
std::list<ModPlatform::IndexedVersionType> releases;
if (ui->releaseCb->isChecked())
releases.push_back(ModPlatform::IndexedVersionType(ModPlatform::IndexedVersionType::VersionType::Release));
if (ui->betaCb->isChecked())
releases.push_back(ModPlatform::IndexedVersionType(ModPlatform::IndexedVersionType::VersionType::Beta));
if (ui->alphaCb->isChecked())
releases.push_back(ModPlatform::IndexedVersionType(ModPlatform::IndexedVersionType::VersionType::Alpha));
if (ui->unknownCb->isChecked())
releases.push_back(ModPlatform::IndexedVersionType(ModPlatform::IndexedVersionType::VersionType::Unknown));
m_filter_changed = releases != m_filter->releases;
m_filter->releases = releases;
if (m_filter_changed)
emit filterChanged();
}
#include "ModFilterWidget.moc"

View File

@ -64,13 +64,23 @@ class ModFilterWidget : public QTabWidget {
QString side;
bool hideInstalled;
QStringList categoryIds;
bool openSource;
bool operator==(const Filter& other) const
{
return hideInstalled == other.hideInstalled && side == other.side && loaders == other.loaders && versions == other.versions &&
releases == other.releases && categoryIds == other.categoryIds;
releases == other.releases && categoryIds == other.categoryIds && openSource == other.openSource;
}
bool operator!=(const Filter& other) const { return !(*this == other); }
bool checkMcVersions(QStringList value)
{
for (auto mcVersion : versions)
if (value.contains(mcVersion.toString()))
return true;
return versions.empty();
}
};
static unique_qobject_ptr<ModFilterWidget> create(MinecraftInstance* instance, bool extended, QWidget* parent = nullptr);
@ -98,6 +108,8 @@ class ModFilterWidget : public QTabWidget {
void onSideFilterChanged();
void onHideInstalledFilterChanged();
void onShowAllVersionsChanged();
void onOpenSourceFilterChanged();
void onReleaseFilterChanged();
private:
Ui::ModFilterWidget* ui;

View File

@ -63,8 +63,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>308</width>
<height>598</height>
<width>294</width>
<height>781</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
@ -188,6 +188,50 @@
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="openSource">
<property name="text">
<string>Open source only</string>
</property>
</widget>
</item>
<item>
<widget class="QGroupBox" name="releaseGroup">
<property name="title">
<string>Release type</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_6">
<item>
<widget class="QCheckBox" name="releaseCb">
<property name="text">
<string>Release</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="betaCb">
<property name="text">
<string>Beta</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="alphaCb">
<property name="text">
<string>Alpha</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="unknownCb">
<property name="text">
<string>Unknown</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">

View File

@ -47,6 +47,9 @@
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse|Qt::TextBrowserInteraction|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item>
@ -68,6 +71,9 @@
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="textInteractionFlags">
<set>Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse|Qt::TextBrowserInteraction|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
</property>
</widget>
</item>
</layout>

View File

@ -87,7 +87,7 @@ void ThemeCustomizationWidget::applyIconTheme(int index)
{
auto settings = APPLICATION->settings();
auto originalIconTheme = settings->get("IconTheme").toString();
auto newIconTheme = ui->iconsComboBox->currentData().toString();
auto newIconTheme = ui->iconsComboBox->itemData(index).toString();
if (originalIconTheme != newIconTheme) {
settings->set("IconTheme", newIconTheme);
APPLICATION->themeManager()->applyCurrentlySelectedTheme();
@ -100,7 +100,7 @@ void ThemeCustomizationWidget::applyWidgetTheme(int index)
{
auto settings = APPLICATION->settings();
auto originalAppTheme = settings->get("ApplicationTheme").toString();
auto newAppTheme = ui->widgetStyleComboBox->currentData().toString();
auto newAppTheme = ui->widgetStyleComboBox->itemData(index).toString();
if (originalAppTheme != newAppTheme) {
settings->set("ApplicationTheme", newAppTheme);
APPLICATION->themeManager()->applyCurrentlySelectedTheme();
@ -113,7 +113,7 @@ void ThemeCustomizationWidget::applyCatTheme(int index)
{
auto settings = APPLICATION->settings();
auto originalCat = settings->get("BackgroundCat").toString();
auto newCat = ui->backgroundCatComboBox->currentData().toString();
auto newCat = ui->backgroundCatComboBox->itemData(index).toString();
if (originalCat != newCat) {
settings->set("BackgroundCat", newCat);
}