GH-2150 Separate Java settings UI used in the wizard into a widget

This commit is contained in:
Petr Mrázek 2018-02-18 12:39:35 +01:00
parent 65bca65489
commit 06ccff0f47
6 changed files with 565 additions and 445 deletions

View File

@ -163,6 +163,8 @@ SET(MULTIMC_SOURCES
widgets/FocusLineEdit.h
widgets/IconLabel.cpp
widgets/IconLabel.h
widgets/JavaSettingsWidget.cpp
widgets/JavaSettingsWidget.h
widgets/LabeledToolButton.cpp
widgets/LabeledToolButton.h
widgets/LineSeparator.cpp

View File

@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>553</width>
<height>583</height>
<height>522</height>
</rect>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
@ -211,19 +211,6 @@
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacerMinecraft">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<widget class="QWidget" name="javaTab">

View File

@ -17,184 +17,35 @@
#include <sys.h>
#include <QFileDialog>
#include <JavaCommon.h>
#include "widgets/JavaSettingsWidget.h"
JavaWizardPage::JavaWizardPage(QWidget *parent)
:BaseWizardPage(parent)
{
m_availableMemory = Sys::getSystemRam() / Sys::megabyte;
goodIcon = MMC->getThemedIcon("status-good");
yellowIcon = MMC->getThemedIcon("status-yellow");
badIcon = MMC->getThemedIcon("status-bad");
setupUi();
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, &JavaWizardPage::javaVersionSelected);
connect(m_javaBrowseBtn, &QPushButton::clicked, this, &JavaWizardPage::on_javaBrowseBtn_clicked);
connect(m_javaPathTextBox, &QLineEdit::textEdited, this, &JavaWizardPage::javaPathEdited);
connect(m_javaStatusBtn, &QToolButton::clicked, this, &JavaWizardPage::on_javaStatusBtn_clicked);
}
void JavaWizardPage::setupUi()
{
setObjectName(QStringLiteral("javaPage"));
m_verticalLayout = new QVBoxLayout(this);
m_verticalLayout->setObjectName(QStringLiteral("verticalLayout"));
QVBoxLayout * layout = new QVBoxLayout(this);
m_versionWidget = new VersionSelectWidget(MMC->javalist().get(), this);
m_versionWidget->setResizeOn(2);
m_verticalLayout->addWidget(m_versionWidget);
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"));
/*
QSizePolicy sizePolicy2(QSizePolicy::Fixed, QSizePolicy::Fixed);
sizePolicy2.setHorizontalStretch(0);
sizePolicy2.setVerticalStretch(0);
sizePolicy2.setHeightForWidth(m_javaBrowseBtn->sizePolicy().hasHeightForWidth());
m_javaBrowseBtn->setSizePolicy(sizePolicy2);
m_javaBrowseBtn->setMaximumSize(QSize(28, 16777215));
*/
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_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(" MB"));
m_minMemSpinBox->setMinimum(128);
m_minMemSpinBox->setMaximum(m_availableMemory);
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(" MB"));
m_maxMemSpinBox->setMinimum(128);
m_maxMemSpinBox->setMaximum(m_availableMemory);
m_maxMemSpinBox->setSingleStep(128);
m_labelMaxMem->setBuddy(m_maxMemSpinBox);
m_gridLayout_2->addWidget(m_maxMemSpinBox, 1, 1, 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(" MB"));
m_permGenSpinBox->setMinimum(64);
m_permGenSpinBox->setMaximum(m_availableMemory);
m_permGenSpinBox->setSingleStep(8);
m_gridLayout_2->addWidget(m_permGenSpinBox, 2, 1, 1, 1);
m_permGenSpinBox->setVisible(false);
m_verticalLayout->addWidget(m_memoryGroupBox);
m_java_widget = new JavaSettingsWidget(this);
layout->addWidget(m_java_widget);
setLayout(layout);
retranslate();
}
void JavaWizardPage::refresh()
{
m_versionWidget->loadList();
m_java_widget->refresh();
}
void JavaWizardPage::initializePage()
{
m_versionWidget->initialize();
auto s = MMC->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);
}
bool JavaWizardPage::validatePage()
{
auto settings = MMC->settings();
auto path = m_javaPathTextBox->text();
switch(javaStatus)
{
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"
"MultiMC 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"
),
QMessageBox::Warning,
QMessageBox::Yes | QMessageBox::No,
QMessageBox::NoButton
)->exec();
if(button == QMessageBox::No)
{
return false;
}
}
break;
case JavaStatus::Pending:
{
return false;
}
case JavaStatus::Good:
{
settings->set("JavaPath", path);
}
}
// Memory
auto s = MMC->settings();
s->set("MinMemAlloc", m_minMemSpinBox->value());
s->set("MaxMemAlloc", m_maxMemSpinBox->value());
if (m_permGenSpinBox->isVisible())
{
s->set("PermGen", m_permGenSpinBox->value());
}
else
{
s->reset("PermGen");
}
return true;
m_java_widget->initialize();
}
bool JavaWizardPage::wantsRefreshButton()
@ -202,221 +53,37 @@ bool JavaWizardPage::wantsRefreshButton()
return true;
}
void JavaWizardPage::memoryValueChanged(int)
bool JavaWizardPage::validatePage()
{
bool actuallyChanged = false;
int min = m_minMemSpinBox->value();
int max = m_maxMemSpinBox->value();
int permgen = m_permGenSpinBox->value();
QObject *obj = sender();
if (obj == m_minMemSpinBox && min != observedMinMemory)
auto settings = MMC->settings();
auto result = m_java_widget->validate();
switch(result)
{
observedMinMemory = min;
actuallyChanged = true;
if (min > max)
{
observedMaxMemory = min;
m_maxMemSpinBox->setValue(min);
}
}
else if (obj == m_maxMemSpinBox && max != observedMaxMemory)
{
observedMaxMemory = max;
actuallyChanged = true;
if (min > max)
{
observedMinMemory = max;
m_minMemSpinBox->setValue(max);
}
}
else if (obj == m_permGenSpinBox && permgen != observedPermGenMemory)
{
observedPermGenMemory = permgen;
actuallyChanged = true;
}
if(actuallyChanged)
{
checkJavaPathOnEdit(m_javaPathTextBox->text());
}
}
void JavaWizardPage::javaVersionSelected(BaseVersionPtr 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 JavaWizardPage::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 JavaWizardPage::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 success") : QObject::tr("Java test failure"),
text,
failed ? QMessageBox::Critical : QMessageBox::Information
)->show();
}
void JavaWizardPage::setJavaStatus(JavaWizardPage::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 JavaWizardPage::javaPathEdited(const QString& path)
{
checkJavaPathOnEdit(path);
}
void JavaWizardPage::checkJavaPathOnEdit(const QString& path)
{
auto realPath = FS::ResolveExecutable(path);
QFileInfo pathInfo(realPath);
if (pathInfo.baseName().toLower().contains("java"))
{
checkJavaPath(path);
}
else
{
if(!m_checker)
case JavaSettingsWidget::ValidationStatus::Bad:
{
setJavaStatus(JavaStatus::NotSet);
return false;
}
}
}
void JavaWizardPage::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 = m_minMemSpinBox->value();
m_checker->m_maxMem = m_maxMemSpinBox->value();
if(m_permGenSpinBox->isVisible())
{
m_checker->m_permGen = m_permGenSpinBox->value();
}
connect(m_checker.get(), &JavaChecker::checkFinished, this, &JavaWizardPage::checkFinished);
m_checker->performCheck();
}
void JavaWizardPage::checkFinished(JavaCheckResult result)
{
m_result = result;
switch(result.validity)
{
case JavaCheckResult::Validity::Valid:
case JavaSettingsWidget::ValidationStatus::AllOK:
{
setJavaStatus(JavaStatus::Good);
break;
settings->set("JavaPath", m_java_widget->javaPath());
}
case JavaCheckResult::Validity::ReturnedInvalidData:
case JavaSettingsWidget::ValidationStatus::JavaBad:
{
setJavaStatus(JavaStatus::ReturnedInvalidData);
break;
// Memory
auto s = MMC->settings();
s->set("MinMemAlloc", m_java_widget->minHeapSize());
s->set("MaxMemAlloc", m_java_widget->maxHeapSize());
if (m_java_widget->permGenEnabled())
{
s->set("PermGen", m_java_widget->permGenSize());
}
else
{
s->reset("PermGen");
}
return true;
}
case JavaCheckResult::Validity::Errored:
{
setJavaStatus(JavaStatus::DoesNotStart);
break;
}
}
m_checker.reset();
if(!queuedCheck.isNull())
{
checkJavaPath(queuedCheck);
queuedCheck.clear();
}
}
@ -425,11 +92,5 @@ void JavaWizardPage::retranslate()
setTitle(tr("Java"));
setSubTitle(tr("You do not have a working Java set up yet or it went missing.\n"
"Please select one of the following or browse for a java executable."));
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"));
m_java_widget->retranslate();
}

View File

@ -1,21 +1,8 @@
#pragma once
#include "BaseWizardPage.h"
#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;
class JavaSettingsWidget;
class JavaWizardPage : public BaseWizardPage
{
@ -32,58 +19,11 @@ public:
void initializePage() override;
bool validatePage() override;
enum class JavaStatus
{
NotSet,
Pending,
Good,
DoesNotExist,
DoesNotStart,
ReturnedInvalidData
} javaStatus = JavaStatus::NotSet;
protected slots:
void memoryValueChanged(int);
void javaPathEdited(const QString &path);
void javaVersionSelected(BaseVersionPtr 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();
void retranslate() override;
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;
QSpinBox *m_minMemSpinBox = nullptr;
QLabel *m_labelPermGen = nullptr;
QSpinBox *m_permGenSpinBox = nullptr;
QIcon goodIcon;
QIcon yellowIcon;
QIcon badIcon;
int observedMinMemory = 0;
int observedMaxMemory = 0;
int observedPermGenMemory = 0;
QString queuedCheck;
uint64_t m_availableMemory = 0ull;
shared_qobject_ptr<JavaChecker> m_checker;
JavaCheckResult m_result;
JavaSettingsWidget *m_java_widget = nullptr;
};

View File

@ -0,0 +1,428 @@
#include "JavaSettingsWidget.h"
#include <MultiMC.h>
#include <java/JavaInstall.h>
#include <dialogs/CustomMessageBox.h>
#include <java/JavaUtils.h>
#include <sys.h>
#include <QVBoxLayout>
#include <QGroupBox>
#include <QSpinBox>
#include <QLabel>
#include <QLineEdit>
#include <QPushButton>
#include <QToolButton>
#include <widgets/VersionSelectWidget.h>
#include <FileSystem.h>
#include <QFileDialog>
JavaSettingsWidget::JavaSettingsWidget(QWidget* parent) : QWidget(parent)
{
m_availableMemory = Sys::getSystemRam() / Sys::megabyte;
goodIcon = MMC->getThemedIcon("status-good");
yellowIcon = MMC->getThemedIcon("status-yellow");
badIcon = MMC->getThemedIcon("status-bad");
setupUi();
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);
}
void JavaSettingsWidget::setupUi()
{
setObjectName(QStringLiteral("javaSettingsWidget"));
m_verticalLayout = new QVBoxLayout(this);
m_verticalLayout->setObjectName(QStringLiteral("verticalLayout"));
m_versionWidget = new VersionSelectWidget(MMC->javalist().get(), this);
m_versionWidget->setResizeOn(2);
m_verticalLayout->addWidget(m_versionWidget);
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_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_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(" MB"));
m_minMemSpinBox->setMinimum(128);
m_minMemSpinBox->setMaximum(m_availableMemory);
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(" MB"));
m_maxMemSpinBox->setMinimum(128);
m_maxMemSpinBox->setMaximum(m_availableMemory);
m_maxMemSpinBox->setSingleStep(128);
m_labelMaxMem->setBuddy(m_maxMemSpinBox);
m_gridLayout_2->addWidget(m_maxMemSpinBox, 1, 1, 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(" MB"));
m_permGenSpinBox->setMinimum(64);
m_permGenSpinBox->setMaximum(m_availableMemory);
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();
auto s = MMC->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);
}
void JavaSettingsWidget::refresh()
{
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"
"MultiMC 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"
),
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;
}
}
}
QString JavaSettingsWidget::javaPath() const
{
return m_javaPathTextBox->text();
}
int JavaSettingsWidget::maxHeapSize() const
{
return m_maxMemSpinBox->value();
}
int JavaSettingsWidget::minHeapSize() const
{
return m_minMemSpinBox->value();
}
bool JavaSettingsWidget::permGenEnabled() const
{
return m_permGenSpinBox->isVisible();
}
int JavaSettingsWidget::permGenSize() const
{
return m_permGenSpinBox->value();
}
void JavaSettingsWidget::memoryValueChanged(int)
{
bool actuallyChanged = false;
int min = m_minMemSpinBox->value();
int max = m_maxMemSpinBox->value();
int permgen = m_permGenSpinBox->value();
QObject *obj = sender();
if (obj == m_minMemSpinBox && min != observedMinMemory)
{
observedMinMemory = min;
actuallyChanged = true;
if (min > max)
{
observedMaxMemory = min;
m_maxMemSpinBox->setValue(min);
}
}
else if (obj == m_maxMemSpinBox && max != observedMaxMemory)
{
observedMaxMemory = max;
actuallyChanged = true;
if (min > max)
{
observedMinMemory = max;
m_minMemSpinBox->setValue(max);
}
}
else if (obj == m_permGenSpinBox && permgen != observedPermGenMemory)
{
observedPermGenMemory = permgen;
actuallyChanged = true;
}
if(actuallyChanged)
{
checkJavaPathOnEdit(m_javaPathTextBox->text());
}
}
void JavaSettingsWidget::javaVersionSelected(BaseVersionPtr 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 success") : QObject::tr("Java test failure"),
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 = m_minMemSpinBox->value();
m_checker->m_maxMem = m_maxMemSpinBox->value();
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"));
}

View File

@ -0,0 +1,102 @@
#pragma once
#include <QWidget>
#include <java/JavaChecker.h>
#include <BaseVersion.h>
#include <QObjectPtr.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.
*/
class JavaSettingsWidget : public QWidget
{
Q_OBJECT
public:
explicit JavaSettingsWidget(QWidget *parent);
virtual ~JavaSettingsWidget() {};
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;
protected slots:
void memoryValueChanged(int);
void javaPathEdited(const QString &path);
void javaVersionSelected(BaseVersionPtr 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;
QSpinBox *m_minMemSpinBox = nullptr;
QLabel *m_labelPermGen = nullptr;
QSpinBox *m_permGenSpinBox = nullptr;
QIcon goodIcon;
QIcon yellowIcon;
QIcon badIcon;
int observedMinMemory = 0;
int observedMaxMemory = 0;
int observedPermGenMemory = 0;
QString queuedCheck;
uint64_t m_availableMemory = 0ull;
shared_qobject_ptr<JavaChecker> m_checker;
JavaCheckResult m_result;
};