From bc05ad30aa7c3da5d76947e82012f50466bb5d39 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Sun, 20 Jul 2014 23:47:46 +0200 Subject: [PATCH] Rework the settings dialog. Rework all of it. Thoroughly. Also introduces the ColumnResizer from: https://github.com/agateau/columnresizer/ --- CMakeLists.txt | 29 +- gui/ColumnResizer.cpp | 202 ++++ gui/ColumnResizer.h | 38 + gui/MainWindow.cpp | 12 +- gui/dialogs/AboutDialog.ui | 39 +- gui/pages/global/AccountListPage.cpp | 3 +- gui/pages/global/AccountListPage.h | 2 +- gui/pages/global/AccountListPage.ui | 144 +-- gui/pages/global/BaseSettingsPage.cpp | 28 - gui/pages/global/BaseSettingsPage.h | 35 - gui/pages/global/ExternalToolsPage.cpp | 77 +- gui/pages/global/ExternalToolsPage.h | 12 +- gui/pages/global/ExternalToolsPage.ui | 296 +++--- gui/pages/global/JavaPage.cpp | 146 +++ gui/pages/global/JavaPage.h | 72 ++ gui/pages/global/JavaPage.ui | 303 ++++++ gui/pages/global/MinecraftPage.cpp | 104 ++ gui/pages/global/MinecraftPage.h | 69 ++ gui/pages/global/MinecraftPage.ui | 184 ++++ .../{SettingsPage.cpp => MultiMCPage.cpp} | 259 +---- .../global/{SettingsPage.h => MultiMCPage.h} | 43 +- gui/pages/global/MultiMCPage.ui | 399 +++++++ gui/pages/global/ProxyPage.cpp | 95 ++ gui/pages/global/ProxyPage.h | 66 ++ gui/pages/global/ProxyPage.ui | 197 ++++ gui/pages/global/SettingsPage.ui | 985 ------------------ gui/widgets/PageContainer.cpp | 3 + resources/multimc/16x16/minecraft.png | Bin 0 -> 782 bytes resources/multimc/24x24/minecraft.png | Bin 0 -> 1500 bytes resources/multimc/256x256/minecraft.png | Bin 0 -> 49869 bytes resources/multimc/32x32/minecraft.png | Bin 0 -> 2495 bytes resources/multimc/48x48/minecraft.png | Bin 0 -> 5077 bytes resources/multimc/index.theme | 3 + resources/multimc/multimc.qrc | 13 + resources/multimc/scalable/java.svg | 773 ++++++++++++++ resources/multimc/scalable/proxy.svg | 260 +++++ 36 files changed, 3357 insertions(+), 1534 deletions(-) create mode 100644 gui/ColumnResizer.cpp create mode 100644 gui/ColumnResizer.h delete mode 100644 gui/pages/global/BaseSettingsPage.cpp delete mode 100644 gui/pages/global/BaseSettingsPage.h create mode 100644 gui/pages/global/JavaPage.cpp create mode 100644 gui/pages/global/JavaPage.h create mode 100644 gui/pages/global/JavaPage.ui create mode 100644 gui/pages/global/MinecraftPage.cpp create mode 100644 gui/pages/global/MinecraftPage.h create mode 100644 gui/pages/global/MinecraftPage.ui rename gui/pages/global/{SettingsPage.cpp => MultiMCPage.cpp} (54%) rename gui/pages/global/{SettingsPage.h => MultiMCPage.h} (65%) create mode 100644 gui/pages/global/MultiMCPage.ui create mode 100644 gui/pages/global/ProxyPage.cpp create mode 100644 gui/pages/global/ProxyPage.h create mode 100644 gui/pages/global/ProxyPage.ui delete mode 100644 gui/pages/global/SettingsPage.ui create mode 100644 resources/multimc/16x16/minecraft.png create mode 100644 resources/multimc/24x24/minecraft.png create mode 100644 resources/multimc/256x256/minecraft.png create mode 100644 resources/multimc/32x32/minecraft.png create mode 100644 resources/multimc/48x48/minecraft.png create mode 100644 resources/multimc/scalable/java.svg create mode 100644 resources/multimc/scalable/proxy.svg diff --git a/CMakeLists.txt b/CMakeLists.txt index 7cae21dd..7efd42e6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -283,6 +283,8 @@ SET(MULTIMC_SOURCES # GUI - general utilities gui/GuiUtil.h gui/GuiUtil.cpp + gui/ColumnResizer.h + gui/ColumnResizer.cpp # GUI - windows gui/MainWindow.h @@ -312,14 +314,20 @@ SET(MULTIMC_SOURCES gui/pages/ScreenshotsPage.h gui/pages/OtherLogsPage.cpp gui/pages/OtherLogsPage.h - gui/pages/global/SettingsPage.cpp - gui/pages/global/SettingsPage.h - gui/pages/global/ExternalToolsPage.cpp - gui/pages/global/ExternalToolsPage.h - gui/pages/global/BaseSettingsPage.cpp - gui/pages/global/BaseSettingsPage.h + + # GUI - global settings pages gui/pages/global/AccountListPage.cpp gui/pages/global/AccountListPage.h + gui/pages/global/ExternalToolsPage.cpp + gui/pages/global/ExternalToolsPage.h + gui/pages/global/JavaPage.cpp + gui/pages/global/JavaPage.h + gui/pages/global/MinecraftPage.cpp + gui/pages/global/MinecraftPage.h + gui/pages/global/MultiMCPage.cpp + gui/pages/global/MultiMCPage.h + gui/pages/global/ProxyPage.cpp + gui/pages/global/ProxyPage.h # GUI - dialogs gui/dialogs/AboutDialog.cpp @@ -648,9 +656,14 @@ SET(MULTIMC_UIS gui/pages/NotesPage.ui gui/pages/ScreenshotsPage.ui gui/pages/OtherLogsPage.ui - gui/pages/global/SettingsPage.ui - gui/pages/global/ExternalToolsPage.ui + + # Global settings pages gui/pages/global/AccountListPage.ui + gui/pages/global/ExternalToolsPage.ui + gui/pages/global/JavaPage.ui + gui/pages/global/MinecraftPage.ui + gui/pages/global/MultiMCPage.ui + gui/pages/global/ProxyPage.ui # Dialogs gui/dialogs/CopyInstanceDialog.ui diff --git a/gui/ColumnResizer.cpp b/gui/ColumnResizer.cpp new file mode 100644 index 00000000..1c5597aa --- /dev/null +++ b/gui/ColumnResizer.cpp @@ -0,0 +1,202 @@ +/* + * Copyright 2011 Aurélien Gâteau + * License: LGPL v2.1 or later (see COPYING) + */ +#include "ColumnResizer.h" + +#include +#include +#include +#include +#include +#include + +class FormLayoutWidgetItem : public QWidgetItem +{ +public: + FormLayoutWidgetItem(QWidget* widget, QFormLayout* formLayout, QFormLayout::ItemRole itemRole) + : QWidgetItem(widget) + , m_width(-1) + , m_formLayout(formLayout) + , m_itemRole(itemRole) + {} + + QSize sizeHint() const + { + QSize size = QWidgetItem::sizeHint(); + if (m_width != -1) { + size.setWidth(m_width); + } + return size; + } + + QSize minimumSize() const + { + QSize size = QWidgetItem::minimumSize(); + if (m_width != -1) { + size.setWidth(m_width); + } + return size; + } + + QSize maximumSize() const + { + QSize size = QWidgetItem::maximumSize(); + if (m_width != -1) { + size.setWidth(m_width); + } + return size; + } + + void setWidth(int width) + { + if (width != m_width) { + m_width = width; + invalidate(); + } + } + + void setGeometry(const QRect& _rect) + { + QRect rect = _rect; + int width = widget()->sizeHint().width(); + if (m_itemRole == QFormLayout::LabelRole && m_formLayout->labelAlignment() & Qt::AlignRight) { + rect.setLeft(rect.right() - width); + } + QWidgetItem::setGeometry(rect); + } + + QFormLayout* formLayout() const + { + return m_formLayout; + } + +private: + int m_width; + QFormLayout* m_formLayout; + QFormLayout::ItemRole m_itemRole; +}; + +typedef QPair GridColumnInfo; + +class ColumnResizerPrivate +{ +public: + ColumnResizerPrivate(ColumnResizer* q_ptr) + : q(q_ptr) + , m_updateTimer(new QTimer(q)) + { + m_updateTimer->setSingleShot(true); + m_updateTimer->setInterval(0); + QObject::connect(m_updateTimer, SIGNAL(timeout()), q, SLOT(updateWidth())); + } + + void scheduleWidthUpdate() + { + m_updateTimer->start(); + } + + ColumnResizer* q; + QTimer* m_updateTimer; + QList m_widgets; + QList m_wrWidgetItemList; + QList m_gridColumnInfoList; +}; + +ColumnResizer::ColumnResizer(QObject* parent) +: QObject(parent) +, d(new ColumnResizerPrivate(this)) +{} + +ColumnResizer::~ColumnResizer() +{ + delete d; +} + +void ColumnResizer::addWidget(QWidget* widget) +{ + d->m_widgets.append(widget); + widget->installEventFilter(this); + d->scheduleWidthUpdate(); +} + +void ColumnResizer::updateWidth() +{ + int width = 0; + Q_FOREACH(QWidget* widget, d->m_widgets) { + width = qMax(widget->sizeHint().width(), width); + } + Q_FOREACH(FormLayoutWidgetItem* item, d->m_wrWidgetItemList) { + item->setWidth(width); + item->formLayout()->update(); + } + Q_FOREACH(GridColumnInfo info, d->m_gridColumnInfoList) { + info.first->setColumnMinimumWidth(info.second, width); + } +} + +bool ColumnResizer::eventFilter(QObject*, QEvent* event) +{ + if (event->type() == QEvent::Resize) { + d->scheduleWidthUpdate(); + } + return false; +} + +void ColumnResizer::addWidgetsFromLayout(QLayout* layout, int column) +{ + Q_ASSERT(column >= 0); + QGridLayout* gridLayout = qobject_cast(layout); + QFormLayout* formLayout = qobject_cast(layout); + if (gridLayout) { + addWidgetsFromGridLayout(gridLayout, column); + } else if (formLayout) { + if (column > QFormLayout::SpanningRole) { + qCritical() << "column should not be more than" << QFormLayout::SpanningRole << "for QFormLayout"; + return; + } + QFormLayout::ItemRole role = static_cast(column); + addWidgetsFromFormLayout(formLayout, role); + } else { + qCritical() << "Don't know how to handle layout" << layout; + } +} + +void ColumnResizer::addWidgetsFromGridLayout(QGridLayout* layout, int column) +{ + for (int row = 0; row < layout->rowCount(); ++row) { + QLayoutItem* item = layout->itemAtPosition(row, column); + if (!item) { + continue; + } + QWidget* widget = item->widget(); + if (!widget) { + continue; + } + addWidget(widget); + } + d->m_gridColumnInfoList << GridColumnInfo(layout, column); +} + +void ColumnResizer::addWidgetsFromFormLayout(QFormLayout* layout, QFormLayout::ItemRole role) +{ + for (int row = 0; row < layout->rowCount(); ++row) { + QLayoutItem* item = layout->itemAt(row, role); + if (!item) { + continue; + } + QWidget* widget = item->widget(); + if (!widget) { + continue; + } + layout->removeItem(item); + delete item; + FormLayoutWidgetItem* newItem = new FormLayoutWidgetItem(widget, layout, role); + layout->setItem(row, role, newItem); + addWidget(widget); + d->m_wrWidgetItemList << newItem; + } +} + +#include +// vi: ts=4 sw=4 et diff --git a/gui/ColumnResizer.h b/gui/ColumnResizer.h new file mode 100644 index 00000000..4bbac383 --- /dev/null +++ b/gui/ColumnResizer.h @@ -0,0 +1,38 @@ +/* + * Copyright 2011 Aurélien Gâteau + * License: LGPL v2.1 or later (see COPYING) + */ +#pragma once + +#include + +#include +#include + +class QEvent; +class QGridLayout; +class QLayout; +class QWidget; + +class ColumnResizerPrivate; +class ColumnResizer : public QObject +{ + Q_OBJECT +public: + ColumnResizer(QObject* parent = 0); + ~ColumnResizer(); + + void addWidget(QWidget* widget); + void addWidgetsFromLayout(QLayout*, int column); + void addWidgetsFromGridLayout(QGridLayout*, int column); + void addWidgetsFromFormLayout(QFormLayout*, QFormLayout::ItemRole role); + +private Q_SLOTS: + void updateWidth(); + +protected: + bool eventFilter(QObject*, QEvent* event); + +private: + ColumnResizerPrivate* const d; +}; diff --git a/gui/MainWindow.cpp b/gui/MainWindow.cpp index 81ee466b..ce03d7b9 100644 --- a/gui/MainWindow.cpp +++ b/gui/MainWindow.cpp @@ -62,9 +62,12 @@ #include "gui/dialogs/EditAccountDialog.h" #include "gui/dialogs/NotificationDialog.h" -#include "gui/pages/global/SettingsPage.h" +#include "gui/pages/global/MultiMCPage.h" #include "gui/pages/global/ExternalToolsPage.h" #include "gui/pages/global/AccountListPage.h" +#include "pages/global/ProxyPage.h" +#include "pages/global/JavaPage.h" +#include "pages/global/MinecraftPage.h" #include "gui/ConsoleWindow.h" #include "pagedialog/PageDialog.h" @@ -250,9 +253,12 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWi // set up global pages dialog { m_globalSettingsProvider = std::make_shared(tr("Settings")); - m_globalSettingsProvider->addPage(); - m_globalSettingsProvider->addPage(); + m_globalSettingsProvider->addPage(); + m_globalSettingsProvider->addPage(); + m_globalSettingsProvider->addPage(); + m_globalSettingsProvider->addPage(); m_globalSettingsProvider->addPage(); + m_globalSettingsProvider->addPage(); } // Update the menu when the active account changes. diff --git a/gui/dialogs/AboutDialog.ui b/gui/dialogs/AboutDialog.ui index 04983299..93fa8963 100644 --- a/gui/dialogs/AboutDialog.ui +++ b/gui/dialogs/AboutDialog.ui @@ -96,7 +96,7 @@ - 1 + 0 @@ -104,7 +104,7 @@ 0 0 689 - 331 + 311 @@ -229,7 +229,7 @@ 0 0 689 - 331 + 311 @@ -245,8 +245,8 @@ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;"> -<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html> +</style></head><body style=" font-family:'Bitstream Vera Sans'; font-size:11pt; font-weight:400; font-style:normal;"> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;"><br /></p></body></html> Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse @@ -271,7 +271,7 @@ p, li { white-space: pre-wrap; } 0 0 689 - 331 + 311 @@ -298,7 +298,7 @@ p, li { white-space: pre-wrap; } <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'DejaVu Sans Mono'; font-size:9pt; font-weight:400; font-style:normal;"> +</style></head><body style=" font-family:'DejaVu Sans Mono'; font-size:11pt; font-weight:400; font-style:normal;"> <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Bitstream Vera Sans'; font-size:18pt; font-weight:600;">MultiMC</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Copyright 2012-2014 MultiMC Contributors</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Licensed under the Apache License, Version 2.0 (the &quot;License&quot;);</span></p> @@ -422,7 +422,7 @@ p, li { white-space: pre-wrap; } <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;"> */</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:8pt;"><br /></p> <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Bitstream Vera Sans'; font-size:18pt; font-weight:600;">Java IconLoader class</span></p> -<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:11pt;"><br /></p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Copyright (c) 2011, Chris Molini</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">All rights reserved.</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:8pt;"><br /></p> @@ -447,8 +447,13 @@ p, li { white-space: pre-wrap; } <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS</span></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.</span></p> +<p align="center" style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:8pt;"><br /></p> +<p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Bitstream Vera Sans'; font-size:18pt; font-weight:600;">ColumnResizer</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:8pt;"><br /></p> -<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:8pt;"><br /></p></body></html> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">/*</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;"> * Copyright 2011 Aurélien Gâteau &lt;agateau@kde.org&gt;</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;"> * License: LGPL v2.1 or later (see COPYING)</span></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;"> */</span></p></body></html> @@ -459,8 +464,8 @@ p, li { white-space: pre-wrap; } 0 0 - 689 - 331 + 98 + 88 @@ -473,12 +478,12 @@ p, li { white-space: pre-wrap; } <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Bitstream Vera Sans'; font-size:11pt;">We keep MultiMC open source because we think it's important to be able to see the source code for a project like this, and we do so using the Apache license.</span></p> -<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Bitstream Vera Sans'; font-size:11pt;"><br /></p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Bitstream Vera Sans'; font-size:11pt;">Part of the reason for using the Apache license is we don't want people using the &quot;MultiMC&quot; name when redistributing the project. This means people must take the time to go through the source code and remove all references to &quot;MultiMC&quot;, including but not limited to the project icon and the title of windows, (no *MultiMC-fork* in the title).</span></p> -<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Bitstream Vera Sans'; font-size:11pt;"><br /></p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Bitstream Vera Sans'; font-size:11pt;">The Apache license covers reasonable use for the name - a mention of the project's origins in the About dialog and the license is acceptable. However, it should be abundantly clear that the project is a fork </span><span style=" font-family:'Bitstream Vera Sans'; font-size:11pt; font-weight:600;">without</span><span style=" font-family:'Bitstream Vera Sans'; font-size:11pt;"> implying that you have our blessing.</span></p></body></html> +</style></head><body style=" font-family:'Bitstream Vera Sans'; font-size:11pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">We keep MultiMC open source because we think it's important to be able to see the source code for a project like this, and we do so using the Apache license.</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Part of the reason for using the Apache license is we don't want people using the &quot;MultiMC&quot; name when redistributing the project. This means people must take the time to go through the source code and remove all references to &quot;MultiMC&quot;, including but not limited to the project icon and the title of windows, (no *MultiMC-fork* in the title).</p> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The Apache license covers reasonable use for the name - a mention of the project's origins in the About dialog and the license is acceptable. However, it should be abundantly clear that the project is a fork <span style=" font-weight:600;">without</span> implying that you have our blessing.</p></body></html> Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse|Qt::TextBrowserInteraction|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse diff --git a/gui/pages/global/AccountListPage.cpp b/gui/pages/global/AccountListPage.cpp index cad7d5bc..00487d57 100644 --- a/gui/pages/global/AccountListPage.cpp +++ b/gui/pages/global/AccountListPage.cpp @@ -34,9 +34,10 @@ #include AccountListPage::AccountListPage(QWidget *parent) - : QDialog(parent), ui(new Ui::AccountListPage) + : QWidget(parent), ui(new Ui::AccountListPage) { ui->setupUi(this); + ui->tabWidget->tabBar()->hide(); m_accounts = MMC->accounts(); diff --git a/gui/pages/global/AccountListPage.h b/gui/pages/global/AccountListPage.h index fd4724d1..fd2c96e3 100644 --- a/gui/pages/global/AccountListPage.h +++ b/gui/pages/global/AccountListPage.h @@ -29,7 +29,7 @@ class AccountListPage; class AuthenticateTask; -class AccountListPage : public QDialog, public BasePage +class AccountListPage : public QWidget, public BasePage { Q_OBJECT public: diff --git a/gui/pages/global/AccountListPage.ui b/gui/pages/global/AccountListPage.ui index 1e5b07eb..8ad78cf4 100644 --- a/gui/pages/global/AccountListPage.ui +++ b/gui/pages/global/AccountListPage.ui @@ -6,81 +6,107 @@ 0 0 - 400 - 300 + 694 + 609 Manage Accounts + + 0 + + + 0 + + + 0 + + + 0 + - - - <html><head/><body><p>Welcome! If you're new here, you can click the &quot;Add&quot; button to add your Mojang or Minecraft account.</p></body></html> + + + 0 - - true - - - - - - - - - - + + + Tab 1 + + - + - &Add + <html><head/><body><p>Welcome! If you're new here, you can click the &quot;Add&quot; button to add your Mojang or Minecraft account.</p></body></html> + + + true - - - &Remove - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - <html><head/><body><p>Set the currently selected account as the active account. The active account is the account that is used to log in (unless it is overridden in an instance-specific setting).</p></body></html> - - - &Set Default - - - - - - - Set no default account. This will cause MultiMC to prompt you to select an account every time you launch an instance that doesn't have its own default set. - - - &No Default - - + + + + + + + + + + &Add + + + + + + + &Remove + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + <html><head/><body><p>Set the currently selected account as the active account. The active account is the account that is used to log in (unless it is overridden in an instance-specific setting).</p></body></html> + + + &Set Default + + + + + + + Set no default account. This will cause MultiMC to prompt you to select an account every time you launch an instance that doesn't have its own default set. + + + &No Default + + + + + + - - + + diff --git a/gui/pages/global/BaseSettingsPage.cpp b/gui/pages/global/BaseSettingsPage.cpp deleted file mode 100644 index 167b23c0..00000000 --- a/gui/pages/global/BaseSettingsPage.cpp +++ /dev/null @@ -1,28 +0,0 @@ -/* Copyright 2014 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 "BaseSettingsPage.h" - -#include "MultiMC.h" - -void BaseSettingsPage::opened() -{ - loadSettings(MMC->settings().get()); -} -bool BaseSettingsPage::apply() -{ - applySettings(MMC->settings().get()); - return true; -} diff --git a/gui/pages/global/BaseSettingsPage.h b/gui/pages/global/BaseSettingsPage.h deleted file mode 100644 index 55e5f2a4..00000000 --- a/gui/pages/global/BaseSettingsPage.h +++ /dev/null @@ -1,35 +0,0 @@ -/* Copyright 2014 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 "gui/pages/BasePage.h" - -class SettingsObject; - -class BaseSettingsPage : public BasePage -{ -public: - virtual ~BaseSettingsPage() - { - } - - void opened() override; - bool apply() override; - -protected: - virtual void loadSettings(SettingsObject *object) = 0; - virtual void applySettings(SettingsObject *object) = 0; -}; diff --git a/gui/pages/global/ExternalToolsPage.cpp b/gui/pages/global/ExternalToolsPage.cpp index e0312ee5..417a13e3 100644 --- a/gui/pages/global/ExternalToolsPage.cpp +++ b/gui/pages/global/ExternalToolsPage.cpp @@ -18,6 +18,7 @@ #include #include +#include #include @@ -30,10 +31,16 @@ ExternalToolsPage::ExternalToolsPage(QWidget *parent) : ui(new Ui::ExternalToolsPage) { ui->setupUi(this); + ui->tabWidget->tabBar()->hide(); + + #if QT_VERSION >= QT_VERSION_CHECK(5, 2, 0) + ui->jsonEditorTextBox->setClearButtonEnabled(true); + #endif ui->mceditLink->setOpenExternalLinks(true); ui->jvisualvmLink->setOpenExternalLinks(true); ui->jprofilerLink->setOpenExternalLinks(true); + loadSettings(); } ExternalToolsPage::~ExternalToolsPage() @@ -41,17 +48,35 @@ ExternalToolsPage::~ExternalToolsPage() delete ui; } -void ExternalToolsPage::loadSettings(SettingsObject *object) +void ExternalToolsPage::loadSettings() { - ui->jprofilerPathEdit->setText(object->get("JProfilerPath").toString()); - ui->jvisualvmPathEdit->setText(object->get("JVisualVMPath").toString()); - ui->mceditPathEdit->setText(object->get("MCEditPath").toString()); + auto s = MMC->settings(); + ui->jprofilerPathEdit->setText(s->get("JProfilerPath").toString()); + ui->jvisualvmPathEdit->setText(s->get("JVisualVMPath").toString()); + ui->mceditPathEdit->setText(s->get("MCEditPath").toString()); + + // Editors + ui->jsonEditorTextBox->setText(s->get("JsonEditor").toString()); } -void ExternalToolsPage::applySettings(SettingsObject *object) +void ExternalToolsPage::applySettings() { - object->set("JProfilerPath", ui->jprofilerPathEdit->text()); - object->set("JVisualVMPath", ui->jvisualvmPathEdit->text()); - object->set("MCEditPath", ui->mceditPathEdit->text()); + auto s = MMC->settings(); + s->set("JProfilerPath", ui->jprofilerPathEdit->text()); + s->set("JVisualVMPath", ui->jvisualvmPathEdit->text()); + s->set("MCEditPath", ui->mceditPathEdit->text()); + + // Editors + QString jsonEditor = ui->jsonEditorTextBox->text(); + if (!jsonEditor.isEmpty() && + (!QFileInfo(jsonEditor).exists() || !QFileInfo(jsonEditor).isExecutable())) + { + QString found = QStandardPaths::findExecutable(jsonEditor); + if (!found.isEmpty()) + { + jsonEditor = found; + } + } + s->set("JsonEditor", jsonEditor); } void ExternalToolsPage::on_jprofilerPathBtn_clicked() @@ -175,3 +200,39 @@ void ExternalToolsPage::on_mceditCheckBtn_clicked() QMessageBox::information(this, tr("OK"), tr("MCEdit setup seems to be OK")); } } + +void ExternalToolsPage::on_jsonEditorBrowseBtn_clicked() +{ + QString raw_file = QFileDialog::getOpenFileName( + this, tr("JSON Editor"), + ui->jsonEditorTextBox->text().isEmpty() +#if defined(Q_OS_LINUX) + ? QString("/usr/bin") +#else + ? QStandardPaths::standardLocations(QStandardPaths::ApplicationsLocation).first() +#endif + : ui->jsonEditorTextBox->text()); + QString cooked_file = NormalizePath(raw_file); + + if (cooked_file.isEmpty()) + { + return; + } + + // it has to exist and be an executable + if (QFileInfo(cooked_file).exists() && QFileInfo(cooked_file).isExecutable()) + { + ui->jsonEditorTextBox->setText(cooked_file); + } + else + { + QMessageBox::warning(this, tr("Invalid"), + tr("The file chosen does not seem to be an executable")); + } +} + +bool ExternalToolsPage::apply() +{ + applySettings(); + return true; +} diff --git a/gui/pages/global/ExternalToolsPage.h b/gui/pages/global/ExternalToolsPage.h index 1b35a92b..027e164e 100644 --- a/gui/pages/global/ExternalToolsPage.h +++ b/gui/pages/global/ExternalToolsPage.h @@ -17,13 +17,13 @@ #include -#include "BaseSettingsPage.h" +#include "gui/pages/BasePage.h" namespace Ui { class ExternalToolsPage; } -class ExternalToolsPage : public QWidget, public BaseSettingsPage +class ExternalToolsPage : public QWidget, public BasePage { Q_OBJECT @@ -47,10 +47,11 @@ public: { return "External-tools"; } + virtual bool apply(); -protected: - void loadSettings(SettingsObject *object) override; - void applySettings(SettingsObject *object) override; +private: + void loadSettings(); + void applySettings(); private: Ui::ExternalToolsPage *ui; @@ -63,4 +64,5 @@ slots: void on_jvisualvmCheckBtn_clicked(); void on_mceditPathBtn_clicked(); void on_mceditCheckBtn_clicked(); + void on_jsonEditorBrowseBtn_clicked(); }; diff --git a/gui/pages/global/ExternalToolsPage.ui b/gui/pages/global/ExternalToolsPage.ui index 96650f0f..ba1b6f01 100644 --- a/gui/pages/global/ExternalToolsPage.ui +++ b/gui/pages/global/ExternalToolsPage.ui @@ -6,138 +6,190 @@ 0 0 - 494 - 562 + 673 + 751 Form + + 0 + + + 0 + + + 0 + + + 0 + - - - JProfiler + + + 0 - - - - - - - - - - ... - - - - - - - - - Check - - - - - - - <html><head/><body><p><a href="http://www.ej-technologies.com/products/jprofiler/overview.html"><span style=" text-decoration: underline; color:#0000ff;">http://www.ej-technologies.com/products/jprofiler/overview.html</span></a></p></body></html> - - - - + + + Tab 1 + + + + + + JProfiler + + + + + + + + + + + ... + + + + + + + + + Check + + + + + + + <html><head/><body><p><a href="http://www.ej-technologies.com/products/jprofiler/overview.html"><span style=" text-decoration: underline; color:#0000ff;">http://www.ej-technologies.com/products/jprofiler/overview.html</span></a></p></body></html> + + + + + + + + + + JVisualVM + + + + + + + + + + + ... + + + + + + + + + Check + + + + + + + <html><head/><body><p><a href="http://visualvm.java.net/"><span style=" text-decoration: underline; color:#0000ff;">http://visualvm.java.net/</span></a></p></body></html> + + + + + + + + + + MCEdit + + + + + + + + + + + ... + + + + + + + + + Check + + + + + + + <html><head/><body><p><a href="http://www.mcedit.net/"><span style=" text-decoration: underline; color:#0000ff;">http://www.mcedit.net/</span></a></p></body></html> + + + + + + + + + + External Editors (leave empty for system default) + + + + + + + + + Text Editor: + + + + + + + ... + + + + + + + + + + Qt::Vertical + + + + 20 + 216 + + + + + + - - - - JVisualVM - - - - - - - - - - - ... - - - - - - - - - Check - - - - - - - <html><head/><body><p><a href="http://visualvm.java.net/"><span style=" text-decoration: underline; color:#0000ff;">http://visualvm.java.net/</span></a></p></body></html> - - - - - - - - - - MCEdit - - - - - - - - - - - ... - - - - - - - - - Check - - - - - - - <html><head/><body><p><a href="http://www.mcedit.net/"><span style=" text-decoration: underline; color:#0000ff;">http://www.mcedit.net/</span></a></p></body></html> - - - - - - - - - - Qt::Vertical - - - - 20 - 160 - - - - diff --git a/gui/pages/global/JavaPage.cpp b/gui/pages/global/JavaPage.cpp new file mode 100644 index 00000000..86451411 --- /dev/null +++ b/gui/pages/global/JavaPage.cpp @@ -0,0 +1,146 @@ +/* Copyright 2013 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 "JavaPage.h" +#include "ui_JavaPage.h" + +#include +#include +#include + +#include + +#include "logic/NagUtils.h" + +#include "gui/Platform.h" +#include "gui/dialogs/VersionSelectDialog.h" +#include + +#include "logic/java/JavaUtils.h" +#include "logic/java/JavaVersionList.h" +#include "logic/java/JavaChecker.h" + +#include "logic/settings/SettingsObject.h" +#include "MultiMC.h" + +JavaPage::JavaPage(QWidget *parent) : QWidget(parent), ui(new Ui::JavaPage) +{ + ui->setupUi(this); + ui->tabWidget->tabBar()->hide(); + + auto resizer = new ColumnResizer(this); + resizer->addWidgetsFromLayout(ui->javaSettingsGroupBox->layout(), 0); + resizer->addWidgetsFromLayout(ui->customCommandsGroupBox->layout(), 0); + + loadSettings(); +} + +JavaPage::~JavaPage() +{ + delete ui; +} + +bool JavaPage::apply() +{ + applySettings(); + return true; +} + +void JavaPage::applySettings() +{ + auto s = MMC->settings(); + // Memory + s->set("MinMemAlloc", ui->minMemSpinBox->value()); + s->set("MaxMemAlloc", ui->maxMemSpinBox->value()); + s->set("PermGen", ui->permGenSpinBox->value()); + + // Java Settings + s->set("JavaPath", ui->javaPathTextBox->text()); + s->set("JvmArgs", ui->jvmArgsTextBox->text()); + NagUtils::checkJVMArgs(s->get("JvmArgs").toString(), this->parentWidget()); + + // Custom Commands + s->set("PreLaunchCommand", ui->preLaunchCmdTextBox->text()); + s->set("PostExitCommand", ui->postExitCmdTextBox->text()); +} +void JavaPage::loadSettings() +{ + auto s = MMC->settings(); + // Memory + ui->minMemSpinBox->setValue(s->get("MinMemAlloc").toInt()); + ui->maxMemSpinBox->setValue(s->get("MaxMemAlloc").toInt()); + ui->permGenSpinBox->setValue(s->get("PermGen").toInt()); + + // Java Settings + ui->javaPathTextBox->setText(s->get("JavaPath").toString()); + ui->jvmArgsTextBox->setText(s->get("JvmArgs").toString()); + + // Custom Commands + ui->preLaunchCmdTextBox->setText(s->get("PreLaunchCommand").toString()); + ui->postExitCmdTextBox->setText(s->get("PostExitCommand").toString()); +} + +void JavaPage::on_javaDetectBtn_clicked() +{ + JavaVersionPtr java; + + VersionSelectDialog vselect(MMC->javalist().get(), tr("Select a Java version"), this, true); + vselect.setResizeOn(2); + vselect.exec(); + + if (vselect.result() == QDialog::Accepted && vselect.selectedVersion()) + { + java = std::dynamic_pointer_cast(vselect.selectedVersion()); + ui->javaPathTextBox->setText(java->path); + } +} +void JavaPage::on_javaBrowseBtn_clicked() +{ + QString dir = QFileDialog::getOpenFileName(this, tr("Find Java executable")); + if (!dir.isNull()) + { + ui->javaPathTextBox->setText(dir); + } +} +void JavaPage::on_javaTestBtn_clicked() +{ + checker.reset(new JavaChecker()); + connect(checker.get(), SIGNAL(checkFinished(JavaCheckResult)), this, + SLOT(checkFinished(JavaCheckResult))); + checker->path = ui->javaPathTextBox->text(); + checker->performCheck(); +} + +void JavaPage::checkFinished(JavaCheckResult result) +{ + if (result.valid) + { + QString text; + text += "Java test succeeded!\n"; + if (result.is_64bit) + text += "Using 64bit java.\n"; + text += "\n"; + text += "Platform reported: " + result.realPlatform + "\n"; + text += "Java version reported: " + result.javaVersion; + QMessageBox::information(this, tr("Java test success"), text); + } + else + { + QMessageBox::warning( + this, tr("Java test failure"), + tr("The specified java binary didn't work. You should use the auto-detect feature, " + "or set the path to the java executable.")); + } +} diff --git a/gui/pages/global/JavaPage.h b/gui/pages/global/JavaPage.h new file mode 100644 index 00000000..d0228bd2 --- /dev/null +++ b/gui/pages/global/JavaPage.h @@ -0,0 +1,72 @@ +/* Copyright 2013 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 +#include + +#include "logic/java/JavaChecker.h" +#include "gui/pages/BasePage.h" + +class SettingsObject; + +namespace Ui +{ +class JavaPage; +} + +class JavaPage : public QWidget, public BasePage +{ + Q_OBJECT + +public: + explicit JavaPage(QWidget *parent = 0); + ~JavaPage(); + + QString displayName() const override + { + return tr("Java"); + } + QIcon icon() const override + { + return QIcon::fromTheme("java"); + } + QString id() const override + { + return "java-settings"; + } + QString helpPage() const override + { + return "Java-settings"; + } + bool apply() override; + +private: + void applySettings(); + void loadSettings(); + +private +slots: + void on_javaDetectBtn_clicked(); + void on_javaTestBtn_clicked(); + void on_javaBrowseBtn_clicked(); + + void checkFinished(JavaCheckResult result); + +private: + Ui::JavaPage *ui; + std::shared_ptr checker; +}; diff --git a/gui/pages/global/JavaPage.ui b/gui/pages/global/JavaPage.ui new file mode 100644 index 00000000..6ae41a49 --- /dev/null +++ b/gui/pages/global/JavaPage.ui @@ -0,0 +1,303 @@ + + + JavaPage + + + + 0 + 0 + 545 + 609 + + + + + 0 + 0 + + + + Settings + + + + :/icons/toolbar/settings:/icons/toolbar/settings + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 0 + + + + Tab 1 + + + + + + Memory + + + + + + The maximum amount of memory Minecraft is allowed to use. + + + MB + + + 512 + + + 65536 + + + 128 + + + 1024 + + + + + + + Minimum memory allocation: + + + + + + + Maximum memory allocation: + + + + + + + The amount of memory Minecraft is started with. + + + MB + + + 256 + + + 65536 + + + 128 + + + 256 + + + + + + + PermGen: + + + + + + + The amount of memory available to store loaded Java classes. + + + MB + + + 64 + + + 999999999 + + + 8 + + + 64 + + + + + + + + + + Java Runtime + + + + + + + 0 + 0 + + + + Java path: + + + + + + + + 0 + 0 + + + + Auto-detect... + + + + + + + + 0 + 0 + + + + Test + + + + + + + + 0 + 0 + + + + JVM arguments: + + + + + + + + + + + + + 0 + 0 + + + + + 28 + 16777215 + + + + ... + + + + + + + + + + + + + + + Custom Commands + + + + + + Post-exit command: + + + + + + + Pre-launch command: + + + + + + + + + + + + + + + + + 0 + 0 + + + + Pre-launch command runs before the instance launches and post-exit command runs after it exits. Both will be run in MultiMC's working directory with INST_ID, INST_DIR, and INST_NAME as environment variables. + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop + + + true + + + + + + + + + + + minMemSpinBox + maxMemSpinBox + permGenSpinBox + javaPathTextBox + javaBrowseBtn + javaDetectBtn + javaTestBtn + jvmArgsTextBox + preLaunchCmdTextBox + postExitCmdTextBox + + + + diff --git a/gui/pages/global/MinecraftPage.cpp b/gui/pages/global/MinecraftPage.cpp new file mode 100644 index 00000000..0fe56fde --- /dev/null +++ b/gui/pages/global/MinecraftPage.cpp @@ -0,0 +1,104 @@ +/* Copyright 2013 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 "MinecraftPage.h" +#include "ui_MinecraftPage.h" + +#include +#include +#include + +#include + +#include "gui/Platform.h" +#include "gui/dialogs/VersionSelectDialog.h" +#include "gui/dialogs/CustomMessageBox.h" + +#include "logic/NagUtils.h" + +#include "logic/java/JavaUtils.h" +#include "logic/java/JavaVersionList.h" +#include "logic/java/JavaChecker.h" + +#include "logic/updater/UpdateChecker.h" + +#include "logic/tools/BaseProfiler.h" + +#include "logic/settings/SettingsObject.h" +#include "MultiMC.h" + +MinecraftPage::MinecraftPage(QWidget *parent) : QWidget(parent), ui(new Ui::MinecraftPage) +{ + ui->setupUi(this); + ui->tabWidget->tabBar()->hide(); + loadSettings(); + updateCheckboxStuff(); +} + +MinecraftPage::~MinecraftPage() +{ + delete ui; +} + +bool MinecraftPage::apply() +{ + applySettings(); + return true; +} + +void MinecraftPage::updateCheckboxStuff() +{ + ui->windowWidthSpinBox->setEnabled(!ui->maximizedCheckBox->isChecked()); + ui->windowHeightSpinBox->setEnabled(!ui->maximizedCheckBox->isChecked()); +} + +void MinecraftPage::on_maximizedCheckBox_clicked(bool checked) +{ + Q_UNUSED(checked); + updateCheckboxStuff(); +} + + +void MinecraftPage::applySettings() +{ + auto s = MMC->settings(); + // Minecraft version updates + s->set("AutoUpdateMinecraftVersions", ui->autoupdateMinecraft->isChecked()); + + // Console + s->set("ShowConsole", ui->showConsoleCheck->isChecked()); + s->set("AutoCloseConsole", ui->autoCloseConsoleCheck->isChecked()); + + // Window Size + s->set("LaunchMaximized", ui->maximizedCheckBox->isChecked()); + s->set("MinecraftWinWidth", ui->windowWidthSpinBox->value()); + s->set("MinecraftWinHeight", ui->windowHeightSpinBox->value()); +} + +void MinecraftPage::loadSettings() +{ + auto s = MMC->settings(); + // Minecraft version updates + ui->autoupdateMinecraft->setChecked(s->get("AutoUpdateMinecraftVersions").toBool()); + + // Console + ui->showConsoleCheck->setChecked(s->get("ShowConsole").toBool()); + ui->autoCloseConsoleCheck->setChecked(s->get("AutoCloseConsole").toBool()); + + // Window Size + ui->maximizedCheckBox->setChecked(s->get("LaunchMaximized").toBool()); + ui->windowWidthSpinBox->setValue(s->get("MinecraftWinWidth").toInt()); + ui->windowHeightSpinBox->setValue(s->get("MinecraftWinHeight").toInt()); +} diff --git a/gui/pages/global/MinecraftPage.h b/gui/pages/global/MinecraftPage.h new file mode 100644 index 00000000..90299020 --- /dev/null +++ b/gui/pages/global/MinecraftPage.h @@ -0,0 +1,69 @@ +/* Copyright 2013 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 +#include + +#include "logic/java/JavaChecker.h" +#include "gui/pages/BasePage.h" + +class SettingsObject; + +namespace Ui +{ +class MinecraftPage; +} + +class MinecraftPage : public QWidget, public BasePage +{ + Q_OBJECT + +public: + explicit MinecraftPage(QWidget *parent = 0); + ~MinecraftPage(); + + QString displayName() const override + { + return tr("Minecraft"); + } + QIcon icon() const override + { + return QIcon::fromTheme("minecraft"); + } + QString id() const override + { + return "minecraft-settings"; + } + QString helpPage() const override + { + return "Minecraft-settings"; + } + bool apply() override; + +private: + void updateCheckboxStuff(); + void applySettings(); + void loadSettings(); + +private +slots: + void on_maximizedCheckBox_clicked(bool checked); + +private: + Ui::MinecraftPage *ui; + +}; diff --git a/gui/pages/global/MinecraftPage.ui b/gui/pages/global/MinecraftPage.ui new file mode 100644 index 00000000..e938d09d --- /dev/null +++ b/gui/pages/global/MinecraftPage.ui @@ -0,0 +1,184 @@ + + + MinecraftPage + + + + 0 + 0 + 545 + 609 + + + + + 0 + 0 + + + + Settings + + + + :/icons/toolbar/settings:/icons/toolbar/settings + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QTabWidget::Rounded + + + 0 + + + + Minecraft + + + + + + Minecraft Version Updates + + + + + + Automatically update to latest version revision + + + + + + + + + + Window Size + + + + + + Start Minecraft maximized? + + + + + + + + + Window height: + + + + + + + Window width: + + + + + + + 854 + + + 65536 + + + 1 + + + 854 + + + + + + + 480 + + + 65536 + + + 480 + + + + + + + + + + + + Console Settings + + + + + + Show console while the game is running? + + + + + + + Automatically close console when the game quits? + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + tabWidget + autoupdateMinecraft + maximizedCheckBox + windowWidthSpinBox + windowHeightSpinBox + showConsoleCheck + autoCloseConsoleCheck + + + + diff --git a/gui/pages/global/SettingsPage.cpp b/gui/pages/global/MultiMCPage.cpp similarity index 54% rename from gui/pages/global/SettingsPage.cpp rename to gui/pages/global/MultiMCPage.cpp index 37b0539c..2d6eb7d5 100644 --- a/gui/pages/global/SettingsPage.cpp +++ b/gui/pages/global/MultiMCPage.cpp @@ -13,8 +13,8 @@ * limitations under the License. */ -#include "SettingsPage.h" -#include "ui_SettingsPage.h" +#include "MultiMCPage.h" +#include "ui_MultiMCPage.h" #include #include @@ -25,6 +25,7 @@ #include "gui/Platform.h" #include "gui/dialogs/VersionSelectDialog.h" #include "gui/dialogs/CustomMessageBox.h" +#include #include "logic/NagUtils.h" @@ -48,22 +49,20 @@ enum InstSortMode Sort_LastLaunch }; -SettingsPage::SettingsPage(QWidget *parent) : QWidget(parent), ui(new Ui::SettingsPage) +MultiMCPage::MultiMCPage(QWidget *parent) : QWidget(parent), ui(new Ui::MultiMCPage) { - MultiMCPlatform::fixWM_CLASS(this); ui->setupUi(this); ui->sortingModeGroup->setId(ui->sortByNameBtn, Sort_Name); ui->sortingModeGroup->setId(ui->sortLastLaunchedBtn, Sort_LastLaunch); -#if QT_VERSION >= QT_VERSION_CHECK(5, 2, 0) - ui->jsonEditorTextBox->setClearButtonEnabled(true); -#endif + auto resizer = new ColumnResizer(this); + resizer->addWidgetsFromLayout(ui->groupBox->layout(), 1); + resizer->addWidgetsFromLayout(ui->foldersBox->layout(), 1); - restoreGeometry( - QByteArray::fromBase64(MMC->settings()->get("SettingsGeometry").toByteArray())); + loadSettings(); QObject::connect(MMC->updateChecker().get(), &UpdateChecker::channelListLoaded, this, - &SettingsPage::refreshUpdateChannelList); + &MultiMCPage::refreshUpdateChannelList); if (MMC->updateChecker()->hasChannels()) { @@ -73,32 +72,20 @@ SettingsPage::SettingsPage(QWidget *parent) : QWidget(parent), ui(new Ui::Settin { MMC->updateChecker()->updateChanList(false); } - connect(ui->proxyGroup, SIGNAL(buttonClicked(int)), SLOT(proxyChanged(int))); } -SettingsPage::~SettingsPage() +MultiMCPage::~MultiMCPage() { delete ui; } -void SettingsPage::closeEvent(QCloseEvent *ev) +bool MultiMCPage::apply() { - MMC->settings()->set("SettingsGeometry", saveGeometry().toBase64()); - - QWidget::closeEvent(ev); + applySettings(); + return true; } -void SettingsPage::updateCheckboxStuff() -{ - ui->windowWidthSpinBox->setEnabled(!ui->maximizedCheckBox->isChecked()); - ui->windowHeightSpinBox->setEnabled(!ui->maximizedCheckBox->isChecked()); - ui->proxyAddrBox->setEnabled(!ui->proxyNoneBtn->isChecked() && - !ui->proxyDefaultBtn->isChecked()); - ui->proxyAuthBox->setEnabled(!ui->proxyNoneBtn->isChecked() && - !ui->proxyDefaultBtn->isChecked()); -} - -void SettingsPage::on_ftbLauncherBrowseBtn_clicked() +void MultiMCPage::on_ftbLauncherBrowseBtn_clicked() { QString raw_dir = QFileDialog::getExistingDirectory(this, tr("FTB Launcher Directory"), ui->ftbLauncherBox->text()); @@ -110,7 +97,7 @@ void SettingsPage::on_ftbLauncherBrowseBtn_clicked() ui->ftbLauncherBox->setText(cooked_dir); } } -void SettingsPage::on_ftbBrowseBtn_clicked() +void MultiMCPage::on_ftbBrowseBtn_clicked() { QString raw_dir = QFileDialog::getExistingDirectory(this, tr("FTB Directory"), ui->ftbBox->text()); @@ -123,7 +110,7 @@ void SettingsPage::on_ftbBrowseBtn_clicked() } } -void SettingsPage::on_instDirBrowseBtn_clicked() +void MultiMCPage::on_instDirBrowseBtn_clicked() { QString raw_dir = QFileDialog::getExistingDirectory(this, tr("Instance Directory"), ui->instDirTextBox->text()); @@ -135,7 +122,7 @@ void SettingsPage::on_instDirBrowseBtn_clicked() ui->instDirTextBox->setText(cooked_dir); } } -void SettingsPage::on_iconsDirBrowseBtn_clicked() +void MultiMCPage::on_iconsDirBrowseBtn_clicked() { QString raw_dir = QFileDialog::getExistingDirectory(this, tr("Icons Directory"), ui->iconsDirTextBox->text()); @@ -147,7 +134,7 @@ void SettingsPage::on_iconsDirBrowseBtn_clicked() ui->iconsDirTextBox->setText(cooked_dir); } } -void SettingsPage::on_modsDirBrowseBtn_clicked() +void MultiMCPage::on_modsDirBrowseBtn_clicked() { QString raw_dir = QFileDialog::getExistingDirectory(this, tr("Mods Directory"), ui->modsDirTextBox->text()); @@ -159,7 +146,7 @@ void SettingsPage::on_modsDirBrowseBtn_clicked() ui->modsDirTextBox->setText(cooked_dir); } } -void SettingsPage::on_lwjglDirBrowseBtn_clicked() +void MultiMCPage::on_lwjglDirBrowseBtn_clicked() { QString raw_dir = QFileDialog::getExistingDirectory(this, tr("LWJGL Directory"), ui->lwjglDirTextBox->text()); @@ -172,48 +159,7 @@ void SettingsPage::on_lwjglDirBrowseBtn_clicked() } } -void SettingsPage::on_jsonEditorBrowseBtn_clicked() -{ - QString raw_file = QFileDialog::getOpenFileName( - this, tr("JSON Editor"), - ui->jsonEditorTextBox->text().isEmpty() -#if defined(Q_OS_LINUX) - ? QString("/usr/bin") -#else - ? QStandardPaths::standardLocations(QStandardPaths::ApplicationsLocation).first() -#endif - : ui->jsonEditorTextBox->text()); - QString cooked_file = NormalizePath(raw_file); - - if (cooked_file.isEmpty()) - { - return; - } - - // it has to exist and be an executable - if (QFileInfo(cooked_file).exists() && QFileInfo(cooked_file).isExecutable()) - { - ui->jsonEditorTextBox->setText(cooked_file); - } - else - { - QMessageBox::warning(this, tr("Invalid"), - tr("The file chosen does not seem to be an executable")); - } -} - -void SettingsPage::on_maximizedCheckBox_clicked(bool checked) -{ - Q_UNUSED(checked); - updateCheckboxStuff(); -} - -void SettingsPage::proxyChanged(int) -{ - updateCheckboxStuff(); -} - -void SettingsPage::refreshUpdateChannelList() +void MultiMCPage::refreshUpdateChannelList() { // Stop listening for selection changes. It's going to change a lot while we update it and // we don't need to update the @@ -258,12 +204,12 @@ void SettingsPage::refreshUpdateChannelList() ui->updateChannelComboBox->setEnabled(true); } -void SettingsPage::updateChannelSelectionChanged(int index) +void MultiMCPage::updateChannelSelectionChanged(int index) { refreshUpdateChannelDesc(); } -void SettingsPage::refreshUpdateChannelDesc() +void MultiMCPage::refreshUpdateChannelDesc() { // Get the channel list. QList channelList = MMC->updateChecker()->getChannelList(); @@ -285,8 +231,9 @@ void SettingsPage::refreshUpdateChannelDesc() } } -void SettingsPage::applySettings(SettingsObject *s) +void MultiMCPage::applySettings() { + auto s = MMC->settings(); // Language s->set("Language", ui->languageBox->itemData(ui->languageBox->currentIndex()).toLocale().bcp47Name()); @@ -325,62 +272,6 @@ void SettingsPage::applySettings(SettingsObject *s) s->set("LWJGLDir", ui->lwjglDirTextBox->text()); s->set("IconsDir", ui->iconsDirTextBox->text()); - // Editors - QString jsonEditor = ui->jsonEditorTextBox->text(); - if (!jsonEditor.isEmpty() && - (!QFileInfo(jsonEditor).exists() || !QFileInfo(jsonEditor).isExecutable())) - { - QString found = QStandardPaths::findExecutable(jsonEditor); - if (!found.isEmpty()) - { - jsonEditor = found; - } - } - s->set("JsonEditor", jsonEditor); - - // Minecraft version updates - s->set("AutoUpdateMinecraftVersions", ui->autoupdateMinecraft->isChecked()); - - // Console - s->set("ShowConsole", ui->showConsoleCheck->isChecked()); - s->set("AutoCloseConsole", ui->autoCloseConsoleCheck->isChecked()); - - // Window Size - s->set("LaunchMaximized", ui->maximizedCheckBox->isChecked()); - s->set("MinecraftWinWidth", ui->windowWidthSpinBox->value()); - s->set("MinecraftWinHeight", ui->windowHeightSpinBox->value()); - - // Proxy - QString proxyType = "None"; - if (ui->proxyDefaultBtn->isChecked()) - proxyType = "Default"; - else if (ui->proxyNoneBtn->isChecked()) - proxyType = "None"; - else if (ui->proxySOCKS5Btn->isChecked()) - proxyType = "SOCKS5"; - else if (ui->proxyHTTPBtn->isChecked()) - proxyType = "HTTP"; - - s->set("ProxyType", proxyType); - s->set("ProxyAddr", ui->proxyAddrEdit->text()); - s->set("ProxyPort", ui->proxyPortEdit->value()); - s->set("ProxyUser", ui->proxyUserEdit->text()); - s->set("ProxyPass", ui->proxyPassEdit->text()); - - // Memory - s->set("MinMemAlloc", ui->minMemSpinBox->value()); - s->set("MaxMemAlloc", ui->maxMemSpinBox->value()); - s->set("PermGen", ui->permGenSpinBox->value()); - - // Java Settings - s->set("JavaPath", ui->javaPathTextBox->text()); - s->set("JvmArgs", ui->jvmArgsTextBox->text()); - NagUtils::checkJVMArgs(s->get("JvmArgs").toString(), this->parentWidget()); - - // Custom Commands - s->set("PreLaunchCommand", ui->preLaunchCmdTextBox->text()); - s->set("PostExitCommand", ui->postExitCmdTextBox->text()); - auto sortMode = (InstSortMode)ui->sortingModeGroup->checkedId(); switch (sortMode) { @@ -392,11 +283,10 @@ void SettingsPage::applySettings(SettingsObject *s) s->set("InstSortMode", "Name"); break; } - - s->set("PostExitCommand", ui->postExitCmdTextBox->text()); } -void SettingsPage::loadSettings(SettingsObject *s) +void MultiMCPage::loadSettings() { + auto s = MMC->settings(); // Language ui->languageBox->clear(); ui->languageBox->addItem(tr("English"), QLocale(QLocale::English)); @@ -437,26 +327,6 @@ void SettingsPage::loadSettings(SettingsObject *s) ui->lwjglDirTextBox->setText(s->get("LWJGLDir").toString()); ui->iconsDirTextBox->setText(s->get("IconsDir").toString()); - // Editors - ui->jsonEditorTextBox->setText(s->get("JsonEditor").toString()); - - // Minecraft version updates - ui->autoupdateMinecraft->setChecked(s->get("AutoUpdateMinecraftVersions").toBool()); - - // Console - ui->showConsoleCheck->setChecked(s->get("ShowConsole").toBool()); - ui->autoCloseConsoleCheck->setChecked(s->get("AutoCloseConsole").toBool()); - - // Window Size - ui->maximizedCheckBox->setChecked(s->get("LaunchMaximized").toBool()); - ui->windowWidthSpinBox->setValue(s->get("MinecraftWinWidth").toInt()); - ui->windowHeightSpinBox->setValue(s->get("MinecraftWinHeight").toInt()); - - // Memory - ui->minMemSpinBox->setValue(s->get("MinMemAlloc").toInt()); - ui->maxMemSpinBox->setValue(s->get("MaxMemAlloc").toInt()); - ui->permGenSpinBox->setValue(s->get("PermGen").toInt()); - QString sortMode = s->get("InstSortMode").toString(); if (sortMode == "LastLaunch") @@ -467,81 +337,4 @@ void SettingsPage::loadSettings(SettingsObject *s) { ui->sortByNameBtn->setChecked(true); } - - // Proxy - QString proxyType = s->get("ProxyType").toString(); - if (proxyType == "Default") - ui->proxyDefaultBtn->setChecked(true); - else if (proxyType == "None") - ui->proxyNoneBtn->setChecked(true); - else if (proxyType == "SOCKS5") - ui->proxySOCKS5Btn->setChecked(true); - else if (proxyType == "HTTP") - ui->proxyHTTPBtn->setChecked(true); - - ui->proxyAddrEdit->setText(s->get("ProxyAddr").toString()); - ui->proxyPortEdit->setValue(s->get("ProxyPort").value()); - ui->proxyUserEdit->setText(s->get("ProxyUser").toString()); - ui->proxyPassEdit->setText(s->get("ProxyPass").toString()); - - // Java Settings - ui->javaPathTextBox->setText(s->get("JavaPath").toString()); - ui->jvmArgsTextBox->setText(s->get("JvmArgs").toString()); - - // Custom Commands - ui->preLaunchCmdTextBox->setText(s->get("PreLaunchCommand").toString()); - ui->postExitCmdTextBox->setText(s->get("PostExitCommand").toString()); -} - -void SettingsPage::on_javaDetectBtn_clicked() -{ - JavaVersionPtr java; - - VersionSelectDialog vselect(MMC->javalist().get(), tr("Select a Java version"), this, true); - vselect.setResizeOn(2); - vselect.exec(); - - if (vselect.result() == QDialog::Accepted && vselect.selectedVersion()) - { - java = std::dynamic_pointer_cast(vselect.selectedVersion()); - ui->javaPathTextBox->setText(java->path); - } -} -void SettingsPage::on_javaBrowseBtn_clicked() -{ - QString dir = QFileDialog::getOpenFileName(this, tr("Find Java executable")); - if (!dir.isNull()) - { - ui->javaPathTextBox->setText(dir); - } -} -void SettingsPage::on_javaTestBtn_clicked() -{ - checker.reset(new JavaChecker()); - connect(checker.get(), SIGNAL(checkFinished(JavaCheckResult)), this, - SLOT(checkFinished(JavaCheckResult))); - checker->path = ui->javaPathTextBox->text(); - checker->performCheck(); -} - -void SettingsPage::checkFinished(JavaCheckResult result) -{ - if (result.valid) - { - QString text; - text += "Java test succeeded!\n"; - if (result.is_64bit) - text += "Using 64bit java.\n"; - text += "\n"; - text += "Platform reported: " + result.realPlatform + "\n"; - text += "Java version reported: " + result.javaVersion; - QMessageBox::information(this, tr("Java test success"), text); - } - else - { - QMessageBox::warning( - this, tr("Java test failure"), - tr("The specified java binary didn't work. You should use the auto-detect feature, " - "or set the path to the java executable.")); - } } diff --git a/gui/pages/global/SettingsPage.h b/gui/pages/global/MultiMCPage.h similarity index 65% rename from gui/pages/global/SettingsPage.h rename to gui/pages/global/MultiMCPage.h index 46a38ec7..b465355f 100644 --- a/gui/pages/global/SettingsPage.h +++ b/gui/pages/global/MultiMCPage.h @@ -19,47 +19,44 @@ #include #include "logic/java/JavaChecker.h" -#include "BaseSettingsPage.h" +#include "gui/pages/BasePage.h" class SettingsObject; namespace Ui { -class SettingsPage; +class MultiMCPage; } -class SettingsPage : public QWidget, public BaseSettingsPage +class MultiMCPage : public QWidget, public BasePage { Q_OBJECT public: - explicit SettingsPage(QWidget *parent = 0); - ~SettingsPage(); + explicit MultiMCPage(QWidget *parent = 0); + ~MultiMCPage(); QString displayName() const override { - return tr("Settings"); + return tr("MultiMC"); } QIcon icon() const override { - return QIcon::fromTheme("settings"); + return QIcon::fromTheme("multimc"); } QString id() const override { - return "global-settings"; + return "multimc-settings"; } QString helpPage() const override { - return "Global-settings"; + return "MultiMC-settings"; } + bool apply() override; - void updateCheckboxStuff(); - - -protected: - void applySettings(SettingsObject *s) override; - void loadSettings(SettingsObject *s) override; - virtual void closeEvent(QCloseEvent *ev); +private: + void applySettings(); + void loadSettings(); private slots: @@ -71,16 +68,6 @@ slots: void on_lwjglDirBrowseBtn_clicked(); void on_iconsDirBrowseBtn_clicked(); - void on_jsonEditorBrowseBtn_clicked(); - - void on_maximizedCheckBox_clicked(bool checked); - - void on_javaDetectBtn_clicked(); - void on_javaTestBtn_clicked(); - void on_javaBrowseBtn_clicked(); - - void checkFinished(JavaCheckResult result); - /*! * Updates the list of update channels in the combo box. */ @@ -92,11 +79,9 @@ slots: void refreshUpdateChannelDesc(); void updateChannelSelectionChanged(int index); - void proxyChanged(int); private: - Ui::SettingsPage *ui; - std::shared_ptr checker; + Ui::MultiMCPage *ui; /*! * Stores the currently selected update channel. diff --git a/gui/pages/global/MultiMCPage.ui b/gui/pages/global/MultiMCPage.ui new file mode 100644 index 00000000..f456ebc1 --- /dev/null +++ b/gui/pages/global/MultiMCPage.ui @@ -0,0 +1,399 @@ + + + MultiMCPage + + + + 0 + 0 + 545 + 609 + + + + + 0 + 0 + + + + Settings + + + + :/icons/toolbar/settings:/icons/toolbar/settings + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QTabWidget::Rounded + + + 0 + + + + Features + + + + + + Update Settings + + + + + + Check for updates when MultiMC starts? + + + + + + + Update Channel: + + + + + + + false + + + + + + + No channel selected. + + + true + + + + + + + + + + FTB + + + + + + Launcher: + + + + + + + false + + + + + + + + + + Files: + + + + + + + true + + + ... + + + + + + + false + + + Qt::TabFocus + + + ... + + + + + + + Track FTB instances + + + + + + + + + + Folders + + + + + + Instances: + + + + + + + + + + ... + + + + + + + Mods: + + + + + + + + + + + + + ... + + + + + + + LWJGL: + + + + + + + ... + + + + + + + + + + Icons: + + + + + + + ... + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + User Interface + + + + + + MultiMC notifications + + + + + + Reset hidden notifications + + + true + + + + + + + + + + true + + + Instance view sorting mode + + + + + + By last launched + + + sortingModeGroup + + + + + + + By name + + + sortingModeGroup + + + + + + + + + + Language (needs restart): + + + + + + + + + + + + Icon Theme (needs restart, work in progress) + + + + + + + 0 + 0 + + + + Qt::StrongFocus + + + + Default + + + + + Simple + + + + + Simple (Light Icons) + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + tabWidget + autoUpdateCheckBox + updateChannelComboBox + trackFtbBox + ftbLauncherBox + ftbLauncherBrowseBtn + ftbBox + ftbBrowseBtn + instDirTextBox + instDirBrowseBtn + modsDirTextBox + modsDirBrowseBtn + lwjglDirTextBox + lwjglDirBrowseBtn + iconsDirTextBox + iconsDirBrowseBtn + resetNotificationsBtn + sortLastLaunchedBtn + sortByNameBtn + languageBox + themeComboBox + + + + + + + diff --git a/gui/pages/global/ProxyPage.cpp b/gui/pages/global/ProxyPage.cpp new file mode 100644 index 00000000..5578fbb7 --- /dev/null +++ b/gui/pages/global/ProxyPage.cpp @@ -0,0 +1,95 @@ +/* Copyright 2013 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 "ProxyPage.h" +#include "ui_ProxyPage.h" + +#include "logic/settings/SettingsObject.h" +#include "MultiMC.h" + +ProxyPage::ProxyPage(QWidget *parent) : QWidget(parent), ui(new Ui::ProxyPage) +{ + ui->setupUi(this); + ui->tabWidget->tabBar()->hide(); + loadSettings(); + updateCheckboxStuff(); + + connect(ui->proxyGroup, SIGNAL(buttonClicked(int)), SLOT(proxyChanged(int))); +} + +ProxyPage::~ProxyPage() +{ + delete ui; +} + +bool ProxyPage::apply() +{ + applySettings(); + return true; +} + +void ProxyPage::updateCheckboxStuff() +{ + ui->proxyAddrBox->setEnabled(!ui->proxyNoneBtn->isChecked() && + !ui->proxyDefaultBtn->isChecked()); + ui->proxyAuthBox->setEnabled(!ui->proxyNoneBtn->isChecked() && + !ui->proxyDefaultBtn->isChecked()); +} + +void ProxyPage::proxyChanged(int) +{ + updateCheckboxStuff(); +} + +void ProxyPage::applySettings() +{ + auto s = MMC->settings(); + + // Proxy + QString proxyType = "None"; + if (ui->proxyDefaultBtn->isChecked()) + proxyType = "Default"; + else if (ui->proxyNoneBtn->isChecked()) + proxyType = "None"; + else if (ui->proxySOCKS5Btn->isChecked()) + proxyType = "SOCKS5"; + else if (ui->proxyHTTPBtn->isChecked()) + proxyType = "HTTP"; + + s->set("ProxyType", proxyType); + s->set("ProxyAddr", ui->proxyAddrEdit->text()); + s->set("ProxyPort", ui->proxyPortEdit->value()); + s->set("ProxyUser", ui->proxyUserEdit->text()); + s->set("ProxyPass", ui->proxyPassEdit->text()); +} +void ProxyPage::loadSettings() +{ + auto s = MMC->settings(); + // Proxy + QString proxyType = s->get("ProxyType").toString(); + if (proxyType == "Default") + ui->proxyDefaultBtn->setChecked(true); + else if (proxyType == "None") + ui->proxyNoneBtn->setChecked(true); + else if (proxyType == "SOCKS5") + ui->proxySOCKS5Btn->setChecked(true); + else if (proxyType == "HTTP") + ui->proxyHTTPBtn->setChecked(true); + + ui->proxyAddrEdit->setText(s->get("ProxyAddr").toString()); + ui->proxyPortEdit->setValue(s->get("ProxyPort").value()); + ui->proxyUserEdit->setText(s->get("ProxyUser").toString()); + ui->proxyPassEdit->setText(s->get("ProxyPass").toString()); +} diff --git a/gui/pages/global/ProxyPage.h b/gui/pages/global/ProxyPage.h new file mode 100644 index 00000000..700a3af0 --- /dev/null +++ b/gui/pages/global/ProxyPage.h @@ -0,0 +1,66 @@ +/* Copyright 2013 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 +#include + +#include "logic/java/JavaChecker.h" +#include "gui/pages/BasePage.h" + +namespace Ui +{ +class ProxyPage; +} + +class ProxyPage : public QWidget, public BasePage +{ + Q_OBJECT + +public: + explicit ProxyPage(QWidget *parent = 0); + ~ProxyPage(); + + QString displayName() const override + { + return tr("Proxy"); + } + QIcon icon() const override + { + return QIcon::fromTheme("proxy"); + } + QString id() const override + { + return "proxy-settings"; + } + QString helpPage() const override + { + return "Proxy-settings"; + } + bool apply() override; + +private: + void updateCheckboxStuff(); + void applySettings(); + void loadSettings(); + +private +slots: + void proxyChanged(int); + +private: + Ui::ProxyPage *ui; +}; diff --git a/gui/pages/global/ProxyPage.ui b/gui/pages/global/ProxyPage.ui new file mode 100644 index 00000000..7cddd66d --- /dev/null +++ b/gui/pages/global/ProxyPage.ui @@ -0,0 +1,197 @@ + + + ProxyPage + + + + 0 + 0 + 607 + 632 + + + + + 0 + 0 + + + + Settings + + + + :/icons/toolbar/settings:/icons/toolbar/settings + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + + + + + Type + + + + + + Uses your system's default proxy settings. + + + Default + + + proxyGroup + + + + + + + None + + + proxyGroup + + + + + + + SOCKS5 + + + proxyGroup + + + + + + + HTTP + + + proxyGroup + + + + + + + + + + Address and Port + + + + + + 127.0.0.1 + + + + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + QAbstractSpinBox::PlusMinus + + + 65535 + + + 8080 + + + + + + + + + + Authentication + + + + + + + + + Username: + + + + + + + Password: + + + + + + + QLineEdit::Password + + + + + + + Note: Proxy username and password are stored in plain text inside MultiMC's configuration file! + + + true + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + + + + + diff --git a/gui/pages/global/SettingsPage.ui b/gui/pages/global/SettingsPage.ui deleted file mode 100644 index ed1d8cda..00000000 --- a/gui/pages/global/SettingsPage.ui +++ /dev/null @@ -1,985 +0,0 @@ - - - SettingsPage - - - - 0 - 0 - 545 - 609 - - - - - 0 - 0 - - - - Settings - - - - :/icons/toolbar/settings:/icons/toolbar/settings - - - - - - QTabWidget::Rounded - - - 0 - - - - Features - - - - - - Update Settings - - - - - - Check for updates when MultiMC starts? - - - - - - - Update Channel: - - - - - - - false - - - - - - - No channel selected. - - - true - - - - - - - - - - FTB - - - - - - false - - - - 0 - 0 - - - - - 28 - 16777215 - - - - Qt::TabFocus - - - ... - - - - - - - Launcher: - - - - - - - false - - - - - - - Track FTB instances - - - - - - - - - - true - - - - 0 - 0 - - - - - 28 - 16777215 - - - - ... - - - - - - - Files: - - - - - - - - - - Folders - - - - - - Instances: - - - - - - - - - - ... - - - - - - - Mods: - - - - - - - - - - - - - ... - - - - - - - LWJGL: - - - - - - - ... - - - - - - - - - - Icons: - - - - - - - ... - - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - User Interface - - - - - - - - - 0 - 0 - - - - Language (needs restart): - - - - - - - - - - - - Reset hidden notifications - - - true - - - - - - - true - - - Sorting Mode - - - - - - By last launched - - - sortingModeGroup - - - - - - - By name - - - sortingModeGroup - - - - - - - - - - Icon Theme - - - - - - - 0 - 0 - - - - Qt::StrongFocus - - - - Default - - - - - Simple - - - - - Simple (Light Icons) - - - - - - - - - - - External Editors (leave empty for system default) - - - - - - - - - JSON Editor: - - - - - - - ... - - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - Minecraft - - - - - - Minecraft Version Updates - - - - - - Automatically update to latest version revision - - - - - - - - - - Window Size - - - - - - Start Minecraft maximized? - - - - - - - - - Window height: - - - - - - - Window width: - - - - - - - 854 - - - 65536 - - - 1 - - - 854 - - - - - - - 480 - - - 65536 - - - 480 - - - - - - - - - - - - Console Settings - - - - - - Show console while the game is running? - - - - - - - Automatically close console when the game quits? - - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - Java - - - - - - Memory - - - - - - The maximum amount of memory Minecraft is allowed to use. - - - MB - - - 512 - - - 65536 - - - 128 - - - 1024 - - - - - - - Minimum memory allocation: - - - - - - - Maximum memory allocation: - - - - - - - The amount of memory Minecraft is started with. - - - MB - - - 256 - - - 65536 - - - 128 - - - 256 - - - - - - - PermGen: - - - - - - - The amount of memory available to store loaded Java classes. - - - MB - - - 64 - - - 999999999 - - - 8 - - - 64 - - - - - - - - - - Java Settings - - - - - - - 0 - 0 - - - - Java path: - - - - - - - - 0 - 0 - - - - Auto-detect... - - - - - - - - 0 - 0 - - - - Test - - - - - - - - 0 - 0 - - - - JVM arguments: - - - - - - - - - - - - - 0 - 0 - - - - - 28 - 16777215 - - - - ... - - - - - - - - - - - - - - - Custom Commands - - - - - - Post-exit command: - - - - - - - Pre-launch command: - - - - - - - - - - - - - - - - - 0 - 0 - - - - Pre-launch command runs before the instance launches and post-exit command runs after it exits. Both will be run in MultiMC's working directory with INST_ID, INST_DIR, and INST_NAME as environment variables. - - - Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop - - - true - - - - - - - - Network settings. - - - Network - - - - - - Proxy - - - - - - Type - - - - - - Uses your system's default proxy settings. - - - Default - - - proxyGroup - - - - - - - None - - - proxyGroup - - - - - - - SOCKS5 - - - proxyGroup - - - - - - - HTTP - - - proxyGroup - - - - - - - - - - Address and Port - - - - - - 127.0.0.1 - - - - - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - QAbstractSpinBox::PlusMinus - - - 65535 - - - 8080 - - - - - - - - - - Authentication - - - - - - - - - Username: - - - - - - - Password: - - - - - - - QLineEdit::Password - - - - - - - Note: Proxy username and password are stored in plain text inside MultiMC's configuration file! - - - true - - - - - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - - - - settingsTabs - autoUpdateCheckBox - updateChannelComboBox - trackFtbBox - ftbLauncherBox - ftbLauncherBrowseBtn - ftbBox - ftbBrowseBtn - instDirTextBox - instDirBrowseBtn - modsDirTextBox - modsDirBrowseBtn - lwjglDirTextBox - lwjglDirBrowseBtn - iconsDirTextBox - iconsDirBrowseBtn - languageBox - resetNotificationsBtn - sortLastLaunchedBtn - sortByNameBtn - themeComboBox - jsonEditorTextBox - jsonEditorBrowseBtn - autoupdateMinecraft - maximizedCheckBox - windowWidthSpinBox - windowHeightSpinBox - showConsoleCheck - autoCloseConsoleCheck - minMemSpinBox - maxMemSpinBox - permGenSpinBox - javaPathTextBox - javaBrowseBtn - javaDetectBtn - javaTestBtn - jvmArgsTextBox - preLaunchCmdTextBox - postExitCmdTextBox - proxyDefaultBtn - proxyNoneBtn - proxySOCKS5Btn - proxyHTTPBtn - proxyAddrEdit - proxyPortEdit - proxyUserEdit - proxyPassEdit - - - - - - - - diff --git a/gui/widgets/PageContainer.cpp b/gui/widgets/PageContainer.cpp index a68f94cd..0620c725 100644 --- a/gui/widgets/PageContainer.cpp +++ b/gui/widgets/PageContainer.cpp @@ -124,6 +124,9 @@ void PageContainer::createUI() headerHLayout->addSpacerItem( new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Ignored)); headerHLayout->addWidget(m_iconHeader); + const int rightMargin = MMC->style()->pixelMetric(QStyle::PM_LayoutRightMargin); + headerHLayout->addSpacerItem( + new QSpacerItem(rightMargin, 0, QSizePolicy::Fixed, QSizePolicy::Ignored)); m_pageStack->setMargin(0); m_pageStack->addWidget(new QWidget(this)); diff --git a/resources/multimc/16x16/minecraft.png b/resources/multimc/16x16/minecraft.png new file mode 100644 index 0000000000000000000000000000000000000000..e9f2f2a5f583aa14c5ab25a2e8c75c51fa36a736 GIT binary patch literal 782 zcmV+p1M&QcP)kG&5#mP*F)0$%%P9trJ9pJx_inShv-9rG%scb0g?IrueaeT2AHU|Y_>Y{q^!SrW zl3Z*yn-*~Htq z(~sy(pPex~6NVu{5TKMoN=cSwNGa*}`^2&O;Qpicy?No(r{C`b);>J>&f#WlEuChh z6HT7yq-lzjl3J~XQVOLe%w~rAQial-Pj@qZ@9h_^ykY^Ie&exO?Qn@|GhnXbuQs@ItIf?XeqsB1kM4%DTmW;+^nPEA8tvOX>JOE9;K5~@M^^Z= zv&%5L%hJ(0`B-rE@(*l%+oiMBCp2yZ-~yC78b=#?YQkXZK(@ermI`-C?|0(AwBVC_@>6{$s+N z@R8DG-@pK(#L(d9SqVEB6W056evb;c6 zLLP2NrW4I@FK3jDaD|U01eTYRngZ#2Xbb>0z(^%j%K>4@XKxsj<|&1pv#=aeEqfTN zAj@+miAK0KNu~*eeb2zLtw#6mm}5)xcrqZ%GJH{>^MYb#VG51!*cdM$%L|G;C-mLQ zzCmqHUiO8{PN&Z}o}hJ(?FdrKXOd)iLQpFQm|QbSQiO0B#L4^nfJ>i$_wveoaGX+Y zJu?tR5s{iw_AD$5;%Q2Epm1yp={f7J;~f97wfEwIXIgvi#8bWY&TEe6J+rz{;o8Qp zOp^@T4?hc~d*R0B_O<_g<3D-n)T1YdadN)38zCHCzy5RQ>Os4|0E|&f-=SO?jQ{`u M07*qoM6N<$f;XjsZU6uP literal 0 HcmV?d00001 diff --git a/resources/multimc/24x24/minecraft.png b/resources/multimc/24x24/minecraft.png new file mode 100644 index 0000000000000000000000000000000000000000..b31177c9cac2456db32e062614c322e993a323f1 GIT binary patch literal 1500 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

i|JSt@Wyl>H+LB%=w3qORK-y$lGFh&!F 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 literal 0 HcmV?d00001 diff --git a/resources/multimc/32x32/minecraft.png b/resources/multimc/32x32/minecraft.png new file mode 100644 index 0000000000000000000000000000000000000000..816bec98f5f48c4fba292d92da47f06052fa7391 GIT binary patch literal 2495 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 scalable/console_error.svg + + scalable/proxy.svg + + + scalable/java.svg + + + 16x16/minecraft.png + 24x24/minecraft.png + 32x32/minecraft.png + 48x48/minecraft.png + 256x256/minecraft.png + 16x16/about.png 22x22/about.png diff --git a/resources/multimc/scalable/java.svg b/resources/multimc/scalable/java.svg new file mode 100644 index 00000000..fd15e5c6 --- /dev/null +++ b/resources/multimc/scalable/java.svg @@ -0,0 +1,773 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/resources/multimc/scalable/proxy.svg b/resources/multimc/scalable/proxy.svg new file mode 100644 index 00000000..55ee6f93 --- /dev/null +++ b/resources/multimc/scalable/proxy.svg @@ -0,0 +1,260 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + +