aboutsummaryrefslogtreecommitdiff
path: root/launcher/ui
diff options
context:
space:
mode:
Diffstat (limited to 'launcher/ui')
-rw-r--r--launcher/ui/GuiUtil.cpp1
-rw-r--r--launcher/ui/InstanceWindow.cpp50
-rw-r--r--launcher/ui/InstanceWindow.h44
-rw-r--r--launcher/ui/MainWindow.cpp219
-rw-r--r--launcher/ui/MainWindow.h14
-rw-r--r--launcher/ui/dialogs/AboutDialog.cpp2
-rw-r--r--launcher/ui/dialogs/CopyInstanceDialog.cpp46
-rw-r--r--launcher/ui/dialogs/ExportInstanceDialog.cpp4
-rw-r--r--launcher/ui/dialogs/NewComponentDialog.cpp41
-rw-r--r--launcher/ui/dialogs/NewInstanceDialog.cpp46
-rw-r--r--launcher/ui/dialogs/NewsDialog.cpp49
-rw-r--r--launcher/ui/dialogs/NewsDialog.h30
-rw-r--r--launcher/ui/dialogs/NewsDialog.ui113
-rw-r--r--launcher/ui/dialogs/ProfileSetupDialog.cpp46
-rw-r--r--launcher/ui/dialogs/SkinUploadDialog.cpp39
-rw-r--r--launcher/ui/dialogs/UpdateDialog.cpp37
-rw-r--r--launcher/ui/instanceview/InstanceDelegate.cpp46
-rw-r--r--launcher/ui/instanceview/InstanceView.cpp90
-rw-r--r--launcher/ui/instanceview/InstanceView.h44
-rw-r--r--launcher/ui/instanceview/VisualGroup.cpp49
-rw-r--r--launcher/ui/pages/global/AccountListPage.cpp18
-rw-r--r--launcher/ui/pages/global/CustomCommandsPage.cpp2
-rw-r--r--launcher/ui/pages/global/JavaPage.cpp5
-rw-r--r--launcher/ui/pages/global/LauncherPage.cpp38
-rw-r--r--launcher/ui/pages/global/LauncherPage.h5
-rw-r--r--launcher/ui/pages/global/LauncherPage.ui5
-rw-r--r--launcher/ui/pages/global/MinecraftPage.cpp13
-rw-r--r--launcher/ui/pages/global/MinecraftPage.ui60
-rw-r--r--launcher/ui/pages/global/ProxyPage.cpp16
-rw-r--r--launcher/ui/pages/global/ProxyPage.h9
-rw-r--r--launcher/ui/pages/instance/ExternalResourcesPage.cpp297
-rw-r--r--launcher/ui/pages/instance/ExternalResourcesPage.h73
-rw-r--r--launcher/ui/pages/instance/ExternalResourcesPage.ui (renamed from launcher/ui/pages/instance/ModFolderPage.ui)49
-rw-r--r--launcher/ui/pages/instance/InstanceSettingsPage.cpp34
-rw-r--r--launcher/ui/pages/instance/InstanceSettingsPage.ui68
-rw-r--r--launcher/ui/pages/instance/LogPage.cpp3
-rw-r--r--launcher/ui/pages/instance/ModFolderPage.cpp381
-rw-r--r--launcher/ui/pages/instance/ModFolderPage.h113
-rw-r--r--launcher/ui/pages/instance/ResourcePackPage.h20
-rw-r--r--launcher/ui/pages/instance/ScreenshotsPage.cpp5
-rw-r--r--launcher/ui/pages/instance/ScreenshotsPage.h1
-rw-r--r--launcher/ui/pages/instance/ServersPage.cpp13
-rw-r--r--launcher/ui/pages/instance/ServersPage.h3
-rw-r--r--launcher/ui/pages/instance/ShaderPackPage.h16
-rw-r--r--launcher/ui/pages/instance/TexturePackPage.h18
-rw-r--r--launcher/ui/pages/instance/VersionPage.cpp2
-rw-r--r--launcher/ui/pages/instance/WorldListPage.cpp1
-rw-r--r--launcher/ui/pages/modplatform/ImportPage.cpp2
-rw-r--r--launcher/ui/pages/modplatform/ModModel.cpp10
-rw-r--r--launcher/ui/pages/modplatform/flame/FlameModPage.cpp2
-rw-r--r--launcher/ui/pages/modplatform/flame/FlameModPage.h2
-rw-r--r--launcher/ui/pages/modplatform/flame/FlameModel.cpp16
-rw-r--r--launcher/ui/pages/modplatform/flame/FlameModel.h1
-rw-r--r--launcher/ui/pages/modplatform/flame/FlamePage.cpp25
-rw-r--r--launcher/ui/pages/modplatform/flame/FlamePage.ui2
-rw-r--r--launcher/ui/pages/modplatform/legacy_ftb/ListModel.cpp4
-rw-r--r--launcher/ui/pages/modplatform/legacy_ftb/Page.cpp3
-rw-r--r--launcher/ui/pages/modplatform/legacy_ftb/Page.ui6
-rw-r--r--launcher/ui/pages/modplatform/modrinth/ModrinthModPage.cpp2
-rw-r--r--launcher/ui/pages/modplatform/modrinth/ModrinthModPage.h2
-rw-r--r--launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp26
-rw-r--r--launcher/ui/pages/modplatform/modrinth/ModrinthModel.h2
-rw-r--r--launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp35
-rw-r--r--launcher/ui/pages/modplatform/modrinth/ModrinthPage.ui3
-rw-r--r--launcher/ui/pages/modplatform/technic/TechnicModel.cpp5
-rw-r--r--launcher/ui/widgets/CustomCommands.cpp2
-rw-r--r--launcher/ui/widgets/CustomCommands.h2
-rw-r--r--launcher/ui/widgets/JavaSettingsWidget.cpp5
-rw-r--r--launcher/ui/widgets/LabeledToolButton.cpp44
-rw-r--r--launcher/ui/widgets/LogView.cpp37
-rw-r--r--launcher/ui/widgets/PageContainer.cpp4
-rw-r--r--launcher/ui/widgets/VersionListView.cpp42
72 files changed, 1698 insertions, 864 deletions
diff --git a/launcher/ui/GuiUtil.cpp b/launcher/ui/GuiUtil.cpp
index b1ea5ee9..5a62e4d0 100644
--- a/launcher/ui/GuiUtil.cpp
+++ b/launcher/ui/GuiUtil.cpp
@@ -39,7 +39,6 @@
#include <QClipboard>
#include <QApplication>
#include <QFileDialog>
-#include <QStandardPaths>
#include "ui/dialogs/ProgressDialog.h"
#include "ui/dialogs/CustomMessageBox.h"
diff --git a/launcher/ui/InstanceWindow.cpp b/launcher/ui/InstanceWindow.cpp
index ae765c3c..0ad8c594 100644
--- a/launcher/ui/InstanceWindow.cpp
+++ b/launcher/ui/InstanceWindow.cpp
@@ -1,16 +1,36 @@
-/* Copyright 2013-2021 MultiMC Contributors
+// SPDX-License-Identifier: GPL-3.0-only
+/*
+ * PolyMC - Minecraft Launcher
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
*
- * 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
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
*
- * 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.
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * This file incorporates work covered by the following copyright and
+ * permission notice:
+ *
+ * Copyright 2013-2021 MultiMC Contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
#include "InstanceWindow.h"
@@ -97,9 +117,9 @@ InstanceWindow::InstanceWindow(InstancePtr instance, QWidget *parent)
// set up instance and launch process recognition
{
auto launchTask = m_instance->getLaunchTask();
- on_InstanceLaunchTask_changed(launchTask);
- connect(m_instance.get(), &BaseInstance::launchTaskChanged, this, &InstanceWindow::on_InstanceLaunchTask_changed);
- connect(m_instance.get(), &BaseInstance::runningStatusChanged, this, &InstanceWindow::on_RunningState_changed);
+ instanceLaunchTaskChanged(launchTask);
+ connect(m_instance.get(), &BaseInstance::launchTaskChanged, this, &InstanceWindow::instanceLaunchTaskChanged);
+ connect(m_instance.get(), &BaseInstance::runningStatusChanged, this, &InstanceWindow::runningStateChanged);
}
// set up instance destruction detection
@@ -152,12 +172,12 @@ void InstanceWindow::on_btnLaunchMinecraftOffline_clicked()
APPLICATION->launch(m_instance, false, nullptr);
}
-void InstanceWindow::on_InstanceLaunchTask_changed(shared_qobject_ptr<LaunchTask> proc)
+void InstanceWindow::instanceLaunchTaskChanged(shared_qobject_ptr<LaunchTask> proc)
{
m_proc = proc;
}
-void InstanceWindow::on_RunningState_changed(bool running)
+void InstanceWindow::runningStateChanged(bool running)
{
updateLaunchButtons();
m_container->refreshContainer();
diff --git a/launcher/ui/InstanceWindow.h b/launcher/ui/InstanceWindow.h
index 1acf684e..aec07868 100644
--- a/launcher/ui/InstanceWindow.h
+++ b/launcher/ui/InstanceWindow.h
@@ -1,16 +1,36 @@
-/* Copyright 2013-2021 MultiMC Contributors
+// SPDX-License-Identifier: GPL-3.0-only
+/*
+ * PolyMC - Minecraft Launcher
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
*
- * 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
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
*
- * 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.
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * This file incorporates work covered by the following copyright and
+ * permission notice:
+ *
+ * Copyright 2013-2021 MultiMC Contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
#pragma once
@@ -55,8 +75,8 @@ slots:
void on_btnKillMinecraft_clicked();
void on_btnLaunchMinecraftOffline_clicked();
- void on_InstanceLaunchTask_changed(shared_qobject_ptr<LaunchTask> proc);
- void on_RunningState_changed(bool running);
+ void instanceLaunchTaskChanged(shared_qobject_ptr<LaunchTask> proc);
+ void runningStateChanged(bool running);
void on_instanceStatusChanged(BaseInstance::Status, BaseInstance::Status newStatus);
protected:
diff --git a/launcher/ui/MainWindow.cpp b/launcher/ui/MainWindow.cpp
index 210442df..d58f158e 100644
--- a/launcher/ui/MainWindow.cpp
+++ b/launcher/ui/MainWindow.cpp
@@ -42,31 +42,31 @@
#include "MainWindow.h"
-#include <QtCore/QVariant>
-#include <QtCore/QUrl>
-#include <QtCore/QDir>
-#include <QtCore/QFileInfo>
-
-#include <QtGui/QKeyEvent>
-
-#include <QtWidgets/QAction>
-#include <QtWidgets/QApplication>
-#include <QtWidgets/QButtonGroup>
-#include <QtWidgets/QHBoxLayout>
-#include <QtWidgets/QHeaderView>
-#include <QtWidgets/QMainWindow>
-#include <QtWidgets/QStatusBar>
-#include <QtWidgets/QToolBar>
-#include <QtWidgets/QWidget>
-#include <QtWidgets/QMenu>
-#include <QtWidgets/QMenuBar>
-#include <QtWidgets/QMessageBox>
-#include <QtWidgets/QInputDialog>
-#include <QtWidgets/QLabel>
-#include <QtWidgets/QToolButton>
-#include <QtWidgets/QWidgetAction>
-#include <QtWidgets/QProgressDialog>
-#include <QtWidgets/QShortcut>
+#include <QVariant>
+#include <QUrl>
+#include <QDir>
+#include <QFileInfo>
+
+#include <QKeyEvent>
+#include <QAction>
+
+#include <QApplication>
+#include <QButtonGroup>
+#include <QHBoxLayout>
+#include <QHeaderView>
+#include <QMainWindow>
+#include <QStatusBar>
+#include <QToolBar>
+#include <QWidget>
+#include <QMenu>
+#include <QMenuBar>
+#include <QMessageBox>
+#include <QInputDialog>
+#include <QLabel>
+#include <QToolButton>
+#include <QWidgetAction>
+#include <QProgressDialog>
+#include <QShortcut>
#include <BaseInstance.h>
#include <InstanceList.h>
@@ -95,6 +95,7 @@
#include "ui/instanceview/InstanceDelegate.h"
#include "ui/widgets/LabeledToolButton.h"
#include "ui/dialogs/NewInstanceDialog.h"
+#include "ui/dialogs/NewsDialog.h"
#include "ui/dialogs/ProgressDialog.h"
#include "ui/dialogs/AboutDialog.h"
#include "ui/dialogs/VersionSelectDialog.h"
@@ -224,6 +225,7 @@ public:
TranslatedAction actionMoreNews;
TranslatedAction actionManageAccounts;
TranslatedAction actionLaunchInstance;
+ TranslatedAction actionKillInstance;
TranslatedAction actionRenameInstance;
TranslatedAction actionChangeInstGroup;
TranslatedAction actionChangeInstIcon;
@@ -233,7 +235,6 @@ public:
TranslatedAction actionMods;
TranslatedAction actionViewSelectedInstFolder;
TranslatedAction actionViewSelectedMCFolder;
- TranslatedAction actionViewSelectedModsFolder;
TranslatedAction actionDeleteInstance;
TranslatedAction actionConfig_Folder;
TranslatedAction actionCAT;
@@ -282,29 +283,8 @@ public:
TranslatedToolbar instanceToolBar;
TranslatedToolbar newsToolBar;
QVector<TranslatedToolbar *> all_toolbars;
- bool m_kill = false;
- void updateLaunchAction()
- {
- if(m_kill)
- {
- actionLaunchInstance.setTextId(QT_TRANSLATE_NOOP("MainWindow", "&Kill"));
- actionLaunchInstance.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "Kill the running instance"));
- }
- else
- {
- actionLaunchInstance.setTextId(QT_TRANSLATE_NOOP("MainWindow", "&Launch"));
- actionLaunchInstance.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "Launch the selected instance."));
- }
- actionLaunchInstance.retranslate();
- }
- void setLaunchAction(bool kill)
- {
- m_kill = kill;
- updateLaunchAction();
- }
-
- void createMainToolbarActions(QMainWindow *MainWindow)
+ void createMainToolbarActions(MainWindow *MainWindow)
{
actionAddInstance = TranslatedAction(MainWindow);
actionAddInstance->setObjectName(QStringLiteral("actionAddInstance"));
@@ -503,9 +483,12 @@ public:
menuBar->setVisible(APPLICATION->settings()->get("MenuBarInsteadOfToolBar").toBool());
fileMenu = menuBar->addMenu(tr("&File"));
+ // Workaround for QTBUG-94802 (https://bugreports.qt.io/browse/QTBUG-94802); also present for other menus
+ fileMenu->setSeparatorsCollapsible(false);
fileMenu->addAction(actionAddInstance);
fileMenu->addAction(actionLaunchInstance);
fileMenu->addAction(actionLaunchInstanceOffline);
+ fileMenu->addAction(actionKillInstance);
fileMenu->addAction(actionCloseWindow);
fileMenu->addSeparator();
fileMenu->addAction(actionEditInstance);
@@ -526,15 +509,18 @@ public:
fileMenu->addAction(actionSettings);
viewMenu = menuBar->addMenu(tr("&View"));
+ viewMenu->setSeparatorsCollapsible(false);
viewMenu->addAction(actionCAT);
viewMenu->addSeparator();
menuBar->addMenu(foldersMenu);
profileMenu = menuBar->addMenu(tr("&Profiles"));
+ profileMenu->setSeparatorsCollapsible(false);
profileMenu->addAction(actionManageAccounts);
helpMenu = menuBar->addMenu(tr("&Help"));
+ helpMenu->setSeparatorsCollapsible(false);
helpMenu->addAction(actionAbout);
helpMenu->addAction(actionOpenWiki);
helpMenu->addAction(actionNewsMenuBar);
@@ -580,10 +566,9 @@ public:
}
// "Instance actions" are actions that require an instance to be selected (i.e. "new instance" is not here)
+ // Actions that also require other conditions (e.g. a running instance) won't be changed.
void setInstanceActionsEnabled(bool enabled)
{
- actionLaunchInstance->setEnabled(enabled);
- actionLaunchInstanceOffline->setEnabled(enabled);
actionEditInstance->setEnabled(enabled);
actionEditInstNotes->setEnabled(enabled);
actionMods->setEnabled(enabled);
@@ -670,6 +655,14 @@ public:
actionLaunchInstanceOffline.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "Launch the selected instance in offline mode."));
all_actions.append(&actionLaunchInstanceOffline);
+ actionKillInstance = TranslatedAction(MainWindow);
+ actionKillInstance->setObjectName(QStringLiteral("actionKillInstance"));
+ actionKillInstance->setDisabled(true);
+ actionKillInstance.setTextId(QT_TRANSLATE_NOOP("MainWindow", "&Kill"));
+ actionKillInstance.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "Kill the running instance"));
+ actionKillInstance->setShortcut(QKeySequence(tr("Ctrl+K")));
+ all_actions.append(&actionKillInstance);
+
actionEditInstance = TranslatedAction(MainWindow);
actionEditInstance->setObjectName(QStringLiteral("actionEditInstance"));
actionEditInstance.setTextId(QT_TRANSLATE_NOOP("MainWindow", "Edit Inst&ance..."));
@@ -715,14 +708,6 @@ public:
actionViewSelectedMCFolder->setShortcut(QKeySequence(tr("Ctrl+M")));
all_actions.append(&actionViewSelectedMCFolder);
- /*
- actionViewSelectedModsFolder = TranslatedAction(MainWindow);
- actionViewSelectedModsFolder->setObjectName(QStringLiteral("actionViewSelectedModsFolder"));
- actionViewSelectedModsFolder.setTextId(QT_TRANSLATE_NOOP("MainWindow", "Mods Folder"));
- actionViewSelectedModsFolder.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "Open the selected instance's mods folder in a file browser."));
- all_actions.append(&actionViewSelectedModsFolder);
- */
-
actionConfig_Folder = TranslatedAction(MainWindow);
actionConfig_Folder->setObjectName(QStringLiteral("actionConfig_Folder"));
actionConfig_Folder.setTextId(QT_TRANSLATE_NOOP("MainWindow", "Confi&g Folder"));
@@ -785,6 +770,7 @@ public:
instanceToolBar->addAction(actionLaunchInstance);
instanceToolBar->addAction(actionLaunchInstanceOffline);
+ instanceToolBar->addAction(actionKillInstance);
instanceToolBar->addSeparator();
@@ -798,9 +784,6 @@ public:
instanceToolBar->addSeparator();
instanceToolBar->addAction(actionViewSelectedMCFolder);
- /*
- instanceToolBar->addAction(actionViewSelectedModsFolder);
- */
instanceToolBar->addAction(actionConfig_Folder);
instanceToolBar->addAction(actionViewSelectedInstFolder);
@@ -822,7 +805,7 @@ public:
}
MainWindow->resize(800, 600);
MainWindow->setWindowIcon(APPLICATION->getThemedIcon("logo"));
- MainWindow->setWindowTitle(BuildConfig.LAUNCHER_DISPLAYNAME);
+ MainWindow->setWindowTitle(APPLICATION->applicationDisplayName());
#ifndef QT_NO_ACCESSIBILITY
MainWindow->setAccessibleName(BuildConfig.LAUNCHER_NAME);
#endif
@@ -857,8 +840,6 @@ public:
void retranslateUi(MainWindow *MainWindow)
{
- QString winTitle = tr("%1 - Version %2", "Launcher - Version X").arg(BuildConfig.LAUNCHER_DISPLAYNAME, BuildConfig.printableVersionString());
- MainWindow->setWindowTitle(winTitle);
// all the actions
for(auto * item: all_actions)
{
@@ -1031,7 +1012,6 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new MainWindow
}
-#ifdef LAUNCHER_WITH_UPDATER
if(BuildConfig.UPDATER_ENABLED)
{
bool updatesAllowed = APPLICATION->updatesAreAllowed();
@@ -1049,8 +1029,15 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new MainWindow
{
updater->checkForUpdate(APPLICATION->settings()->get("UpdateChannel").toString(), false);
}
+
+ if (APPLICATION->updateChecker()->getExternalUpdater())
+ {
+ connect(APPLICATION->updateChecker()->getExternalUpdater(),
+ &ExternalUpdater::canCheckForUpdatesChanged,
+ this,
+ &MainWindow::updatesAllowedChanged);
+ }
}
-#endif
setSelectedInstanceById(APPLICATION->settings()->get("SelectedInstance").toString());
@@ -1184,14 +1171,10 @@ void MainWindow::updateToolsMenu()
QToolButton *launchButton = dynamic_cast<QToolButton*>(ui->instanceToolBar->widgetForAction(ui->actionLaunchInstance));
QToolButton *launchOfflineButton = dynamic_cast<QToolButton*>(ui->instanceToolBar->widgetForAction(ui->actionLaunchInstanceOffline));
- if(m_selectedInstance && m_selectedInstance->isRunning())
- {
- ui->actionLaunchInstance->setMenu(nullptr);
- ui->actionLaunchInstanceOffline->setMenu(nullptr);
- launchButton->setPopupMode(QToolButton::InstantPopup);
- launchOfflineButton->setPopupMode(QToolButton::InstantPopup);
- return;
- }
+ bool currentInstanceRunning = m_selectedInstance && m_selectedInstance->isRunning();
+
+ ui->actionLaunchInstance->setDisabled(!m_selectedInstance || currentInstanceRunning);
+ ui->actionLaunchInstanceOffline->setDisabled(!m_selectedInstance || currentInstanceRunning);
QMenu *launchMenu = ui->actionLaunchInstance->menu();
QMenu *launchOfflineMenu = ui->actionLaunchInstanceOffline->menu();
@@ -1219,6 +1202,9 @@ void MainWindow::updateToolsMenu()
normalLaunchOffline->setShortcut(QKeySequence(tr("Ctrl+Shift+O")));
if (m_selectedInstance)
{
+ normalLaunch->setEnabled(m_selectedInstance->canLaunch());
+ normalLaunchOffline->setEnabled(m_selectedInstance->canLaunch());
+
connect(normalLaunch, &QAction::triggered, [this]() {
APPLICATION->launch(m_selectedInstance, true);
});
@@ -1249,6 +1235,9 @@ void MainWindow::updateToolsMenu()
}
else if (m_selectedInstance)
{
+ profilerAction->setEnabled(m_selectedInstance->canLaunch());
+ profilerOfflineAction->setEnabled(m_selectedInstance->canLaunch());
+
connect(profilerAction, &QAction::triggered, [this, profiler]()
{
APPLICATION->launch(m_selectedInstance, true, profiler.get());
@@ -1360,7 +1349,6 @@ void MainWindow::repopulateAccountsMenu()
ui->profileMenu->addAction(ui->actionManageAccounts);
}
-#ifdef LAUNCHER_WITH_UPDATER
void MainWindow::updatesAllowedChanged(bool allowed)
{
if(!BuildConfig.UPDATER_ENABLED)
@@ -1369,7 +1357,6 @@ void MainWindow::updatesAllowedChanged(bool allowed)
}
ui->actionCheckUpdate->setEnabled(allowed);
}
-#endif
/*
* Assumes the sender is a QAction
@@ -1475,7 +1462,6 @@ void MainWindow::updateNewsLabel()
}
}
-#ifdef LAUNCHER_WITH_UPDATER
void MainWindow::updateAvailable(GoUpdate::Status status)
{
if(!APPLICATION->updatesAreAllowed())
@@ -1501,11 +1487,14 @@ void MainWindow::updateNotAvailable()
UpdateDialog dlg(false, this);
dlg.exec();
}
-#endif
QList<int> stringToIntList(const QString &string)
{
+#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
+ QStringList split = string.split(',', Qt::SkipEmptyParts);
+#else
QStringList split = string.split(',', QString::SkipEmptyParts);
+#endif
QList<int> out;
for (int i = 0; i < split.size(); ++i)
{
@@ -1523,7 +1512,6 @@ QString intListToString(const QList<int> &list)
return slist.join(',');
}
-#ifdef LAUNCHER_WITH_UPDATER
void MainWindow::downloadUpdates(GoUpdate::Status status)
{
if(!APPLICATION->updatesAreAllowed())
@@ -1557,7 +1545,6 @@ void MainWindow::downloadUpdates(GoUpdate::Status status)
CustomMessageBox::selectable(this, tr("Error"), updateTask.failReason(), QMessageBox::Warning)->show();
}
}
-#endif
void MainWindow::onCatToggled(bool state)
{
@@ -1870,7 +1857,6 @@ void MainWindow::on_actionConfig_Folder_triggered()
}
}
-#ifdef LAUNCHER_WITH_UPDATER
void MainWindow::checkForUpdates()
{
if(BuildConfig.UPDATER_ENABLED)
@@ -1883,7 +1869,6 @@ void MainWindow::checkForUpdates()
qWarning() << "Updater not set up. Cannot check for updates.";
}
}
-#endif
void MainWindow::on_actionSettings_triggered()
{
@@ -1905,11 +1890,6 @@ void MainWindow::globalSettingsClosed()
update();
}
-void MainWindow::on_actionInstanceSettings_triggered()
-{
- APPLICATION->showInstanceWindow(m_selectedInstance, "settings");
-}
-
void MainWindow::on_actionEditInstNotes_triggered()
{
APPLICATION->showInstanceWindow(m_selectedInstance, "notes");
@@ -1952,20 +1932,17 @@ void MainWindow::on_actionOpenWiki_triggered()
void MainWindow::on_actionMoreNews_triggered()
{
- DesktopServices::openUrl(QUrl(BuildConfig.NEWS_OPEN_URL));
+ auto entries = m_newsChecker->getNewsEntries();
+ NewsDialog news_dialog(entries, this);
+ news_dialog.exec();
}
void MainWindow::newsButtonClicked()
{
- QList<NewsEntryPtr> entries = m_newsChecker->getNewsEntries();
- if (entries.count() > 0)
- {
- DesktopServices::openUrl(QUrl(entries[0]->link));
- }
- else
- {
- DesktopServices::openUrl(QUrl(BuildConfig.NEWS_OPEN_URL));
- }
+ auto entries = m_newsChecker->getNewsEntries();
+ NewsDialog news_dialog(entries, this);
+ news_dialog.toggleArticleList();
+ news_dialog.exec();
}
void MainWindow::on_actionAbout_triggered()
@@ -2035,20 +2012,6 @@ void MainWindow::on_actionViewSelectedMCFolder_triggered()
}
}
-void MainWindow::on_actionViewSelectedModsFolder_triggered()
-{
- if (m_selectedInstance)
- {
- QString str = m_selectedInstance->modsRoot();
- if (!FS::ensureFilePathExists(str))
- {
- // TODO: report error
- return;
- }
- DesktopServices::openDirectory(QDir(str).absolutePath());
- }
-}
-
void MainWindow::closeEvent(QCloseEvent *event)
{
// Save the window state and geometry.
@@ -2081,15 +2044,7 @@ void MainWindow::instanceActivated(QModelIndex index)
void MainWindow::on_actionLaunchInstance_triggered()
{
- if (!m_selectedInstance)
- {
- return;
- }
- if(m_selectedInstance->isRunning())
- {
- APPLICATION->kill(m_selectedInstance);
- }
- else
+ if(m_selectedInstance && !m_selectedInstance->isRunning())
{
APPLICATION->launch(m_selectedInstance);
}
@@ -2108,6 +2063,14 @@ void MainWindow::on_actionLaunchInstanceOffline_triggered()
}
}
+void MainWindow::on_actionKillInstance_triggered()
+{
+ if(m_selectedInstance && m_selectedInstance->isRunning())
+ {
+ APPLICATION->kill(m_selectedInstance);
+ }
+}
+
void MainWindow::taskEnd()
{
QObject *sender = QObject::sender();
@@ -2141,17 +2104,9 @@ void MainWindow::instanceChanged(const QModelIndex &current, const QModelIndex &
{
ui->instanceToolBar->setEnabled(true);
ui->setInstanceActionsEnabled(true);
- if(m_selectedInstance->isRunning())
- {
- ui->actionLaunchInstance->setEnabled(true);
- ui->setLaunchAction(true);
- }
- else
- {
- ui->actionLaunchInstance->setEnabled(m_selectedInstance->canLaunch());
- ui->setLaunchAction(false);
- }
+ ui->actionLaunchInstance->setEnabled(m_selectedInstance->canLaunch());
ui->actionLaunchInstanceOffline->setEnabled(m_selectedInstance->canLaunch());
+ ui->actionKillInstance->setEnabled(m_selectedInstance->isRunning());
ui->actionExportInstance->setEnabled(m_selectedInstance->canExport());
ui->renameButton->setText(m_selectedInstance->name());
m_statusLeft->setText(m_selectedInstance->getStatusbarDescription());
@@ -2168,6 +2123,9 @@ void MainWindow::instanceChanged(const QModelIndex &current, const QModelIndex &
{
ui->instanceToolBar->setEnabled(false);
ui->setInstanceActionsEnabled(false);
+ ui->actionLaunchInstance->setEnabled(false);
+ ui->actionLaunchInstanceOffline->setEnabled(false);
+ ui->actionKillInstance->setEnabled(false);
APPLICATION->settings()->set("SelectedInstance", QString());
selectionBad();
return;
@@ -2197,6 +2155,7 @@ void MainWindow::selectionBad()
statusBar()->clearMessage();
ui->instanceToolBar->setEnabled(false);
ui->setInstanceActionsEnabled(false);
+ updateToolsMenu();
ui->renameButton->setText(tr("Rename Instance"));
updateInstanceToolIcon("grass");
diff --git a/launcher/ui/MainWindow.h b/launcher/ui/MainWindow.h
index 6c64756f..d7930b5a 100644
--- a/launcher/ui/MainWindow.h
+++ b/launcher/ui/MainWindow.h
@@ -78,9 +78,7 @@ public:
void checkInstancePathForProblems();
-#ifdef LAUNCHER_WITH_UPDATER
void updatesAllowedChanged(bool allowed);
-#endif
void droppedURLs(QList<QUrl> urls);
signals:
@@ -120,20 +118,14 @@ private slots:
void on_actionViewSelectedMCFolder_triggered();
- void on_actionViewSelectedModsFolder_triggered();
-
void refreshInstances();
void on_actionViewCentralModsFolder_triggered();
-#ifdef LAUNCHER_WITH_UPDATER
void checkForUpdates();
-#endif
void on_actionSettings_triggered();
- void on_actionInstanceSettings_triggered();
-
void on_actionManageAccounts_triggered();
void on_actionReportBug_triggered();
@@ -148,6 +140,8 @@ private slots:
void on_actionLaunchInstanceOffline_triggered();
+ void on_actionKillInstance_triggered();
+
void on_actionDeleteInstance_triggered();
void deleteGroup();
@@ -195,11 +189,9 @@ private slots:
void startTask(Task *task);
-#ifdef LAUNCHER_WITH_UPDATER
void updateAvailable(GoUpdate::Status status);
void updateNotAvailable();
-#endif
void defaultAccountChanged();
@@ -209,12 +201,10 @@ private slots:
void updateNewsLabel();
-#ifdef LAUNCHER_WITH_UPDATER
/*!
* Runs the DownloadTask and installs updates.
*/
void downloadUpdates(GoUpdate::Status status);
-#endif
void konamiTriggered();
diff --git a/launcher/ui/dialogs/AboutDialog.cpp b/launcher/ui/dialogs/AboutDialog.cpp
index 8dadb755..c5367d5b 100644
--- a/launcher/ui/dialogs/AboutDialog.cpp
+++ b/launcher/ui/dialogs/AboutDialog.cpp
@@ -64,7 +64,9 @@ QString getCreditsHtml()
{
QString output;
QTextStream stream(&output);
+#if QT_VERSION <= QT_VERSION_CHECK(6, 0, 0)
stream.setCodec(QTextCodec::codecForName("UTF-8"));
+#endif
stream << "<center>\n";
//: %1 is the name of the launcher, determined at build time, e.g. "PolyMC Developers"
diff --git a/launcher/ui/dialogs/CopyInstanceDialog.cpp b/launcher/ui/dialogs/CopyInstanceDialog.cpp
index e5113981..9ec341bc 100644
--- a/launcher/ui/dialogs/CopyInstanceDialog.cpp
+++ b/launcher/ui/dialogs/CopyInstanceDialog.cpp
@@ -1,16 +1,36 @@
-/* Copyright 2013-2021 MultiMC Contributors
+// SPDX-License-Identifier: GPL-3.0-only
+/*
+ * PolyMC - Minecraft Launcher
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
*
- * 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
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
*
- * 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.
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * This file incorporates work covered by the following copyright and
+ * permission notice:
+ *
+ * Copyright 2013-2021 MultiMC Contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
#include <QLayout>
@@ -39,8 +59,14 @@ CopyInstanceDialog::CopyInstanceDialog(InstancePtr original, QWidget *parent)
ui->iconButton->setIcon(APPLICATION->icons()->getIcon(InstIconKey));
ui->instNameTextBox->setText(original->name());
ui->instNameTextBox->setFocus();
+#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
+ auto groupList = APPLICATION->instances()->getGroups();
+ QSet<QString> groups(groupList.begin(), groupList.end());
+ groupList = QStringList(groups.values());
+#else
auto groups = APPLICATION->instances()->getGroups().toSet();
auto groupList = QStringList(groups.toList());
+#endif
groupList.sort(Qt::CaseInsensitive);
groupList.removeOne("");
groupList.push_front("");
diff --git a/launcher/ui/dialogs/ExportInstanceDialog.cpp b/launcher/ui/dialogs/ExportInstanceDialog.cpp
index 8631edf6..9f32dd8e 100644
--- a/launcher/ui/dialogs/ExportInstanceDialog.cpp
+++ b/launcher/ui/dialogs/ExportInstanceDialog.cpp
@@ -488,7 +488,11 @@ void ExportInstanceDialog::loadPackIgnore()
}
auto data = ignoreFile.readAll();
auto string = QString::fromUtf8(data);
+#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
+ proxyModel->setBlockedPaths(string.split('\n', Qt::SkipEmptyParts));
+#else
proxyModel->setBlockedPaths(string.split('\n', QString::SkipEmptyParts));
+#endif
}
void ExportInstanceDialog::savePackIgnore()
diff --git a/launcher/ui/dialogs/NewComponentDialog.cpp b/launcher/ui/dialogs/NewComponentDialog.cpp
index 1bbafb0c..ea790e8c 100644
--- a/launcher/ui/dialogs/NewComponentDialog.cpp
+++ b/launcher/ui/dialogs/NewComponentDialog.cpp
@@ -1,16 +1,36 @@
-/* Copyright 2013-2021 MultiMC Contributors
+// SPDX-License-Identifier: GPL-3.0-only
+/*
+ * PolyMC - Minecraft Launcher
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
*
- * 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
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
*
- * 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.
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * This file incorporates work covered by the following copyright and
+ * permission notice:
+ *
+ * Copyright 2013-2021 MultiMC Contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
#include "Application.h"
@@ -46,7 +66,6 @@ NewComponentDialog::NewComponentDialog(const QString & initialName, const QStrin
connect(ui->nameTextBox, &QLineEdit::textChanged, this, &NewComponentDialog::updateDialogState);
connect(ui->uidTextBox, &QLineEdit::textChanged, this, &NewComponentDialog::updateDialogState);
- auto groups = APPLICATION->instances()->getGroups().toSet();
ui->nameTextBox->setFocus();
originalPlaceholderText = ui->uidTextBox->placeholderText();
diff --git a/launcher/ui/dialogs/NewInstanceDialog.cpp b/launcher/ui/dialogs/NewInstanceDialog.cpp
index 05ea091d..5b8ecc5b 100644
--- a/launcher/ui/dialogs/NewInstanceDialog.cpp
+++ b/launcher/ui/dialogs/NewInstanceDialog.cpp
@@ -1,16 +1,36 @@
-/* Copyright 2013-2021 MultiMC Contributors
+// SPDX-License-Identifier: GPL-3.0-only
+/*
+ * PolyMC - Minecraft Launcher
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
*
- * 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
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
*
- * 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.
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * This file incorporates work covered by the following copyright and
+ * permission notice:
+ *
+ * Copyright 2013-2021 MultiMC Contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
#include "Application.h"
@@ -54,8 +74,14 @@ NewInstanceDialog::NewInstanceDialog(const QString & initialGroup, const QString
InstIconKey = "default";
ui->iconButton->setIcon(APPLICATION->icons()->getIcon(InstIconKey));
+#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
+ auto groupList = APPLICATION->instances()->getGroups();
+ auto groups = QSet<QString>(groupList.begin(), groupList.end());
+ groupList = groups.values();
+#else
auto groups = APPLICATION->instances()->getGroups().toSet();
auto groupList = QStringList(groups.toList());
+#endif
groupList.sort(Qt::CaseInsensitive);
groupList.removeOne("");
groupList.push_front(initialGroup);
diff --git a/launcher/ui/dialogs/NewsDialog.cpp b/launcher/ui/dialogs/NewsDialog.cpp
new file mode 100644
index 00000000..d3b21627
--- /dev/null
+++ b/launcher/ui/dialogs/NewsDialog.cpp
@@ -0,0 +1,49 @@
+#include "NewsDialog.h"
+#include "ui_NewsDialog.h"
+
+NewsDialog::NewsDialog(QList<NewsEntryPtr> entries, QWidget* parent) : QDialog(parent), ui(new Ui::NewsDialog())
+{
+ ui->setupUi(this);
+
+ for (auto entry : entries) {
+ ui->articleListWidget->addItem(entry->title);
+ m_entries.insert(entry->title, entry);
+ }
+
+ connect(ui->articleListWidget, &QListWidget::currentTextChanged, this, &NewsDialog::selectedArticleChanged);
+ connect(ui->toggleListButton, &QPushButton::clicked, this, &NewsDialog::toggleArticleList);
+
+ m_article_list_hidden = ui->articleListWidget->isHidden();
+
+ auto first_item = ui->articleListWidget->item(0);
+ first_item->setSelected(true);
+
+ auto article_entry = m_entries.constFind(first_item->text()).value();
+ ui->articleTitleLabel->setText(QString("<a href='%1'>%2</a>").arg(article_entry->link, first_item->text()));
+ ui->currentArticleContentBrowser->setText(article_entry->content);
+}
+
+NewsDialog::~NewsDialog()
+{
+ delete ui;
+}
+
+void NewsDialog::selectedArticleChanged(const QString& new_title)
+{
+ auto const& article_entry = m_entries.constFind(new_title).value();
+
+ ui->articleTitleLabel->setText(QString("<a href='%1'>%2</a>").arg(article_entry->link, new_title));
+ ui->currentArticleContentBrowser->setText(article_entry->content);
+}
+
+void NewsDialog::toggleArticleList()
+{
+ m_article_list_hidden = !m_article_list_hidden;
+
+ ui->articleListWidget->setHidden(m_article_list_hidden);
+
+ if (m_article_list_hidden)
+ ui->toggleListButton->setText(tr("Show article list"));
+ else
+ ui->toggleListButton->setText(tr("Hide article list"));
+}
diff --git a/launcher/ui/dialogs/NewsDialog.h b/launcher/ui/dialogs/NewsDialog.h
new file mode 100644
index 00000000..add6b8dd
--- /dev/null
+++ b/launcher/ui/dialogs/NewsDialog.h
@@ -0,0 +1,30 @@
+#pragma once
+
+#include <QDialog>
+#include <QHash>
+
+#include "news/NewsEntry.h"
+
+namespace Ui {
+class NewsDialog;
+}
+
+class NewsDialog : public QDialog {
+ Q_OBJECT
+
+ public:
+ NewsDialog(QList<NewsEntryPtr> entries, QWidget* parent = nullptr);
+ ~NewsDialog();
+
+ public slots:
+ void toggleArticleList();
+
+ private slots:
+ void selectedArticleChanged(const QString& new_title);
+
+ private:
+ Ui::NewsDialog* ui;
+
+ QHash<QString, NewsEntryPtr> m_entries;
+ bool m_article_list_hidden = false;
+};
diff --git a/launcher/ui/dialogs/NewsDialog.ui b/launcher/ui/dialogs/NewsDialog.ui
new file mode 100644
index 00000000..2aaa08f1
--- /dev/null
+++ b/launcher/ui/dialogs/NewsDialog.ui
@@ -0,0 +1,113 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>NewsDialog</class>
+ <widget class="QDialog" name="NewsDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>800</width>
+ <height>500</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>News</string>
+ </property>
+ <property name="sizeGripEnabled">
+ <bool>true</bool>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <layout class="QVBoxLayout" name="leftVerticalLayout">
+ <item>
+ <widget class="QListWidget" name="articleListWidget">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Minimum" vsizetype="Expanding">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QVBoxLayout" name="rightVerticalLayout">
+ <item>
+ <widget class="QLabel" name="articleTitleLabel">
+ <property name="text">
+ <string notr="true">Placeholder</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ <property name="openExternalLinks">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QTextBrowser" name="currentArticleContentBrowser">
+ <property name="textInteractionFlags">
+ <set>Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse|Qt::TextBrowserInteraction|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
+ </property>
+ <property name="openExternalLinks">
+ <bool>true</bool>
+ </property>
+ <property name="openLinks">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="0" column="1">
+ <widget class="QPushButton" name="closeButton">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
+ <horstretch>10</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Close</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="0">
+ <widget class="QPushButton" name="toggleListButton">
+ <property name="text">
+ <string>Hide article list</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>closeButton</sender>
+ <signal>clicked()</signal>
+ <receiver>NewsDialog</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>199</x>
+ <y>277</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>199</x>
+ <y>149</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/launcher/ui/dialogs/ProfileSetupDialog.cpp b/launcher/ui/dialogs/ProfileSetupDialog.cpp
index 76b6af49..64c0b924 100644
--- a/launcher/ui/dialogs/ProfileSetupDialog.cpp
+++ b/launcher/ui/dialogs/ProfileSetupDialog.cpp
@@ -1,16 +1,36 @@
-/* Copyright 2013-2021 MultiMC Contributors
+// SPDX-License-Identifier: GPL-3.0-only
+/*
+ * PolyMC - Minecraft Launcher
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
*
- * 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
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
*
- * 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.
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * This file incorporates work covered by the following copyright and
+ * permission notice:
+ *
+ * Copyright 2013-2021 MultiMC Contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
#include "ProfileSetupDialog.h"
@@ -18,7 +38,7 @@
#include <QPushButton>
#include <QAction>
-#include <QRegExpValidator>
+#include <QRegularExpressionValidator>
#include <QJsonDocument>
#include <QDebug>
@@ -39,9 +59,9 @@ ProfileSetupDialog::ProfileSetupDialog(MinecraftAccountPtr accountToSetup, QWidg
yellowIcon = APPLICATION->getThemedIcon("status-yellow");
badIcon = APPLICATION->getThemedIcon("status-bad");
- QRegExp permittedNames("[a-zA-Z0-9_]{3,16}");
+ QRegularExpression permittedNames("[a-zA-Z0-9_]{3,16}");
auto nameEdit = ui->nameEdit;
- nameEdit->setValidator(new QRegExpValidator(permittedNames));
+ nameEdit->setValidator(new QRegularExpressionValidator(permittedNames));
nameEdit->setClearButtonEnabled(true);
validityAction = nameEdit->addAction(yellowIcon, QLineEdit::LeadingPosition);
connect(nameEdit, &QLineEdit::textEdited, this, &ProfileSetupDialog::nameEdited);
diff --git a/launcher/ui/dialogs/SkinUploadDialog.cpp b/launcher/ui/dialogs/SkinUploadDialog.cpp
index 8d137afc..b5b78690 100644
--- a/launcher/ui/dialogs/SkinUploadDialog.cpp
+++ b/launcher/ui/dialogs/SkinUploadDialog.cpp
@@ -1,3 +1,38 @@
+// SPDX-License-Identifier: GPL-3.0-only
+/*
+ * PolyMC - Minecraft Launcher
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * This file incorporates work covered by the following copyright and
+ * permission notice:
+ *
+ * Copyright 2013-2021 MultiMC Contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
#include <QFileInfo>
#include <QFileDialog>
#include <QPainter>
@@ -22,10 +57,10 @@ void SkinUploadDialog::on_buttonBox_accepted()
{
QString fileName;
QString input = ui->skinPathTextBox->text();
- QRegExp urlPrefixMatcher("^([a-z]+)://.+$");
+ QRegularExpression urlPrefixMatcher(QRegularExpression::anchoredPattern("^([a-z]+)://.+$"));
bool isLocalFile = false;
// it has an URL prefix -> it is an URL
- if(urlPrefixMatcher.exactMatch(input))
+ if(urlPrefixMatcher.match(input).hasMatch())
{
QUrl fileURL = input;
if(fileURL.isValid())
diff --git a/launcher/ui/dialogs/UpdateDialog.cpp b/launcher/ui/dialogs/UpdateDialog.cpp
index ec77d146..e0c5a495 100644
--- a/launcher/ui/dialogs/UpdateDialog.cpp
+++ b/launcher/ui/dialogs/UpdateDialog.cpp
@@ -1,3 +1,38 @@
+// SPDX-License-Identifier: GPL-3.0-only
+/*
+ * PolyMC - Minecraft Launcher
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * This file incorporates work covered by the following copyright and
+ * permission notice:
+ *
+ * Copyright 2013-2021 MultiMC Contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
#include "UpdateDialog.h"
#include "ui_UpdateDialog.h"
#include <QDebug>
@@ -58,7 +93,7 @@ QString reprocessMarkdown(QByteArray markdown)
QString output = hoedown.process(markdown);
// HACK: easier than customizing hoedown
- output.replace(QRegExp("GH-([0-9]+)"), "<a href=\"https://github.com/PolyMC/PolyMC/issues/\\1\">GH-\\1</a>");
+ output.replace(QRegularExpression("GH-([0-9]+)"), "<a href=\"https://github.com/PolyMC/PolyMC/issues/\\1\">GH-\\1</a>");
qDebug() << output;
return output;
}
diff --git a/launcher/ui/instanceview/InstanceDelegate.cpp b/launcher/ui/instanceview/InstanceDelegate.cpp
index b446e39d..137cc8d5 100644
--- a/launcher/ui/instanceview/InstanceDelegate.cpp
+++ b/launcher/ui/instanceview/InstanceDelegate.cpp
@@ -1,16 +1,36 @@
-/* Copyright 2013-2021 MultiMC Contributors
+// SPDX-License-Identifier: GPL-3.0-only
+/*
+ * PolyMC - Minecraft Launcher
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
*
- * 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
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
*
- * 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.
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * This file incorporates work covered by the following copyright and
+ * permission notice:
+ *
+ * Copyright 2013-2021 MultiMC Contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
#include "InstanceDelegate.h"
@@ -24,7 +44,7 @@
#include "InstanceView.h"
#include "BaseInstance.h"
#include "InstanceList.h"
-#include <xdgicon.h>
+#include <QIcon>
#include <QTextEdit>
// Origin: Qt
@@ -61,7 +81,7 @@ void drawSelectionRect(QPainter *painter, const QStyleOptionViewItem &option,
painter->fillRect(rect, option.palette.brush(QPalette::Highlight));
else
{
- QColor backgroundColor = option.palette.color(QPalette::Background);
+ QColor backgroundColor = option.palette.color(QPalette::Window);
backgroundColor.setAlpha(160);
painter->fillRect(rect, QBrush(backgroundColor));
}
@@ -142,7 +162,7 @@ void drawBadges(QPainter *painter, const QStyleOptionViewItem &option, BaseInsta
return;
}
// FIXME: inject this.
- auto icon = XdgIcon::fromTheme(it.next());
+ auto icon = QIcon::fromTheme(it.next());
// opt.icon.paint(painter, iconbox, Qt::AlignCenter, mode, state);
const QPixmap pixmap;
// itemSide
diff --git a/launcher/ui/instanceview/InstanceView.cpp b/launcher/ui/instanceview/InstanceView.cpp
index 25aec1ab..fbeffe35 100644
--- a/launcher/ui/instanceview/InstanceView.cpp
+++ b/launcher/ui/instanceview/InstanceView.cpp
@@ -1,16 +1,36 @@
-/* Copyright 2013-2021 MultiMC Contributors
+// SPDX-License-Identifier: GPL-3.0-only
+/*
+ * PolyMC - Minecraft Launcher
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
*
- * 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
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
*
- * 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.
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * This file incorporates work covered by the following copyright and
+ * permission notice:
+ *
+ * Copyright 2013-2021 MultiMC Contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
#include "InstanceView.h"
@@ -425,7 +445,12 @@ void InstanceView::mouseReleaseEvent(QMouseEvent *event)
{
emit clicked(index);
}
+#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
+ QStyleOptionViewItem option;
+ initViewItemOption(&option);
+#else
QStyleOptionViewItem option = viewOptions();
+#endif
if (m_pressedAlreadySelected)
{
option.state |= QStyle::State_Selected;
@@ -461,7 +486,12 @@ void InstanceView::mouseDoubleClickEvent(QMouseEvent *event)
QPersistentModelIndex persistent = index;
emit doubleClicked(persistent);
+#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
+ QStyleOptionViewItem option;
+ initViewItemOption(&option);
+#else
QStyleOptionViewItem option = viewOptions();
+#endif
if ((model()->flags(index) & Qt::ItemIsEnabled) && !style()->styleHint(QStyle::SH_ItemView_ActivateItemOnSingleClick, &option, this))
{
emit activated(index);
@@ -474,7 +504,12 @@ void InstanceView::paintEvent(QPaintEvent *event)
QPainter painter(this->viewport());
- QStyleOptionViewItem option(viewOptions());
+#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
+ QStyleOptionViewItem option;
+ initViewItemOption(&option);
+#else
+ QStyleOptionViewItem option = viewOptions();
+#endif
option.widget = this;
int wpWidth = viewport()->width();
@@ -528,9 +563,9 @@ void InstanceView::paintEvent(QPaintEvent *event)
#if 0
if (!m_lastDragPosition.isNull())
{
- QPair<Group *, int> pair = rowDropPos(m_lastDragPosition);
- Group *category = pair.first;
- int row = pair.second;
+ std::pair<VisualGroup *, VisualGroup::HitResults> pair = rowDropPos(m_lastDragPosition);
+ VisualGroup *category = pair.first;
+ VisualGroup::HitResults row = pair.second;
if (category)
{
int internalRow = row - category->firstItemIndex;
@@ -618,7 +653,7 @@ void InstanceView::dropEvent(QDropEvent *event)
{
if(event->possibleActions() & Qt::MoveAction)
{
- QPair<VisualGroup *, VisualGroup::HitResults> dropPos = rowDropPos(event->pos());
+ std::pair<VisualGroup *, VisualGroup::HitResults> dropPos = rowDropPos(event->pos());
const VisualGroup *group = dropPos.first;
auto hitresult = dropPos.second;
@@ -709,10 +744,18 @@ QRect InstanceView::geometryRect(const QModelIndex &index) const
int x = pos.first;
// int y = pos.second;
+
+#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
+ QStyleOptionViewItem option;
+ initViewItemOption(&option);
+#else
+ QStyleOptionViewItem option = viewOptions();
+#endif
+
QRect out;
out.setTop(cat->verticalPosition() + cat->headerHeight() + 5 + cat->rowTopOf(index));
out.setLeft(m_spacing + x * (itemWidth() + m_spacing));
- out.setSize(itemDelegate()->sizeHint(viewOptions(), index));
+ out.setSize(itemDelegate()->sizeHint(option, index));
geometryCache.insert(row, new QRect(out));
return out;
}
@@ -759,7 +802,12 @@ QPixmap InstanceView::renderToPixmap(const QModelIndexList &indices, QRect *r) c
QPixmap pixmap(r->size());
pixmap.fill(Qt::transparent);
QPainter painter(&pixmap);
+#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
+ QStyleOptionViewItem option;
+ initViewItemOption(&option);
+#else
QStyleOptionViewItem option = viewOptions();
+#endif
option.state |= QStyle::State_Selected;
for (int j = 0; j < paintPairs.count(); ++j)
{
@@ -770,16 +818,16 @@ QPixmap InstanceView::renderToPixmap(const QModelIndexList &indices, QRect *r) c
return pixmap;
}
-QList<QPair<QRect, QModelIndex>> InstanceView::draggablePaintPairs(const QModelIndexList &indices, QRect *r) const
+QList<std::pair<QRect, QModelIndex>> InstanceView::draggablePaintPairs(const QModelIndexList &indices, QRect *r) const
{
Q_ASSERT(r);
QRect &rect = *r;
- QList<QPair<QRect, QModelIndex>> ret;
+ QList<std::pair<QRect, QModelIndex>> ret;
for (int i = 0; i < indices.count(); ++i)
{
const QModelIndex &index = indices.at(i);
const QRect current = geometryRect(index);
- ret += qMakePair(current, index);
+ ret += std::make_pair(current, index);
rect |= current;
}
return ret;
@@ -790,11 +838,11 @@ bool InstanceView::isDragEventAccepted(QDropEvent *event)
return true;
}
-QPair<VisualGroup *, VisualGroup::HitResults> InstanceView::rowDropPos(const QPoint &pos)
+std::pair<VisualGroup *, VisualGroup::HitResults> InstanceView::rowDropPos(const QPoint &pos)
{
VisualGroup::HitResults hitresult;
auto group = categoryAt(pos + offset(), hitresult);
- return qMakePair<VisualGroup*, int>(group, hitresult);
+ return std::make_pair(group, hitresult);
}
QPoint InstanceView::offset() const
diff --git a/launcher/ui/instanceview/InstanceView.h b/launcher/ui/instanceview/InstanceView.h
index 406362e6..ac338274 100644
--- a/launcher/ui/instanceview/InstanceView.h
+++ b/launcher/ui/instanceview/InstanceView.h
@@ -1,16 +1,36 @@
-/* Copyright 2013-2021 MultiMC Contributors
+// SPDX-License-Identifier: GPL-3.0-only
+/*
+ * PolyMC - Minecraft Launcher
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
*
- * 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
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
*
- * 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.
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * This file incorporates work covered by the following copyright and
+ * permission notice:
+ *
+ * Copyright 2013-2021 MultiMC Contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
#pragma once
@@ -143,11 +163,11 @@ private: /* methods */
int calculateItemsPerRow() const;
int verticalScrollToValue(const QModelIndex &index, const QRect &rect, QListView::ScrollHint hint) const;
QPixmap renderToPixmap(const QModelIndexList &indices, QRect *r) const;
- QList<QPair<QRect, QModelIndex>> draggablePaintPairs(const QModelIndexList &indices, QRect *r) const;
+ QList<std::pair<QRect, QModelIndex>> draggablePaintPairs(const QModelIndexList &indices, QRect *r) const;
bool isDragEventAccepted(QDropEvent *event);
- QPair<VisualGroup *, VisualGroup::HitResults> rowDropPos(const QPoint &pos);
+ std::pair<VisualGroup *, VisualGroup::HitResults> rowDropPos(const QPoint &pos);
QPoint offset() const;
};
diff --git a/launcher/ui/instanceview/VisualGroup.cpp b/launcher/ui/instanceview/VisualGroup.cpp
index 8991fb2d..e6bca17d 100644
--- a/launcher/ui/instanceview/VisualGroup.cpp
+++ b/launcher/ui/instanceview/VisualGroup.cpp
@@ -1,16 +1,36 @@
-/* Copyright 2013-2021 MultiMC Contributors
+// SPDX-License-Identifier: GPL-3.0-only
+/*
+ * PolyMC - Minecraft Launcher
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
*
- * 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
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
*
- * 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.
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * This file incorporates work covered by the following copyright and
+ * permission notice:
+ *
+ * Copyright 2013-2021 MultiMC Contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
#include "VisualGroup.h"
@@ -55,7 +75,14 @@ void VisualGroup::update()
positionInRow = 0;
maxRowHeight = 0;
}
- auto itemHeight = view->itemDelegate()->sizeHint(view->viewOptions(), item).height();
+#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
+ QStyleOptionViewItem viewItemOption;
+ view->initViewItemOption(&viewItemOption);
+#else
+ QStyleOptionViewItem viewItemOption = view->viewOptions();
+#endif
+
+ auto itemHeight = view->itemDelegate()->sizeHint(viewItemOption, item).height();
if(itemHeight > maxRowHeight)
{
maxRowHeight = itemHeight;
diff --git a/launcher/ui/pages/global/AccountListPage.cpp b/launcher/ui/pages/global/AccountListPage.cpp
index 6e1e2183..a608771e 100644
--- a/launcher/ui/pages/global/AccountListPage.cpp
+++ b/launcher/ui/pages/global/AccountListPage.cpp
@@ -73,9 +73,11 @@ AccountListPage::AccountListPage(QWidget *parent)
m_accounts = APPLICATION->accounts();
ui->listView->setModel(m_accounts.get());
- ui->listView->header()->setSectionResizeMode(0, QHeaderView::Stretch);
- ui->listView->header()->setSectionResizeMode(1, QHeaderView::Stretch);
- ui->listView->header()->setSectionResizeMode(2, QHeaderView::ResizeToContents);
+ ui->listView->header()->setSectionResizeMode(AccountList::VListColumns::ProfileNameColumn, QHeaderView::Stretch);
+ ui->listView->header()->setSectionResizeMode(AccountList::VListColumns::NameColumn, QHeaderView::Stretch);
+ ui->listView->header()->setSectionResizeMode(AccountList::VListColumns::MigrationColumn, QHeaderView::ResizeToContents);
+ ui->listView->header()->setSectionResizeMode(AccountList::VListColumns::TypeColumn, QHeaderView::ResizeToContents);
+ ui->listView->header()->setSectionResizeMode(AccountList::VListColumns::StatusColumn, QHeaderView::ResizeToContents);
ui->listView->setSelectionMode(QAbstractItemView::SingleSelection);
// Expand the account column
@@ -253,19 +255,21 @@ void AccountListPage::updateButtonStates()
{
// If there is no selection, disable buttons that require something selected.
QModelIndexList selection = ui->listView->selectionModel()->selectedIndexes();
- bool hasSelection = selection.size() > 0;
+ bool hasSelection = !selection.empty();
bool accountIsReady = false;
+ bool accountIsOnline = false;
if (hasSelection)
{
QModelIndex selected = selection.first();
MinecraftAccountPtr account = selected.data(AccountList::PointerRole).value<MinecraftAccountPtr>();
accountIsReady = !account->isActive();
+ accountIsOnline = !account->isOffline();
}
ui->actionRemove->setEnabled(accountIsReady);
ui->actionSetDefault->setEnabled(accountIsReady);
- ui->actionUploadSkin->setEnabled(accountIsReady);
- ui->actionDeleteSkin->setEnabled(accountIsReady);
- ui->actionRefresh->setEnabled(accountIsReady);
+ ui->actionUploadSkin->setEnabled(accountIsReady && accountIsOnline);
+ ui->actionDeleteSkin->setEnabled(accountIsReady && accountIsOnline);
+ ui->actionRefresh->setEnabled(accountIsReady && accountIsOnline);
if(m_accounts->defaultAccount().get() == nullptr) {
ui->actionNoDefault->setEnabled(false);
diff --git a/launcher/ui/pages/global/CustomCommandsPage.cpp b/launcher/ui/pages/global/CustomCommandsPage.cpp
index 436d766e..df1420ca 100644
--- a/launcher/ui/pages/global/CustomCommandsPage.cpp
+++ b/launcher/ui/pages/global/CustomCommandsPage.cpp
@@ -2,7 +2,7 @@
/*
* PolyMC - Minecraft Launcher
* Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
- * Copyright (c) 2022 Sefa Eyeoglu <contact@scrumplex.net>
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/launcher/ui/pages/global/JavaPage.cpp b/launcher/ui/pages/global/JavaPage.cpp
index 025771e8..2cee15bf 100644
--- a/launcher/ui/pages/global/JavaPage.cpp
+++ b/launcher/ui/pages/global/JavaPage.cpp
@@ -127,6 +127,11 @@ void JavaPage::loadSettings()
void JavaPage::on_javaDetectBtn_clicked()
{
+ if (JavaUtils::getJavaCheckPath().isEmpty()) {
+ JavaCommon::javaCheckNotFound(this);
+ return;
+ }
+
JavaInstallPtr java;
VersionSelectDialog vselect(APPLICATION->javalist().get(), tr("Select a Java version"), this, true);
diff --git a/launcher/ui/pages/global/LauncherPage.cpp b/launcher/ui/pages/global/LauncherPage.cpp
index edbf609f..73ef0024 100644
--- a/launcher/ui/pages/global/LauncherPage.cpp
+++ b/launcher/ui/pages/global/LauncherPage.cpp
@@ -78,7 +78,6 @@ LauncherPage::LauncherPage(QWidget *parent) : QWidget(parent), ui(new Ui::Launch
m_languageModel = APPLICATION->translations();
loadSettings();
-#ifdef LAUNCHER_WITH_UPDATER
if(BuildConfig.UPDATER_ENABLED)
{
QObject::connect(APPLICATION->updateChecker().get(), &UpdateChecker::channelListLoaded, this, &LauncherPage::refreshUpdateChannelList);
@@ -91,9 +90,18 @@ LauncherPage::LauncherPage(QWidget *parent) : QWidget(parent), ui(new Ui::Launch
{
APPLICATION->updateChecker()->updateChanList(false);
}
- ui->updateSettingsBox->setHidden(false);
+
+ if (APPLICATION->updateChecker()->getExternalUpdater())
+ {
+ ui->updateChannelComboBox->setVisible(false);
+ ui->updateChannelDescLabel->setVisible(false);
+ ui->updateChannelLabel->setVisible(false);
+ }
+ }
+ else
+ {
+ ui->updateSettingsBox->setHidden(true);
}
-#endif
connect(ui->fontSizeBox, SIGNAL(valueChanged(int)), SLOT(refreshFontPreview()));
connect(ui->consoleFont, SIGNAL(currentFontChanged(QFont)), SLOT(refreshFontPreview()));
}
@@ -188,7 +196,6 @@ void LauncherPage::on_metadataDisableBtn_clicked()
ui->metadataWarningLabel->setHidden(!ui->metadataDisableBtn->isChecked());
}
-#ifdef LAUNCHER_WITH_UPDATER
void LauncherPage::refreshUpdateChannelList()
{
// Stop listening for selection changes. It's going to change a lot while we update it and
@@ -260,14 +267,22 @@ void LauncherPage::refreshUpdateChannelDesc()
m_currentUpdateChannel = selected.id;
}
}
-#endif
void LauncherPage::applySettings()
{
auto s = APPLICATION->settings();
// Updates
- s->set("AutoUpdate", ui->autoUpdateCheckBox->isChecked());
+ if (BuildConfig.UPDATER_ENABLED && APPLICATION->updateChecker()->getExternalUpdater())
+ {
+ APPLICATION->updateChecker()->getExternalUpdater()->setAutomaticallyChecksForUpdates(
+ ui->autoUpdateCheckBox->isChecked());
+ }
+ else
+ {
+ s->set("AutoUpdate", ui->autoUpdateCheckBox->isChecked());
+ }
+
s->set("UpdateChannel", m_currentUpdateChannel);
auto original = s->get("IconTheme").toString();
//FIXME: make generic
@@ -352,7 +367,16 @@ void LauncherPage::loadSettings()
{
auto s = APPLICATION->settings();
// Updates
- ui->autoUpdateCheckBox->setChecked(s->get("AutoUpdate").toBool());
+ if (BuildConfig.UPDATER_ENABLED && APPLICATION->updateChecker()->getExternalUpdater())
+ {
+ ui->autoUpdateCheckBox->setChecked(
+ APPLICATION->updateChecker()->getExternalUpdater()->getAutomaticallyChecksForUpdates());
+ }
+ else
+ {
+ ui->autoUpdateCheckBox->setChecked(s->get("AutoUpdate").toBool());
+ }
+
m_currentUpdateChannel = s->get("UpdateChannel").toString();
//FIXME: make generic
auto theme = s->get("IconTheme").toString();
diff --git a/launcher/ui/pages/global/LauncherPage.h b/launcher/ui/pages/global/LauncherPage.h
index ccfd7e9e..f38c922e 100644
--- a/launcher/ui/pages/global/LauncherPage.h
+++ b/launcher/ui/pages/global/LauncherPage.h
@@ -90,7 +90,6 @@ slots:
void on_iconsDirBrowseBtn_clicked();
void on_metadataDisableBtn_clicked();
-#ifdef LAUNCHER_WITH_UPDATER
/*!
* Updates the list of update channels in the combo box.
*/
@@ -101,13 +100,13 @@ slots:
*/
void refreshUpdateChannelDesc();
- void updateChannelSelectionChanged(int index);
-#endif
/*!
* Updates the font preview
*/
void refreshFontPreview();
+ void updateChannelSelectionChanged(int index);
+
private:
Ui::LauncherPage *ui;
diff --git a/launcher/ui/pages/global/LauncherPage.ui b/launcher/ui/pages/global/LauncherPage.ui
index ceb68c5b..645f7ef6 100644
--- a/launcher/ui/pages/global/LauncherPage.ui
+++ b/launcher/ui/pages/global/LauncherPage.ui
@@ -50,14 +50,11 @@
<property name="title">
<string>Update Settings</string>
</property>
- <property name="visible">
- <bool>false</bool>
- </property>
<layout class="QVBoxLayout" name="verticalLayout_7">
<item>
<widget class="QCheckBox" name="autoUpdateCheckBox">
<property name="text">
- <string>Check for updates on start?</string>
+ <string>Check for updates automatically</string>
</property>
</widget>
</item>
diff --git a/launcher/ui/pages/global/MinecraftPage.cpp b/launcher/ui/pages/global/MinecraftPage.cpp
index f49f5a92..e3ac7e7c 100644
--- a/launcher/ui/pages/global/MinecraftPage.cpp
+++ b/launcher/ui/pages/global/MinecraftPage.cpp
@@ -87,6 +87,11 @@ void MinecraftPage::applySettings()
s->set("UseNativeOpenAL", ui->useNativeOpenALCheck->isChecked());
s->set("UseNativeGLFW", ui->useNativeGLFWCheck->isChecked());
+ // Peformance related options
+ s->set("EnableFeralGamemode", ui->enableFeralGamemodeCheck->isChecked());
+ s->set("EnableMangoHud", ui->enableMangoHud->isChecked());
+ s->set("UseDiscreteGpu", ui->useDiscreteGpuCheck->isChecked());
+
// Game time
s->set("ShowGameTime", ui->showGameTime->isChecked());
s->set("ShowGlobalGameTime", ui->showGlobalGameTime->isChecked());
@@ -109,6 +114,14 @@ void MinecraftPage::loadSettings()
ui->useNativeOpenALCheck->setChecked(s->get("UseNativeOpenAL").toBool());
ui->useNativeGLFWCheck->setChecked(s->get("UseNativeGLFW").toBool());
+ ui->enableFeralGamemodeCheck->setChecked(s->get("EnableFeralGamemode").toBool());
+ ui->enableMangoHud->setChecked(s->get("EnableMangoHud").toBool());
+ ui->useDiscreteGpuCheck->setChecked(s->get("UseDiscreteGpu").toBool());
+
+#if !defined(Q_OS_LINUX)
+ ui->perfomanceGroupBox->setVisible(false);
+#endif
+
ui->showGameTime->setChecked(s->get("ShowGameTime").toBool());
ui->showGlobalGameTime->setChecked(s->get("ShowGlobalGameTime").toBool());
ui->recordGameTime->setChecked(s->get("RecordGameTime").toBool());
diff --git a/launcher/ui/pages/global/MinecraftPage.ui b/launcher/ui/pages/global/MinecraftPage.ui
index 353390bd..640f436d 100644
--- a/launcher/ui/pages/global/MinecraftPage.ui
+++ b/launcher/ui/pages/global/MinecraftPage.ui
@@ -135,6 +135,45 @@
</widget>
</item>
<item>
+ <widget class="QGroupBox" name="perfomanceGroupBox">
+ <property name="title">
+ <string>Performance</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_2">
+ <item>
+ <widget class="QCheckBox" name="enableFeralGamemodeCheck">
+ <property name="toolTip">
+ <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Enable Feral Interactive's GameMode, to potentially improve gaming performance.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+ </property>
+ <property name="text">
+ <string>Enable Feral GameMode</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="enableMangoHud">
+ <property name="toolTip">
+ <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Enable MangoHud's advanced performance overlay.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+ </property>
+ <property name="text">
+ <string>Enable MangoHud</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="useDiscreteGpuCheck">
+ <property name="toolTip">
+ <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Use the discrete GPU instead of the primary GPU.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+ </property>
+ <property name="text">
+ <string>Use discrete GPU</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
<widget class="QGroupBox" name="gameTimeGroupBox">
<property name="title">
<string>Game time</string>
@@ -181,15 +220,15 @@
</widget>
</item>
<item>
- <widget class="QCheckBox" name="quitAfterGameStopCheck">
- <property name="toolTip">
- <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The launcher will automatically quit after the game exits or crashes.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
- </property>
- <property name="text">
- <string>&amp;Quit the launcher after game window closes</string>
- </property>
- </widget>
- </item>
+ <widget class="QCheckBox" name="quitAfterGameStopCheck">
+ <property name="toolTip">
+ <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;The launcher will automatically quit after the game exits or crashes.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+ </property>
+ <property name="text">
+ <string>&amp;Quit the launcher after game window closes</string>
+ </property>
+ </widget>
+ </item>
</layout>
</widget>
</item>
@@ -218,6 +257,9 @@
<tabstop>windowHeightSpinBox</tabstop>
<tabstop>useNativeGLFWCheck</tabstop>
<tabstop>useNativeOpenALCheck</tabstop>
+ <tabstop>enableFeralGamemodeCheck</tabstop>
+ <tabstop>enableMangoHud</tabstop>
+ <tabstop>useDiscreteGpuCheck</tabstop>
</tabstops>
<resources/>
<connections/>
diff --git a/launcher/ui/pages/global/ProxyPage.cpp b/launcher/ui/pages/global/ProxyPage.cpp
index aefd1e74..ffff8456 100644
--- a/launcher/ui/pages/global/ProxyPage.cpp
+++ b/launcher/ui/pages/global/ProxyPage.cpp
@@ -2,6 +2,7 @@
/*
* PolyMC - Minecraft Launcher
* Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -36,11 +37,11 @@
#include "ProxyPage.h"
#include "ui_ProxyPage.h"
+#include <QButtonGroup>
#include <QTabBar>
#include "settings/SettingsObject.h"
#include "Application.h"
-#include "Application.h"
ProxyPage::ProxyPage(QWidget *parent) : QWidget(parent), ui(new Ui::ProxyPage)
{
@@ -49,7 +50,8 @@ ProxyPage::ProxyPage(QWidget *parent) : QWidget(parent), ui(new Ui::ProxyPage)
loadSettings();
updateCheckboxStuff();
- connect(ui->proxyGroup, SIGNAL(buttonClicked(int)), SLOT(proxyChanged(int)));
+ connect(ui->proxyGroup, QOverload<QAbstractButton *>::of(&QButtonGroup::buttonClicked),
+ this, &ProxyPage::proxyGroupChanged);
}
ProxyPage::~ProxyPage()
@@ -65,13 +67,13 @@ bool ProxyPage::apply()
void ProxyPage::updateCheckboxStuff()
{
- ui->proxyAddrBox->setEnabled(!ui->proxyNoneBtn->isChecked() &&
- !ui->proxyDefaultBtn->isChecked());
- ui->proxyAuthBox->setEnabled(!ui->proxyNoneBtn->isChecked() &&
- !ui->proxyDefaultBtn->isChecked());
+ bool enableEditing = ui->proxyHTTPBtn->isChecked()
+ || ui->proxySOCKS5Btn->isChecked();
+ ui->proxyAddrBox->setEnabled(enableEditing);
+ ui->proxyAuthBox->setEnabled(enableEditing);
}
-void ProxyPage::proxyChanged(int)
+void ProxyPage::proxyGroupChanged(QAbstractButton *button)
{
updateCheckboxStuff();
}
diff --git a/launcher/ui/pages/global/ProxyPage.h b/launcher/ui/pages/global/ProxyPage.h
index e3677774..279a9029 100644
--- a/launcher/ui/pages/global/ProxyPage.h
+++ b/launcher/ui/pages/global/ProxyPage.h
@@ -2,6 +2,7 @@
/*
* PolyMC - Minecraft Launcher
* Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -36,6 +37,7 @@
#pragma once
#include <memory>
+#include <QAbstractButton>
#include <QDialog>
#include "ui/pages/BasePage.h"
@@ -73,15 +75,14 @@ public:
bool apply() override;
void retranslate() override;
+private slots:
+ void proxyGroupChanged(QAbstractButton *button);
+
private:
void updateCheckboxStuff();
void applySettings();
void loadSettings();
-private
-slots:
- void proxyChanged(int);
-
private:
Ui::ProxyPage *ui;
};
diff --git a/launcher/ui/pages/instance/ExternalResourcesPage.cpp b/launcher/ui/pages/instance/ExternalResourcesPage.cpp
new file mode 100644
index 00000000..d06f412b
--- /dev/null
+++ b/launcher/ui/pages/instance/ExternalResourcesPage.cpp
@@ -0,0 +1,297 @@
+#include "ExternalResourcesPage.h"
+#include "ui_ExternalResourcesPage.h"
+
+#include "DesktopServices.h"
+#include "Version.h"
+#include "minecraft/mod/ModFolderModel.h"
+#include "ui/GuiUtil.h"
+
+#include <QKeyEvent>
+#include <QMenu>
+
+namespace {
+// FIXME: wasteful
+void RemoveThePrefix(QString& string)
+{
+ QRegularExpression regex(QStringLiteral("^(?:the|teh) +"), QRegularExpression::CaseInsensitiveOption);
+ string.remove(regex);
+ string = string.trimmed();
+}
+} // namespace
+
+class SortProxy : public QSortFilterProxyModel {
+ public:
+ explicit SortProxy(QObject* parent = nullptr) : QSortFilterProxyModel(parent) {}
+
+ protected:
+ bool filterAcceptsRow(int source_row, const QModelIndex& source_parent) const override
+ {
+ ModFolderModel* model = qobject_cast<ModFolderModel*>(sourceModel());
+ if (!model)
+ return false;
+
+ const auto& mod = model->at(source_row);
+
+ if (mod.name().contains(filterRegularExpression()))
+ return true;
+ if (mod.description().contains(filterRegularExpression()))
+ return true;
+
+ for (auto& author : mod.authors()) {
+ if (author.contains(filterRegularExpression())) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ bool lessThan(const QModelIndex& source_left, const QModelIndex& source_right) const override
+ {
+ ModFolderModel* model = qobject_cast<ModFolderModel*>(sourceModel());
+ if (!model || !source_left.isValid() || !source_right.isValid() || source_left.column() != source_right.column()) {
+ return QSortFilterProxyModel::lessThan(source_left, source_right);
+ }
+
+ // we are now guaranteed to have two valid indexes in the same column... we love the provided invariants unconditionally and
+ // proceed.
+
+ auto column = (ModFolderModel::Columns) source_left.column();
+ bool invert = false;
+ switch (column) {
+ // GH-2550 - sort by enabled/disabled
+ case ModFolderModel::ActiveColumn: {
+ auto dataL = source_left.data(Qt::CheckStateRole).toBool();
+ auto dataR = source_right.data(Qt::CheckStateRole).toBool();
+ if (dataL != dataR)
+ return dataL > dataR;
+
+ // fallthrough
+ invert = sortOrder() == Qt::DescendingOrder;
+ }
+ // GH-2722 - sort mod names in a way that discards "The" prefixes
+ case ModFolderModel::NameColumn: {
+ auto dataL = model->data(model->index(source_left.row(), ModFolderModel::NameColumn)).toString();
+ RemoveThePrefix(dataL);
+ auto dataR = model->data(model->index(source_right.row(), ModFolderModel::NameColumn)).toString();
+ RemoveThePrefix(dataR);
+
+ auto less = dataL.compare(dataR, sortCaseSensitivity());
+ if (less != 0)
+ return invert ? (less > 0) : (less < 0);
+
+ // fallthrough
+ invert = sortOrder() == Qt::DescendingOrder;
+ }
+ // GH-2762 - sort versions by parsing them as versions
+ case ModFolderModel::VersionColumn: {
+ auto dataL = Version(model->data(model->index(source_left.row(), ModFolderModel::VersionColumn)).toString());
+ auto dataR = Version(model->data(model->index(source_right.row(), ModFolderModel::VersionColumn)).toString());
+ return invert ? (dataL > dataR) : (dataL < dataR);
+ }
+ default: {
+ return QSortFilterProxyModel::lessThan(source_left, source_right);
+ }
+ }
+ }
+};
+
+ExternalResourcesPage::ExternalResourcesPage(BaseInstance* instance, std::shared_ptr<ModFolderModel> model, QWidget* parent)
+ : QMainWindow(parent), m_instance(instance), ui(new Ui::ExternalResourcesPage), m_model(model)
+{
+ ui->setupUi(this);
+
+ runningStateChanged(m_instance && m_instance->isRunning());
+
+ ui->actionsToolbar->insertSpacer(ui->actionViewConfigs);
+
+ m_filterModel = new SortProxy(this);
+ m_filterModel->setDynamicSortFilter(true);
+ m_filterModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
+ m_filterModel->setSortCaseSensitivity(Qt::CaseInsensitive);
+ m_filterModel->setSourceModel(m_model.get());
+ m_filterModel->setFilterKeyColumn(-1);
+ ui->treeView->setModel(m_filterModel);
+
+ ui->treeView->installEventFilter(this);
+ ui->treeView->sortByColumn(1, Qt::AscendingOrder);
+ ui->treeView->setContextMenuPolicy(Qt::CustomContextMenu);
+
+ // The default function names by Qt are pretty ugly, so let's just connect the actions manually,
+ // to make it easier to read :)
+ connect(ui->actionAddItem, &QAction::triggered, this, &ExternalResourcesPage::addItem);
+ connect(ui->actionRemoveItem, &QAction::triggered, this, &ExternalResourcesPage::removeItem);
+ connect(ui->actionEnableItem, &QAction::triggered, this, &ExternalResourcesPage::enableItem);
+ connect(ui->actionDisableItem, &QAction::triggered, this, &ExternalResourcesPage::disableItem);
+ connect(ui->actionViewConfigs, &QAction::triggered, this, &ExternalResourcesPage::viewConfigs);
+ connect(ui->actionViewFolder, &QAction::triggered, this, &ExternalResourcesPage::viewFolder);
+
+ connect(ui->treeView, &ModListView::customContextMenuRequested, this, &ExternalResourcesPage::ShowContextMenu);
+ connect(ui->treeView, &ModListView::activated, this, &ExternalResourcesPage::itemActivated);
+
+ auto selection_model = ui->treeView->selectionModel();
+ connect(selection_model, &QItemSelectionModel::currentChanged, this, &ExternalResourcesPage::current);
+ connect(ui->filterEdit, &QLineEdit::textChanged, this, &ExternalResourcesPage::filterTextChanged);
+ connect(m_instance, &BaseInstance::runningStatusChanged, this, &ExternalResourcesPage::runningStateChanged);
+}
+
+ExternalResourcesPage::~ExternalResourcesPage()
+{
+ m_model->stopWatching();
+ delete ui;
+}
+
+void ExternalResourcesPage::itemActivated(const QModelIndex&)
+{
+ if (!m_controlsEnabled)
+ return;
+
+ auto selection = m_filterModel->mapSelectionToSource(ui->treeView->selectionModel()->selection());
+ m_model->setModStatus(selection.indexes(), ModFolderModel::Toggle);
+}
+
+QMenu* ExternalResourcesPage::createPopupMenu()
+{
+ QMenu* filteredMenu = QMainWindow::createPopupMenu();
+ filteredMenu->removeAction(ui->actionsToolbar->toggleViewAction());
+ return filteredMenu;
+}
+
+void ExternalResourcesPage::ShowContextMenu(const QPoint& pos)
+{
+ auto menu = ui->actionsToolbar->createContextMenu(this, tr("Context menu"));
+ menu->exec(ui->treeView->mapToGlobal(pos));
+ delete menu;
+}
+
+void ExternalResourcesPage::openedImpl()
+{
+ m_model->startWatching();
+}
+
+void ExternalResourcesPage::closedImpl()
+{
+ m_model->stopWatching();
+}
+
+void ExternalResourcesPage::retranslate()
+{
+ ui->retranslateUi(this);
+}
+
+void ExternalResourcesPage::filterTextChanged(const QString& newContents)
+{
+ m_viewFilter = newContents;
+ m_filterModel->setFilterFixedString(m_viewFilter);
+}
+
+void ExternalResourcesPage::runningStateChanged(bool running)
+{
+ if (m_controlsEnabled == !running)
+ return;
+
+ m_controlsEnabled = !running;
+ ui->actionAddItem->setEnabled(m_controlsEnabled);
+ ui->actionDisableItem->setEnabled(m_controlsEnabled);
+ ui->actionEnableItem->setEnabled(m_controlsEnabled);
+ ui->actionRemoveItem->setEnabled(m_controlsEnabled);
+}
+
+bool ExternalResourcesPage::shouldDisplay() const
+{
+ return true;
+}
+
+bool ExternalResourcesPage::listFilter(QKeyEvent* keyEvent)
+{
+ switch (keyEvent->key()) {
+ case Qt::Key_Delete:
+ removeItem();
+ return true;
+ case Qt::Key_Plus:
+ addItem();
+ return true;
+ default:
+ break;
+ }
+ return QWidget::eventFilter(ui->treeView, keyEvent);
+}
+
+bool ExternalResourcesPage::eventFilter(QObject* obj, QEvent* ev)
+{
+ if (ev->type() != QEvent::KeyPress)
+ return QWidget::eventFilter(obj, ev);
+
+ QKeyEvent* keyEvent = static_cast<QKeyEvent*>(ev);
+ if (obj == ui->treeView)
+ return listFilter(keyEvent);
+
+ return QWidget::eventFilter(obj, ev);
+}
+
+void ExternalResourcesPage::addItem()
+{
+ if (!m_controlsEnabled)
+ return;
+
+
+ auto list = GuiUtil::BrowseForFiles(
+ helpPage(), tr("Select %1", "Select whatever type of files the page contains. Example: 'Loader Mods'").arg(displayName()),
+ m_fileSelectionFilter.arg(displayName()), APPLICATION->settings()->get("CentralModsDir").toString(), this->parentWidget());
+
+ if (!list.isEmpty()) {
+ for (auto filename : list) {
+ m_model->installMod(filename);
+ }
+ }
+}
+
+void ExternalResourcesPage::removeItem()
+{
+ if (!m_controlsEnabled)
+ return;
+
+ auto selection = m_filterModel->mapSelectionToSource(ui->treeView->selectionModel()->selection());
+ m_model->deleteMods(selection.indexes());
+}
+
+void ExternalResourcesPage::enableItem()
+{
+ if (!m_controlsEnabled)
+ return;
+
+ auto selection = m_filterModel->mapSelectionToSource(ui->treeView->selectionModel()->selection());
+ m_model->setModStatus(selection.indexes(), ModFolderModel::Enable);
+}
+
+void ExternalResourcesPage::disableItem()
+{
+ if (!m_controlsEnabled)
+ return;
+
+ auto selection = m_filterModel->mapSelectionToSource(ui->treeView->selectionModel()->selection());
+ m_model->setModStatus(selection.indexes(), ModFolderModel::Disable);
+}
+
+void ExternalResourcesPage::viewConfigs()
+{
+ DesktopServices::openDirectory(m_instance->instanceConfigFolder(), true);
+}
+
+void ExternalResourcesPage::viewFolder()
+{
+ DesktopServices::openDirectory(m_model->dir().absolutePath(), true);
+}
+
+void ExternalResourcesPage::current(const QModelIndex& current, const QModelIndex& previous)
+{
+ if (!current.isValid()) {
+ ui->frame->clear();
+ return;
+ }
+
+ auto sourceCurrent = m_filterModel->mapToSource(current);
+ int row = sourceCurrent.row();
+ Mod& m = m_model->operator[](row);
+ ui->frame->updateWithMod(m);
+}
diff --git a/launcher/ui/pages/instance/ExternalResourcesPage.h b/launcher/ui/pages/instance/ExternalResourcesPage.h
new file mode 100644
index 00000000..41237139
--- /dev/null
+++ b/launcher/ui/pages/instance/ExternalResourcesPage.h
@@ -0,0 +1,73 @@
+#pragma once
+
+#include <QMainWindow>
+#include <QSortFilterProxyModel>
+
+#include "Application.h"
+#include "minecraft/MinecraftInstance.h"
+#include "ui/pages/BasePage.h"
+
+class ModFolderModel;
+
+namespace Ui {
+class ExternalResourcesPage;
+}
+
+/* This page is used as a base for pages in which the user can manage external resources
+ * related to the game, such as mods, shaders or resource packs. */
+class ExternalResourcesPage : public QMainWindow, public BasePage {
+ Q_OBJECT
+
+ public:
+ // FIXME: Switch to different model (or change the name of this one)
+ explicit ExternalResourcesPage(BaseInstance* instance, std::shared_ptr<ModFolderModel> model, QWidget* parent = nullptr);
+ virtual ~ExternalResourcesPage();
+
+ virtual QString displayName() const override = 0;
+ virtual QIcon icon() const override = 0;
+ virtual QString id() const override = 0;
+ virtual QString helpPage() const override = 0;
+
+ virtual bool shouldDisplay() const override = 0;
+
+ void openedImpl() override;
+ void closedImpl() override;
+
+ void retranslate() override;
+
+ protected:
+ bool eventFilter(QObject* obj, QEvent* ev) override;
+ bool listFilter(QKeyEvent* ev);
+ QMenu* createPopupMenu() override;
+
+ public slots:
+ void current(const QModelIndex& current, const QModelIndex& previous);
+
+ protected slots:
+ void itemActivated(const QModelIndex& index);
+ void filterTextChanged(const QString& newContents);
+ void runningStateChanged(bool running);
+
+ virtual void addItem();
+ virtual void removeItem();
+
+ virtual void enableItem();
+ virtual void disableItem();
+
+ virtual void viewFolder();
+ virtual void viewConfigs();
+
+ void ShowContextMenu(const QPoint& pos);
+
+ protected:
+ BaseInstance* m_instance = nullptr;
+
+ Ui::ExternalResourcesPage* ui = nullptr;
+ std::shared_ptr<ModFolderModel> m_model;
+ QSortFilterProxyModel* m_filterModel = nullptr;
+
+ QString m_fileSelectionFilter;
+ QString m_viewFilter;
+
+ bool m_controlsEnabled = true;
+};
diff --git a/launcher/ui/pages/instance/ModFolderPage.ui b/launcher/ui/pages/instance/ExternalResourcesPage.ui
index ab59b0df..17bf455a 100644
--- a/launcher/ui/pages/instance/ModFolderPage.ui
+++ b/launcher/ui/pages/instance/ExternalResourcesPage.ui
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
- <class>ModFolderPage</class>
- <widget class="QMainWindow" name="ModFolderPage">
+ <class>ExternalResourcesPage</class>
+ <widget class="QMainWindow" name="ExternalResourcesPage">
<property name="geometry">
<rect>
<x>0</x>
@@ -53,7 +53,7 @@
</widget>
</item>
<item row="1" column="1" colspan="3">
- <widget class="ModListView" name="modTreeView">
+ <widget class="ModListView" name="treeView">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
@@ -83,15 +83,15 @@
<attribute name="toolBarBreak">
<bool>false</bool>
</attribute>
- <addaction name="actionAdd"/>
+ <addaction name="actionAddItem"/>
<addaction name="separator"/>
- <addaction name="actionRemove"/>
- <addaction name="actionEnable"/>
- <addaction name="actionDisable"/>
- <addaction name="actionView_configs"/>
- <addaction name="actionView_Folder"/>
+ <addaction name="actionRemoveItem"/>
+ <addaction name="actionEnableItem"/>
+ <addaction name="actionDisableItem"/>
+ <addaction name="actionViewConfigs"/>
+ <addaction name="actionViewFolder"/>
</widget>
- <action name="actionAdd">
+ <action name="actionAddItem">
<property name="text">
<string>&amp;Add</string>
</property>
@@ -99,31 +99,31 @@
<string>Add</string>
</property>
</action>
- <action name="actionRemove">
+ <action name="actionRemoveItem">
<property name="text">
<string>&amp;Remove</string>
</property>
<property name="toolTip">
- <string>Remove selected mods</string>
+ <string>Remove selected item</string>
</property>
</action>
- <action name="actionEnable">
+ <action name="actionEnableItem">
<property name="text">
<string>&amp;Enable</string>
</property>
<property name="toolTip">
- <string>Enable selected mods</string>
+ <string>Enable selected item</string>
</property>
</action>
- <action name="actionDisable">
+ <action name="actionDisableItem">
<property name="text">
<string>&amp;Disable</string>
</property>
<property name="toolTip">
- <string>Disable selected mods</string>
+ <string>Disable selected item</string>
</property>
</action>
- <action name="actionView_configs">
+ <action name="actionViewConfigs">
<property name="text">
<string>View &amp;Configs</string>
</property>
@@ -131,11 +131,22 @@
<string>Open the 'config' folder in the system file manager.</string>
</property>
</action>
- <action name="actionView_Folder">
+ <action name="actionViewFolder">
<property name="text">
<string>View &amp;Folder</string>
</property>
</action>
+ <action name="actionDownloadItem">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>&amp;Download</string>
+ </property>
+ <property name="toolTip">
+ <string>Download a new resource</string>
+ </property>
+ </action>
</widget>
<customwidgets>
<customwidget>
@@ -156,7 +167,7 @@
</customwidget>
</customwidgets>
<tabstops>
- <tabstop>modTreeView</tabstop>
+ <tabstop>treeView</tabstop>
<tabstop>filterEdit</tabstop>
</tabstops>
<resources/>
diff --git a/launcher/ui/pages/instance/InstanceSettingsPage.cpp b/launcher/ui/pages/instance/InstanceSettingsPage.cpp
index b4562843..fcc110de 100644
--- a/launcher/ui/pages/instance/InstanceSettingsPage.cpp
+++ b/launcher/ui/pages/instance/InstanceSettingsPage.cpp
@@ -2,7 +2,7 @@
/*
* PolyMC - Minecraft Launcher
* Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
- * Copyright (c) 2022 Sefa Eyeoglu <contact@scrumplex.net>
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -50,6 +50,7 @@
#include "Application.h"
#include "java/JavaInstallList.h"
+#include "java/JavaUtils.h"
#include "FileSystem.h"
@@ -232,6 +233,22 @@ void InstanceSettingsPage::applySettings()
m_settings->reset("UseNativeGLFW");
}
+ // Performance
+ bool performance = ui->perfomanceGroupBox->isChecked();
+ m_settings->set("OverridePerformance", performance);
+ if(performance)
+ {
+ m_settings->set("EnableFeralGamemode", ui->enableFeralGamemodeCheck->isChecked());
+ m_settings->set("EnableMangoHud", ui->enableMangoHud->isChecked());
+ m_settings->set("UseDiscreteGpu", ui->useDiscreteGpuCheck->isChecked());
+ }
+ else
+ {
+ m_settings->reset("EnableFeralGamemode");
+ m_settings->reset("EnableMangoHud");
+ m_settings->reset("UseDiscreteGpu");
+ }
+
// Game time
bool gameTime = ui->gameTimeGroupBox->isChecked();
m_settings->set("OverrideGameTime", gameTime);
@@ -325,6 +342,16 @@ void InstanceSettingsPage::loadSettings()
ui->useNativeGLFWCheck->setChecked(m_settings->get("UseNativeGLFW").toBool());
ui->useNativeOpenALCheck->setChecked(m_settings->get("UseNativeOpenAL").toBool());
+ // Performance
+ ui->perfomanceGroupBox->setChecked(m_settings->get("OverridePerformance").toBool());
+ ui->enableFeralGamemodeCheck->setChecked(m_settings->get("EnableFeralGamemode").toBool());
+ ui->enableMangoHud->setChecked(m_settings->get("EnableMangoHud").toBool());
+ ui->useDiscreteGpuCheck->setChecked(m_settings->get("UseDiscreteGpu").toBool());
+
+ #if !defined(Q_OS_LINUX)
+ ui->perfomanceGroupBox->setVisible(false);
+ #endif
+
// Miscellanous
ui->gameTimeGroupBox->setChecked(m_settings->get("OverrideGameTime").toBool());
ui->showGameTime->setChecked(m_settings->get("ShowGameTime").toBool());
@@ -336,6 +363,11 @@ void InstanceSettingsPage::loadSettings()
void InstanceSettingsPage::on_javaDetectBtn_clicked()
{
+ if (JavaUtils::getJavaCheckPath().isEmpty()) {
+ JavaCommon::javaCheckNotFound(this);
+ return;
+ }
+
JavaInstallPtr java;
VersionSelectDialog vselect(APPLICATION->javalist().get(), tr("Select a Java version"), this, true);
diff --git a/launcher/ui/pages/instance/InstanceSettingsPage.ui b/launcher/ui/pages/instance/InstanceSettingsPage.ui
index cb66b3ce..8b3c3370 100644
--- a/launcher/ui/pages/instance/InstanceSettingsPage.ui
+++ b/launcher/ui/pages/instance/InstanceSettingsPage.ui
@@ -455,6 +455,74 @@
</item>
</layout>
</widget>
+ <widget class="QWidget" name="performancePage">
+ <attribute name="title">
+ <string>Performance</string>
+ </attribute>
+ <layout class="QVBoxLayout" name="verticalLayout_14">
+ <item>
+ <widget class="QGroupBox" name="perfomanceGroupBox">
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="title">
+ <string>Performance</string>
+ </property>
+ <property name="checkable">
+ <bool>true</bool>
+ </property>
+ <property name="checked">
+ <bool>false</bool>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_13">
+ <item>
+ <widget class="QCheckBox" name="enableFeralGamemodeCheck">
+ <property name="toolTip">
+ <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Enable Feral Interactive's GameMode, to potentially improve gaming performance.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+ </property>
+ <property name="text">
+ <string>Enable Feral GameMode</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="enableMangoHud">
+ <property name="toolTip">
+ <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Enable MangoHud's advanced performance overlay.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+ </property>
+ <property name="text">
+ <string>Enable MangoHud</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="useDiscreteGpuCheck">
+ <property name="toolTip">
+ <string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Use the discrete GPU instead of the primary GPU.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+ </property>
+ <property name="text">
+ <string>Use discrete GPU</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacer_2">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
<widget class="QWidget" name="miscellaneousPage">
<attribute name="title">
<string>Miscellaneous</string>
diff --git a/launcher/ui/pages/instance/LogPage.cpp b/launcher/ui/pages/instance/LogPage.cpp
index a6c98c08..3d9fb025 100644
--- a/launcher/ui/pages/instance/LogPage.cpp
+++ b/launcher/ui/pages/instance/LogPage.cpp
@@ -40,7 +40,6 @@
#include "Application.h"
#include <QIcon>
-#include <QIdentityProxyModel>
#include <QScrollBar>
#include <QShortcut>
@@ -64,7 +63,7 @@ public:
{
case Qt::FontRole:
return m_font;
- case Qt::TextColorRole:
+ case Qt::ForegroundRole:
{
MessageLevel::Enum level = (MessageLevel::Enum) QIdentityProxyModel::data(index, LogModel::LevelRole).toInt();
return m_colors->getFront(level);
diff --git a/launcher/ui/pages/instance/ModFolderPage.cpp b/launcher/ui/pages/instance/ModFolderPage.cpp
index d929a0ea..4432ccc8 100644
--- a/launcher/ui/pages/instance/ModFolderPage.cpp
+++ b/launcher/ui/pages/instance/ModFolderPage.cpp
@@ -35,370 +35,99 @@
*/
#include "ModFolderPage.h"
-#include "ui_ModFolderPage.h"
+#include "ui_ExternalResourcesPage.h"
-#include <QMessageBox>
+#include <QAbstractItemModel>
#include <QEvent>
#include <QKeyEvent>
-#include <QAbstractItemModel>
#include <QMenu>
+#include <QMessageBox>
#include <QSortFilterProxyModel>
#include "Application.h"
+#include "ui/GuiUtil.h"
#include "ui/dialogs/CustomMessageBox.h"
#include "ui/dialogs/ModDownloadDialog.h"
-#include "ui/GuiUtil.h"
#include "DesktopServices.h"
-#include "minecraft/mod/ModFolderModel.h"
-#include "minecraft/mod/Mod.h"
-#include "minecraft/VersionFilterData.h"
#include "minecraft/PackProfile.h"
+#include "minecraft/VersionFilterData.h"
+#include "minecraft/mod/Mod.h"
+#include "minecraft/mod/ModFolderModel.h"
#include "modplatform/ModAPI.h"
#include "Version.h"
+#include "tasks/ConcurrentTask.h"
#include "ui/dialogs/ProgressDialog.h"
-#include "tasks/SequentialTask.h"
-
-namespace {
- // FIXME: wasteful
- void RemoveThePrefix(QString & string) {
- QRegularExpression regex(QStringLiteral("^(([Tt][Hh][eE])|([Tt][eE][Hh])) +"));
- string.remove(regex);
- string = string.trimmed();
- }
-}
-
-class ModSortProxy : public QSortFilterProxyModel
-{
-public:
- explicit ModSortProxy(QObject *parent = 0) : QSortFilterProxyModel(parent)
- {
- }
-
-protected:
- bool filterAcceptsRow(int source_row, const QModelIndex & source_parent) const override {
- ModFolderModel *model = qobject_cast<ModFolderModel *>(sourceModel());
- if(!model) {
- return false;
- }
- const auto &mod = model->at(source_row);
- if(mod.name().contains(filterRegExp())) {
- return true;
- }
- if(mod.description().contains(filterRegExp())) {
- return true;
- }
- for(auto & author: mod.authors()) {
- if (author.contains(filterRegExp())) {
- return true;
- }
- }
- return false;
- }
-
- bool lessThan(const QModelIndex & source_left, const QModelIndex & source_right) const override
- {
- ModFolderModel *model = qobject_cast<ModFolderModel *>(sourceModel());
- if(
- !model ||
- !source_left.isValid() ||
- !source_right.isValid() ||
- source_left.column() != source_right.column()
- ) {
- return QSortFilterProxyModel::lessThan(source_left, source_right);
- }
-
- // we are now guaranteed to have two valid indexes in the same column... we love the provided invariants unconditionally and proceed.
- auto column = (ModFolderModel::Columns) source_left.column();
- bool invert = false;
- switch(column) {
- // GH-2550 - sort by enabled/disabled
- case ModFolderModel::ActiveColumn: {
- auto dataL = source_left.data(Qt::CheckStateRole).toBool();
- auto dataR = source_right.data(Qt::CheckStateRole).toBool();
- if(dataL != dataR) {
- return dataL > dataR;
- }
- // fallthrough
- invert = sortOrder() == Qt::DescendingOrder;
- }
- // GH-2722 - sort mod names in a way that discards "The" prefixes
- case ModFolderModel::NameColumn: {
- auto dataL = model->data(model->index(source_left.row(), ModFolderModel::NameColumn)).toString();
- RemoveThePrefix(dataL);
- auto dataR = model->data(model->index(source_right.row(), ModFolderModel::NameColumn)).toString();
- RemoveThePrefix(dataR);
-
- auto less = dataL.compare(dataR, sortCaseSensitivity());
- if(less != 0) {
- return invert ? (less > 0) : (less < 0);
- }
- // fallthrough
- invert = sortOrder() == Qt::DescendingOrder;
- }
- // GH-2762 - sort versions by parsing them as versions
- case ModFolderModel::VersionColumn: {
- auto dataL = Version(model->data(model->index(source_left.row(), ModFolderModel::VersionColumn)).toString());
- auto dataR = Version(model->data(model->index(source_right.row(), ModFolderModel::VersionColumn)).toString());
- return invert ? (dataL > dataR) : (dataL < dataR);
- }
- default: {
- return QSortFilterProxyModel::lessThan(source_left, source_right);
- }
- }
- }
-};
-
-ModFolderPage::ModFolderPage(
- BaseInstance *inst,
- std::shared_ptr<ModFolderModel> mods,
- QString id,
- QString iconName,
- QString displayName,
- QString helpPage,
- QWidget *parent
-) :
- QMainWindow(parent),
- ui(new Ui::ModFolderPage)
+ModFolderPage::ModFolderPage(BaseInstance* inst, std::shared_ptr<ModFolderModel> mods, QWidget* parent)
+ : ExternalResourcesPage(inst, mods, parent)
{
- ui->setupUi(this);
-
// This is structured like that so that these changes
- // do not affect the Resouce pack and Shader pack tabs
- if(id == "mods") {
- auto act = new QAction(tr("Download mods"), this);
- act->setToolTip(tr("Download mods from online mod platforms"));
- ui->actionsToolbar->insertActionBefore(ui->actionAdd, act);
- connect(act, &QAction::triggered, this, &ModFolderPage::on_actionInstall_mods_triggered);
-
- ui->actionAdd->setText(tr("Add .jar"));
- ui->actionAdd->setToolTip(tr("Add mods via local file"));
- }
-
- ui->actionsToolbar->insertSpacer(ui->actionView_configs);
-
- m_inst = inst;
- on_RunningState_changed(m_inst && m_inst->isRunning());
- m_mods = mods;
- m_id = id;
- m_displayName = displayName;
- m_iconName = iconName;
- m_helpName = helpPage;
- m_fileSelectionFilter = "%1 (*.zip *.jar)";
- m_filterModel = new ModSortProxy(this);
- m_filterModel->setDynamicSortFilter(true);
- m_filterModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
- m_filterModel->setSortCaseSensitivity(Qt::CaseInsensitive);
- m_filterModel->setSourceModel(m_mods.get());
- m_filterModel->setFilterKeyColumn(-1);
- ui->modTreeView->setModel(m_filterModel);
- ui->modTreeView->installEventFilter(this);
- ui->modTreeView->sortByColumn(1, Qt::AscendingOrder);
- ui->modTreeView->setContextMenuPolicy(Qt::CustomContextMenu);
- connect(ui->modTreeView, &ModListView::customContextMenuRequested, this, &ModFolderPage::ShowContextMenu);
- connect(ui->modTreeView, &ModListView::activated, this, &ModFolderPage::modItemActivated);
+ // do not affect the Resource pack and Shader pack tabs
+ {
+ ui->actionDownloadItem->setText(tr("Download mods"));
+ ui->actionDownloadItem->setToolTip(tr("Download mods from online mod platforms"));
+ ui->actionDownloadItem->setEnabled(true);
+ ui->actionAddItem->setText(tr("Add file"));
+ ui->actionAddItem->setToolTip(tr("Add a locally downloaded file"));
- auto smodel = ui->modTreeView->selectionModel();
- connect(smodel, &QItemSelectionModel::currentChanged, this, &ModFolderPage::modCurrent);
- connect(ui->filterEdit, &QLineEdit::textChanged, this, &ModFolderPage::on_filterTextChanged);
- connect(m_inst, &BaseInstance::runningStatusChanged, this, &ModFolderPage::on_RunningState_changed);
-}
+ ui->actionsToolbar->insertActionBefore(ui->actionAddItem, ui->actionDownloadItem);
-void ModFolderPage::modItemActivated(const QModelIndex&)
-{
- if(!m_controlsEnabled) {
- return;
+ connect(ui->actionDownloadItem, &QAction::triggered, this, &ModFolderPage::installMods);
}
- auto selection = m_filterModel->mapSelectionToSource(ui->modTreeView->selectionModel()->selection());
- m_mods->setModStatus(selection.indexes(), ModFolderModel::Toggle);
-}
-
-QMenu * ModFolderPage::createPopupMenu()
-{
- QMenu* filteredMenu = QMainWindow::createPopupMenu();
- filteredMenu->removeAction(ui->actionsToolbar->toggleViewAction() );
- return filteredMenu;
}
-void ModFolderPage::ShowContextMenu(const QPoint& pos)
-{
- auto menu = ui->actionsToolbar->createContextMenu(this, tr("Context menu"));
- menu->exec(ui->modTreeView->mapToGlobal(pos));
- delete menu;
-}
-
-void ModFolderPage::openedImpl()
-{
- m_mods->startWatching();
-}
-
-void ModFolderPage::closedImpl()
-{
- m_mods->stopWatching();
-}
-
-void ModFolderPage::on_filterTextChanged(const QString& newContents)
-{
- m_viewFilter = newContents;
- m_filterModel->setFilterFixedString(m_viewFilter);
-}
-
-
-CoreModFolderPage::CoreModFolderPage(BaseInstance *inst, std::shared_ptr<ModFolderModel> mods,
- QString id, QString iconName, QString displayName,
- QString helpPage, QWidget *parent)
- : ModFolderPage(inst, mods, id, iconName, displayName, helpPage, parent)
-{
-}
-
-ModFolderPage::~ModFolderPage()
-{
- m_mods->stopWatching();
- delete ui;
-}
-
-void ModFolderPage::on_RunningState_changed(bool running)
-{
- if(m_controlsEnabled == !running) {
- return;
- }
- m_controlsEnabled = !running;
- ui->actionsToolbar->setEnabled(m_controlsEnabled);
-}
+CoreModFolderPage::CoreModFolderPage(BaseInstance* inst, std::shared_ptr<ModFolderModel> mods, QWidget* parent)
+ : ModFolderPage(inst, mods, parent)
+{}
bool ModFolderPage::shouldDisplay() const
{
return true;
}
-void ModFolderPage::retranslate()
-{
- ui->retranslateUi(this);
-}
-
bool CoreModFolderPage::shouldDisplay() const
{
- if (ModFolderPage::shouldDisplay())
- {
- auto inst = dynamic_cast<MinecraftInstance *>(m_inst);
+ if (ModFolderPage::shouldDisplay()) {
+ auto inst = dynamic_cast<MinecraftInstance*>(m_instance);
if (!inst)
return true;
+
auto version = inst->getPackProfile();
+
if (!version)
return true;
- if(!version->getComponent("net.minecraftforge"))
- {
+ if (!version->getComponent("net.minecraftforge"))
return false;
- }
- if(!version->getComponent("net.minecraft"))
- {
+ if (!version->getComponent("net.minecraft"))
return false;
- }
- if(version->getComponent("net.minecraft")->getReleaseDateTime() < g_VersionFilterData.legacyCutoffDate)
- {
+ if (version->getComponent("net.minecraft")->getReleaseDateTime() < g_VersionFilterData.legacyCutoffDate)
return true;
- }
+
}
return false;
}
-bool ModFolderPage::modListFilter(QKeyEvent *keyEvent)
+void ModFolderPage::installMods()
{
- switch (keyEvent->key())
- {
- case Qt::Key_Delete:
- on_actionRemove_triggered();
- return true;
- case Qt::Key_Plus:
- on_actionAdd_triggered();
- return true;
- default:
- break;
- }
- return QWidget::eventFilter(ui->modTreeView, keyEvent);
-}
-
-bool ModFolderPage::eventFilter(QObject *obj, QEvent *ev)
-{
- if (ev->type() != QEvent::KeyPress)
- {
- return QWidget::eventFilter(obj, ev);
- }
- QKeyEvent *keyEvent = static_cast<QKeyEvent *>(ev);
- if (obj == ui->modTreeView)
- return modListFilter(keyEvent);
- return QWidget::eventFilter(obj, ev);
-}
-
-void ModFolderPage::on_actionAdd_triggered()
-{
- if(!m_controlsEnabled) {
+ if (!m_controlsEnabled)
return;
- }
- auto list = GuiUtil::BrowseForFiles(
- m_helpName,
- tr("Select %1",
- "Select whatever type of files the page contains. Example: 'Loader Mods'")
- .arg(m_displayName),
- m_fileSelectionFilter.arg(m_displayName), APPLICATION->settings()->get("CentralModsDir").toString(),
- this->parentWidget());
- if (!list.empty())
- {
- for (auto filename : list)
- {
- m_mods->installMod(filename);
- }
- }
-}
-
-void ModFolderPage::on_actionEnable_triggered()
-{
- if(!m_controlsEnabled) {
- return;
- }
- auto selection = m_filterModel->mapSelectionToSource(ui->modTreeView->selectionModel()->selection());
- m_mods->setModStatus(selection.indexes(), ModFolderModel::Enable);
-}
-
-void ModFolderPage::on_actionDisable_triggered()
-{
- if(!m_controlsEnabled) {
- return;
- }
- auto selection = m_filterModel->mapSelectionToSource(ui->modTreeView->selectionModel()->selection());
- m_mods->setModStatus(selection.indexes(), ModFolderModel::Disable);
-}
-
-void ModFolderPage::on_actionRemove_triggered()
-{
- if(!m_controlsEnabled) {
- return;
- }
- auto selection = m_filterModel->mapSelectionToSource(ui->modTreeView->selectionModel()->selection());
- m_mods->deleteMods(selection.indexes());
-}
-
-void ModFolderPage::on_actionInstall_mods_triggered()
-{
- if(!m_controlsEnabled) {
- return;
- }
- if(m_inst->typeName() != "Minecraft"){
- return; //this is a null instance or a legacy instance
- }
- auto profile = ((MinecraftInstance *)m_inst)->getPackProfile();
+ if (m_instance->typeName() != "Minecraft")
+ return; // this is a null instance or a legacy instance
+
+ auto profile = static_cast<MinecraftInstance*>(m_instance)->getPackProfile();
if (profile->getModLoaders() == ModAPI::Unspecified) {
- QMessageBox::critical(this,tr("Error"),tr("Please install a mod loader first!"));
+ QMessageBox::critical(this, tr("Error"), tr("Please install a mod loader first!"));
return;
}
- ModDownloadDialog mdownload(m_mods, this, m_inst);
+
+ ModDownloadDialog mdownload(m_model, this, m_instance);
if (mdownload.exec()) {
- SequentialTask* tasks = new SequentialTask(this);
+ ConcurrentTask* tasks = new ConcurrentTask(this);
connect(tasks, &Task::failed, [this, tasks](QString reason) {
CustomMessageBox::selectable(this, tr("Error"), reason, QMessageBox::Critical)->show();
tasks->deleteLater();
@@ -409,40 +138,20 @@ void ModFolderPage::on_actionInstall_mods_triggered()
});
connect(tasks, &Task::succeeded, [this, tasks]() {
QStringList warnings = tasks->warnings();
- if (warnings.count()) { CustomMessageBox::selectable(this, tr("Warnings"), warnings.join('\n'), QMessageBox::Warning)->show(); }
+ if (warnings.count())
+ CustomMessageBox::selectable(this, tr("Warnings"), warnings.join('\n'), QMessageBox::Warning)->show();
+
tasks->deleteLater();
});
- for (auto task : mdownload.getTasks()) {
+ for (auto& task : mdownload.getTasks()) {
tasks->addTask(task);
}
ProgressDialog loadDialog(this);
loadDialog.setSkipButton(true, tr("Abort"));
loadDialog.execWithTask(tasks);
- m_mods->update();
- }
-}
-void ModFolderPage::on_actionView_configs_triggered()
-{
- DesktopServices::openDirectory(m_inst->instanceConfigFolder(), true);
-}
-
-void ModFolderPage::on_actionView_Folder_triggered()
-{
- DesktopServices::openDirectory(m_mods->dir().absolutePath(), true);
-}
-
-void ModFolderPage::modCurrent(const QModelIndex &current, const QModelIndex &previous)
-{
- if (!current.isValid())
- {
- ui->frame->clear();
- return;
+ m_model->update();
}
- auto sourceCurrent = m_filterModel->mapToSource(current);
- int row = sourceCurrent.row();
- Mod &m = m_mods->operator[](row);
- ui->frame->updateWithMod(m);
}
diff --git a/launcher/ui/pages/instance/ModFolderPage.h b/launcher/ui/pages/instance/ModFolderPage.h
index 2dd44e85..19caa732 100644
--- a/launcher/ui/pages/instance/ModFolderPage.h
+++ b/launcher/ui/pages/instance/ModFolderPage.h
@@ -2,6 +2,7 @@
/*
* PolyMC - Minecraft Launcher
* Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -35,109 +36,31 @@
#pragma once
-#include <QMainWindow>
+#include "ExternalResourcesPage.h"
-#include "minecraft/MinecraftInstance.h"
-#include "ui/pages/BasePage.h"
-
-#include <Application.h>
-#include <QSortFilterProxyModel>
-
-class ModFolderModel;
-namespace Ui
-{
-class ModFolderPage;
-}
-
-class ModFolderPage : public QMainWindow, public BasePage
-{
+class ModFolderPage : public ExternalResourcesPage {
Q_OBJECT
-public:
- explicit ModFolderPage(
- BaseInstance *inst,
- std::shared_ptr<ModFolderModel> mods,
- QString id,
- QString iconName,
- QString displayName,
- QString helpPage = "",
- QWidget *parent = 0
- );
- virtual ~ModFolderPage();
-
- void setFilter(const QString & filter)
- {
- m_fileSelectionFilter = filter;
- }
+ public:
+ explicit ModFolderPage(BaseInstance* inst, std::shared_ptr<ModFolderModel> mods, QWidget* parent = nullptr);
+ virtual ~ModFolderPage() = default;
- virtual QString displayName() const override
- {
- return m_displayName;
- }
- virtual QIcon icon() const override
- {
- return APPLICATION->getThemedIcon(m_iconName);
- }
- virtual QString id() const override
- {
- return m_id;
- }
- virtual QString helpPage() const override
- {
- return m_helpName;
- }
- virtual bool shouldDisplay() const override;
- void retranslate() override;
-
- virtual void openedImpl() override;
- virtual void closedImpl() override;
-protected:
- bool eventFilter(QObject *obj, QEvent *ev) override;
- bool modListFilter(QKeyEvent *ev);
- QMenu * createPopupMenu() override;
+ void setFilter(const QString& filter) { m_fileSelectionFilter = filter; }
-protected:
- BaseInstance *m_inst = nullptr;
+ virtual QString displayName() const override { return tr("Mods"); }
+ virtual QIcon icon() const override { return APPLICATION->getThemedIcon("loadermods"); }
+ virtual QString id() const override { return "mods"; }
+ virtual QString helpPage() const override { return "Loader-mods"; }
-protected:
- Ui::ModFolderPage *ui = nullptr;
- std::shared_ptr<ModFolderModel> m_mods;
- QSortFilterProxyModel *m_filterModel = nullptr;
- QString m_iconName;
- QString m_id;
- QString m_displayName;
- QString m_helpName;
- QString m_fileSelectionFilter;
- QString m_viewFilter;
- bool m_controlsEnabled = true;
-
-public
-slots:
- void modCurrent(const QModelIndex &current, const QModelIndex &previous);
+ virtual bool shouldDisplay() const override;
-private
-slots:
- void modItemActivated(const QModelIndex &index);
- void on_filterTextChanged(const QString & newContents);
- void on_RunningState_changed(bool running);
- void on_actionAdd_triggered();
- void on_actionRemove_triggered();
- void on_actionEnable_triggered();
- void on_actionDisable_triggered();
- void on_actionInstall_mods_triggered();
- void on_actionView_Folder_triggered();
- void on_actionView_configs_triggered();
- void ShowContextMenu(const QPoint &pos);
+ private slots:
+ void installMods();
};
-class CoreModFolderPage : public ModFolderPage
-{
-public:
- explicit CoreModFolderPage(BaseInstance *inst, std::shared_ptr<ModFolderModel> mods, QString id,
- QString iconName, QString displayName, QString helpPage = "",
- QWidget *parent = 0);
- virtual ~CoreModFolderPage()
- {
- }
+class CoreModFolderPage : public ModFolderPage {
+ public:
+ explicit CoreModFolderPage(BaseInstance* inst, std::shared_ptr<ModFolderModel> mods, QWidget* parent = 0);
+ virtual ~CoreModFolderPage() = default;
virtual bool shouldDisplay() const;
};
diff --git a/launcher/ui/pages/instance/ResourcePackPage.h b/launcher/ui/pages/instance/ResourcePackPage.h
index 8054926c..a6c9fdd3 100644
--- a/launcher/ui/pages/instance/ResourcePackPage.h
+++ b/launcher/ui/pages/instance/ResourcePackPage.h
@@ -35,24 +35,28 @@
#pragma once
-#include "ModFolderPage.h"
-#include "ui_ModFolderPage.h"
+#include "ExternalResourcesPage.h"
+#include "ui_ExternalResourcesPage.h"
-class ResourcePackPage : public ModFolderPage
+class ResourcePackPage : public ExternalResourcesPage
{
Q_OBJECT
public:
explicit ResourcePackPage(MinecraftInstance *instance, QWidget *parent = 0)
- : ModFolderPage(instance, instance->resourcePackList(), "resourcepacks",
- "resourcepacks", tr("Resource packs"), "Resource-packs", parent)
+ : ExternalResourcesPage(instance, instance->resourcePackList(), parent)
{
- ui->actionView_configs->setVisible(false);
+ ui->actionViewConfigs->setVisible(false);
}
virtual ~ResourcePackPage() {}
+ QString displayName() const override { return tr("Resource packs"); }
+ QIcon icon() const override { return APPLICATION->getThemedIcon("resourcepacks"); }
+ QString id() const override { return "resourcepacks"; }
+ QString helpPage() const override { return "Resource-packs"; }
+
virtual bool shouldDisplay() const override
{
- return !m_inst->traits().contains("no-texturepacks") &&
- !m_inst->traits().contains("texturepacks");
+ return !m_instance->traits().contains("no-texturepacks") &&
+ !m_instance->traits().contains("texturepacks");
}
};
diff --git a/launcher/ui/pages/instance/ScreenshotsPage.cpp b/launcher/ui/pages/instance/ScreenshotsPage.cpp
index 51163e28..c97253e4 100644
--- a/launcher/ui/pages/instance/ScreenshotsPage.cpp
+++ b/launcher/ui/pages/instance/ScreenshotsPage.cpp
@@ -50,6 +50,7 @@
#include <QClipboard>
#include <QKeyEvent>
#include <QMenu>
+#include <QRegularExpression>
#include <Application.h>
@@ -154,7 +155,7 @@ public:
if (role == Qt::DisplayRole || role == Qt::EditRole)
{
QVariant result = sourceModel()->data(mapToSource(proxyIndex), role);
- return result.toString().remove(QRegExp("\\.png$"));
+ return result.toString().remove(QRegularExpression("\\.png$"));
}
if (role == Qt::DecorationRole)
{
@@ -270,7 +271,7 @@ ScreenshotsPage::ScreenshotsPage(QString path, QWidget *parent)
ui->listView->setViewMode(QListView::IconMode);
ui->listView->setResizeMode(QListView::Adjust);
ui->listView->installEventFilter(this);
- ui->listView->setEditTriggers(0);
+ ui->listView->setEditTriggers(QAbstractItemView::NoEditTriggers);
ui->listView->setItemDelegate(new CenteredEditingDelegate(this));
ui->listView->setContextMenuPolicy(Qt::CustomContextMenu);
connect(ui->listView, &QListView::customContextMenuRequested, this, &ScreenshotsPage::ShowContextMenu);
diff --git a/launcher/ui/pages/instance/ScreenshotsPage.h b/launcher/ui/pages/instance/ScreenshotsPage.h
index c34c9755..c22706af 100644
--- a/launcher/ui/pages/instance/ScreenshotsPage.h
+++ b/launcher/ui/pages/instance/ScreenshotsPage.h
@@ -35,7 +35,6 @@
#pragma once
-#include <QItemSelection>
#include <QMainWindow>
#include "ui/pages/BasePage.h"
diff --git a/launcher/ui/pages/instance/ServersPage.cpp b/launcher/ui/pages/instance/ServersPage.cpp
index c3bde612..e5cce96c 100644
--- a/launcher/ui/pages/instance/ServersPage.cpp
+++ b/launcher/ui/pages/instance/ServersPage.cpp
@@ -48,7 +48,6 @@
#include <QFileSystemWatcher>
#include <QMenu>
-#include <QTimer>
static const int COLUMN_COUNT = 2; // 3 , TBD: latency and other nice things.
@@ -289,7 +288,11 @@ public:
return false;
}
beginMoveRows(QModelIndex(), row, row, QModelIndex(), row - 1);
+#if QT_VERSION >= QT_VERSION_CHECK(5, 13, 0)
+ m_servers.swapItemsAt(row-1, row);
+#else
m_servers.swap(row-1, row);
+#endif
endMoveRows();
scheduleSave();
return true;
@@ -307,7 +310,11 @@ public:
return false;
}
beginMoveRows(QModelIndex(), row, row, QModelIndex(), row + 2);
+#if QT_VERSION >= QT_VERSION_CHECK(5, 13, 0)
+ m_servers.swapItemsAt(row+1, row);
+#else
m_servers.swap(row+1, row);
+#endif
endMoveRows();
scheduleSave();
return true;
@@ -616,7 +623,7 @@ ServersPage::ServersPage(InstancePtr inst, QWidget* parent)
auto selectionModel = ui->serversView->selectionModel();
connect(selectionModel, &QItemSelectionModel::currentChanged, this, &ServersPage::currentChanged);
- connect(m_inst.get(), &MinecraftInstance::runningStatusChanged, this, &ServersPage::on_RunningState_changed);
+ connect(m_inst.get(), &MinecraftInstance::runningStatusChanged, this, &ServersPage::runningStateChanged);
connect(ui->nameLine, &QLineEdit::textEdited, this, &ServersPage::nameEdited);
connect(ui->addressLine, &QLineEdit::textEdited, this, &ServersPage::addressEdited);
connect(ui->resourceComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(resourceIndexChanged(int)));
@@ -656,7 +663,7 @@ QMenu * ServersPage::createPopupMenu()
return filteredMenu;
}
-void ServersPage::on_RunningState_changed(bool running)
+void ServersPage::runningStateChanged(bool running)
{
if(m_locked == running)
{
diff --git a/launcher/ui/pages/instance/ServersPage.h b/launcher/ui/pages/instance/ServersPage.h
index 5173712c..37399d49 100644
--- a/launcher/ui/pages/instance/ServersPage.h
+++ b/launcher/ui/pages/instance/ServersPage.h
@@ -2,6 +2,7 @@
/*
* PolyMC - Minecraft Launcher
* Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -97,7 +98,7 @@ private slots:
void on_actionMove_Down_triggered();
void on_actionJoin_triggered();
- void on_RunningState_changed(bool running);
+ void runningStateChanged(bool running);
void nameEdited(const QString & name);
void addressEdited(const QString & address);
diff --git a/launcher/ui/pages/instance/ShaderPackPage.h b/launcher/ui/pages/instance/ShaderPackPage.h
index 7d4f5074..2cc056c8 100644
--- a/launcher/ui/pages/instance/ShaderPackPage.h
+++ b/launcher/ui/pages/instance/ShaderPackPage.h
@@ -35,21 +35,25 @@
#pragma once
-#include "ModFolderPage.h"
-#include "ui_ModFolderPage.h"
+#include "ExternalResourcesPage.h"
+#include "ui_ExternalResourcesPage.h"
-class ShaderPackPage : public ModFolderPage
+class ShaderPackPage : public ExternalResourcesPage
{
Q_OBJECT
public:
explicit ShaderPackPage(MinecraftInstance *instance, QWidget *parent = 0)
- : ModFolderPage(instance, instance->shaderPackList(), "shaderpacks",
- "shaderpacks", tr("Shader packs"), "Resource-packs", parent)
+ : ExternalResourcesPage(instance, instance->shaderPackList(), parent)
{
- ui->actionView_configs->setVisible(false);
+ ui->actionViewConfigs->setVisible(false);
}
virtual ~ShaderPackPage() {}
+ QString displayName() const override { return tr("Shader packs"); }
+ QIcon icon() const override { return APPLICATION->getThemedIcon("shaderpacks"); }
+ QString id() const override { return "shaderpacks"; }
+ QString helpPage() const override { return "Resource-packs"; }
+
virtual bool shouldDisplay() const override
{
return true;
diff --git a/launcher/ui/pages/instance/TexturePackPage.h b/launcher/ui/pages/instance/TexturePackPage.h
index e8cefe6e..f550a5bc 100644
--- a/launcher/ui/pages/instance/TexturePackPage.h
+++ b/launcher/ui/pages/instance/TexturePackPage.h
@@ -35,23 +35,27 @@
#pragma once
-#include "ModFolderPage.h"
-#include "ui_ModFolderPage.h"
+#include "ExternalResourcesPage.h"
+#include "ui_ExternalResourcesPage.h"
-class TexturePackPage : public ModFolderPage
+class TexturePackPage : public ExternalResourcesPage
{
Q_OBJECT
public:
explicit TexturePackPage(MinecraftInstance *instance, QWidget *parent = 0)
- : ModFolderPage(instance, instance->texturePackList(), "texturepacks", "resourcepacks",
- tr("Texture packs"), "Texture-packs", parent)
+ : ExternalResourcesPage(instance, instance->texturePackList(), parent)
{
- ui->actionView_configs->setVisible(false);
+ ui->actionViewConfigs->setVisible(false);
}
virtual ~TexturePackPage() {}
+ QString displayName() const override { return tr("Texture packs"); }
+ QIcon icon() const override { return APPLICATION->getThemedIcon("resourcepacks"); }
+ QString id() const override { return "texturepacks"; }
+ QString helpPage() const override { return "Texture-packs"; }
+
virtual bool shouldDisplay() const override
{
- return m_inst->traits().contains("texturepacks");
+ return m_instance->traits().contains("texturepacks");
}
};
diff --git a/launcher/ui/pages/instance/VersionPage.cpp b/launcher/ui/pages/instance/VersionPage.cpp
index 23e2367b..468ff35c 100644
--- a/launcher/ui/pages/instance/VersionPage.cpp
+++ b/launcher/ui/pages/instance/VersionPage.cpp
@@ -2,7 +2,7 @@
/*
* PolyMC - Minecraft Launcher
* Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
- * Copyright (c) 2022 Sefa Eyeoglu <contact@scrumplex.net>
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/launcher/ui/pages/instance/WorldListPage.cpp b/launcher/ui/pages/instance/WorldListPage.cpp
index ff30dd82..647b04a7 100644
--- a/launcher/ui/pages/instance/WorldListPage.cpp
+++ b/launcher/ui/pages/instance/WorldListPage.cpp
@@ -47,7 +47,6 @@
#include <QInputDialog>
#include <QProcess>
#include <Qt>
-#include <QSortFilterProxyModel>
#include "tools/MCEditTool.h"
#include "FileSystem.h"
diff --git a/launcher/ui/pages/modplatform/ImportPage.cpp b/launcher/ui/pages/modplatform/ImportPage.cpp
index 0b8577b1..30196aad 100644
--- a/launcher/ui/pages/modplatform/ImportPage.cpp
+++ b/launcher/ui/pages/modplatform/ImportPage.cpp
@@ -2,7 +2,7 @@
/*
* PolyMC - Minecraft Launcher
* Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
- * Copyright (c) 2022 Sefa Eyeoglu <contact@scrumplex.net>
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/launcher/ui/pages/modplatform/ModModel.cpp b/launcher/ui/pages/modplatform/ModModel.cpp
index 98eec31c..94b1f099 100644
--- a/launcher/ui/pages/modplatform/ModModel.cpp
+++ b/launcher/ui/pages/modplatform/ModModel.cpp
@@ -53,7 +53,11 @@ auto ListModel::data(const QModelIndex& index, int role) const -> QVariant
}
case Qt::DecorationRole: {
if (m_logoMap.contains(pack.logoName)) {
- return (m_logoMap.value(pack.logoName));
+ auto icon = m_logoMap.value(pack.logoName);
+ // FIXME: This doesn't really belong here, but Qt doesn't offer a good way right now ;(
+ auto icon_scaled = QIcon(icon.pixmap(48, 48).scaledToWidth(48));
+
+ return icon_scaled;
}
QIcon icon = APPLICATION->getThemedIcon("screenshot-placeholder");
// un-const-ify this
@@ -215,6 +219,10 @@ void ListModel::searchRequestFinished(QJsonDocument& doc)
searchState = CanPossiblyFetchMore;
}
+ // When you have a Qt build with assertions turned on, proceeding here will abort the application
+ if (newList.size() == 0)
+ return;
+
beginInsertRows(QModelIndex(), modpacks.size(), modpacks.size() + newList.size() - 1);
modpacks.append(newList);
endInsertRows();
diff --git a/launcher/ui/pages/modplatform/flame/FlameModPage.cpp b/launcher/ui/pages/modplatform/flame/FlameModPage.cpp
index 1c160fd4..10d34218 100644
--- a/launcher/ui/pages/modplatform/flame/FlameModPage.cpp
+++ b/launcher/ui/pages/modplatform/flame/FlameModPage.cpp
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-3.0-only
/*
* PolyMC - Minecraft Launcher
- * Copyright (c) 2022 Sefa Eyeoglu <contact@scrumplex.net>
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/launcher/ui/pages/modplatform/flame/FlameModPage.h b/launcher/ui/pages/modplatform/flame/FlameModPage.h
index 86e1a17b..445d0368 100644
--- a/launcher/ui/pages/modplatform/flame/FlameModPage.h
+++ b/launcher/ui/pages/modplatform/flame/FlameModPage.h
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-3.0-only
/*
* PolyMC - Minecraft Launcher
- * Copyright (c) 2022 Sefa Eyeoglu <contact@scrumplex.net>
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/launcher/ui/pages/modplatform/flame/FlameModel.cpp b/launcher/ui/pages/modplatform/flame/FlameModel.cpp
index f97536e8..b9804681 100644
--- a/launcher/ui/pages/modplatform/flame/FlameModel.cpp
+++ b/launcher/ui/pages/modplatform/flame/FlameModel.cpp
@@ -57,6 +57,17 @@ QVariant ListModel::data(const QModelIndex& index, int role) const
return QVariant();
}
+bool ListModel::setData(const QModelIndex &index, const QVariant &value, int role)
+{
+ int pos = index.row();
+ if (pos >= modpacks.size() || pos < 0 || !index.isValid())
+ return false;
+
+ modpacks[pos] = value.value<Flame::IndexedPack>();
+
+ return true;
+}
+
void ListModel::logoLoaded(QString logo, QIcon out)
{
m_loadingLogos.removeAll(logo);
@@ -210,6 +221,11 @@ void Flame::ListModel::searchRequestFinished()
nextSearchOffset += 25;
searchState = CanPossiblyFetchMore;
}
+
+ // When you have a Qt build with assertions turned on, proceeding here will abort the application
+ if (newList.size() == 0)
+ return;
+
beginInsertRows(QModelIndex(), modpacks.size(), modpacks.size() + newList.size() - 1);
modpacks.append(newList);
endInsertRows();
diff --git a/launcher/ui/pages/modplatform/flame/FlameModel.h b/launcher/ui/pages/modplatform/flame/FlameModel.h
index 536f6add..cab666cc 100644
--- a/launcher/ui/pages/modplatform/flame/FlameModel.h
+++ b/launcher/ui/pages/modplatform/flame/FlameModel.h
@@ -34,6 +34,7 @@ public:
int rowCount(const QModelIndex &parent) const override;
int columnCount(const QModelIndex &parent) const override;
QVariant data(const QModelIndex &index, int role) const override;
+ bool setData(const QModelIndex &index, const QVariant &value, int role) override;
Qt::ItemFlags flags(const QModelIndex &index) const override;
bool canFetchMore(const QModelIndex & parent) const override;
void fetchMore(const QModelIndex & parent) override;
diff --git a/launcher/ui/pages/modplatform/flame/FlamePage.cpp b/launcher/ui/pages/modplatform/flame/FlamePage.cpp
index b65ace6b..7d2ba2e2 100644
--- a/launcher/ui/pages/modplatform/flame/FlamePage.cpp
+++ b/launcher/ui/pages/modplatform/flame/FlamePage.cpp
@@ -107,18 +107,18 @@ void FlamePage::triggerSearch()
listModel->searchWithTerm(ui->searchEdit->text(), ui->sortByBox->currentIndex());
}
-void FlamePage::onSelectionChanged(QModelIndex first, QModelIndex second)
+void FlamePage::onSelectionChanged(QModelIndex curr, QModelIndex prev)
{
ui->versionSelectionBox->clear();
- if (!first.isValid()) {
+ if (!curr.isValid()) {
if (isOpened) {
dialog->setSuggestedPack();
}
return;
}
- current = listModel->data(first, Qt::UserRole).value<Flame::IndexedPack>();
+ current = listModel->data(curr, Qt::UserRole).value<Flame::IndexedPack>();
if (current.versionsLoaded == false) {
qDebug() << "Loading flame modpack versions";
@@ -127,7 +127,7 @@ void FlamePage::onSelectionChanged(QModelIndex first, QModelIndex second)
int addonId = current.addonId;
netJob->addNetAction(Net::Download::makeByteArray(QString("https://api.curseforge.com/v1/mods/%1/files").arg(addonId), response));
- QObject::connect(netJob, &NetJob::succeeded, this, [this, response, addonId] {
+ QObject::connect(netJob, &NetJob::succeeded, this, [this, response, addonId, curr] {
if (addonId != current.addonId) {
return; // wrong request
}
@@ -151,6 +151,16 @@ void FlamePage::onSelectionChanged(QModelIndex first, QModelIndex second)
ui->versionSelectionBox->addItem(version.version, QVariant(version.downloadUrl));
}
+ QVariant current_updated;
+ current_updated.setValue(current);
+
+ if (!listModel->setData(curr, current_updated, Qt::UserRole))
+ qWarning() << "Failed to cache versions for the current pack!";
+
+ // TODO: Check whether it's a connection issue or the project disabled 3rd-party distribution.
+ if (current.versionsLoaded && ui->versionSelectionBox->count() < 1) {
+ ui->versionSelectionBox->addItem(tr("No version is available!"), -1);
+ }
suggestCurrent();
});
QObject::connect(netJob, &NetJob::finished, this, [response, netJob] {
@@ -166,6 +176,11 @@ void FlamePage::onSelectionChanged(QModelIndex first, QModelIndex second)
suggestCurrent();
}
+ // TODO: Check whether it's a connection issue or the project disabled 3rd-party distribution.
+ if (current.versionsLoaded && ui->versionSelectionBox->count() < 1) {
+ ui->versionSelectionBox->addItem(tr("No version is available!"), -1);
+ }
+
updateUi();
}
@@ -175,7 +190,7 @@ void FlamePage::suggestCurrent()
return;
}
- if (selectedVersion.isEmpty()) {
+ if (selectedVersion.isEmpty() || selectedVersion == "-1") {
dialog->setSuggestedPack();
return;
}
diff --git a/launcher/ui/pages/modplatform/flame/FlamePage.ui b/launcher/ui/pages/modplatform/flame/FlamePage.ui
index 9fab9773..aab16421 100644
--- a/launcher/ui/pages/modplatform/flame/FlamePage.ui
+++ b/launcher/ui/pages/modplatform/flame/FlamePage.ui
@@ -19,7 +19,7 @@
</font>
</property>
<property name="text">
- <string>Note: CurseForge's API is very unreliable. CurseForge and some mod authors have disallowed downloading mods in third-party applications like PolyMC. As such, you may need to manually download some mods to be able to install a modpack.</string>
+ <string>Note: CurseForge allows creators to block access to third-party tools like PolyMC. As such, you may need to manually download some mods to be able to install a modpack.</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
diff --git a/launcher/ui/pages/modplatform/legacy_ftb/ListModel.cpp b/launcher/ui/pages/modplatform/legacy_ftb/ListModel.cpp
index 06e9db4f..2d135e59 100644
--- a/launcher/ui/pages/modplatform/legacy_ftb/ListModel.cpp
+++ b/launcher/ui/pages/modplatform/legacy_ftb/ListModel.cpp
@@ -46,8 +46,6 @@
#include <BuildConfig.h>
-#include <net/NetJob.h>
-
namespace LegacyFTB {
FilterModel::FilterModel(QObject *parent) : QSortFilterProxyModel(parent)
@@ -170,7 +168,7 @@ QVariant ListModel::data(const QModelIndex &index, int role) const
((ListModel *)this)->requestLogo(pack.logo);
return icon;
}
- else if(role == Qt::TextColorRole)
+ else if(role == Qt::ForegroundRole)
{
if(pack.broken)
{
diff --git a/launcher/ui/pages/modplatform/legacy_ftb/Page.cpp b/launcher/ui/pages/modplatform/legacy_ftb/Page.cpp
index 7667d169..6ffbd312 100644
--- a/launcher/ui/pages/modplatform/legacy_ftb/Page.cpp
+++ b/launcher/ui/pages/modplatform/legacy_ftb/Page.cpp
@@ -2,6 +2,7 @@
/*
* PolyMC - Minecraft Launcher
* Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -151,7 +152,7 @@ void Page::openedImpl()
ftbFetchTask->fetch();
ftbPrivatePacks->load();
- ftbFetchTask->fetchPrivate(ftbPrivatePacks->getCurrentPackCodes().toList());
+ ftbFetchTask->fetchPrivate(ftbPrivatePacks->getCurrentPackCodes().values());
initialized = true;
}
suggestCurrent();
diff --git a/launcher/ui/pages/modplatform/legacy_ftb/Page.ui b/launcher/ui/pages/modplatform/legacy_ftb/Page.ui
index 15e5d432..f4231d8d 100644
--- a/launcher/ui/pages/modplatform/legacy_ftb/Page.ui
+++ b/launcher/ui/pages/modplatform/legacy_ftb/Page.ui
@@ -25,7 +25,7 @@
<widget class="QTreeView" name="publicPackList">
<property name="maximumSize">
<size>
- <width>250</width>
+ <width>16777215</width>
<height>16777215</height>
</size>
</property>
@@ -51,7 +51,7 @@
<widget class="QTreeView" name="thirdPartyPackList">
<property name="maximumSize">
<size>
- <width>250</width>
+ <width>16777215</width>
<height>16777215</height>
</size>
</property>
@@ -71,7 +71,7 @@
<widget class="QTreeView" name="privatePackList">
<property name="maximumSize">
<size>
- <width>250</width>
+ <width>16777215</width>
<height>16777215</height>
</size>
</property>
diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthModPage.cpp b/launcher/ui/pages/modplatform/modrinth/ModrinthModPage.cpp
index 0b81ea93..5fa00b9b 100644
--- a/launcher/ui/pages/modplatform/modrinth/ModrinthModPage.cpp
+++ b/launcher/ui/pages/modplatform/modrinth/ModrinthModPage.cpp
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-3.0-only
/*
* PolyMC - Minecraft Launcher
- * Copyright (c) 2022 Sefa Eyeoglu <contact@scrumplex.net>
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthModPage.h b/launcher/ui/pages/modplatform/modrinth/ModrinthModPage.h
index c39acaa0..94985f63 100644
--- a/launcher/ui/pages/modplatform/modrinth/ModrinthModPage.h
+++ b/launcher/ui/pages/modplatform/modrinth/ModrinthModPage.h
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-3.0-only
/*
* PolyMC - Minecraft Launcher
- * Copyright (c) 2022 Sefa Eyeoglu <contact@scrumplex.net>
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp
index 07d1687c..3633d575 100644
--- a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp
+++ b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp
@@ -87,6 +87,7 @@ auto ModpackListModel::data(const QModelIndex& index, int role) const -> QVarian
} else if (role == Qt::DecorationRole) {
if (m_logoMap.contains(pack.iconName)) {
auto icon = m_logoMap.value(pack.iconName);
+ // FIXME: This doesn't really belong here, but Qt doesn't offer a good way right now ;(
auto icon_scaled = QIcon(icon.pixmap(48, 48).scaledToWidth(48));
return icon_scaled;
@@ -103,6 +104,17 @@ auto ModpackListModel::data(const QModelIndex& index, int role) const -> QVarian
return {};
}
+bool ModpackListModel::setData(const QModelIndex &index, const QVariant &value, int role)
+{
+ int pos = index.row();
+ if (pos >= modpacks.size() || pos < 0 || !index.isValid())
+ return false;
+
+ modpacks[pos] = value.value<Modrinth::Modpack>();
+
+ return true;
+}
+
void ModpackListModel::performPaginatedSearch()
{
// TODO: Move to standalone API
@@ -160,15 +172,15 @@ static auto sortFromIndex(int index) -> QString
{
switch(index){
default:
- case 1:
+ case 0:
return "relevance";
- case 2:
+ case 1:
return "downloads";
- case 3:
+ case 2:
return "follows";
- case 4:
+ case 3:
return "newest";
- case 5:
+ case 4:
return "updated";
}
@@ -278,6 +290,10 @@ void ModpackListModel::searchRequestFinished(QJsonDocument& doc_all)
searchState = CanPossiblyFetchMore;
}
+ // When you have a Qt build with assertions turned on, proceeding here will abort the application
+ if (newList.size() == 0)
+ return;
+
beginInsertRows(QModelIndex(), modpacks.size(), modpacks.size() + newList.size() - 1);
modpacks.append(newList);
endInsertRows();
diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.h b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.h
index 1b4d8da4..6f33e11e 100644
--- a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.h
+++ b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.h
@@ -39,7 +39,6 @@
#include "modplatform/modrinth/ModrinthPackManifest.h"
#include "ui/pages/modplatform/modrinth/ModrinthPage.h"
-#include "net/NetJob.h"
class ModPage;
class Version;
@@ -64,6 +63,7 @@ class ModpackListModel : public QAbstractListModel {
/* Retrieve information from the model at a given index with the given role */
auto data(const QModelIndex& index, int role) const -> QVariant override;
+ bool setData(const QModelIndex &index, const QVariant &value, int role) override;
inline void setActiveJob(NetJob::Ptr ptr) { jobPtr = ptr; }
diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp
index d8500674..df29c0c3 100644
--- a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp
+++ b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp
@@ -101,18 +101,18 @@ bool ModrinthPage::eventFilter(QObject* watched, QEvent* event)
return QObject::eventFilter(watched, event);
}
-void ModrinthPage::onSelectionChanged(QModelIndex first, QModelIndex second)
+void ModrinthPage::onSelectionChanged(QModelIndex curr, QModelIndex prev)
{
ui->versionSelectionBox->clear();
- if (!first.isValid()) {
+ if (!curr.isValid()) {
if (isOpened) {
dialog->setSuggestedPack();
}
return;
}
- current = m_model->data(first, Qt::UserRole).value<Modrinth::Modpack>();
+ current = m_model->data(curr, Qt::UserRole).value<Modrinth::Modpack>();
auto name = current.name;
if (!current.extraInfoLoaded) {
@@ -125,7 +125,7 @@ void ModrinthPage::onSelectionChanged(QModelIndex first, QModelIndex second)
netJob->addNetAction(Net::Download::makeByteArray(QString("%1/project/%2").arg(BuildConfig.MODRINTH_PROD_URL, id), response));
- QObject::connect(netJob, &NetJob::succeeded, this, [this, response, id] {
+ QObject::connect(netJob, &NetJob::succeeded, this, [this, response, id, curr] {
if (id != current.id) {
return; // wrong request?
}
@@ -149,6 +149,13 @@ void ModrinthPage::onSelectionChanged(QModelIndex first, QModelIndex second)
}
updateUI();
+
+ QVariant current_updated;
+ current_updated.setValue(current);
+
+ if (!m_model->setData(curr, current_updated, Qt::UserRole))
+ qWarning() << "Failed to cache extra info for the current pack!";
+
suggestCurrent();
});
QObject::connect(netJob, &NetJob::finished, this, [response, netJob] {
@@ -170,7 +177,7 @@ void ModrinthPage::onSelectionChanged(QModelIndex first, QModelIndex second)
netJob->addNetAction(
Net::Download::makeByteArray(QString("%1/project/%2/version").arg(BuildConfig.MODRINTH_PROD_URL, id), response));
- QObject::connect(netJob, &NetJob::succeeded, this, [this, response, id] {
+ QObject::connect(netJob, &NetJob::succeeded, this, [this, response, id, curr] {
if (id != current.id) {
return; // wrong request?
}
@@ -192,9 +199,18 @@ void ModrinthPage::onSelectionChanged(QModelIndex first, QModelIndex second)
}
for (auto version : current.versions) {
- ui->versionSelectionBox->addItem(version.version, QVariant(version.id));
+ if (!version.name.contains(version.version))
+ ui->versionSelectionBox->addItem(QString("%1 — %2").arg(version.name, version.version), QVariant(version.id));
+ else
+ ui->versionSelectionBox->addItem(version.name, QVariant(version.id));
}
+ QVariant current_updated;
+ current_updated.setValue(current);
+
+ if (!m_model->setData(curr, current_updated, Qt::UserRole))
+ qWarning() << "Failed to cache versions for the current pack!";
+
suggestCurrent();
});
QObject::connect(netJob, &NetJob::finished, this, [response, netJob] {
@@ -205,7 +221,10 @@ void ModrinthPage::onSelectionChanged(QModelIndex first, QModelIndex second)
} else {
for (auto version : current.versions) {
- ui->versionSelectionBox->addItem(QString("%1 - %2").arg(version.name, version.version), QVariant(version.id));
+ if (!version.name.contains(version.version))
+ ui->versionSelectionBox->addItem(QString("%1 - %2").arg(version.name, version.version), QVariant(version.id));
+ else
+ ui->versionSelectionBox->addItem(version.name, QVariant(version.id));
}
suggestCurrent();
@@ -224,7 +243,7 @@ void ModrinthPage::updateUI()
// TODO: Implement multiple authors with links
text += "<br>" + tr(" by ") + QString("<a href=%1>%2</a>").arg(std::get<1>(current.author).toString(), std::get<0>(current.author));
- if(current.extraInfoLoaded) {
+ if (current.extraInfoLoaded) {
if (!current.extra.donate.isEmpty()) {
text += "<br><br>" + tr("Donate information: ");
auto donateToStr = [](Modrinth::DonationData& donate) -> QString {
diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.ui b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.ui
index ae9556ed..6a34701d 100644
--- a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.ui
+++ b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.ui
@@ -63,9 +63,6 @@
<height>48</height>
</size>
</property>
- <property name="uniformItemSizes">
- <bool>true</bool>
- </property>
</widget>
</item>
<item>
diff --git a/launcher/ui/pages/modplatform/technic/TechnicModel.cpp b/launcher/ui/pages/modplatform/technic/TechnicModel.cpp
index 9c9d1e75..742f4f2a 100644
--- a/launcher/ui/pages/modplatform/technic/TechnicModel.cpp
+++ b/launcher/ui/pages/modplatform/technic/TechnicModel.cpp
@@ -217,6 +217,11 @@ void Technic::ListModel::searchRequestFinished()
return;
}
searchState = Finished;
+
+ // When you have a Qt build with assertions turned on, proceeding here will abort the application
+ if (newList.size() == 0)
+ return;
+
beginInsertRows(QModelIndex(), modpacks.size(), modpacks.size() + newList.size() - 1);
modpacks.append(newList);
endInsertRows();
diff --git a/launcher/ui/widgets/CustomCommands.cpp b/launcher/ui/widgets/CustomCommands.cpp
index 5a718b54..5ab90395 100644
--- a/launcher/ui/widgets/CustomCommands.cpp
+++ b/launcher/ui/widgets/CustomCommands.cpp
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-3.0-only
/*
* PolyMC - Minecraft Launcher
- * Copyright (c) 2022 Sefa Eyeoglu <contact@scrumplex.net>
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/launcher/ui/widgets/CustomCommands.h b/launcher/ui/widgets/CustomCommands.h
index 4a7a17ef..ed10ba95 100644
--- a/launcher/ui/widgets/CustomCommands.h
+++ b/launcher/ui/widgets/CustomCommands.h
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-3.0-only
/*
* PolyMC - Minecraft Launcher
- * Copyright (c) 2022 Sefa Eyeoglu <contact@scrumplex.net>
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/launcher/ui/widgets/JavaSettingsWidget.cpp b/launcher/ui/widgets/JavaSettingsWidget.cpp
index 340518b1..f0765909 100644
--- a/launcher/ui/widgets/JavaSettingsWidget.cpp
+++ b/launcher/ui/widgets/JavaSettingsWidget.cpp
@@ -11,6 +11,7 @@
#include <sys.h>
+#include "JavaCommon.h"
#include "java/JavaInstall.h"
#include "java/JavaUtils.h"
#include "FileSystem.h"
@@ -133,6 +134,10 @@ void JavaSettingsWidget::initialize()
void JavaSettingsWidget::refresh()
{
+ if (JavaUtils::getJavaCheckPath().isEmpty()) {
+ JavaCommon::javaCheckNotFound(this);
+ return;
+ }
m_versionWidget->loadList();
}
diff --git a/launcher/ui/widgets/LabeledToolButton.cpp b/launcher/ui/widgets/LabeledToolButton.cpp
index ab2d3278..f52e49c9 100644
--- a/launcher/ui/widgets/LabeledToolButton.cpp
+++ b/launcher/ui/widgets/LabeledToolButton.cpp
@@ -1,16 +1,36 @@
-/* Copyright 2013-2021 MultiMC Contributors
+// SPDX-License-Identifier: GPL-3.0-only
+/*
+ * PolyMC - Minecraft Launcher
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * This file incorporates work covered by the following copyright and
+ * permission notice:
+ *
+ * Copyright 2013-2021 MultiMC Contributors
*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
+ * 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
+ * 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.
+ * 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 <QLabel>
@@ -80,9 +100,7 @@ QSize LabeledToolButton::sizeHint() const
if (popupMode() == MenuButtonPopup)
w += style()->pixelMetric(QStyle::PM_MenuButtonIndicator, &opt, this);
- QSize rawSize = style()->sizeFromContents(QStyle::CT_ToolButton, &opt, QSize(w, h), this);
- QSize sizeHint = rawSize.expandedTo(QApplication::globalStrut());
- return sizeHint;
+ return style()->sizeFromContents(QStyle::CT_ToolButton, &opt, QSize(w, h), this);
}
diff --git a/launcher/ui/widgets/LogView.cpp b/launcher/ui/widgets/LogView.cpp
index 26a2a527..9c46438d 100644
--- a/launcher/ui/widgets/LogView.cpp
+++ b/launcher/ui/widgets/LogView.cpp
@@ -1,3 +1,38 @@
+// SPDX-License-Identifier: GPL-3.0-only
+/*
+ * PolyMC - Minecraft Launcher
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * This file incorporates work covered by the following copyright and
+ * permission notice:
+ *
+ * Copyright 2013-2021 MultiMC Contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
#include "LogView.h"
#include <QTextBlock>
#include <QScrollBar>
@@ -102,7 +137,7 @@ void LogView::rowsInserted(const QModelIndex& parent, int first, int last)
{
format.setFont(font.value<QFont>());
}
- auto fg = m_model->data(idx, Qt::TextColorRole);
+ auto fg = m_model->data(idx, Qt::ForegroundRole);
if(fg.isValid())
{
format.setForeground(fg.value<QColor>());
diff --git a/launcher/ui/widgets/PageContainer.cpp b/launcher/ui/widgets/PageContainer.cpp
index 2af7d731..419ccb66 100644
--- a/launcher/ui/widgets/PageContainer.cpp
+++ b/launcher/ui/widgets/PageContainer.cpp
@@ -66,7 +66,7 @@ public:
protected:
bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
{
- const QString pattern = filterRegExp().pattern();
+ const QString pattern = filterRegularExpression().pattern();
const auto model = static_cast<PageModel *>(sourceModel());
const auto page = model->pages().at(sourceRow);
if (!page->shouldDisplay())
@@ -171,7 +171,7 @@ void PageContainer::createUI()
headerHLayout->addSpacerItem(new QSpacerItem(rightMargin, 0, QSizePolicy::Fixed, QSizePolicy::Ignored));
headerHLayout->setContentsMargins(0, 6, 0, 0);
- m_pageStack->setMargin(0);
+ m_pageStack->setContentsMargins(0, 0, 0, 0);
m_pageStack->addWidget(new QWidget(this));
m_layout = new QGridLayout;
diff --git a/launcher/ui/widgets/VersionListView.cpp b/launcher/ui/widgets/VersionListView.cpp
index aba0b1a1..0e126c65 100644
--- a/launcher/ui/widgets/VersionListView.cpp
+++ b/launcher/ui/widgets/VersionListView.cpp
@@ -1,16 +1,36 @@
-/* Copyright 2013-2021 MultiMC Contributors
+// SPDX-License-Identifier: GPL-3.0-only
+/*
+ * PolyMC - Minecraft Launcher
+ * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
*
- * 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
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3.
*
- * http://www.apache.org/licenses/LICENSE-2.0
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
*
- * 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.
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * This file incorporates work covered by the following copyright and
+ * permission notice:
+ *
+ * Copyright 2013-2021 MultiMC Contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*/
#include <QHeaderView>
@@ -136,7 +156,7 @@ void VersionListView::paintInfoLabel(QPaintEvent *event) const
auto innerBounds = bounds;
innerBounds.adjust(10, 10, -10, -10);
- QColor background = QApplication::palette().color(QPalette::Foreground);
+ QColor background = QApplication::palette().color(QPalette::WindowText);
QColor foreground = QApplication::palette().color(QPalette::Base);
foreground.setAlpha(190);
painter.setFont(font);