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.cpp140
-rw-r--r--launcher/ui/MainWindow.h13
-rw-r--r--launcher/ui/dialogs/AboutDialog.cpp13
-rw-r--r--launcher/ui/dialogs/AboutDialog.ui20
-rw-r--r--launcher/ui/dialogs/BlockedModsDialog.cpp28
-rw-r--r--launcher/ui/dialogs/BlockedModsDialog.h22
-rw-r--r--launcher/ui/dialogs/BlockedModsDialog.ui84
-rw-r--r--launcher/ui/dialogs/ChooseProviderDialog.cpp96
-rw-r--r--launcher/ui/dialogs/ChooseProviderDialog.h56
-rw-r--r--launcher/ui/dialogs/ChooseProviderDialog.ui89
-rw-r--r--launcher/ui/dialogs/CopyInstanceDialog.cpp46
-rw-r--r--launcher/ui/dialogs/ExportInstanceDialog.cpp4
-rw-r--r--launcher/ui/dialogs/LoginDialog.cpp2
-rw-r--r--launcher/ui/dialogs/MSALoginDialog.cpp2
-rw-r--r--launcher/ui/dialogs/ModDownloadDialog.cpp33
-rw-r--r--launcher/ui/dialogs/ModDownloadDialog.h21
-rw-r--r--launcher/ui/dialogs/ModUpdateDialog.cpp409
-rw-r--r--launcher/ui/dialogs/ModUpdateDialog.h62
-rw-r--r--launcher/ui/dialogs/NewComponentDialog.cpp41
-rw-r--r--launcher/ui/dialogs/NewInstanceDialog.cpp73
-rw-r--r--launcher/ui/dialogs/NewInstanceDialog.h41
-rw-r--r--launcher/ui/dialogs/NewsDialog.cpp2
-rw-r--r--launcher/ui/dialogs/OfflineLoginDialog.cpp2
-rw-r--r--launcher/ui/dialogs/ProfileSetupDialog.cpp46
-rw-r--r--launcher/ui/dialogs/ProgressDialog.cpp38
-rw-r--r--launcher/ui/dialogs/ReviewMessageBox.cpp2
-rw-r--r--launcher/ui/dialogs/ScrollMessageBox.ui2
-rw-r--r--launcher/ui/dialogs/SkinUploadDialog.cpp125
-rw-r--r--launcher/ui/dialogs/SkinUploadDialog.ui6
-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/APIPage.cpp16
-rw-r--r--launcher/ui/pages/global/APIPage.ui6
-rw-r--r--launcher/ui/pages/global/AccountListPage.cpp2
-rw-r--r--launcher/ui/pages/global/CustomCommandsPage.cpp2
-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/ProxyPage.cpp16
-rw-r--r--launcher/ui/pages/global/ProxyPage.h9
-rw-r--r--launcher/ui/pages/instance/ExternalResourcesPage.cpp10
-rw-r--r--launcher/ui/pages/instance/ExternalResourcesPage.h2
-rw-r--r--launcher/ui/pages/instance/ExternalResourcesPage.ui11
-rw-r--r--launcher/ui/pages/instance/InstanceSettingsPage.cpp4
-rw-r--r--launcher/ui/pages/instance/LogPage.cpp3
-rw-r--r--launcher/ui/pages/instance/ModFolderPage.cpp103
-rw-r--r--launcher/ui/pages/instance/ModFolderPage.h3
-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/VersionPage.cpp2
-rw-r--r--launcher/ui/pages/instance/WorldListPage.cpp13
-rw-r--r--launcher/ui/pages/instance/WorldListPage.h2
-rw-r--r--launcher/ui/pages/modplatform/ImportPage.cpp2
-rw-r--r--launcher/ui/pages/modplatform/ImportPage.ui2
-rw-r--r--launcher/ui/pages/modplatform/ModModel.cpp4
-rw-r--r--launcher/ui/pages/modplatform/atlauncher/AtlPage.cpp59
-rw-r--r--launcher/ui/pages/modplatform/atlauncher/AtlPage.h6
-rw-r--r--launcher/ui/pages/modplatform/atlauncher/AtlUserInteractionSupportImpl.cpp95
-rw-r--r--launcher/ui/pages/modplatform/atlauncher/AtlUserInteractionSupportImpl.h56
-rw-r--r--launcher/ui/pages/modplatform/flame/FlameModPage.cpp4
-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/ftb/FtbPage.cpp3
-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.cpp15
-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/themes/DarkTheme.cpp1
-rw-r--r--launcher/ui/widgets/CustomCommands.cpp2
-rw-r--r--launcher/ui/widgets/CustomCommands.h2
-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
-rw-r--r--launcher/ui/widgets/WideBar.cpp49
-rw-r--r--launcher/ui/widgets/WideBar.h31
92 files changed, 2193 insertions, 524 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 f68cf61a..299401f5 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>
@@ -235,7 +235,6 @@ public:
TranslatedAction actionMods;
TranslatedAction actionViewSelectedInstFolder;
TranslatedAction actionViewSelectedMCFolder;
- TranslatedAction actionViewSelectedModsFolder;
TranslatedAction actionDeleteInstance;
TranslatedAction actionConfig_Folder;
TranslatedAction actionCAT;
@@ -253,6 +252,9 @@ public:
TranslatedAction actionViewInstanceFolder;
TranslatedAction actionViewCentralModsFolder;
+ QMenu * editMenu = nullptr;
+ TranslatedAction actionUndoTrashInstance;
+
QMenu * helpMenu = nullptr;
TranslatedToolButton helpMenuButton;
TranslatedAction actionReportBug;
@@ -285,7 +287,7 @@ public:
TranslatedToolbar newsToolBar;
QVector<TranslatedToolbar *> all_toolbars;
- void createMainToolbarActions(QMainWindow *MainWindow)
+ void createMainToolbarActions(MainWindow *MainWindow)
{
actionAddInstance = TranslatedAction(MainWindow);
actionAddInstance->setObjectName(QStringLiteral("actionAddInstance"));
@@ -336,6 +338,14 @@ public:
actionSettings->setShortcut(QKeySequence::Preferences);
all_actions.append(&actionSettings);
+ actionUndoTrashInstance = TranslatedAction(MainWindow);
+ connect(actionUndoTrashInstance, SIGNAL(triggered(bool)), MainWindow, SLOT(undoTrashInstance()));
+ actionUndoTrashInstance->setObjectName(QStringLiteral("actionUndoTrashInstance"));
+ actionUndoTrashInstance.setTextId(QT_TRANSLATE_NOOP("MainWindow", "&Undo Last Instance Deletion"));
+ actionUndoTrashInstance->setEnabled(APPLICATION->instances()->trashedSomething());
+ actionUndoTrashInstance->setShortcut(QKeySequence("Ctrl+Z"));
+ all_actions.append(&actionUndoTrashInstance);
+
if (!BuildConfig.BUG_TRACKER_URL.isEmpty()) {
actionReportBug = TranslatedAction(MainWindow);
actionReportBug->setObjectName(QStringLiteral("actionReportBug"));
@@ -509,6 +519,9 @@ public:
fileMenu->addSeparator();
fileMenu->addAction(actionSettings);
+ editMenu = menuBar->addMenu(tr("&Edit"));
+ editMenu->addAction(actionUndoTrashInstance);
+
viewMenu = menuBar->addMenu(tr("&View"));
viewMenu->setSeparatorsCollapsible(false);
viewMenu->addAction(actionCAT);
@@ -709,14 +722,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"));
@@ -741,9 +746,10 @@ public:
actionDeleteInstance = TranslatedAction(MainWindow);
actionDeleteInstance->setObjectName(QStringLiteral("actionDeleteInstance"));
- actionDeleteInstance.setTextId(QT_TRANSLATE_NOOP("MainWindow", "Dele&te Instance..."));
+ actionDeleteInstance.setTextId(QT_TRANSLATE_NOOP("MainWindow", "Dele&te Instance"));
actionDeleteInstance.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "Delete the selected instance."));
actionDeleteInstance->setShortcuts({QKeySequence(tr("Backspace")), QKeySequence::Delete});
+ actionDeleteInstance->setAutoRepeat(false);
all_actions.append(&actionDeleteInstance);
actionCopyInstance = TranslatedAction(MainWindow);
@@ -793,9 +799,6 @@ public:
instanceToolBar->addSeparator();
instanceToolBar->addAction(actionViewSelectedMCFolder);
- /*
- instanceToolBar->addAction(actionViewSelectedModsFolder);
- */
instanceToolBar->addAction(actionConfig_Folder);
instanceToolBar->addAction(actionViewSelectedInstFolder);
@@ -1024,7 +1027,6 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new MainWindow
}
-#ifdef LAUNCHER_WITH_UPDATER
if(BuildConfig.UPDATER_ENABLED)
{
bool updatesAllowed = APPLICATION->updatesAreAllowed();
@@ -1042,8 +1044,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());
@@ -1156,6 +1165,11 @@ void MainWindow::showInstanceContextMenu(const QPoint &pos)
connect(actionDeleteGroup, SIGNAL(triggered(bool)), SLOT(deleteGroup()));
actions.append(actionDeleteGroup);
}
+
+ QAction *actionUndoTrashInstance = new QAction("Undo last trash instance", this);
+ connect(actionUndoTrashInstance, SIGNAL(triggered(bool)), SLOT(undoTrashInstance()));
+ actionUndoTrashInstance->setEnabled(APPLICATION->instances()->trashedSomething());
+ actions.append(actionUndoTrashInstance);
}
QMenu myMenu;
myMenu.addActions(actions);
@@ -1355,7 +1369,6 @@ void MainWindow::repopulateAccountsMenu()
ui->profileMenu->addAction(ui->actionManageAccounts);
}
-#ifdef LAUNCHER_WITH_UPDATER
void MainWindow::updatesAllowedChanged(bool allowed)
{
if(!BuildConfig.UPDATER_ENABLED)
@@ -1364,7 +1377,6 @@ void MainWindow::updatesAllowedChanged(bool allowed)
}
ui->actionCheckUpdate->setEnabled(allowed);
}
-#endif
/*
* Assumes the sender is a QAction
@@ -1453,6 +1465,7 @@ void MainWindow::updateNewsLabel()
{
newsLabel->setText(tr("Loading news..."));
newsLabel->setEnabled(false);
+ ui->actionMoreNews->setVisible(false);
}
else
{
@@ -1461,16 +1474,17 @@ void MainWindow::updateNewsLabel()
{
newsLabel->setText(entries[0]->title);
newsLabel->setEnabled(true);
+ ui->actionMoreNews->setVisible(true);
}
else
{
newsLabel->setText(tr("No news available."));
newsLabel->setEnabled(false);
+ ui->actionMoreNews->setVisible(false);
}
}
}
-#ifdef LAUNCHER_WITH_UPDATER
void MainWindow::updateAvailable(GoUpdate::Status status)
{
if(!APPLICATION->updatesAreAllowed())
@@ -1496,11 +1510,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)
{
@@ -1518,7 +1535,6 @@ QString intListToString(const QList<int> &list)
return slist.join(',');
}
-#ifdef LAUNCHER_WITH_UPDATER
void MainWindow::downloadUpdates(GoUpdate::Status status)
{
if(!APPLICATION->updatesAreAllowed())
@@ -1552,7 +1568,6 @@ void MainWindow::downloadUpdates(GoUpdate::Status status)
CustomMessageBox::selectable(this, tr("Error"), updateTask.failReason(), QMessageBox::Warning)->show();
}
}
-#endif
void MainWindow::onCatToggled(bool state)
{
@@ -1840,6 +1855,11 @@ void MainWindow::deleteGroup()
}
}
+void MainWindow::undoTrashInstance()
+{
+ APPLICATION->instances()->undoTrashInstance();
+}
+
void MainWindow::on_actionViewInstanceFolder_triggered()
{
QString str = APPLICATION->settings()->get("InstanceDir").toString();
@@ -1865,7 +1885,6 @@ void MainWindow::on_actionConfig_Folder_triggered()
}
}
-#ifdef LAUNCHER_WITH_UPDATER
void MainWindow::checkForUpdates()
{
if(BuildConfig.UPDATER_ENABLED)
@@ -1878,7 +1897,6 @@ void MainWindow::checkForUpdates()
qWarning() << "Updater not set up. Cannot check for updates.";
}
}
-#endif
void MainWindow::on_actionSettings_triggered()
{
@@ -1900,11 +1918,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");
@@ -1972,7 +1985,12 @@ void MainWindow::on_actionDeleteInstance_triggered()
{
return;
}
+
auto id = m_selectedInstance->id();
+ if (APPLICATION->instances()->trashInstance(id)) {
+ return;
+ }
+
auto response = CustomMessageBox::selectable(
this,
tr("CAREFUL!"),
@@ -2027,20 +2045,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.
diff --git a/launcher/ui/MainWindow.h b/launcher/ui/MainWindow.h
index 4615975e..dde3d02c 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();
@@ -153,6 +145,7 @@ private slots:
void on_actionDeleteInstance_triggered();
void deleteGroup();
+ void undoTrashInstance();
void on_actionExportInstance_triggered();
@@ -197,11 +190,9 @@ private slots:
void startTask(Task *task);
-#ifdef LAUNCHER_WITH_UPDATER
void updateAvailable(GoUpdate::Status status);
void updateNotAvailable();
-#endif
void defaultAccountChanged();
@@ -211,12 +202,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..743c34f1 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"
@@ -145,10 +147,15 @@ AboutDialog::AboutDialog(QWidget *parent) : QDialog(parent), ui(new Ui::AboutDia
else
ui->platformLabel->setVisible(false);
- if (BuildConfig.VERSION_BUILD >= 0)
- ui->buildNumLabel->setText(tr("Build Number") +": " + QString::number(BuildConfig.VERSION_BUILD));
+ if (!BuildConfig.GIT_COMMIT.isEmpty())
+ ui->commitLabel->setText(tr("Commit: %1").arg(BuildConfig.GIT_COMMIT));
else
- ui->buildNumLabel->setVisible(false);
+ ui->commitLabel->setVisible(false);
+
+ if (!BuildConfig.BUILD_DATE.isEmpty())
+ ui->buildDateLabel->setText(tr("Build date: %1").arg(BuildConfig.BUILD_DATE));
+ else
+ ui->buildDateLabel->setVisible(false);
if (!BuildConfig.VERSION_CHANNEL.isEmpty())
ui->channelLabel->setText(tr("Channel") +": " + BuildConfig.VERSION_CHANNEL);
diff --git a/launcher/ui/dialogs/AboutDialog.ui b/launcher/ui/dialogs/AboutDialog.ui
index 6323992b..6eaa0c4e 100644
--- a/launcher/ui/dialogs/AboutDialog.ui
+++ b/launcher/ui/dialogs/AboutDialog.ui
@@ -184,12 +184,28 @@
</widget>
</item>
<item>
- <widget class="QLabel" name="buildNumLabel">
+ <widget class="QLabel" name="buildDateLabel">
<property name="cursor">
<cursorShape>IBeamCursor</cursorShape>
</property>
<property name="text">
- <string>Build Number:</string>
+ <string>Build Date:</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignCenter</set>
+ </property>
+ <property name="textInteractionFlags">
+ <set>Qt::TextSelectableByMouse</set>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="commitLabel">
+ <property name="cursor">
+ <cursorShape>IBeamCursor</cursorShape>
+ </property>
+ <property name="text">
+ <string>Commit:</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
diff --git a/launcher/ui/dialogs/BlockedModsDialog.cpp b/launcher/ui/dialogs/BlockedModsDialog.cpp
new file mode 100644
index 00000000..fe87b517
--- /dev/null
+++ b/launcher/ui/dialogs/BlockedModsDialog.cpp
@@ -0,0 +1,28 @@
+#include "BlockedModsDialog.h"
+#include "ui_BlockedModsDialog.h"
+#include <QPushButton>
+#include <QDialogButtonBox>
+#include <QDesktopServices>
+
+
+BlockedModsDialog::BlockedModsDialog(QWidget *parent, const QString &title, const QString &text, const QString &body, const QList<QUrl> &urls) :
+ QDialog(parent), ui(new Ui::BlockedModsDialog), urls(urls) {
+ ui->setupUi(this);
+
+ auto openAllButton = ui->buttonBox->addButton(tr("Open All"), QDialogButtonBox::ActionRole);
+ connect(openAllButton, &QPushButton::clicked, this, &BlockedModsDialog::openAll);
+
+ this->setWindowTitle(title);
+ ui->label->setText(text);
+ ui->textBrowser->setText(body);
+}
+
+BlockedModsDialog::~BlockedModsDialog() {
+ delete ui;
+}
+
+void BlockedModsDialog::openAll() {
+ for(auto &url : urls) {
+ QDesktopServices::openUrl(url);
+ }
+}
diff --git a/launcher/ui/dialogs/BlockedModsDialog.h b/launcher/ui/dialogs/BlockedModsDialog.h
new file mode 100644
index 00000000..5f5bd61b
--- /dev/null
+++ b/launcher/ui/dialogs/BlockedModsDialog.h
@@ -0,0 +1,22 @@
+#pragma once
+
+#include <QDialog>
+
+
+QT_BEGIN_NAMESPACE
+namespace Ui { class BlockedModsDialog; }
+QT_END_NAMESPACE
+
+class BlockedModsDialog : public QDialog {
+Q_OBJECT
+
+public:
+ BlockedModsDialog(QWidget *parent, const QString &title, const QString &text, const QString &body, const QList<QUrl> &urls);
+
+ ~BlockedModsDialog() override;
+
+private:
+ Ui::BlockedModsDialog *ui;
+ const QList<QUrl> &urls;
+ void openAll();
+};
diff --git a/launcher/ui/dialogs/BlockedModsDialog.ui b/launcher/ui/dialogs/BlockedModsDialog.ui
new file mode 100644
index 00000000..f4ae95b6
--- /dev/null
+++ b/launcher/ui/dialogs/BlockedModsDialog.ui
@@ -0,0 +1,84 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>BlockedModsDialog</class>
+ <widget class="QDialog" name="BlockedModsDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>455</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string notr="true">BlockedModsDialog</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="0" column="0">
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string notr="true"/>
+ </property>
+ <property name="textFormat">
+ <enum>Qt::RichText</enum>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0">
+ <widget class="QDialogButtonBox" name="buttonBox">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="standardButtons">
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QTextBrowser" name="textBrowser">
+ <property name="acceptRichText">
+ <bool>true</bool>
+ </property>
+ <property name="openExternalLinks">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>BlockedModsDialog</receiver>
+ <slot>accept()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>199</x>
+ <y>425</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>199</x>
+ <y>227</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>rejected()</signal>
+ <receiver>BlockedModsDialog</receiver>
+ <slot>reject()</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>199</x>
+ <y>425</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>199</x>
+ <y>227</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/launcher/ui/dialogs/ChooseProviderDialog.cpp b/launcher/ui/dialogs/ChooseProviderDialog.cpp
new file mode 100644
index 00000000..89935d9a
--- /dev/null
+++ b/launcher/ui/dialogs/ChooseProviderDialog.cpp
@@ -0,0 +1,96 @@
+#include "ChooseProviderDialog.h"
+#include "ui_ChooseProviderDialog.h"
+
+#include <QPushButton>
+#include <QRadioButton>
+
+#include "modplatform/ModIndex.h"
+
+static ModPlatform::ProviderCapabilities ProviderCaps;
+
+ChooseProviderDialog::ChooseProviderDialog(QWidget* parent, bool single_choice, bool allow_skipping)
+ : QDialog(parent), ui(new Ui::ChooseProviderDialog)
+{
+ ui->setupUi(this);
+
+ addProviders();
+ m_providers.button(0)->click();
+
+ connect(ui->skipOneButton, &QPushButton::clicked, this, &ChooseProviderDialog::skipOne);
+ connect(ui->skipAllButton, &QPushButton::clicked, this, &ChooseProviderDialog::skipAll);
+
+ connect(ui->confirmOneButton, &QPushButton::clicked, this, &ChooseProviderDialog::confirmOne);
+ connect(ui->confirmAllButton, &QPushButton::clicked, this, &ChooseProviderDialog::confirmAll);
+
+ if (single_choice) {
+ ui->providersLayout->removeWidget(ui->skipAllButton);
+ ui->providersLayout->removeWidget(ui->confirmAllButton);
+ }
+
+ if (!allow_skipping) {
+ ui->providersLayout->removeWidget(ui->skipOneButton);
+ ui->providersLayout->removeWidget(ui->skipAllButton);
+ }
+}
+
+ChooseProviderDialog::~ChooseProviderDialog()
+{
+ delete ui;
+}
+
+void ChooseProviderDialog::setDescription(QString desc)
+{
+ ui->explanationLabel->setText(desc);
+}
+
+void ChooseProviderDialog::skipOne()
+{
+ reject();
+}
+void ChooseProviderDialog::skipAll()
+{
+ m_response.skip_all = true;
+ reject();
+}
+
+void ChooseProviderDialog::confirmOne()
+{
+ m_response.chosen = getSelectedProvider();
+ m_response.try_others = ui->tryOthersCheckbox->isChecked();
+ accept();
+}
+void ChooseProviderDialog::confirmAll()
+{
+ m_response.chosen = getSelectedProvider();
+ m_response.confirm_all = true;
+ m_response.try_others = ui->tryOthersCheckbox->isChecked();
+ accept();
+}
+
+auto ChooseProviderDialog::getSelectedProvider() const -> ModPlatform::Provider
+{
+ return ModPlatform::Provider(m_providers.checkedId());
+}
+
+void ChooseProviderDialog::addProviders()
+{
+ int btn_index = 0;
+ QRadioButton* btn;
+
+ for (auto& provider : { ModPlatform::Provider::MODRINTH, ModPlatform::Provider::FLAME }) {
+ btn = new QRadioButton(ProviderCaps.readableName(provider), this);
+ m_providers.addButton(btn, btn_index++);
+ ui->providersLayout->addWidget(btn);
+ }
+}
+
+void ChooseProviderDialog::disableInput()
+{
+ for (auto& btn : m_providers.buttons())
+ btn->setEnabled(false);
+
+ ui->skipOneButton->setEnabled(false);
+ ui->skipAllButton->setEnabled(false);
+ ui->confirmOneButton->setEnabled(false);
+ ui->confirmAllButton->setEnabled(false);
+}
diff --git a/launcher/ui/dialogs/ChooseProviderDialog.h b/launcher/ui/dialogs/ChooseProviderDialog.h
new file mode 100644
index 00000000..4a3b9f29
--- /dev/null
+++ b/launcher/ui/dialogs/ChooseProviderDialog.h
@@ -0,0 +1,56 @@
+#pragma once
+
+#include <QButtonGroup>
+#include <QDialog>
+
+namespace Ui {
+class ChooseProviderDialog;
+}
+
+namespace ModPlatform {
+enum class Provider;
+}
+
+class Mod;
+class NetJob;
+class ModUpdateDialog;
+
+class ChooseProviderDialog : public QDialog {
+ Q_OBJECT
+
+ struct Response {
+ bool skip_all = false;
+ bool confirm_all = false;
+
+ bool try_others = false;
+
+ ModPlatform::Provider chosen;
+ };
+
+ public:
+ explicit ChooseProviderDialog(QWidget* parent, bool single_choice = false, bool allow_skipping = true);
+ ~ChooseProviderDialog();
+
+ auto getResponse() const -> Response { return m_response; }
+
+ void setDescription(QString desc);
+
+ private slots:
+ void skipOne();
+ void skipAll();
+ void confirmOne();
+ void confirmAll();
+
+ private:
+ void addProviders();
+ void disableInput();
+
+ auto getSelectedProvider() const -> ModPlatform::Provider;
+
+ private:
+ Ui::ChooseProviderDialog* ui;
+
+ QButtonGroup m_providers;
+
+ Response m_response;
+};
diff --git a/launcher/ui/dialogs/ChooseProviderDialog.ui b/launcher/ui/dialogs/ChooseProviderDialog.ui
new file mode 100644
index 00000000..78cd9613
--- /dev/null
+++ b/launcher/ui/dialogs/ChooseProviderDialog.ui
@@ -0,0 +1,89 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ChooseProviderDialog</class>
+ <widget class="QDialog" name="ChooseProviderDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>453</width>
+ <height>197</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Choose a mod provider</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="0" column="0" colspan="2">
+ <widget class="QLabel" name="explanationLabel">
+ <property name="alignment">
+ <set>Qt::AlignJustify|Qt::AlignTop</set>
+ </property>
+ <property name="wordWrap">
+ <bool>true</bool>
+ </property>
+ <property name="indent">
+ <number>-1</number>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0" colspan="2">
+ <layout class="QFormLayout" name="providersLayout">
+ <property name="labelAlignment">
+ <set>Qt::AlignHCenter|Qt::AlignTop</set>
+ </property>
+ <property name="formAlignment">
+ <set>Qt::AlignHCenter|Qt::AlignTop</set>
+ </property>
+ </layout>
+ </item>
+ <item row="4" column="0" colspan="2">
+ <layout class="QHBoxLayout" name="buttonsLayout">
+ <item>
+ <widget class="QPushButton" name="skipOneButton">
+ <property name="text">
+ <string>Skip this mod</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="skipAllButton">
+ <property name="text">
+ <string>Skip all</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="confirmAllButton">
+ <property name="text">
+ <string>Confirm for all</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="confirmOneButton">
+ <property name="text">
+ <string>Confirm</string>
+ </property>
+ <property name="default">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item row="3" column="0">
+ <widget class="QCheckBox" name="tryOthersCheckbox">
+ <property name="text">
+ <string>Try to automatically use other providers if the chosen one fails</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
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/LoginDialog.cpp b/launcher/ui/dialogs/LoginDialog.cpp
index 194315a7..30394b72 100644
--- a/launcher/ui/dialogs/LoginDialog.cpp
+++ b/launcher/ui/dialogs/LoginDialog.cpp
@@ -115,5 +115,5 @@ MinecraftAccountPtr LoginDialog::newAccount(QWidget *parent, QString msg)
{
return dlg.m_account;
}
- return 0;
+ return nullptr;
}
diff --git a/launcher/ui/dialogs/MSALoginDialog.cpp b/launcher/ui/dialogs/MSALoginDialog.cpp
index b11b6980..be49babb 100644
--- a/launcher/ui/dialogs/MSALoginDialog.cpp
+++ b/launcher/ui/dialogs/MSALoginDialog.cpp
@@ -169,5 +169,5 @@ MinecraftAccountPtr MSALoginDialog::newAccount(QWidget *parent, QString msg)
{
return dlg.m_account;
}
- return 0;
+ return nullptr;
}
diff --git a/launcher/ui/dialogs/ModDownloadDialog.cpp b/launcher/ui/dialogs/ModDownloadDialog.cpp
index f01c9c07..e4fc3ecc 100644
--- a/launcher/ui/dialogs/ModDownloadDialog.cpp
+++ b/launcher/ui/dialogs/ModDownloadDialog.cpp
@@ -1,9 +1,28 @@
+// 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/>.
+ */
+
#include "ModDownloadDialog.h"
#include <BaseVersion.h>
#include <icons/IconList.h>
#include <InstanceList.h>
+#include "Application.h"
#include "ProgressDialog.h"
#include "ReviewMessageBox.h"
@@ -100,13 +119,13 @@ void ModDownloadDialog::accept()
QList<BasePage *> ModDownloadDialog::getPages()
{
- modrinthPage = new ModrinthModPage(this, m_instance);
- flameModPage = new FlameModPage(this, m_instance);
- return
- {
- modrinthPage,
- flameModPage
- };
+ QList<BasePage *> pages;
+
+ pages.append(new ModrinthModPage(this, m_instance));
+ if (APPLICATION->currentCapabilities() & Application::SupportsFlame)
+ pages.append(new FlameModPage(this, m_instance));
+
+ return pages;
}
void ModDownloadDialog::addSelectedMod(const QString& name, ModDownloadTask* task)
diff --git a/launcher/ui/dialogs/ModDownloadDialog.h b/launcher/ui/dialogs/ModDownloadDialog.h
index 5c565ad3..1fa1f058 100644
--- a/launcher/ui/dialogs/ModDownloadDialog.h
+++ b/launcher/ui/dialogs/ModDownloadDialog.h
@@ -1,3 +1,21 @@
+// 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/>.
+ */
+
#pragma once
#include <QDialog>
@@ -48,9 +66,6 @@ private:
QDialogButtonBox * m_buttons = nullptr;
QVBoxLayout *m_verticalLayout = nullptr;
-
- ModrinthModPage *modrinthPage = nullptr;
- FlameModPage *flameModPage = nullptr;
QHash<QString, ModDownloadTask*> modTask;
BaseInstance *m_instance;
};
diff --git a/launcher/ui/dialogs/ModUpdateDialog.cpp b/launcher/ui/dialogs/ModUpdateDialog.cpp
new file mode 100644
index 00000000..d73c8ebb
--- /dev/null
+++ b/launcher/ui/dialogs/ModUpdateDialog.cpp
@@ -0,0 +1,409 @@
+#include "ModUpdateDialog.h"
+#include "ChooseProviderDialog.h"
+#include "CustomMessageBox.h"
+#include "ProgressDialog.h"
+#include "ScrollMessageBox.h"
+#include "ui_ReviewMessageBox.h"
+
+#include "FileSystem.h"
+#include "Json.h"
+
+#include "tasks/ConcurrentTask.h"
+
+#include "minecraft/MinecraftInstance.h"
+#include "minecraft/PackProfile.h"
+
+#include "modplatform/EnsureMetadataTask.h"
+#include "modplatform/flame/FlameCheckUpdate.h"
+#include "modplatform/modrinth/ModrinthCheckUpdate.h"
+
+#include <HoeDown.h>
+#include <QTextBrowser>
+#include <QTreeWidgetItem>
+
+static ModPlatform::ProviderCapabilities ProviderCaps;
+
+static std::list<Version> mcVersions(BaseInstance* inst)
+{
+ return { static_cast<MinecraftInstance*>(inst)->getPackProfile()->getComponent("net.minecraft")->getVersion() };
+}
+
+static ModAPI::ModLoaderTypes mcLoaders(BaseInstance* inst)
+{
+ return { static_cast<MinecraftInstance*>(inst)->getPackProfile()->getModLoaders() };
+}
+
+ModUpdateDialog::ModUpdateDialog(QWidget* parent,
+ BaseInstance* instance,
+ const std::shared_ptr<ModFolderModel> mods,
+ QList<Mod::Ptr>& search_for)
+ : ReviewMessageBox(parent, tr("Confirm mods to update"), "")
+ , m_parent(parent)
+ , m_mod_model(mods)
+ , m_candidates(search_for)
+ , m_second_try_metadata(new ConcurrentTask())
+ , m_instance(instance)
+{
+ ReviewMessageBox::setGeometry(0, 0, 800, 600);
+
+ ui->explainLabel->setText(tr("You're about to update the following mods:"));
+ ui->onlyCheckedLabel->setText(tr("Only mods with a check will be updated!"));
+}
+
+void ModUpdateDialog::checkCandidates()
+{
+ // Ensure mods have valid metadata
+ auto went_well = ensureMetadata();
+ if (!went_well) {
+ m_aborted = true;
+ return;
+ }
+
+ // Report failed metadata generation
+ if (!m_failed_metadata.empty()) {
+ QString text;
+ for (const auto& failed : m_failed_metadata) {
+ const auto& mod = std::get<0>(failed);
+ const auto& reason = std::get<1>(failed);
+ text += tr("Mod name: %1<br>File name: %2<br>Reason: %3<br><br>").arg(mod->name(), mod->fileinfo().fileName(), reason);
+ }
+
+ ScrollMessageBox message_dialog(m_parent, tr("Metadata generation failed"),
+ tr("Could not generate metadata for the following mods:<br>"
+ "Do you wish to proceed without those mods?"),
+ text);
+ message_dialog.setModal(true);
+ if (message_dialog.exec() == QDialog::Rejected) {
+ m_aborted = true;
+ QMetaObject::invokeMethod(this, "reject", Qt::QueuedConnection);
+ return;
+ }
+ }
+
+ auto versions = mcVersions(m_instance);
+ auto loaders = mcLoaders(m_instance);
+
+ SequentialTask check_task(m_parent, tr("Checking for updates"));
+
+ if (!m_modrinth_to_update.empty()) {
+ m_modrinth_check_task = new ModrinthCheckUpdate(m_modrinth_to_update, versions, loaders, m_mod_model);
+ connect(m_modrinth_check_task, &CheckUpdateTask::checkFailed, this,
+ [this](Mod* mod, QString reason, QUrl recover_url) { m_failed_check_update.append({mod, reason, recover_url}); });
+ check_task.addTask(m_modrinth_check_task);
+ }
+
+ if (!m_flame_to_update.empty()) {
+ m_flame_check_task = new FlameCheckUpdate(m_flame_to_update, versions, loaders, m_mod_model);
+ connect(m_flame_check_task, &CheckUpdateTask::checkFailed, this,
+ [this](Mod* mod, QString reason, QUrl recover_url) { m_failed_check_update.append({mod, reason, recover_url}); });
+ check_task.addTask(m_flame_check_task);
+ }
+
+ connect(&check_task, &Task::failed, this,
+ [&](QString reason) { CustomMessageBox::selectable(this, tr("Error"), reason, QMessageBox::Critical)->exec(); });
+
+ connect(&check_task, &Task::succeeded, this, [&]() {
+ QStringList warnings = check_task.warnings();
+ if (warnings.count()) {
+ CustomMessageBox::selectable(this, tr("Warnings"), warnings.join('\n'), QMessageBox::Warning)->exec();
+ }
+ });
+
+ // Check for updates
+ ProgressDialog progress_dialog(m_parent);
+ progress_dialog.setSkipButton(true, tr("Abort"));
+ progress_dialog.setWindowTitle(tr("Checking for updates..."));
+ auto ret = progress_dialog.execWithTask(&check_task);
+
+ // If the dialog was skipped / some download error happened
+ if (ret == QDialog::DialogCode::Rejected) {
+ m_aborted = true;
+ QMetaObject::invokeMethod(this, "reject", Qt::QueuedConnection);
+ return;
+ }
+
+ // Add found updates for Modrinth
+ if (m_modrinth_check_task) {
+ auto modrinth_updates = m_modrinth_check_task->getUpdatable();
+ for (auto& updatable : modrinth_updates) {
+ qDebug() << QString("Mod %1 has an update available!").arg(updatable.name);
+
+ appendMod(updatable);
+ m_tasks.insert(updatable.name, updatable.download);
+ }
+ }
+
+ // Add found updated for Flame
+ if (m_flame_check_task) {
+ auto flame_updates = m_flame_check_task->getUpdatable();
+ for (auto& updatable : flame_updates) {
+ qDebug() << QString("Mod %1 has an update available!").arg(updatable.name);
+
+ appendMod(updatable);
+ m_tasks.insert(updatable.name, updatable.download);
+ }
+ }
+
+ // Report failed update checking
+ if (!m_failed_check_update.empty()) {
+ QString text;
+ for (const auto& failed : m_failed_check_update) {
+ const auto& mod = std::get<0>(failed);
+ const auto& reason = std::get<1>(failed);
+ const auto& recover_url = std::get<2>(failed);
+
+ qDebug() << mod->name() << " failed to check for updates!";
+
+ text += tr("Mod name: %1").arg(mod->name()) + "<br>";
+ if (!reason.isEmpty())
+ text += tr("Reason: %1").arg(reason) + "<br>";
+ if (!recover_url.isEmpty())
+ //: %1 is the link to download it manually
+ text += tr("Possible solution: Getting the latest version manually:<br>%1<br>")
+ .arg(QString("<a href='%1'>%1</a>").arg(recover_url.toString()));
+ text += "<br>";
+ }
+
+ ScrollMessageBox message_dialog(m_parent, tr("Failed to check for updates"),
+ tr("Could not check or get the following mods for updates:<br>"
+ "Do you wish to proceed without those mods?"),
+ text);
+ message_dialog.setModal(true);
+ if (message_dialog.exec() == QDialog::Rejected) {
+ m_aborted = true;
+ QMetaObject::invokeMethod(this, "reject", Qt::QueuedConnection);
+ return;
+ }
+ }
+
+ // If there's no mod to be updated
+ if (ui->modTreeWidget->topLevelItemCount() == 0) {
+ m_no_updates = true;
+ } else {
+ // FIXME: Find a more efficient way of doing this!
+
+ // Sort major items in alphabetical order (also sorts the children unfortunately)
+ ui->modTreeWidget->sortItems(0, Qt::SortOrder::AscendingOrder);
+
+ // Re-sort the children
+ auto* item = ui->modTreeWidget->topLevelItem(0);
+ for (int i = 1; item != nullptr; ++i) {
+ item->sortChildren(0, Qt::SortOrder::DescendingOrder);
+ item = ui->modTreeWidget->topLevelItem(i);
+ }
+ }
+
+ if (m_aborted || m_no_updates)
+ QMetaObject::invokeMethod(this, "reject", Qt::QueuedConnection);
+}
+
+// Part 1: Ensure we have a valid metadata
+auto ModUpdateDialog::ensureMetadata() -> bool
+{
+ auto index_dir = indexDir();
+
+ SequentialTask seq(m_parent, tr("Looking for metadata"));
+
+ // A better use of data structures here could remove the need for this QHash
+ QHash<QString, bool> should_try_others;
+ QList<Mod*> modrinth_tmp;
+ QList<Mod*> flame_tmp;
+
+ bool confirm_rest = false;
+ bool try_others_rest = false;
+ bool skip_rest = false;
+ ModPlatform::Provider provider_rest = ModPlatform::Provider::MODRINTH;
+
+ auto addToTmp = [&](Mod* m, ModPlatform::Provider p) {
+ switch (p) {
+ case ModPlatform::Provider::MODRINTH:
+ modrinth_tmp.push_back(m);
+ break;
+ case ModPlatform::Provider::FLAME:
+ flame_tmp.push_back(m);
+ break;
+ }
+ };
+
+ for (auto candidate : m_candidates) {
+ auto* candidate_ptr = candidate.get();
+ if (candidate->status() != ModStatus::NoMetadata) {
+ onMetadataEnsured(candidate_ptr);
+ continue;
+ }
+
+ if (skip_rest)
+ continue;
+
+ if (confirm_rest) {
+ addToTmp(candidate_ptr, provider_rest);
+ should_try_others.insert(candidate->internal_id(), try_others_rest);
+ continue;
+ }
+
+ ChooseProviderDialog chooser(this);
+ chooser.setDescription(tr("The mod '%1' does not have a metadata yet. We need to generate it in order to track relevant "
+ "information on how to update this mod. "
+ "To do this, please select a mod provider which we can use to check for updates for this mod.")
+ .arg(candidate->name()));
+ auto confirmed = chooser.exec() == QDialog::DialogCode::Accepted;
+
+ auto response = chooser.getResponse();
+
+ if (response.skip_all)
+ skip_rest = true;
+ if (response.confirm_all) {
+ confirm_rest = true;
+ provider_rest = response.chosen;
+ try_others_rest = response.try_others;
+ }
+
+ should_try_others.insert(candidate->internal_id(), response.try_others);
+
+ if (confirmed)
+ addToTmp(candidate_ptr, response.chosen);
+ }
+
+ if (!modrinth_tmp.empty()) {
+ auto* modrinth_task = new EnsureMetadataTask(modrinth_tmp, index_dir, ModPlatform::Provider::MODRINTH);
+ connect(modrinth_task, &EnsureMetadataTask::metadataReady, [this](Mod* candidate) { onMetadataEnsured(candidate); });
+ connect(modrinth_task, &EnsureMetadataTask::metadataFailed, [this, &should_try_others](Mod* candidate) {
+ onMetadataFailed(candidate, should_try_others.find(candidate->internal_id()).value(), ModPlatform::Provider::MODRINTH);
+ });
+ seq.addTask(modrinth_task);
+ }
+
+ if (!flame_tmp.empty()) {
+ auto* flame_task = new EnsureMetadataTask(flame_tmp, index_dir, ModPlatform::Provider::FLAME);
+ connect(flame_task, &EnsureMetadataTask::metadataReady, [this](Mod* candidate) { onMetadataEnsured(candidate); });
+ connect(flame_task, &EnsureMetadataTask::metadataFailed, [this, &should_try_others](Mod* candidate) {
+ onMetadataFailed(candidate, should_try_others.find(candidate->internal_id()).value(), ModPlatform::Provider::FLAME);
+ });
+ seq.addTask(flame_task);
+ }
+
+ seq.addTask(m_second_try_metadata);
+
+ ProgressDialog checking_dialog(m_parent);
+ checking_dialog.setSkipButton(true, tr("Abort"));
+ checking_dialog.setWindowTitle(tr("Generating metadata..."));
+ auto ret_metadata = checking_dialog.execWithTask(&seq);
+
+ return (ret_metadata != QDialog::DialogCode::Rejected);
+}
+
+void ModUpdateDialog::onMetadataEnsured(Mod* mod)
+{
+ // When the mod is a folder, for instance
+ if (!mod->metadata())
+ return;
+
+ switch (mod->metadata()->provider) {
+ case ModPlatform::Provider::MODRINTH:
+ m_modrinth_to_update.push_back(mod);
+ break;
+ case ModPlatform::Provider::FLAME:
+ m_flame_to_update.push_back(mod);
+ break;
+ }
+}
+
+ModPlatform::Provider next(ModPlatform::Provider p)
+{
+ switch (p) {
+ case ModPlatform::Provider::MODRINTH:
+ return ModPlatform::Provider::FLAME;
+ case ModPlatform::Provider::FLAME:
+ return ModPlatform::Provider::MODRINTH;
+ }
+
+ return ModPlatform::Provider::FLAME;
+}
+
+void ModUpdateDialog::onMetadataFailed(Mod* mod, bool try_others, ModPlatform::Provider first_choice)
+{
+ if (try_others) {
+ auto index_dir = indexDir();
+
+ auto* task = new EnsureMetadataTask(mod, index_dir, next(first_choice));
+ connect(task, &EnsureMetadataTask::metadataReady, [this](Mod* candidate) { onMetadataEnsured(candidate); });
+ connect(task, &EnsureMetadataTask::metadataFailed, [this](Mod* candidate) { onMetadataFailed(candidate, false); });
+
+ m_second_try_metadata->addTask(task);
+ } else {
+ QString reason{ tr("Couldn't find a valid version on the selected mod provider(s)") };
+
+ m_failed_metadata.append({mod, reason});
+ }
+}
+
+void ModUpdateDialog::appendMod(CheckUpdateTask::UpdatableMod const& info)
+{
+ auto item_top = new QTreeWidgetItem(ui->modTreeWidget);
+ item_top->setCheckState(0, Qt::CheckState::Checked);
+ item_top->setText(0, info.name);
+ item_top->setExpanded(true);
+
+ auto provider_item = new QTreeWidgetItem(item_top);
+ provider_item->setText(0, tr("Provider: %1").arg(ProviderCaps.readableName(info.provider)));
+
+ auto old_version_item = new QTreeWidgetItem(item_top);
+ old_version_item->setText(0, tr("Old version: %1").arg(info.old_version.isEmpty() ? tr("Not installed") : info.old_version));
+
+ auto new_version_item = new QTreeWidgetItem(item_top);
+ new_version_item->setText(0, tr("New version: %1").arg(info.new_version));
+
+ auto changelog_item = new QTreeWidgetItem(item_top);
+ changelog_item->setText(0, tr("Changelog of the latest version"));
+
+ auto changelog = new QTreeWidgetItem(changelog_item);
+ auto changelog_area = new QTextBrowser();
+
+ switch (info.provider) {
+ case ModPlatform::Provider::MODRINTH: {
+ HoeDown h;
+ // HoeDown bug?: \n aren't converted to <br>
+ auto text = h.process(info.changelog.toUtf8());
+
+ // Don't convert if there's an HTML tag right after (Qt rendering weirdness)
+ text.remove(QRegularExpression("(\n+)(?=<)"));
+ text.replace('\n', "<br>");
+
+ changelog_area->setHtml(text);
+ break;
+ }
+ case ModPlatform::Provider::FLAME: {
+ changelog_area->setHtml(info.changelog);
+ break;
+ }
+ }
+
+ changelog_area->setOpenExternalLinks(true);
+ changelog_area->setLineWrapMode(QTextBrowser::LineWrapMode::NoWrap);
+ changelog_area->setVerticalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAsNeeded);
+
+ // HACK: Is there a better way of achieving this?
+ auto font_height = QFontMetrics(changelog_area->font()).height();
+ changelog_area->setMaximumHeight((changelog_area->toPlainText().count(QRegularExpression("\n|<br>")) + 2) * font_height);
+
+ ui->modTreeWidget->setItemWidget(changelog, 0, changelog_area);
+
+ ui->modTreeWidget->addTopLevelItem(item_top);
+}
+
+auto ModUpdateDialog::getTasks() -> const QList<ModDownloadTask*>
+{
+ QList<ModDownloadTask*> list;
+
+ auto* item = ui->modTreeWidget->topLevelItem(0);
+
+ for (int i = 1; item != nullptr; ++i) {
+ if (item->checkState(0) == Qt::CheckState::Checked) {
+ list.push_back(m_tasks.find(item->text(0)).value());
+ }
+
+ item = ui->modTreeWidget->topLevelItem(i);
+ }
+
+ return list;
+}
diff --git a/launcher/ui/dialogs/ModUpdateDialog.h b/launcher/ui/dialogs/ModUpdateDialog.h
new file mode 100644
index 00000000..76aaab36
--- /dev/null
+++ b/launcher/ui/dialogs/ModUpdateDialog.h
@@ -0,0 +1,62 @@
+#pragma once
+
+#include "BaseInstance.h"
+#include "ModDownloadTask.h"
+#include "ReviewMessageBox.h"
+
+#include "minecraft/mod/ModFolderModel.h"
+
+#include "modplatform/CheckUpdateTask.h"
+
+class Mod;
+class ModrinthCheckUpdate;
+class FlameCheckUpdate;
+class ConcurrentTask;
+
+class ModUpdateDialog final : public ReviewMessageBox {
+ Q_OBJECT
+ public:
+ explicit ModUpdateDialog(QWidget* parent,
+ BaseInstance* instance,
+ const std::shared_ptr<ModFolderModel> mod_model,
+ QList<Mod::Ptr>& search_for);
+
+ void checkCandidates();
+
+ void appendMod(const CheckUpdateTask::UpdatableMod& info);
+
+ const QList<ModDownloadTask*> getTasks();
+ auto indexDir() const -> QDir { return m_mod_model->indexDir(); }
+
+ auto noUpdates() const -> bool { return m_no_updates; };
+ auto aborted() const -> bool { return m_aborted; };
+
+ private:
+ auto ensureMetadata() -> bool;
+
+ private slots:
+ void onMetadataEnsured(Mod*);
+ void onMetadataFailed(Mod*, bool try_others = false, ModPlatform::Provider first_choice = ModPlatform::Provider::MODRINTH);
+
+ private:
+ QWidget* m_parent;
+
+ ModrinthCheckUpdate* m_modrinth_check_task = nullptr;
+ FlameCheckUpdate* m_flame_check_task = nullptr;
+
+ const std::shared_ptr<ModFolderModel> m_mod_model;
+
+ QList<Mod::Ptr>& m_candidates;
+ QList<Mod*> m_modrinth_to_update;
+ QList<Mod*> m_flame_to_update;
+
+ ConcurrentTask* m_second_try_metadata;
+ QList<std::tuple<Mod*, QString>> m_failed_metadata;
+ QList<std::tuple<Mod*, QString, QUrl>> m_failed_check_update;
+
+ QHash<QString, ModDownloadTask*> m_tasks;
+ BaseInstance* m_instance;
+
+ bool m_no_updates = false;
+ bool m_aborted = false;
+};
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..35bba9be 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);
@@ -124,20 +150,21 @@ void NewInstanceDialog::accept()
QList<BasePage *> NewInstanceDialog::getPages()
{
+ QList<BasePage *> pages;
+
importPage = new ImportPage(this);
- flamePage = new FlamePage(this);
- auto technicPage = new TechnicPage(this);
- return
- {
- new VanillaPage(this),
- importPage,
- new AtlPage(this),
- flamePage,
- new FtbPage(this),
- new LegacyFTB::Page(this),
- new ModrinthPage(this),
- technicPage
- };
+
+ pages.append(new VanillaPage(this));
+ pages.append(importPage);
+ pages.append(new AtlPage(this));
+ if (APPLICATION->currentCapabilities() & Application::SupportsFlame)
+ pages.append(new FlamePage(this));
+ pages.append(new FtbPage(this));
+ pages.append(new LegacyFTB::Page(this));
+ pages.append(new ModrinthPage(this));
+ pages.append(new TechnicPage(this));
+
+ return pages;
}
QString NewInstanceDialog::dialogTitle()
diff --git a/launcher/ui/dialogs/NewInstanceDialog.h b/launcher/ui/dialogs/NewInstanceDialog.h
index ef74634e..a3c8cd1c 100644
--- a/launcher/ui/dialogs/NewInstanceDialog.h
+++ b/launcher/ui/dialogs/NewInstanceDialog.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
@@ -69,7 +89,6 @@ private:
QString InstIconKey;
ImportPage *importPage = nullptr;
- FlamePage *flamePage = nullptr;
std::unique_ptr<InstanceTask> creationTask;
bool importIcon = false;
diff --git a/launcher/ui/dialogs/NewsDialog.cpp b/launcher/ui/dialogs/NewsDialog.cpp
index df620464..d3b21627 100644
--- a/launcher/ui/dialogs/NewsDialog.cpp
+++ b/launcher/ui/dialogs/NewsDialog.cpp
@@ -16,7 +16,7 @@ NewsDialog::NewsDialog(QList<NewsEntryPtr> entries, QWidget* parent) : QDialog(p
m_article_list_hidden = ui->articleListWidget->isHidden();
auto first_item = ui->articleListWidget->item(0);
- ui->articleListWidget->setItemSelected(first_item, true);
+ 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()));
diff --git a/launcher/ui/dialogs/OfflineLoginDialog.cpp b/launcher/ui/dialogs/OfflineLoginDialog.cpp
index 4f3d8be4..a69537ab 100644
--- a/launcher/ui/dialogs/OfflineLoginDialog.cpp
+++ b/launcher/ui/dialogs/OfflineLoginDialog.cpp
@@ -103,5 +103,5 @@ MinecraftAccountPtr OfflineLoginDialog::newAccount(QWidget *parent, QString msg)
{
return dlg.m_account;
}
- return 0;
+ return nullptr;
}
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/ProgressDialog.cpp b/launcher/ui/dialogs/ProgressDialog.cpp
index e5226016..3c7f53d3 100644
--- a/launcher/ui/dialogs/ProgressDialog.cpp
+++ b/launcher/ui/dialogs/ProgressDialog.cpp
@@ -43,8 +43,8 @@ void ProgressDialog::setSkipButton(bool present, QString label)
void ProgressDialog::on_skipButton_clicked(bool checked)
{
Q_UNUSED(checked);
- task->abort();
- QDialog::reject();
+ if (task->abort())
+ QDialog::reject();
}
ProgressDialog::~ProgressDialog()
@@ -62,24 +62,24 @@ void ProgressDialog::updateSize()
int ProgressDialog::execWithTask(Task* task)
{
this->task = task;
- QDialog::DialogCode result;
if (!task) {
- qDebug() << "Programmer error: progress dialog created with null task.";
- return Accepted;
+ qDebug() << "Programmer error: Progress dialog created with null task.";
+ return QDialog::DialogCode::Accepted;
}
+ QDialog::DialogCode result;
if (handleImmediateResult(result)) {
return result;
}
// Connect signals.
- connect(task, SIGNAL(started()), SLOT(onTaskStarted()));
- connect(task, SIGNAL(failed(QString)), SLOT(onTaskFailed(QString)));
- connect(task, SIGNAL(succeeded()), SLOT(onTaskSucceeded()));
- connect(task, SIGNAL(status(QString)), SLOT(changeStatus(const QString&)));
- connect(task, SIGNAL(stepStatus(QString)), SLOT(changeStatus(const QString&)));
- connect(task, SIGNAL(progress(qint64, qint64)), SLOT(changeProgress(qint64, qint64)));
+ connect(task, &Task::started, this, &ProgressDialog::onTaskStarted);
+ connect(task, &Task::failed, this, &ProgressDialog::onTaskFailed);
+ connect(task, &Task::succeeded, this, &ProgressDialog::onTaskSucceeded);
+ connect(task, &Task::status, this, &ProgressDialog::changeStatus);
+ connect(task, &Task::stepStatus, this, &ProgressDialog::changeStatus);
+ connect(task, &Task::progress, this, &ProgressDialog::changeProgress);
connect(task, &Task::aborted, [this] { onTaskFailed(tr("Aborted by user")); });
@@ -89,19 +89,15 @@ int ProgressDialog::execWithTask(Task* task)
ui->globalProgressBar->setHidden(true);
}
- // if this didn't connect to an already running task, invoke start
+ // It's a good idea to start the task after we entered the dialog's event loop :^)
if (!task->isRunning()) {
- task->start();
- }
- if (task->isRunning()) {
- changeProgress(task->getProgress(), task->getTotalProgress());
- changeStatus(task->getStatus());
- return QDialog::exec();
- } else if (handleImmediateResult(result)) {
- return result;
+ QMetaObject::invokeMethod(task, &Task::start, Qt::QueuedConnection);
} else {
- return QDialog::Rejected;
+ changeStatus(task->getStatus());
+ changeProgress(task->getProgress(), task->getTotalProgress());
}
+
+ return QDialog::exec();
}
// TODO: only provide the unique_ptr overloads
diff --git a/launcher/ui/dialogs/ReviewMessageBox.cpp b/launcher/ui/dialogs/ReviewMessageBox.cpp
index c92234a4..e664e566 100644
--- a/launcher/ui/dialogs/ReviewMessageBox.cpp
+++ b/launcher/ui/dialogs/ReviewMessageBox.cpp
@@ -40,7 +40,7 @@ auto ReviewMessageBox::deselectedMods() -> QStringList
auto* item = ui->modTreeWidget->topLevelItem(0);
- for (int i = 0; item != nullptr; ++i) {
+ for (int i = 1; item != nullptr; ++i) {
if (item->checkState(0) == Qt::CheckState::Unchecked) {
list.append(item->text(0));
}
diff --git a/launcher/ui/dialogs/ScrollMessageBox.ui b/launcher/ui/dialogs/ScrollMessageBox.ui
index 299d2ecc..e684185f 100644
--- a/launcher/ui/dialogs/ScrollMessageBox.ui
+++ b/launcher/ui/dialogs/ScrollMessageBox.ui
@@ -6,7 +6,7 @@
<rect>
<x>0</x>
<y>0</y>
- <width>400</width>
+ <width>500</width>
<height>455</height>
</rect>
</property>
diff --git a/launcher/ui/dialogs/SkinUploadDialog.cpp b/launcher/ui/dialogs/SkinUploadDialog.cpp
index 8d137afc..8180ac1f 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,68 +57,72 @@ void SkinUploadDialog::on_buttonBox_accepted()
{
QString fileName;
QString input = ui->skinPathTextBox->text();
- QRegExp urlPrefixMatcher("^([a-z]+)://.+$");
- bool isLocalFile = false;
- // it has an URL prefix -> it is an URL
- if(urlPrefixMatcher.exactMatch(input))
- {
- QUrl fileURL = input;
- if(fileURL.isValid())
+ ProgressDialog prog(this);
+ SequentialTask skinUpload;
+
+ if (!input.isEmpty()) {
+ QRegularExpression urlPrefixMatcher(QRegularExpression::anchoredPattern("^([a-z]+)://.+$"));
+ bool isLocalFile = false;
+ // it has an URL prefix -> it is an URL
+ if(urlPrefixMatcher.match(input).hasMatch())
{
- // local?
- if(fileURL.isLocalFile())
+ QUrl fileURL = input;
+ if(fileURL.isValid())
{
- isLocalFile = true;
- fileName = fileURL.toLocalFile();
+ // local?
+ if(fileURL.isLocalFile())
+ {
+ isLocalFile = true;
+ fileName = fileURL.toLocalFile();
+ }
+ else
+ {
+ CustomMessageBox::selectable(
+ this,
+ tr("Skin Upload"),
+ tr("Using remote URLs for setting skins is not implemented yet."),
+ QMessageBox::Warning
+ )->exec();
+ close();
+ return;
+ }
}
else
{
CustomMessageBox::selectable(
this,
tr("Skin Upload"),
- tr("Using remote URLs for setting skins is not implemented yet."),
+ tr("You cannot use an invalid URL for uploading skins."),
QMessageBox::Warning
- )->exec();
+ )->exec();
close();
return;
}
}
else
{
- CustomMessageBox::selectable(
- this,
- tr("Skin Upload"),
- tr("You cannot use an invalid URL for uploading skins."),
- QMessageBox::Warning
- )->exec();
+ // just assume it's a path then
+ isLocalFile = true;
+ fileName = ui->skinPathTextBox->text();
+ }
+ if (isLocalFile && !QFile::exists(fileName))
+ {
+ CustomMessageBox::selectable(this, tr("Skin Upload"), tr("Skin file does not exist!"), QMessageBox::Warning)->exec();
close();
return;
}
+ SkinUpload::Model model = SkinUpload::STEVE;
+ if (ui->steveBtn->isChecked())
+ {
+ model = SkinUpload::STEVE;
+ }
+ else if (ui->alexBtn->isChecked())
+ {
+ model = SkinUpload::ALEX;
+ }
+ skinUpload.addTask(shared_qobject_ptr<SkinUpload>(new SkinUpload(this, m_acct->accessToken(), FS::read(fileName), model)));
}
- else
- {
- // just assume it's a path then
- isLocalFile = true;
- fileName = ui->skinPathTextBox->text();
- }
- if (isLocalFile && !QFile::exists(fileName))
- {
- CustomMessageBox::selectable(this, tr("Skin Upload"), tr("Skin file does not exist!"), QMessageBox::Warning)->exec();
- close();
- return;
- }
- SkinUpload::Model model = SkinUpload::STEVE;
- if (ui->steveBtn->isChecked())
- {
- model = SkinUpload::STEVE;
- }
- else if (ui->alexBtn->isChecked())
- {
- model = SkinUpload::ALEX;
- }
- ProgressDialog prog(this);
- SequentialTask skinUpload;
- skinUpload.addTask(shared_qobject_ptr<SkinUpload>(new SkinUpload(this, m_acct->accessToken(), FS::read(fileName), model)));
+
auto selectedCape = ui->capeCombo->currentData().toString();
if(selectedCape != m_acct->accountData()->minecraftProfile.currentCape) {
skinUpload.addTask(shared_qobject_ptr<CapeChange>(new CapeChange(this, m_acct->accessToken(), selectedCape)));
diff --git a/launcher/ui/dialogs/SkinUploadDialog.ui b/launcher/ui/dialogs/SkinUploadDialog.ui
index f4b0ed0a..c7b16645 100644
--- a/launcher/ui/dialogs/SkinUploadDialog.ui
+++ b/launcher/ui/dialogs/SkinUploadDialog.ui
@@ -21,7 +21,11 @@
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
- <widget class="QLineEdit" name="skinPathTextBox"/>
+ <widget class="QLineEdit" name="skinPathTextBox">
+ <property name="placeholderText">
+ <string>Leave empty to keep current skin</string>
+ </property>
+ </widget>
</item>
<item>
<widget class="QPushButton" name="skinBrowseBtn">
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/APIPage.cpp b/launcher/ui/pages/global/APIPage.cpp
index b889e6f7..e3d30475 100644
--- a/launcher/ui/pages/global/APIPage.cpp
+++ b/launcher/ui/pages/global/APIPage.cpp
@@ -40,8 +40,10 @@
#include <QMessageBox>
#include <QFileDialog>
+#include <QRegularExpression>
#include <QStandardPaths>
#include <QTabBar>
+#include <QValidator>
#include <QVariant>
#include "settings/SettingsObject.h"
@@ -63,6 +65,10 @@ APIPage::APIPage(QWidget *parent) :
};
static QRegularExpression validUrlRegExp("https?://.+");
+ static QRegularExpression validMSAClientID(QRegularExpression::anchoredPattern(
+ "[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}"));
+ static QRegularExpression validFlameKey(QRegularExpression::anchoredPattern(
+ "\\$2[ayb]\\$.{56}"));
ui->setupUi(this);
@@ -75,6 +81,8 @@ APIPage::APIPage(QWidget *parent) :
// This function needs to be called even when the ComboBox's index is still in its default state.
updateBaseURLPlaceholder(ui->pasteTypeComboBox->currentIndex());
ui->baseURLEntry->setValidator(new QRegularExpressionValidator(validUrlRegExp, ui->baseURLEntry));
+ ui->msaClientID->setValidator(new QRegularExpressionValidator(validMSAClientID, ui->msaClientID));
+ ui->flameKey->setValidator(new QRegularExpressionValidator(validFlameKey, ui->flameKey));
ui->metaURL->setPlaceholderText(BuildConfig.META_URL);
ui->userAgentLineEdit->setPlaceholderText(BuildConfig.USER_AGENT);
@@ -137,8 +145,8 @@ void APIPage::loadSettings()
ui->msaClientID->setText(msaClientID);
QString metaURL = s->get("MetaURLOverride").toString();
ui->metaURL->setText(metaURL);
- QString curseKey = s->get("CFKeyOverride").toString();
- ui->curseKey->setText(curseKey);
+ QString flameKey = s->get("FlameKeyOverride").toString();
+ ui->flameKey->setText(flameKey);
QString customUserAgent = s->get("UserAgentOverride").toString();
ui->userAgentLineEdit->setText(customUserAgent);
}
@@ -167,8 +175,8 @@ void APIPage::applySettings()
}
s->set("MetaURLOverride", metaURL);
- QString curseKey = ui->curseKey->text();
- s->set("CFKeyOverride", curseKey);
+ QString flameKey = ui->flameKey->text();
+ s->set("FlameKeyOverride", flameKey);
s->set("UserAgentOverride", ui->userAgentLineEdit->text());
}
diff --git a/launcher/ui/pages/global/APIPage.ui b/launcher/ui/pages/global/APIPage.ui
index 5327771c..1ae788c7 100644
--- a/launcher/ui/pages/global/APIPage.ui
+++ b/launcher/ui/pages/global/APIPage.ui
@@ -196,7 +196,7 @@
</widget>
</item>
<item>
- <widget class="QGroupBox" name="groupBox_curse">
+ <widget class="QGroupBox" name="groupBox_flame">
<property name="enabled">
<bool>true</bool>
</property>
@@ -214,7 +214,7 @@
<item row="2" column="0">
<widget class="QLabel" name="label_7">
<property name="text">
- <string>Enter a custom API Key for CurseForge here. </string>
+ <string>Enter a custom API Key for CurseForge here.</string>
</property>
<property name="textFormat">
<enum>Qt::RichText</enum>
@@ -228,7 +228,7 @@
</widget>
</item>
<item row="1" column="0">
- <widget class="QLineEdit" name="curseKey">
+ <widget class="QLineEdit" name="flameKey">
<property name="enabled">
<bool>true</bool>
</property>
diff --git a/launcher/ui/pages/global/AccountListPage.cpp b/launcher/ui/pages/global/AccountListPage.cpp
index a608771e..fcc43add 100644
--- a/launcher/ui/pages/global/AccountListPage.cpp
+++ b/launcher/ui/pages/global/AccountListPage.cpp
@@ -96,7 +96,7 @@ AccountListPage::AccountListPage(QWidget *parent)
updateButtonStates();
// Xbox authentication won't work without a client identifier, so disable the button if it is missing
- if (APPLICATION->getMSAClientID().isEmpty()) {
+ if (~APPLICATION->currentCapabilities() & Application::SupportsMSA) {
ui->actionAddMicrosoft->setVisible(false);
ui->actionAddMicrosoft->setToolTip(tr("No Microsoft Authentication client ID was set."));
}
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/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/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
index 02eeae3d..39fbe3e2 100644
--- a/launcher/ui/pages/instance/ExternalResourcesPage.cpp
+++ b/launcher/ui/pages/instance/ExternalResourcesPage.cpp
@@ -32,13 +32,13 @@ class SortProxy : public QSortFilterProxyModel {
const auto& mod = model->at(source_row);
- if (mod.name().contains(filterRegExp()))
+ if (filterRegularExpression().match(mod.name()).hasMatch())
return true;
- if (mod.description().contains(filterRegExp()))
+ if (filterRegularExpression().match(mod.description()).hasMatch())
return true;
for (auto& author : mod.authors()) {
- if (author.contains(filterRegExp())) {
+ if (filterRegularExpression().match(author).hasMatch()) {
return true;
}
}
@@ -101,7 +101,7 @@ ExternalResourcesPage::ExternalResourcesPage(BaseInstance* instance, std::shared
{
ui->setupUi(this);
- runningStateChanged(m_instance && m_instance->isRunning());
+ ExternalResourcesPage::runningStateChanged(m_instance && m_instance->isRunning());
ui->actionsToolbar->insertSpacer(ui->actionViewConfigs);
@@ -182,7 +182,7 @@ void ExternalResourcesPage::retranslate()
void ExternalResourcesPage::filterTextChanged(const QString& newContents)
{
m_viewFilter = newContents;
- m_filterModel->setFilterFixedString(m_viewFilter);
+ m_filterModel->setFilterRegularExpression(m_viewFilter);
}
void ExternalResourcesPage::runningStateChanged(bool running)
diff --git a/launcher/ui/pages/instance/ExternalResourcesPage.h b/launcher/ui/pages/instance/ExternalResourcesPage.h
index 41237139..ff294678 100644
--- a/launcher/ui/pages/instance/ExternalResourcesPage.h
+++ b/launcher/ui/pages/instance/ExternalResourcesPage.h
@@ -46,7 +46,7 @@ class ExternalResourcesPage : public QMainWindow, public BasePage {
protected slots:
void itemActivated(const QModelIndex& index);
void filterTextChanged(const QString& newContents);
- void runningStateChanged(bool running);
+ virtual void runningStateChanged(bool running);
virtual void addItem();
virtual void removeItem();
diff --git a/launcher/ui/pages/instance/ExternalResourcesPage.ui b/launcher/ui/pages/instance/ExternalResourcesPage.ui
index 17bf455a..a13666b2 100644
--- a/launcher/ui/pages/instance/ExternalResourcesPage.ui
+++ b/launcher/ui/pages/instance/ExternalResourcesPage.ui
@@ -147,6 +147,17 @@
<string>Download a new resource</string>
</property>
</action>
+ <action name="actionUpdateItem">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Check for &amp;Updates</string>
+ </property>
+ <property name="toolTip">
+ <string>Try to check or update all selected resources (all resources if none are selected)</string>
+ </property>
+ </action>
</widget>
<customwidgets>
<customwidget>
diff --git a/launcher/ui/pages/instance/InstanceSettingsPage.cpp b/launcher/ui/pages/instance/InstanceSettingsPage.cpp
index 1d8cd1d7..f11cf992 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
@@ -349,7 +349,7 @@ void InstanceSettingsPage::loadSettings()
ui->useDiscreteGpuCheck->setChecked(m_settings->get("UseDiscreteGpu").toBool());
#if !defined(Q_OS_LINUX)
- ui->perfomanceGroupBox->setVisible(false);
+ ui->settingsTabs->setTabVisible(ui->settingsTabs->indexOf(ui->performancePage), false);
#endif
// Miscellanous
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 4432ccc8..1b2cde0c 100644
--- a/launcher/ui/pages/instance/ModFolderPage.cpp
+++ b/launcher/ui/pages/instance/ModFolderPage.cpp
@@ -49,6 +49,7 @@
#include "ui/GuiUtil.h"
#include "ui/dialogs/CustomMessageBox.h"
#include "ui/dialogs/ModDownloadDialog.h"
+#include "ui/dialogs/ModUpdateDialog.h"
#include "DesktopServices.h"
@@ -78,6 +79,36 @@ ModFolderPage::ModFolderPage(BaseInstance* inst, std::shared_ptr<ModFolderModel>
ui->actionsToolbar->insertActionBefore(ui->actionAddItem, ui->actionDownloadItem);
connect(ui->actionDownloadItem, &QAction::triggered, this, &ModFolderPage::installMods);
+
+ ui->actionUpdateItem->setToolTip(tr("Try to check or update all selected mods (all mods if none are selected)"));
+ ui->actionsToolbar->insertActionAfter(ui->actionAddItem, ui->actionUpdateItem);
+ connect(ui->actionUpdateItem, &QAction::triggered, this, &ModFolderPage::updateMods);
+
+ auto check_allow_update = [this] {
+ return (!m_instance || !m_instance->isRunning()) &&
+ (ui->treeView->selectionModel()->hasSelection() || !m_model->empty());
+ };
+
+ connect(ui->treeView->selectionModel(), &QItemSelectionModel::selectionChanged, this, [this, check_allow_update] {
+ ui->actionUpdateItem->setEnabled(check_allow_update());
+ });
+
+ connect(mods.get(), &ModFolderModel::rowsInserted, this, [this, check_allow_update] {
+ ui->actionUpdateItem->setEnabled(check_allow_update());
+ });
+
+ connect(mods.get(), &ModFolderModel::rowsRemoved, this, [this, check_allow_update] {
+ ui->actionUpdateItem->setEnabled(check_allow_update());
+ });
+
+ connect(mods.get(), &ModFolderModel::updateFinished, this, [this, check_allow_update, mods] {
+ ui->actionUpdateItem->setEnabled(check_allow_update());
+
+ // Prevent a weird crash when trying to open the mods page twice in a session o.O
+ disconnect(mods.get(), &ModFolderModel::updateFinished, this, 0);
+ });
+
+ ModFolderPage::runningStateChanged(m_instance && m_instance->isRunning());
}
}
@@ -85,6 +116,13 @@ CoreModFolderPage::CoreModFolderPage(BaseInstance* inst, std::shared_ptr<ModFold
: ModFolderPage(inst, mods, parent)
{}
+void ModFolderPage::runningStateChanged(bool running)
+{
+ ExternalResourcesPage::runningStateChanged(running);
+ ui->actionDownloadItem->setEnabled(!running);
+ ui->actionUpdateItem->setEnabled(!running);
+}
+
bool ModFolderPage::shouldDisplay() const
{
return true;
@@ -107,7 +145,6 @@ bool CoreModFolderPage::shouldDisplay() const
return false;
if (version->getComponent("net.minecraft")->getReleaseDateTime() < g_VersionFilterData.legacyCutoffDate)
return true;
-
}
return false;
}
@@ -118,7 +155,7 @@ void ModFolderPage::installMods()
return;
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!"));
@@ -140,7 +177,7 @@ void ModFolderPage::installMods()
QStringList warnings = tasks->warnings();
if (warnings.count())
CustomMessageBox::selectable(this, tr("Warnings"), warnings.join('\n'), QMessageBox::Warning)->show();
-
+
tasks->deleteLater();
});
@@ -155,3 +192,63 @@ void ModFolderPage::installMods()
m_model->update();
}
}
+
+void ModFolderPage::updateMods()
+{
+ auto selection = m_filterModel->mapSelectionToSource(ui->treeView->selectionModel()->selection()).indexes();
+
+ auto mods_list = m_model->selectedMods(selection);
+ bool use_all = mods_list.empty();
+ if (use_all)
+ mods_list = m_model->allMods();
+
+ ModUpdateDialog update_dialog(this, m_instance, m_model, mods_list);
+ update_dialog.checkCandidates();
+
+ if (update_dialog.aborted()) {
+ CustomMessageBox::selectable(this, tr("Aborted"), tr("The mod updater was aborted!"), QMessageBox::Warning)->show();
+ return;
+ }
+ if (update_dialog.noUpdates()) {
+ QString message{ tr("'%1' is up-to-date! :)").arg(mods_list.front()->name()) };
+ if (mods_list.size() > 1) {
+ if (use_all) {
+ message = tr("All mods are up-to-date! :)");
+ } else {
+ message = tr("All selected mods are up-to-date! :)");
+ }
+ }
+ CustomMessageBox::selectable(this, tr("Update checker"), message)
+ ->exec();
+ return;
+ }
+
+ if (update_dialog.exec()) {
+ ConcurrentTask* tasks = new ConcurrentTask(this);
+ connect(tasks, &Task::failed, [this, tasks](QString reason) {
+ CustomMessageBox::selectable(this, tr("Error"), reason, QMessageBox::Critical)->show();
+ tasks->deleteLater();
+ });
+ connect(tasks, &Task::aborted, [this, tasks]() {
+ CustomMessageBox::selectable(this, tr("Aborted"), tr("Download stopped by user."), QMessageBox::Information)->show();
+ tasks->deleteLater();
+ });
+ connect(tasks, &Task::succeeded, [this, tasks]() {
+ QStringList warnings = tasks->warnings();
+ if (warnings.count()) {
+ CustomMessageBox::selectable(this, tr("Warnings"), warnings.join('\n'), QMessageBox::Warning)->show();
+ }
+ tasks->deleteLater();
+ });
+
+ for (auto task : update_dialog.getTasks()) {
+ tasks->addTask(task);
+ }
+
+ ProgressDialog loadDialog(this);
+ loadDialog.setSkipButton(true, tr("Abort"));
+ loadDialog.execWithTask(tasks);
+
+ m_model->update();
+ }
+}
diff --git a/launcher/ui/pages/instance/ModFolderPage.h b/launcher/ui/pages/instance/ModFolderPage.h
index 1a9ed7db..93889707 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
@@ -52,9 +53,11 @@ class ModFolderPage : public ExternalResourcesPage {
virtual QString helpPage() const override { return "Loader-mods"; }
virtual bool shouldDisplay() const override;
+ void runningStateChanged(bool running) override;
private slots:
void installMods();
+ void updateMods();
};
class CoreModFolderPage : public ModFolderPage {
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/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..85cc01ff 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"
@@ -212,7 +211,7 @@ void WorldListPage::on_actionDatapacks_triggered()
return;
}
- if(!worldSafetyNagQuestion())
+ if(!worldSafetyNagQuestion(tr("Open World Datapacks Folder")))
return;
auto fullPath = m_worlds->data(index, WorldList::FolderRole).toString();
@@ -270,7 +269,7 @@ void WorldListPage::on_actionMCEdit_triggered()
return;
}
- if(!worldSafetyNagQuestion())
+ if(!worldSafetyNagQuestion(tr("Open World in MCEdit")))
return;
auto fullPath = m_worlds->data(index, WorldList::FolderRole).toString();
@@ -374,11 +373,11 @@ bool WorldListPage::isWorldSafe(QModelIndex)
return !m_inst->isRunning();
}
-bool WorldListPage::worldSafetyNagQuestion()
+bool WorldListPage::worldSafetyNagQuestion(const QString &actionType)
{
if(!isWorldSafe(getSelectedWorld()))
{
- auto result = QMessageBox::question(this, tr("Copy World"), tr("Changing a world while Minecraft is running is potentially unsafe.\nDo you wish to proceed?"));
+ auto result = QMessageBox::question(this, actionType, tr("Changing a world while Minecraft is running is potentially unsafe.\nDo you wish to proceed?"));
if(result == QMessageBox::No)
{
return false;
@@ -396,7 +395,7 @@ void WorldListPage::on_actionCopy_triggered()
return;
}
- if(!worldSafetyNagQuestion())
+ if(!worldSafetyNagQuestion(tr("Copy World")))
return;
auto worldVariant = m_worlds->data(index, WorldList::ObjectRole);
@@ -418,7 +417,7 @@ void WorldListPage::on_actionRename_triggered()
return;
}
- if(!worldSafetyNagQuestion())
+ if(!worldSafetyNagQuestion(tr("Rename World")))
return;
auto worldVariant = m_worlds->data(index, WorldList::ObjectRole);
diff --git a/launcher/ui/pages/instance/WorldListPage.h b/launcher/ui/pages/instance/WorldListPage.h
index 17e36a08..1dc9e53e 100644
--- a/launcher/ui/pages/instance/WorldListPage.h
+++ b/launcher/ui/pages/instance/WorldListPage.h
@@ -93,7 +93,7 @@ protected:
private:
QModelIndex getSelectedWorld();
bool isWorldSafe(QModelIndex index);
- bool worldSafetyNagQuestion();
+ bool worldSafetyNagQuestion(const QString &actionType);
void mceditError();
private:
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/ImportPage.ui b/launcher/ui/pages/modplatform/ImportPage.ui
index 77bc5da5..0a50e871 100644
--- a/launcher/ui/pages/modplatform/ImportPage.ui
+++ b/launcher/ui/pages/modplatform/ImportPage.ui
@@ -40,7 +40,7 @@
<item>
<widget class="QLabel" name="label_5">
<property name="text">
- <string>- Curseforge modpacks (ZIP)</string>
+ <string>- CurseForge modpacks (ZIP)</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
diff --git a/launcher/ui/pages/modplatform/ModModel.cpp b/launcher/ui/pages/modplatform/ModModel.cpp
index 4917b890..94b1f099 100644
--- a/launcher/ui/pages/modplatform/ModModel.cpp
+++ b/launcher/ui/pages/modplatform/ModModel.cpp
@@ -219,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/atlauncher/AtlPage.cpp b/launcher/ui/pages/modplatform/atlauncher/AtlPage.cpp
index 8de5211c..7901b90b 100644
--- a/launcher/ui/pages/modplatform/atlauncher/AtlPage.cpp
+++ b/launcher/ui/pages/modplatform/atlauncher/AtlPage.cpp
@@ -37,13 +37,12 @@
#include "AtlPage.h"
#include "ui_AtlPage.h"
-#include "modplatform/atlauncher/ATLPackInstallTask.h"
+#include "BuildConfig.h"
#include "AtlOptionalModDialog.h"
+#include "AtlUserInteractionSupportImpl.h"
+#include "modplatform/atlauncher/ATLPackInstallTask.h"
#include "ui/dialogs/NewInstanceDialog.h"
-#include "ui/dialogs/VersionSelectDialog.h"
-
-#include <BuildConfig.h>
#include <QMessageBox>
@@ -117,7 +116,9 @@ void AtlPage::suggestCurrent()
return;
}
- dialog->setSuggestedPack(selected.name + " " + selectedVersion, new ATLauncher::PackInstallTask(this, selected.name, selectedVersion));
+ auto uiSupport = new AtlUserInteractionSupportImpl(this);
+ dialog->setSuggestedPack(selected.name + " " + selectedVersion, new ATLauncher::PackInstallTask(uiSupport, selected.name, selectedVersion));
+
auto editedLogoName = selected.safeName;
auto url = QString(BuildConfig.ATL_DOWNLOAD_SERVER_URL + "launcher/images/%1.png").arg(selected.safeName.toLower());
listModel->getLogo(selected.safeName, url, [this, editedLogoName](QString logo)
@@ -172,51 +173,3 @@ void AtlPage::onVersionSelectionChanged(QString data)
selectedVersion = data;
suggestCurrent();
}
-
-QVector<QString> AtlPage::chooseOptionalMods(ATLauncher::PackVersion version, QVector<ATLauncher::VersionMod> mods)
-{
- AtlOptionalModDialog optionalModDialog(this, version, mods);
- optionalModDialog.exec();
- return optionalModDialog.getResult();
-}
-
-QString AtlPage::chooseVersion(Meta::VersionListPtr vlist, QString minecraftVersion) {
- VersionSelectDialog vselect(vlist.get(), "Choose Version", APPLICATION->activeWindow(), false);
- if (minecraftVersion != Q_NULLPTR) {
- vselect.setExactFilter(BaseVersionList::ParentVersionRole, minecraftVersion);
- vselect.setEmptyString(tr("No versions are currently available for Minecraft %1").arg(minecraftVersion));
- }
- else {
- vselect.setEmptyString(tr("No versions are currently available"));
- }
- vselect.setEmptyErrorString(tr("Couldn't load or download the version lists!"));
-
- // select recommended build
- for (int i = 0; i < vlist->versions().size(); i++) {
- auto version = vlist->versions().at(i);
- auto reqs = version->requires();
-
- // filter by minecraft version, if the loader depends on a certain version.
- if (minecraftVersion != Q_NULLPTR) {
- auto iter = std::find_if(reqs.begin(), reqs.end(), [](const Meta::Require &req) {
- return req.uid == "net.minecraft";
- });
- if (iter == reqs.end()) continue;
- if (iter->equalsVersion != minecraftVersion) continue;
- }
-
- // first recommended build we find, we use.
- if (version->isRecommended()) {
- vselect.setCurrentVersion(version->descriptor());
- break;
- }
- }
-
- vselect.exec();
- return vselect.selectedVersion()->descriptor();
-}
-
-void AtlPage::displayMessage(QString message)
-{
- QMessageBox::information(this, tr("Installing"), message);
-}
diff --git a/launcher/ui/pages/modplatform/atlauncher/AtlPage.h b/launcher/ui/pages/modplatform/atlauncher/AtlPage.h
index aa6d5da1..1b3b15c1 100644
--- a/launcher/ui/pages/modplatform/atlauncher/AtlPage.h
+++ b/launcher/ui/pages/modplatform/atlauncher/AtlPage.h
@@ -52,7 +52,7 @@ namespace Ui
class NewInstanceDialog;
-class AtlPage : public QWidget, public BasePage, public ATLauncher::UserInteractionSupport
+class AtlPage : public QWidget, public BasePage
{
Q_OBJECT
@@ -83,10 +83,6 @@ public:
private:
void suggestCurrent();
- QString chooseVersion(Meta::VersionListPtr vlist, QString minecraftVersion) override;
- QVector<QString> chooseOptionalMods(ATLauncher::PackVersion version, QVector<ATLauncher::VersionMod> mods) override;
- void displayMessage(QString message) override;
-
private slots:
void triggerSearch();
diff --git a/launcher/ui/pages/modplatform/atlauncher/AtlUserInteractionSupportImpl.cpp b/launcher/ui/pages/modplatform/atlauncher/AtlUserInteractionSupportImpl.cpp
new file mode 100644
index 00000000..03196685
--- /dev/null
+++ b/launcher/ui/pages/modplatform/atlauncher/AtlUserInteractionSupportImpl.cpp
@@ -0,0 +1,95 @@
+// SPDX-License-Identifier: GPL-3.0-only
+/*
+ * PolyMC - Minecraft Launcher
+ * Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
+ *
+ * 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 2020-2021 Jamie Mansfield <jmansfield@cadixdev.org>
+ *
+ * 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 <QMessageBox>
+#include "AtlUserInteractionSupportImpl.h"
+
+#include "AtlOptionalModDialog.h"
+#include "ui/dialogs/VersionSelectDialog.h"
+
+AtlUserInteractionSupportImpl::AtlUserInteractionSupportImpl(QWidget *parent) : m_parent(parent)
+{
+}
+
+QVector<QString> AtlUserInteractionSupportImpl::chooseOptionalMods(ATLauncher::PackVersion version, QVector<ATLauncher::VersionMod> mods)
+{
+ AtlOptionalModDialog optionalModDialog(m_parent, version, mods);
+ optionalModDialog.exec();
+ return optionalModDialog.getResult();
+}
+
+QString AtlUserInteractionSupportImpl::chooseVersion(Meta::VersionListPtr vlist, QString minecraftVersion)
+{
+ VersionSelectDialog vselect(vlist.get(), "Choose Version", m_parent, false);
+ if (minecraftVersion != nullptr) {
+ vselect.setExactFilter(BaseVersionList::ParentVersionRole, minecraftVersion);
+ vselect.setEmptyString(tr("No versions are currently available for Minecraft %1").arg(minecraftVersion));
+ }
+ else {
+ vselect.setEmptyString(tr("No versions are currently available"));
+ }
+ vselect.setEmptyErrorString(tr("Couldn't load or download the version lists!"));
+
+ // select recommended build
+ for (int i = 0; i < vlist->versions().size(); i++) {
+ auto version = vlist->versions().at(i);
+ auto reqs = version->requires();
+
+ // filter by minecraft version, if the loader depends on a certain version.
+ if (minecraftVersion != nullptr) {
+ auto iter = std::find_if(reqs.begin(), reqs.end(), [](const Meta::Require& req) {
+ return req.uid == "net.minecraft";
+ });
+ if (iter == reqs.end())
+ continue;
+ if (iter->equalsVersion != minecraftVersion)
+ continue;
+ }
+
+ // first recommended build we find, we use.
+ if (version->isRecommended()) {
+ vselect.setCurrentVersion(version->descriptor());
+ break;
+ }
+ }
+
+ vselect.exec();
+ return vselect.selectedVersion()->descriptor();
+}
+
+void AtlUserInteractionSupportImpl::displayMessage(QString message)
+{
+ QMessageBox::information(m_parent, tr("Installing"), message);
+}
diff --git a/launcher/ui/pages/modplatform/atlauncher/AtlUserInteractionSupportImpl.h b/launcher/ui/pages/modplatform/atlauncher/AtlUserInteractionSupportImpl.h
new file mode 100644
index 00000000..aa22fc73
--- /dev/null
+++ b/launcher/ui/pages/modplatform/atlauncher/AtlUserInteractionSupportImpl.h
@@ -0,0 +1,56 @@
+// SPDX-License-Identifier: GPL-3.0-only
+/*
+ * PolyMC - Minecraft Launcher
+ * Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
+ *
+ * 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 2020-2021 Jamie Mansfield <jmansfield@cadixdev.org>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <QObject>
+
+#include "modplatform/atlauncher/ATLPackInstallTask.h"
+
+class AtlUserInteractionSupportImpl : public QObject, public ATLauncher::UserInteractionSupport {
+ Q_OBJECT
+
+public:
+ AtlUserInteractionSupportImpl(QWidget* parent);
+
+private:
+ QString chooseVersion(Meta::VersionListPtr vlist, QString minecraftVersion) override;
+ QVector<QString> chooseOptionalMods(ATLauncher::PackVersion version, QVector<ATLauncher::VersionMod> mods) override;
+ void displayMessage(QString message) override;
+
+private:
+ QWidget* m_parent;
+
+};
diff --git a/launcher/ui/pages/modplatform/flame/FlameModPage.cpp b/launcher/ui/pages/modplatform/flame/FlameModPage.cpp
index 1c160fd4..772fd2e0 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
@@ -64,7 +64,7 @@ FlameModPage::FlameModPage(ModDownloadDialog* dialog, BaseInstance* instance)
auto FlameModPage::validateVersion(ModPlatform::IndexedVersion& ver, QString mineVer, ModAPI::ModLoaderTypes loaders) const -> bool
{
Q_UNUSED(loaders);
- return ver.mcVersion.contains(mineVer);
+ return ver.mcVersion.contains(mineVer) && !ver.downloadUrl.isEmpty();
}
// I don't know why, but doing this on the parent class makes it so that
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/ftb/FtbPage.cpp b/launcher/ui/pages/modplatform/ftb/FtbPage.cpp
index 8a93bc2e..504d7f7b 100644
--- a/launcher/ui/pages/modplatform/ftb/FtbPage.cpp
+++ b/launcher/ui/pages/modplatform/ftb/FtbPage.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
@@ -126,7 +127,7 @@ void FtbPage::suggestCurrent()
return;
}
- dialog->setSuggestedPack(selected.name + " " + selectedVersion, new ModpacksCH::PackInstallTask(selected, selectedVersion));
+ dialog->setSuggestedPack(selected.name + " " + selectedVersion, new ModpacksCH::PackInstallTask(selected, selectedVersion, this));
for(auto art : selected.art) {
if(art.type == "square") {
QString editedLogoName;
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 39b935a6..3633d575 100644
--- a/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp
+++ b/launcher/ui/pages/modplatform/modrinth/ModrinthModel.cpp
@@ -104,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
@@ -279,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/themes/DarkTheme.cpp b/launcher/ui/themes/DarkTheme.cpp
index 31ecd559..712a9d3e 100644
--- a/launcher/ui/themes/DarkTheme.cpp
+++ b/launcher/ui/themes/DarkTheme.cpp
@@ -31,6 +31,7 @@ QPalette DarkTheme::colorScheme()
darkPalette.setColor(QPalette::Link, QColor(42, 130, 218));
darkPalette.setColor(QPalette::Highlight, QColor(42, 130, 218));
darkPalette.setColor(QPalette::HighlightedText, Qt::black);
+ darkPalette.setColor(QPalette::PlaceholderText, Qt::darkGray);
return fadeInactive(darkPalette, fadeAmount(), fadeColor());
}
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/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);
diff --git a/launcher/ui/widgets/WideBar.cpp b/launcher/ui/widgets/WideBar.cpp
index 8d5bd12d..79f1e0c9 100644
--- a/launcher/ui/widgets/WideBar.cpp
+++ b/launcher/ui/widgets/WideBar.cpp
@@ -76,13 +76,20 @@ void WideBar::addSeparator()
m_entries.push_back(entry);
}
-void WideBar::insertActionBefore(QAction* before, QAction* action){
- auto iter = std::find_if(m_entries.begin(), m_entries.end(), [before](BarEntry * entry) {
- return entry->wideAction == before;
+auto WideBar::getMatching(QAction* act) -> QList<BarEntry*>::iterator
+{
+ auto iter = std::find_if(m_entries.begin(), m_entries.end(), [act](BarEntry * entry) {
+ return entry->wideAction == act;
});
- if(iter == m_entries.end()) {
+
+ return iter;
+}
+
+void WideBar::insertActionBefore(QAction* before, QAction* action){
+ auto iter = getMatching(before);
+ if(iter == m_entries.end())
return;
- }
+
auto entry = new BarEntry();
entry->qAction = insertWidget((*iter)->qAction, new ActionButton(action, this));
entry->wideAction = action;
@@ -90,14 +97,24 @@ void WideBar::insertActionBefore(QAction* before, QAction* action){
m_entries.insert(iter, entry);
}
+void WideBar::insertActionAfter(QAction* after, QAction* action){
+ auto iter = getMatching(after);
+ if(iter == m_entries.end())
+ return;
+
+ auto entry = new BarEntry();
+ entry->qAction = insertWidget((*(iter+1))->qAction, new ActionButton(action, this));
+ entry->wideAction = action;
+ entry->type = BarEntry::Action;
+ m_entries.insert(iter + 1, entry);
+}
+
void WideBar::insertSpacer(QAction* action)
{
- auto iter = std::find_if(m_entries.begin(), m_entries.end(), [action](BarEntry * entry) {
- return entry->wideAction == action;
- });
- if(iter == m_entries.end()) {
+ auto iter = getMatching(action);
+ if(iter == m_entries.end())
return;
- }
+
QWidget* spacer = new QWidget();
spacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
@@ -107,6 +124,18 @@ void WideBar::insertSpacer(QAction* action)
m_entries.insert(iter, entry);
}
+void WideBar::insertSeparator(QAction* before)
+{
+ auto iter = getMatching(before);
+ if(iter == m_entries.end())
+ return;
+
+ auto entry = new BarEntry();
+ entry->qAction = QToolBar::insertSeparator(before);
+ entry->type = BarEntry::Separator;
+ m_entries.insert(iter, entry);
+}
+
QMenu * WideBar::createContextMenu(QWidget *parent, const QString & title)
{
QMenu *contextMenu = new QMenu(title, parent);
diff --git a/launcher/ui/widgets/WideBar.h b/launcher/ui/widgets/WideBar.h
index 2b676a8c..8ff62ef2 100644
--- a/launcher/ui/widgets/WideBar.h
+++ b/launcher/ui/widgets/WideBar.h
@@ -1,27 +1,34 @@
#pragma once
-#include <QToolBar>
#include <QAction>
#include <QMap>
+#include <QToolBar>
class QMenu;
-class WideBar : public QToolBar
-{
+class WideBar : public QToolBar {
Q_OBJECT
-public:
- explicit WideBar(const QString &title, QWidget * parent = nullptr);
- explicit WideBar(QWidget * parent = nullptr);
+ public:
+ explicit WideBar(const QString& title, QWidget* parent = nullptr);
+ explicit WideBar(QWidget* parent = nullptr);
virtual ~WideBar();
- void addAction(QAction *action);
+ void addAction(QAction* action);
void addSeparator();
- void insertSpacer(QAction *action);
- void insertActionBefore(QAction *before, QAction *action);
- QMenu *createContextMenu(QWidget *parent = nullptr, const QString & title = QString());
-private:
+ void insertSpacer(QAction* action);
+ void insertSeparator(QAction* before);
+ void insertActionBefore(QAction* before, QAction* action);
+ void insertActionAfter(QAction* after, QAction* action);
+
+ QMenu* createContextMenu(QWidget* parent = nullptr, const QString& title = QString());
+
+ private:
struct BarEntry;
- QList<BarEntry *> m_entries;
+
+ auto getMatching(QAction* act) -> QList<BarEntry*>::iterator;
+
+ private:
+ QList<BarEntry*> m_entries;
};