From 5d14dede508bd67d2e1777ebd77aaa386314a0aa Mon Sep 17 00:00:00 2001 From: arthomnix Date: Sun, 3 Jul 2022 07:54:20 +0100 Subject: [PATCH 01/28] NOISSUE WIP implementation of the ability to create instance shortcuts Currently Linux-only and lacking some features --- launcher/CMakeLists.txt | 4 +- launcher/ui/MainWindow.cpp | 28 +- launcher/ui/MainWindow.h | 4 + launcher/ui/dialogs/CreateShortcutDialog.cpp | 117 ++++++++ launcher/ui/dialogs/CreateShortcutDialog.h | 40 +++ launcher/ui/dialogs/CreateShortcutDialog.ui | 275 +++++++++++++++++++ 6 files changed, 464 insertions(+), 4 deletions(-) create mode 100644 launcher/ui/dialogs/CreateShortcutDialog.cpp create mode 100644 launcher/ui/dialogs/CreateShortcutDialog.h create mode 100644 launcher/ui/dialogs/CreateShortcutDialog.ui diff --git a/launcher/CMakeLists.txt b/launcher/CMakeLists.txt index 2f72e0d3..bc0cce66 100644 --- a/launcher/CMakeLists.txt +++ b/launcher/CMakeLists.txt @@ -778,7 +778,8 @@ SET(LAUNCHER_SOURCES ui/dialogs/VersionSelectDialog.h ui/dialogs/SkinUploadDialog.cpp ui/dialogs/SkinUploadDialog.h - + ui/dialogs/CreateShortcutDialog.cpp + ui/dialogs/CreateShortcutDialog.h # GUI - widgets ui/widgets/Common.cpp @@ -876,6 +877,7 @@ qt5_wrap_ui(LAUNCHER_UI ui/dialogs/AboutDialog.ui ui/dialogs/LoginDialog.ui ui/dialogs/EditAccountDialog.ui + ui/dialogs/CreateShortcutDialog.ui ) qt5_add_resources(LAUNCHER_RESOURCES diff --git a/launcher/ui/MainWindow.cpp b/launcher/ui/MainWindow.cpp index c0ba8839..bbdfb043 100644 --- a/launcher/ui/MainWindow.cpp +++ b/launcher/ui/MainWindow.cpp @@ -83,14 +83,15 @@ #include "ui/dialogs/UpdateDialog.h" #include "ui/dialogs/EditAccountDialog.h" #include "ui/dialogs/NotificationDialog.h" +#include "ui/dialogs/CreateShortcutDialog.h" + #include "ui/dialogs/ExportInstanceDialog.h" - #include "UpdateController.h" + #include "KonamiCode.h" - #include "InstanceImportTask.h" -#include "InstanceCopyTask.h" +#include "InstanceCopyTask.h" #include "MMCTime.h" namespace { @@ -222,6 +223,9 @@ public: TranslatedAction actionLaunchInstanceOffline; TranslatedAction actionScreenshots; TranslatedAction actionExportInstance; +#if defined(Q_OS_LINUX) // currently only implemented for linux; TODO: other OS implementations + TranslatedAction actionCreateShortcut; +#endif QVector all_actions; LabeledToolButton *renameButton = nullptr; @@ -594,6 +598,15 @@ public: instanceToolBar->addSeparator(); +#if defined(Q_OS_LINUX) + actionCreateShortcut = TranslatedAction(MainWindow); + actionCreateShortcut->setObjectName(QStringLiteral("actionCreateShortcut")); + actionCreateShortcut.setTextId(QT_TRANSLATE_NOOP("MainWindow", "Create Shortcut")); + actionCreateShortcut.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "Create a shortcut that launches the selected instance")); + all_actions.append(&actionCreateShortcut); + instanceToolBar->addAction(actionCreateShortcut); +#endif + actionExportInstance = TranslatedAction(MainWindow); actionExportInstance->setObjectName(QStringLiteral("actionExportInstance")); actionExportInstance.setTextId(QT_TRANSLATE_NOOP("MainWindow", "Export Instance")); @@ -1844,6 +1857,15 @@ void MainWindow::on_actionLaunchInstance_triggered() } } +#if defined(Q_OS_LINUX) +void MainWindow::on_actionCreateShortcut_triggered() { + if (m_selectedInstance) + { + CreateShortcutDialog(this, m_selectedInstance).exec(); + } +} +#endif + void MainWindow::activateInstance(InstancePtr instance) { APPLICATION->launch(instance); diff --git a/launcher/ui/MainWindow.h b/launcher/ui/MainWindow.h index e462c524..24d9fee0 100644 --- a/launcher/ui/MainWindow.h +++ b/launcher/ui/MainWindow.h @@ -141,6 +141,10 @@ private slots: void on_actionScreenshots_triggered(); +#if defined(Q_OS_LINUX) + void on_actionCreateShortcut_triggered(); +#endif + void taskEnd(); /** diff --git a/launcher/ui/dialogs/CreateShortcutDialog.cpp b/launcher/ui/dialogs/CreateShortcutDialog.cpp new file mode 100644 index 00000000..71b3c96b --- /dev/null +++ b/launcher/ui/dialogs/CreateShortcutDialog.cpp @@ -0,0 +1,117 @@ +/* + * Copyright 2022 arthomnix + * + * This source is subject to the Microsoft Public License (MS-PL). + * Please see the COPYING.md file for more information. + */ + +#include +#include +#include +#include +#include "CreateShortcutDialog.h" +#include "ui_CreateShortcutDialog.h" +#include "Application.h" +#include "minecraft/auth/AccountList.h" +#include "icons/IconList.h" + +CreateShortcutDialog::CreateShortcutDialog(QWidget *parent, InstancePtr instance) + :QDialog(parent), ui(new Ui::CreateShortcutDialog), m_instance(instance) +{ + ui->setupUi(this); + + QStringList accountNameList; + auto accounts = APPLICATION->accounts(); + + for (int i = 0; i < accounts->count(); i++) + { + accountNameList.append(accounts->at(i)->profileName()); + } + + ui->profileComboBox->addItems(accountNameList); + + if (accounts->defaultAccount()) + { + ui->profileComboBox->setCurrentText(accounts->defaultAccount()->profileName()); + } + + updateDialogState(); +} + +CreateShortcutDialog::~CreateShortcutDialog() +{ + delete ui; +} + +void CreateShortcutDialog::on_shortcutPathBrowse_clicked() +{ + QString linkExtension; +#ifdef Q_OS_LINUX + linkExtension = "desktop"; +#endif +#ifdef Q_OS_WIN + linkExtension = "lnk"; +#endif + QFileDialog fileDialog(this, tr("Select shortcut path"), QStandardPaths::writableLocation(QStandardPaths::DesktopLocation)); + fileDialog.setDefaultSuffix(linkExtension); + fileDialog.setAcceptMode(QFileDialog::AcceptOpen); + fileDialog.setFileMode(QFileDialog::AnyFile); + if (fileDialog.exec()) + { + ui->shortcutPath->setText(fileDialog.selectedFiles().at(0)); + } + updateDialogState(); +} + +void CreateShortcutDialog::accept() +{ + createShortcut(); + QDialog::accept(); +} + + +void CreateShortcutDialog::updateDialogState() +{ + + ui->buttonBox->button(QDialogButtonBox::StandardButton::Ok)->setEnabled( + !ui->shortcutPath->text().isEmpty() + && (!ui->joinServerCheckBox->isChecked() || !ui->joinServer->text().isEmpty()) + && (!ui->offlineUsernameCheckBox->isChecked() || !ui->offlineUsername->text().isEmpty()) + && (!ui->useProfileCheckBox->isChecked() || !ui->profileComboBox->currentText().isEmpty()) + ); + ui->joinServer->setEnabled(ui->joinServerCheckBox->isChecked()); + ui->profileComboBox->setEnabled(ui->useProfileCheckBox->isChecked()); + ui->offlineUsernameCheckBox->setEnabled(ui->launchOfflineCheckBox->isChecked()); + ui->offlineUsername->setEnabled(ui->launchOfflineCheckBox->isChecked() && ui->offlineUsernameCheckBox->isChecked()); +} + +QString CreateShortcutDialog::getLaunchCommand() +{ + return QCoreApplication::applicationFilePath() + + " -l " + m_instance->id() + + (ui->joinServerCheckBox->isChecked() ? " -s " + ui->joinServer->text() : "") + + (ui->useProfileCheckBox->isChecked() ? " -a " + ui->profileComboBox->currentText() : "") + + (ui->launchOfflineCheckBox->isChecked() ? " -o" : "") + + (ui->offlineUsernameCheckBox->isChecked() ? " -n " + ui->offlineUsername->text() : ""); +} + +void CreateShortcutDialog::createShortcut() +{ + // Linux implementation using .desktop file +#ifdef Q_OS_LINUX + QFile desktopFile(ui->shortcutPath->text()); + if (desktopFile.open(QIODevice::WriteOnly)) + { + QTextStream stream(&desktopFile); + qDebug() << m_instance->iconKey(); + stream << "[Desktop Entry]" << endl + << "Type=Application" << endl + << "Name=" << m_instance->name() << " - " << BuildConfig.LAUNCHER_DISPLAYNAME << endl + << "Exec=" << getLaunchCommand() << endl; + desktopFile.setPermissions(QFile::ReadOwner | QFile::ReadGroup | QFile::ReadOther + | QFile::WriteOwner | QFile::ExeOwner | QFile::ExeGroup); + desktopFile.close(); + } +#endif + // TODO: implementations for other operating systems +} \ No newline at end of file diff --git a/launcher/ui/dialogs/CreateShortcutDialog.h b/launcher/ui/dialogs/CreateShortcutDialog.h new file mode 100644 index 00000000..4725fc5e --- /dev/null +++ b/launcher/ui/dialogs/CreateShortcutDialog.h @@ -0,0 +1,40 @@ +/* + * Copyright 2022 arthomnix + * + * This source is subject to the Microsoft Public License (MS-PL). + * Please see the COPYING.md file for more information. + */ + +#pragma once + +#include +#include "minecraft/auth/MinecraftAccount.h" +#include "BaseInstance.h" + +namespace Ui +{ + class CreateShortcutDialog; +} + +class CreateShortcutDialog : public QDialog +{ + Q_OBJECT + +public: + explicit CreateShortcutDialog(QWidget *parent = nullptr, InstancePtr instance = nullptr); + ~CreateShortcutDialog() override; + +private +slots: + void on_shortcutPathBrowse_clicked(); + void updateDialogState(); + void accept() override; + +private: + Ui::CreateShortcutDialog *ui; + InstancePtr m_instance; + + QString getLaunchCommand(); + + void createShortcut(); +}; \ No newline at end of file diff --git a/launcher/ui/dialogs/CreateShortcutDialog.ui b/launcher/ui/dialogs/CreateShortcutDialog.ui new file mode 100644 index 00000000..b3e17d12 --- /dev/null +++ b/launcher/ui/dialogs/CreateShortcutDialog.ui @@ -0,0 +1,275 @@ + + + + CreateShortcutDialog + + + + 0 + 0 + 796 + 230 + + + + + 796 + 230 + + + + Create Shortcut + + + + + + QLayout::SetDefaultConstraint + + + + + Join server on launch: + + + + + + + Shortcut path: + + + + + + + + + + + + + Launch in offline mode + + + + + + + + + + Browse + + + + + + + Use specific profile: + + + + + + + + + + Set offline mode username: + + + + + + + + + Qt::Vertical + + + + 0 + 0 + + + + + + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + buttonBox + accepted() + CreateShortcutDialog + accept() + + + 397 + 207 + + + 397 + 114 + + + + + buttonBox + rejected() + CreateShortcutDialog + reject() + + + 397 + 207 + + + 397 + 114 + + + + + joinServer + textChanged(QString) + CreateShortcutDialog + updateDialogState() + + + 471 + 61 + + + 397 + 114 + + + + + joinServerCheckBox + stateChanged(int) + CreateShortcutDialog + updateDialogState() + + + 122 + 61 + + + 397 + 114 + + + + + launchOfflineCheckBox + stateChanged(int) + CreateShortcutDialog + updateDialogState() + + + 122 + 130 + + + 397 + 114 + + + + + offlineUsername + textChanged(QString) + CreateShortcutDialog + updateDialogState() + + + 471 + 162 + + + 397 + 114 + + + + + offlineUsernameCheckBox + stateChanged(int) + CreateShortcutDialog + updateDialogState() + + + 122 + 162 + + + 397 + 114 + + + + + profileComboBox + currentTextChanged(QString) + CreateShortcutDialog + updateDialogState() + + + 471 + 98 + + + 397 + 114 + + + + + shortcutPath + textChanged(QString) + CreateShortcutDialog + updateDialogState() + + + 471 + 23 + + + 397 + 114 + + + + + useProfileCheckBox + stateChanged(int) + CreateShortcutDialog + updateDialogState() + + + 122 + 98 + + + 397 + 114 + + + + + From b326fef61b628d89b0c508e9435d3dac8d1c9a7d Mon Sep 17 00:00:00 2001 From: arthomnix Date: Sun, 3 Jul 2022 07:56:25 +0100 Subject: [PATCH 02/28] NOISSUE fix arrangement of includes --- launcher/ui/MainWindow.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/launcher/ui/MainWindow.cpp b/launcher/ui/MainWindow.cpp index bbdfb043..c7604759 100644 --- a/launcher/ui/MainWindow.cpp +++ b/launcher/ui/MainWindow.cpp @@ -84,13 +84,12 @@ #include "ui/dialogs/EditAccountDialog.h" #include "ui/dialogs/NotificationDialog.h" #include "ui/dialogs/CreateShortcutDialog.h" - #include "ui/dialogs/ExportInstanceDialog.h" + #include "UpdateController.h" - #include "KonamiCode.h" -#include "InstanceImportTask.h" +#include "InstanceImportTask.h" #include "InstanceCopyTask.h" #include "MMCTime.h" From 6c31125f02012ac2bc8989fb4f6b7884ae7858fb Mon Sep 17 00:00:00 2001 From: arthomnix Date: Sun, 3 Jul 2022 07:57:15 +0100 Subject: [PATCH 03/28] NOISSUE fix arrangement of includes again --- launcher/ui/MainWindow.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/launcher/ui/MainWindow.cpp b/launcher/ui/MainWindow.cpp index c7604759..343d35e1 100644 --- a/launcher/ui/MainWindow.cpp +++ b/launcher/ui/MainWindow.cpp @@ -91,6 +91,7 @@ #include "InstanceImportTask.h" #include "InstanceCopyTask.h" + #include "MMCTime.h" namespace { From a0c44f706203758f75b299e79e4ec677b6dc302c Mon Sep 17 00:00:00 2001 From: arthomnix Date: Sun, 3 Jul 2022 08:27:13 +0100 Subject: [PATCH 04/28] NOISSUE shortcut creation: add icons on linux --- launcher/ui/dialogs/CreateShortcutDialog.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/launcher/ui/dialogs/CreateShortcutDialog.cpp b/launcher/ui/dialogs/CreateShortcutDialog.cpp index 71b3c96b..7e816b0f 100644 --- a/launcher/ui/dialogs/CreateShortcutDialog.cpp +++ b/launcher/ui/dialogs/CreateShortcutDialog.cpp @@ -99,6 +99,13 @@ void CreateShortcutDialog::createShortcut() { // Linux implementation using .desktop file #ifdef Q_OS_LINUX + // save the launcher icon to a file so we can use it in the shortcut + if (!QFileInfo::exists(QCoreApplication::applicationDirPath() + "/shortcut-icon.png")) + { + QPixmap iconPixmap = QIcon(":/logo.svg").pixmap(64, 64); + iconPixmap.save(QCoreApplication::applicationDirPath() + "/shortcut-icon.png"); + } + QFile desktopFile(ui->shortcutPath->text()); if (desktopFile.open(QIODevice::WriteOnly)) { @@ -107,7 +114,8 @@ void CreateShortcutDialog::createShortcut() stream << "[Desktop Entry]" << endl << "Type=Application" << endl << "Name=" << m_instance->name() << " - " << BuildConfig.LAUNCHER_DISPLAYNAME << endl - << "Exec=" << getLaunchCommand() << endl; + << "Exec=" << getLaunchCommand() << endl + << "Icon=" << QCoreApplication::applicationDirPath() << "/shortcut-icon.png" << endl; desktopFile.setPermissions(QFile::ReadOwner | QFile::ReadGroup | QFile::ReadOther | QFile::WriteOwner | QFile::ExeOwner | QFile::ExeGroup); desktopFile.close(); From 645bc3f4458107c61e10fd64266d3c23002b3a58 Mon Sep 17 00:00:00 2001 From: arthomnix Date: Sun, 3 Jul 2022 08:33:46 +0100 Subject: [PATCH 05/28] NOISSUE shortcut creation: set default shortcut filename --- launcher/ui/dialogs/CreateShortcutDialog.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/launcher/ui/dialogs/CreateShortcutDialog.cpp b/launcher/ui/dialogs/CreateShortcutDialog.cpp index 7e816b0f..011b67fd 100644 --- a/launcher/ui/dialogs/CreateShortcutDialog.cpp +++ b/launcher/ui/dialogs/CreateShortcutDialog.cpp @@ -56,6 +56,7 @@ void CreateShortcutDialog::on_shortcutPathBrowse_clicked() fileDialog.setDefaultSuffix(linkExtension); fileDialog.setAcceptMode(QFileDialog::AcceptOpen); fileDialog.setFileMode(QFileDialog::AnyFile); + fileDialog.selectFile(m_instance->id() + "." + linkExtension); if (fileDialog.exec()) { ui->shortcutPath->setText(fileDialog.selectedFiles().at(0)); From 6a3ff58c8c641a232697b93b387be657e2fa2d07 Mon Sep 17 00:00:00 2001 From: arthomnix Date: Sun, 3 Jul 2022 09:52:56 +0100 Subject: [PATCH 06/28] NOISSUE shortcut creation: add option to create launch scripts This allows shortcuts to be created on Macs (which don't have a concept of desktop shortcuts) as well as Linux systems that don't support the desktop file specification. Also included a windows batch file implementation. --- launcher/ui/MainWindow.cpp | 6 -- launcher/ui/MainWindow.h | 2 - launcher/ui/dialogs/CreateShortcutDialog.cpp | 81 ++++++++++++------ launcher/ui/dialogs/CreateShortcutDialog.ui | 86 +++++++++++--------- 4 files changed, 104 insertions(+), 71 deletions(-) diff --git a/launcher/ui/MainWindow.cpp b/launcher/ui/MainWindow.cpp index 343d35e1..139ca780 100644 --- a/launcher/ui/MainWindow.cpp +++ b/launcher/ui/MainWindow.cpp @@ -223,9 +223,7 @@ public: TranslatedAction actionLaunchInstanceOffline; TranslatedAction actionScreenshots; TranslatedAction actionExportInstance; -#if defined(Q_OS_LINUX) // currently only implemented for linux; TODO: other OS implementations TranslatedAction actionCreateShortcut; -#endif QVector all_actions; LabeledToolButton *renameButton = nullptr; @@ -598,14 +596,12 @@ public: instanceToolBar->addSeparator(); -#if defined(Q_OS_LINUX) actionCreateShortcut = TranslatedAction(MainWindow); actionCreateShortcut->setObjectName(QStringLiteral("actionCreateShortcut")); actionCreateShortcut.setTextId(QT_TRANSLATE_NOOP("MainWindow", "Create Shortcut")); actionCreateShortcut.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "Create a shortcut that launches the selected instance")); all_actions.append(&actionCreateShortcut); instanceToolBar->addAction(actionCreateShortcut); -#endif actionExportInstance = TranslatedAction(MainWindow); actionExportInstance->setObjectName(QStringLiteral("actionExportInstance")); @@ -1857,14 +1853,12 @@ void MainWindow::on_actionLaunchInstance_triggered() } } -#if defined(Q_OS_LINUX) void MainWindow::on_actionCreateShortcut_triggered() { if (m_selectedInstance) { CreateShortcutDialog(this, m_selectedInstance).exec(); } } -#endif void MainWindow::activateInstance(InstancePtr instance) { diff --git a/launcher/ui/MainWindow.h b/launcher/ui/MainWindow.h index 24d9fee0..685adba9 100644 --- a/launcher/ui/MainWindow.h +++ b/launcher/ui/MainWindow.h @@ -141,9 +141,7 @@ private slots: void on_actionScreenshots_triggered(); -#if defined(Q_OS_LINUX) void on_actionCreateShortcut_triggered(); -#endif void taskEnd(); diff --git a/launcher/ui/dialogs/CreateShortcutDialog.cpp b/launcher/ui/dialogs/CreateShortcutDialog.cpp index 011b67fd..2c260514 100644 --- a/launcher/ui/dialogs/CreateShortcutDialog.cpp +++ b/launcher/ui/dialogs/CreateShortcutDialog.cpp @@ -35,6 +35,11 @@ CreateShortcutDialog::CreateShortcutDialog(QWidget *parent, InstancePtr instance ui->profileComboBox->setCurrentText(accounts->defaultAccount()->profileName()); } +#if defined(Q_OS_WIN) || (defined(Q_OS_UNIX) && !defined(Q_OS_LINUX)) + ui->createScriptCheckBox->setEnabled(false); + ui->createScriptCheckBox->setChecked(true); +#endif + updateDialogState(); } @@ -46,11 +51,11 @@ CreateShortcutDialog::~CreateShortcutDialog() void CreateShortcutDialog::on_shortcutPathBrowse_clicked() { QString linkExtension; -#ifdef Q_OS_LINUX - linkExtension = "desktop"; +#ifdef Q_OS_UNIX + linkExtension = ui->createScriptCheckBox->isChecked() ? "sh" : "desktop"; #endif #ifdef Q_OS_WIN - linkExtension = "lnk"; + linkExtension = ui->createScriptCheckBox->isChecked() ? "bat" : "lnk"; #endif QFileDialog fileDialog(this, tr("Select shortcut path"), QStandardPaths::writableLocation(QStandardPaths::DesktopLocation)); fileDialog.setDefaultSuffix(linkExtension); @@ -98,29 +103,57 @@ QString CreateShortcutDialog::getLaunchCommand() void CreateShortcutDialog::createShortcut() { - // Linux implementation using .desktop file -#ifdef Q_OS_LINUX - // save the launcher icon to a file so we can use it in the shortcut - if (!QFileInfo::exists(QCoreApplication::applicationDirPath() + "/shortcut-icon.png")) +#ifdef Q_OS_WIN + if (ui->createScriptCheckBox->isChecked()) // on windows, creating .lnk shortcuts requires specific win32 api stuff + // rather than just writing a text file { - QPixmap iconPixmap = QIcon(":/logo.svg").pixmap(64, 64); - iconPixmap.save(QCoreApplication::applicationDirPath() + "/shortcut-icon.png"); - } +#endif + QString shortcutText; +#ifdef Q_OS_UNIX + // Unix shell script + if (ui->createScriptCheckBox->isChecked()) + { + shortcutText = "#!/bin/sh\n" + getLaunchCommand() + " &\n"; + } else + // freedesktop.org desktop entry + { + // save the launcher icon to a file so we can use it in the shortcut + if (!QFileInfo::exists(QCoreApplication::applicationDirPath() + "/shortcut-icon.png")) + { + QPixmap iconPixmap = QIcon(":/logo.svg").pixmap(64, 64); + iconPixmap.save(QCoreApplication::applicationDirPath() + "/shortcut-icon.png"); + } - QFile desktopFile(ui->shortcutPath->text()); - if (desktopFile.open(QIODevice::WriteOnly)) - { - QTextStream stream(&desktopFile); - qDebug() << m_instance->iconKey(); - stream << "[Desktop Entry]" << endl - << "Type=Application" << endl - << "Name=" << m_instance->name() << " - " << BuildConfig.LAUNCHER_DISPLAYNAME << endl - << "Exec=" << getLaunchCommand() << endl - << "Icon=" << QCoreApplication::applicationDirPath() << "/shortcut-icon.png" << endl; - desktopFile.setPermissions(QFile::ReadOwner | QFile::ReadGroup | QFile::ReadOther - | QFile::WriteOwner | QFile::ExeOwner | QFile::ExeGroup); - desktopFile.close(); + shortcutText = "[Desktop Entry]\n" + "Type=Application\n" + "Name=" + m_instance->name() + " - " + BuildConfig.LAUNCHER_DISPLAYNAME + "\n" + + "Exec=" + getLaunchCommand() + "\n" + + "Icon=" + QCoreApplication::applicationDirPath() + "/shortcut-icon.png\n"; + + } +#endif +#ifdef Q_OS_WIN + // Windows batch script implementation + if (ui->createScriptCheckBox->isChecked()) + { + shortcutText = "@ECHO OFF\r\n" + "START /B " + getLaunchCommand() + "\r\n"; + } + else + { + // TODO: windows .lnk implementation + } +#endif + QFile shortcutFile(ui->shortcutPath->text()); + if (shortcutFile.open(QIODevice::WriteOnly)) + { + QTextStream stream(&shortcutFile); + stream << shortcutText; + shortcutFile.setPermissions(QFile::ReadOwner | QFile::ReadGroup | QFile::ReadOther + | QFile::WriteOwner | QFile::ExeOwner | QFile::ExeGroup); + shortcutFile.close(); + } +#ifdef Q_OS_WIN } #endif - // TODO: implementations for other operating systems } \ No newline at end of file diff --git a/launcher/ui/dialogs/CreateShortcutDialog.ui b/launcher/ui/dialogs/CreateShortcutDialog.ui index b3e17d12..c8d1cc87 100644 --- a/launcher/ui/dialogs/CreateShortcutDialog.ui +++ b/launcher/ui/dialogs/CreateShortcutDialog.ui @@ -1,10 +1,4 @@ - CreateShortcutDialog @@ -13,7 +7,7 @@ 0 0 796 - 230 + 232 @@ -31,10 +25,10 @@ QLayout::SetDefaultConstraint - - + + - Join server on launch: + Launch in offline mode @@ -45,22 +39,6 @@ - - - - - - - - - - Launch in offline mode - - - - - - @@ -68,6 +46,29 @@ + + + + + + + + + + + + + Set offline mode username: + + + + + + + Join server on launch: + + + @@ -75,15 +76,8 @@ - - - - - - - Set offline mode username: - - + + @@ -101,11 +95,25 @@ - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + 0 - + + + + Create script instead of shortcut + + + + + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + From 21413b964aa1c0b43b4238af02836ed01c374982 Mon Sep 17 00:00:00 2001 From: arthomnix Date: Sun, 3 Jul 2022 09:56:16 +0100 Subject: [PATCH 07/28] NOISSUE replace copyright header that got removed by qt designer --- launcher/ui/dialogs/CreateShortcutDialog.ui | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/launcher/ui/dialogs/CreateShortcutDialog.ui b/launcher/ui/dialogs/CreateShortcutDialog.ui index c8d1cc87..568bf0a6 100644 --- a/launcher/ui/dialogs/CreateShortcutDialog.ui +++ b/launcher/ui/dialogs/CreateShortcutDialog.ui @@ -1,4 +1,9 @@ + CreateShortcutDialog From 018e6229ca47c81a59b0e74c7e31182d171d0e87 Mon Sep 17 00:00:00 2001 From: arthomnix Date: Sun, 3 Jul 2022 13:07:21 +0100 Subject: [PATCH 08/28] NOISSUE shortcut creation: add windows .lnk support --- launcher/ui/dialogs/CreateShortcutDialog.cpp | 93 +++++++++++++++----- launcher/ui/dialogs/CreateShortcutDialog.h | 9 ++ 2 files changed, 79 insertions(+), 23 deletions(-) diff --git a/launcher/ui/dialogs/CreateShortcutDialog.cpp b/launcher/ui/dialogs/CreateShortcutDialog.cpp index 2c260514..c1b0db08 100644 --- a/launcher/ui/dialogs/CreateShortcutDialog.cpp +++ b/launcher/ui/dialogs/CreateShortcutDialog.cpp @@ -5,8 +5,6 @@ * Please see the COPYING.md file for more information. */ -#include -#include #include #include #include "CreateShortcutDialog.h" @@ -15,6 +13,11 @@ #include "minecraft/auth/AccountList.h" #include "icons/IconList.h" +#ifdef Q_OS_WIN +#include +#include +#endif + CreateShortcutDialog::CreateShortcutDialog(QWidget *parent, InstancePtr instance) :QDialog(parent), ui(new Ui::CreateShortcutDialog), m_instance(instance) { @@ -35,7 +38,7 @@ CreateShortcutDialog::CreateShortcutDialog(QWidget *parent, InstancePtr instance ui->profileComboBox->setCurrentText(accounts->defaultAccount()->profileName()); } -#if defined(Q_OS_WIN) || (defined(Q_OS_UNIX) && !defined(Q_OS_LINUX)) +#if defined(Q_OS_UNIX) && !defined(Q_OS_LINUX) ui->createScriptCheckBox->setEnabled(false); ui->createScriptCheckBox->setChecked(true); #endif @@ -61,7 +64,7 @@ void CreateShortcutDialog::on_shortcutPathBrowse_clicked() fileDialog.setDefaultSuffix(linkExtension); fileDialog.setAcceptMode(QFileDialog::AcceptOpen); fileDialog.setFileMode(QFileDialog::AnyFile); - fileDialog.selectFile(m_instance->id() + "." + linkExtension); + fileDialog.selectFile(m_instance->name() + " - " + BuildConfig.LAUNCHER_DISPLAYNAME + "." + linkExtension); if (fileDialog.exec()) { ui->shortcutPath->setText(fileDialog.selectedFiles().at(0)); @@ -93,12 +96,17 @@ void CreateShortcutDialog::updateDialogState() QString CreateShortcutDialog::getLaunchCommand() { - return QCoreApplication::applicationFilePath() - + " -l " + m_instance->id() - + (ui->joinServerCheckBox->isChecked() ? " -s " + ui->joinServer->text() : "") - + (ui->useProfileCheckBox->isChecked() ? " -a " + ui->profileComboBox->currentText() : "") - + (ui->launchOfflineCheckBox->isChecked() ? " -o" : "") - + (ui->offlineUsernameCheckBox->isChecked() ? " -n " + ui->offlineUsername->text() : ""); + return QDir::toNativeSeparators(QCoreApplication::applicationFilePath()) + + getLaunchArgs(); +} + +QString CreateShortcutDialog::getLaunchArgs() +{ + return " -l " + m_instance->id() + + (ui->joinServerCheckBox->isChecked() ? " -s " + ui->joinServer->text() : "") + + (ui->useProfileCheckBox->isChecked() ? " -a " + ui->profileComboBox->currentText() : "") + + (ui->launchOfflineCheckBox->isChecked() ? " -o" : "") + + (ui->offlineUsernameCheckBox->isChecked() ? " -n " + ui->offlineUsername->text() : ""); } void CreateShortcutDialog::createShortcut() @@ -118,31 +126,24 @@ void CreateShortcutDialog::createShortcut() // freedesktop.org desktop entry { // save the launcher icon to a file so we can use it in the shortcut - if (!QFileInfo::exists(QCoreApplication::applicationDirPath() + "/shortcut-icon.png")) + if (!QFileInfo::exists(QCoreApplication::applicationDirPath() + "/icons/shortcut-icon.png")) { QPixmap iconPixmap = QIcon(":/logo.svg").pixmap(64, 64); - iconPixmap.save(QCoreApplication::applicationDirPath() + "/shortcut-icon.png"); + iconPixmap.save(QCoreApplication::applicationDirPath() + "/icons/shortcut-icon.png"); } shortcutText = "[Desktop Entry]\n" "Type=Application\n" "Name=" + m_instance->name() + " - " + BuildConfig.LAUNCHER_DISPLAYNAME + "\n" + "Exec=" + getLaunchCommand() + "\n" - + "Icon=" + QCoreApplication::applicationDirPath() + "/shortcut-icon.png\n"; + + "Icon=" + QCoreApplication::applicationDirPath() + "/icons/shortcut-icon.png\n"; } #endif #ifdef Q_OS_WIN // Windows batch script implementation - if (ui->createScriptCheckBox->isChecked()) - { - shortcutText = "@ECHO OFF\r\n" - "START /B " + getLaunchCommand() + "\r\n"; - } - else - { - // TODO: windows .lnk implementation - } + shortcutText = "@ECHO OFF\r\n" + "START /B " + getLaunchCommand() + "\r\n"; #endif QFile shortcutFile(ui->shortcutPath->text()); if (shortcutFile.open(QIODevice::WriteOnly)) @@ -154,6 +155,52 @@ void CreateShortcutDialog::createShortcut() shortcutFile.close(); } #ifdef Q_OS_WIN + } else { + if (!QFileInfo::exists(QCoreApplication::applicationDirPath() + "/icons/shortcut-icon.ico")) + { + QPixmap iconPixmap = QIcon(":/logo.svg").pixmap(64, 64); + iconPixmap.save(QCoreApplication::applicationDirPath() + "/icons/shortcut-icon.ico"); + } + + createWindowsLink(QDir::toNativeSeparators(QCoreApplication::applicationFilePath()).toStdString().c_str(), + getLaunchArgs().toStdString().c_str(), + ui->shortcutPath->text().toStdString().c_str(), + (m_instance->name() + " - " + BuildConfig.LAUNCHER_DISPLAYNAME).toStdString().c_str(), + QDir::toNativeSeparators(QCoreApplication::applicationDirPath() + "/icons/shortcut-icon.ico").toStdString().c_str() + ); } #endif -} \ No newline at end of file +} + +#ifdef Q_OS_WIN +void CreateShortcutDialog::createWindowsLink(LPCSTR target, LPCSTR args, LPCSTR filename, LPCSTR desc, LPCSTR iconPath) +{ + HRESULT result; + IShellLink *link; + + CoInitialize(nullptr); + result = CoCreateInstance(CLSID_ShellLink, nullptr, CLSCTX_INPROC_SERVER, IID_IShellLink, (LPVOID *) &link); + if (SUCCEEDED(result)) + { + IPersistFile *file; + + link->SetPath(target); + link->SetArguments(args); + link->SetDescription(desc); + link->SetIconLocation(iconPath, 0); + + result = link->QueryInterface(IID_IPersistFile, (LPVOID *) &file); + + if (SUCCEEDED(result)) + { + WCHAR path[MAX_PATH]; + MultiByteToWideChar(CP_ACP, 0, filename, -1, path, MAX_PATH); + + file->Save(path, TRUE); + file->Release(); + } + link->Release(); + } + CoUninitialize(); +} +#endif \ No newline at end of file diff --git a/launcher/ui/dialogs/CreateShortcutDialog.h b/launcher/ui/dialogs/CreateShortcutDialog.h index 4725fc5e..d28a6b0c 100644 --- a/launcher/ui/dialogs/CreateShortcutDialog.h +++ b/launcher/ui/dialogs/CreateShortcutDialog.h @@ -11,6 +11,10 @@ #include "minecraft/auth/MinecraftAccount.h" #include "BaseInstance.h" +#ifdef Q_OS_WIN +#include +#endif + namespace Ui { class CreateShortcutDialog; @@ -35,6 +39,11 @@ private: InstancePtr m_instance; QString getLaunchCommand(); + QString getLaunchArgs(); void createShortcut(); + +#ifdef Q_OS_WIN + void createWindowsLink(LPCSTR target, LPCSTR args, LPCSTR filename, LPCSTR desc, LPCSTR iconPath); +#endif }; \ No newline at end of file From bf5be5568ec40e494eb49aa8c2da2e93fa1547e5 Mon Sep 17 00:00:00 2001 From: arthomnix Date: Sun, 3 Jul 2022 13:17:25 +0100 Subject: [PATCH 09/28] NOISSUE curly brace formatting --- launcher/ui/dialogs/CreateShortcutDialog.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/launcher/ui/dialogs/CreateShortcutDialog.cpp b/launcher/ui/dialogs/CreateShortcutDialog.cpp index c1b0db08..aa30661b 100644 --- a/launcher/ui/dialogs/CreateShortcutDialog.cpp +++ b/launcher/ui/dialogs/CreateShortcutDialog.cpp @@ -155,7 +155,9 @@ void CreateShortcutDialog::createShortcut() shortcutFile.close(); } #ifdef Q_OS_WIN - } else { + } + else + { if (!QFileInfo::exists(QCoreApplication::applicationDirPath() + "/icons/shortcut-icon.ico")) { QPixmap iconPixmap = QIcon(":/logo.svg").pixmap(64, 64); From 7217e3991ae9785fcbf3f6472da9663e6b148dd1 Mon Sep 17 00:00:00 2001 From: arthomnix Date: Sun, 3 Jul 2022 13:45:58 +0100 Subject: [PATCH 10/28] NOISSUE shortcut support: set working directory in .desktop files --- launcher/ui/dialogs/CreateShortcutDialog.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/launcher/ui/dialogs/CreateShortcutDialog.cpp b/launcher/ui/dialogs/CreateShortcutDialog.cpp index aa30661b..21296cac 100644 --- a/launcher/ui/dialogs/CreateShortcutDialog.cpp +++ b/launcher/ui/dialogs/CreateShortcutDialog.cpp @@ -92,6 +92,10 @@ void CreateShortcutDialog::updateDialogState() ui->profileComboBox->setEnabled(ui->useProfileCheckBox->isChecked()); ui->offlineUsernameCheckBox->setEnabled(ui->launchOfflineCheckBox->isChecked()); ui->offlineUsername->setEnabled(ui->launchOfflineCheckBox->isChecked() && ui->offlineUsernameCheckBox->isChecked()); + if (!ui->launchOfflineCheckBox->isChecked()) + { + ui->offlineUsernameCheckBox->setChecked(false); + } } QString CreateShortcutDialog::getLaunchCommand() @@ -136,6 +140,7 @@ void CreateShortcutDialog::createShortcut() "Type=Application\n" "Name=" + m_instance->name() + " - " + BuildConfig.LAUNCHER_DISPLAYNAME + "\n" + "Exec=" + getLaunchCommand() + "\n" + + "Path=" + QCoreApplication::applicationDirPath() + "\n" + "Icon=" + QCoreApplication::applicationDirPath() + "/icons/shortcut-icon.png\n"; } From 75b87656049cbaaac8661a45741b92bd23a92c61 Mon Sep 17 00:00:00 2001 From: arthomnix Date: Sun, 3 Jul 2022 14:00:55 +0100 Subject: [PATCH 11/28] NOISSUE shortcut creation: set working directory in other shortcut types --- launcher/ui/dialogs/CreateShortcutDialog.cpp | 10 ++++++++-- launcher/ui/dialogs/CreateShortcutDialog.h | 2 +- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/launcher/ui/dialogs/CreateShortcutDialog.cpp b/launcher/ui/dialogs/CreateShortcutDialog.cpp index 21296cac..8d5aade2 100644 --- a/launcher/ui/dialogs/CreateShortcutDialog.cpp +++ b/launcher/ui/dialogs/CreateShortcutDialog.cpp @@ -125,7 +125,9 @@ void CreateShortcutDialog::createShortcut() // Unix shell script if (ui->createScriptCheckBox->isChecked()) { - shortcutText = "#!/bin/sh\n" + getLaunchCommand() + " &\n"; + shortcutText = "#!/bin/sh\n" + + "cd " + QCoreApplication::applicationDirPath() + "\n" + + getLaunchCommand() + " &\n"; } else // freedesktop.org desktop entry { @@ -148,6 +150,7 @@ void CreateShortcutDialog::createShortcut() #ifdef Q_OS_WIN // Windows batch script implementation shortcutText = "@ECHO OFF\r\n" + "CD " + QDir::toNativeSeparators(QCoreApplication::applicationDirPath()) + "\r\n" "START /B " + getLaunchCommand() + "\r\n"; #endif QFile shortcutFile(ui->shortcutPath->text()); @@ -170,6 +173,7 @@ void CreateShortcutDialog::createShortcut() } createWindowsLink(QDir::toNativeSeparators(QCoreApplication::applicationFilePath()).toStdString().c_str(), + QDir::toNativeSeparators(QCoreApplication::applicationFilePath()).toStdString().c_str(), getLaunchArgs().toStdString().c_str(), ui->shortcutPath->text().toStdString().c_str(), (m_instance->name() + " - " + BuildConfig.LAUNCHER_DISPLAYNAME).toStdString().c_str(), @@ -180,7 +184,8 @@ void CreateShortcutDialog::createShortcut() } #ifdef Q_OS_WIN -void CreateShortcutDialog::createWindowsLink(LPCSTR target, LPCSTR args, LPCSTR filename, LPCSTR desc, LPCSTR iconPath) +void CreateShortcutDialog::createWindowsLink(LPCSTR target, LPCSTR workingDir, LPCSTR args, LPCSTR filename, + LPCSTR desc, LPCSTR iconPath) { HRESULT result; IShellLink *link; @@ -192,6 +197,7 @@ void CreateShortcutDialog::createWindowsLink(LPCSTR target, LPCSTR args, LPCSTR IPersistFile *file; link->SetPath(target); + link->SetWorkingDirectory(workingDir); link->SetArguments(args); link->SetDescription(desc); link->SetIconLocation(iconPath, 0); diff --git a/launcher/ui/dialogs/CreateShortcutDialog.h b/launcher/ui/dialogs/CreateShortcutDialog.h index d28a6b0c..22e789e0 100644 --- a/launcher/ui/dialogs/CreateShortcutDialog.h +++ b/launcher/ui/dialogs/CreateShortcutDialog.h @@ -44,6 +44,6 @@ private: void createShortcut(); #ifdef Q_OS_WIN - void createWindowsLink(LPCSTR target, LPCSTR args, LPCSTR filename, LPCSTR desc, LPCSTR iconPath); + void createWindowsLink(LPCSTR target, LPCSTR workingDir, LPCSTR args, LPCSTR filename, LPCSTR desc, LPCSTR iconPath); #endif }; \ No newline at end of file From bbdbe47e72c62c15fc9357ab331b343f68fb7ef4 Mon Sep 17 00:00:00 2001 From: arthomnix Date: Sun, 3 Jul 2022 14:19:50 +0100 Subject: [PATCH 12/28] NOISSUE actually use the directory as the working directory --- launcher/ui/dialogs/CreateShortcutDialog.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/launcher/ui/dialogs/CreateShortcutDialog.cpp b/launcher/ui/dialogs/CreateShortcutDialog.cpp index 8d5aade2..1e57b142 100644 --- a/launcher/ui/dialogs/CreateShortcutDialog.cpp +++ b/launcher/ui/dialogs/CreateShortcutDialog.cpp @@ -173,7 +173,7 @@ void CreateShortcutDialog::createShortcut() } createWindowsLink(QDir::toNativeSeparators(QCoreApplication::applicationFilePath()).toStdString().c_str(), - QDir::toNativeSeparators(QCoreApplication::applicationFilePath()).toStdString().c_str(), + QDir::toNativeSeparators(QCoreApplication::applicationDirPath()).toStdString().c_str(), getLaunchArgs().toStdString().c_str(), ui->shortcutPath->text().toStdString().c_str(), (m_instance->name() + " - " + BuildConfig.LAUNCHER_DISPLAYNAME).toStdString().c_str(), From 7938585abba3c772916b46e488aeeaa9514163de Mon Sep 17 00:00:00 2001 From: arthomnix Date: Sun, 3 Jul 2022 15:47:26 +0100 Subject: [PATCH 13/28] NOISSUE shortcut creation: add version blacklist for joining server on launch These versions are known to crash when joining a server on launch (see MC-145102 and MC-228828) --- launcher/ui/dialogs/CreateShortcutDialog.cpp | 11 +++++++++++ launcher/ui/dialogs/CreateShortcutDialog.h | 16 ++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/launcher/ui/dialogs/CreateShortcutDialog.cpp b/launcher/ui/dialogs/CreateShortcutDialog.cpp index 1e57b142..63cc6a29 100644 --- a/launcher/ui/dialogs/CreateShortcutDialog.cpp +++ b/launcher/ui/dialogs/CreateShortcutDialog.cpp @@ -11,6 +11,8 @@ #include "ui_CreateShortcutDialog.h" #include "Application.h" #include "minecraft/auth/AccountList.h" +#include "minecraft/MinecraftInstance.h" +#include "minecraft/PackProfile.h" #include "icons/IconList.h" #ifdef Q_OS_WIN @@ -38,6 +40,15 @@ CreateShortcutDialog::CreateShortcutDialog(QWidget *parent, InstancePtr instance ui->profileComboBox->setCurrentText(accounts->defaultAccount()->profileName()); } + if (m_instance->typeName() == "Minecraft") + { + MinecraftInstancePtr minecraftInstance = qobject_pointer_cast(m_instance); + QString version = minecraftInstance->getPackProfile()->getComponentVersion("net.minecraft"); + bool enableJoinServer = QRegExp(JOIN_SERVER_DISALLOWED_VERSIONS).exactMatch(version); + ui->joinServerCheckBox->setEnabled(enableJoinServer); + ui->joinServer->setEnabled(enableJoinServer); + } + #if defined(Q_OS_UNIX) && !defined(Q_OS_LINUX) ui->createScriptCheckBox->setEnabled(false); ui->createScriptCheckBox->setChecked(true); diff --git a/launcher/ui/dialogs/CreateShortcutDialog.h b/launcher/ui/dialogs/CreateShortcutDialog.h index 22e789e0..8e6d961f 100644 --- a/launcher/ui/dialogs/CreateShortcutDialog.h +++ b/launcher/ui/dialogs/CreateShortcutDialog.h @@ -15,6 +15,22 @@ #include #endif +const QString JOIN_SERVER_DISALLOWED_VERSIONS( + "(19w0[89][a-z])" + "|(19w1[0-9][a-z])" + "|(1.14.?[1-4]?-pre[0-9])" + "|(1.14.?[1-4]?)" + "|(19w[34][0-9][a-z])" + "|(1.15.?[0-9]?-pre[0-9])" + "|(1.15.?[0-9]?)" + "|(20w[01][0-9][a-z])" + "|(20w20a)" + "|(21w[12][0-9][a-z])" + "|(1.17-pre[0-9])" + "|(1.17-rc[0-9])" + "|(1.17)" + ); + namespace Ui { class CreateShortcutDialog; From 2dc44b3ff52c1bd85a6954258db3e8cb9acb019e Mon Sep 17 00:00:00 2001 From: arthomnix Date: Sun, 3 Jul 2022 16:21:21 +0100 Subject: [PATCH 14/28] NOISSUE fix build --- launcher/ui/dialogs/CreateShortcutDialog.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/launcher/ui/dialogs/CreateShortcutDialog.cpp b/launcher/ui/dialogs/CreateShortcutDialog.cpp index 63cc6a29..50a584ce 100644 --- a/launcher/ui/dialogs/CreateShortcutDialog.cpp +++ b/launcher/ui/dialogs/CreateShortcutDialog.cpp @@ -137,7 +137,7 @@ void CreateShortcutDialog::createShortcut() if (ui->createScriptCheckBox->isChecked()) { shortcutText = "#!/bin/sh\n" - + "cd " + QCoreApplication::applicationDirPath() + "\n" + "cd " + QCoreApplication::applicationDirPath() + "\n" + getLaunchCommand() + " &\n"; } else // freedesktop.org desktop entry From 363588789ebc7a82bd6d9d3ecf77441c02d23686 Mon Sep 17 00:00:00 2001 From: arthomnix Date: Sun, 3 Jul 2022 16:30:30 +0100 Subject: [PATCH 15/28] NOISSUE shortcut creation: fix version check --- launcher/ui/dialogs/CreateShortcutDialog.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/launcher/ui/dialogs/CreateShortcutDialog.cpp b/launcher/ui/dialogs/CreateShortcutDialog.cpp index 50a584ce..3931e931 100644 --- a/launcher/ui/dialogs/CreateShortcutDialog.cpp +++ b/launcher/ui/dialogs/CreateShortcutDialog.cpp @@ -44,7 +44,7 @@ CreateShortcutDialog::CreateShortcutDialog(QWidget *parent, InstancePtr instance { MinecraftInstancePtr minecraftInstance = qobject_pointer_cast(m_instance); QString version = minecraftInstance->getPackProfile()->getComponentVersion("net.minecraft"); - bool enableJoinServer = QRegExp(JOIN_SERVER_DISALLOWED_VERSIONS).exactMatch(version); + bool enableJoinServer = !QRegExp(JOIN_SERVER_DISALLOWED_VERSIONS).exactMatch(version); ui->joinServerCheckBox->setEnabled(enableJoinServer); ui->joinServer->setEnabled(enableJoinServer); } From 6faa0ef7116e1ce71b3722dc8e0d1375616cfa56 Mon Sep 17 00:00:00 2001 From: arthomnix Date: Sun, 3 Jul 2022 16:43:23 +0100 Subject: [PATCH 16/28] NOISSUE shortcut creation: reload pack profile before checking version --- launcher/ui/dialogs/CreateShortcutDialog.cpp | 23 +++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/launcher/ui/dialogs/CreateShortcutDialog.cpp b/launcher/ui/dialogs/CreateShortcutDialog.cpp index 3931e931..fba8cdd7 100644 --- a/launcher/ui/dialogs/CreateShortcutDialog.cpp +++ b/launcher/ui/dialogs/CreateShortcutDialog.cpp @@ -7,6 +7,7 @@ #include #include +#include #include "CreateShortcutDialog.h" #include "ui_CreateShortcutDialog.h" #include "Application.h" @@ -42,11 +43,23 @@ CreateShortcutDialog::CreateShortcutDialog(QWidget *parent, InstancePtr instance if (m_instance->typeName() == "Minecraft") { - MinecraftInstancePtr minecraftInstance = qobject_pointer_cast(m_instance); - QString version = minecraftInstance->getPackProfile()->getComponentVersion("net.minecraft"); - bool enableJoinServer = !QRegExp(JOIN_SERVER_DISALLOWED_VERSIONS).exactMatch(version); - ui->joinServerCheckBox->setEnabled(enableJoinServer); - ui->joinServer->setEnabled(enableJoinServer); + try + { + MinecraftInstancePtr minecraftInstance = qobject_pointer_cast(m_instance); + minecraftInstance->getPackProfile()->reload(Net::Mode::Online); + QString version = minecraftInstance->getPackProfile()->getComponentVersion("net.minecraft"); + bool enableJoinServer = !QRegExp(JOIN_SERVER_DISALLOWED_VERSIONS).exactMatch(version); + ui->joinServerCheckBox->setEnabled(enableJoinServer); + ui->joinServer->setEnabled(enableJoinServer); + } + catch (const Exception &e) + { + QMessageBox::critical(this, tr("Error"), e.cause()); + } + catch (...) + { + QMessageBox::critical(this, tr("Error"), tr("Failed to load pack profile to check version!")); + } } #if defined(Q_OS_UNIX) && !defined(Q_OS_LINUX) From 7df413db1a791c876a38394c11c6ae15307b1975 Mon Sep 17 00:00:00 2001 From: arthomnix Date: Sun, 3 Jul 2022 16:57:20 +0100 Subject: [PATCH 17/28] NOISSUE shortcut creation: blacklist versions by date instead of regex --- launcher/ui/dialogs/CreateShortcutDialog.cpp | 6 ++++-- launcher/ui/dialogs/CreateShortcutDialog.h | 21 ++++++-------------- 2 files changed, 10 insertions(+), 17 deletions(-) diff --git a/launcher/ui/dialogs/CreateShortcutDialog.cpp b/launcher/ui/dialogs/CreateShortcutDialog.cpp index fba8cdd7..3dc91988 100644 --- a/launcher/ui/dialogs/CreateShortcutDialog.cpp +++ b/launcher/ui/dialogs/CreateShortcutDialog.cpp @@ -47,8 +47,10 @@ CreateShortcutDialog::CreateShortcutDialog(QWidget *parent, InstancePtr instance { MinecraftInstancePtr minecraftInstance = qobject_pointer_cast(m_instance); minecraftInstance->getPackProfile()->reload(Net::Mode::Online); - QString version = minecraftInstance->getPackProfile()->getComponentVersion("net.minecraft"); - bool enableJoinServer = !QRegExp(JOIN_SERVER_DISALLOWED_VERSIONS).exactMatch(version); + QDateTime versionDate = minecraftInstance->getPackProfile()->getComponent("net.minecraft")->getReleaseDateTime(); + bool enableJoinServer = (versionDate < MC_145102_START) + || (versionDate >= MC_145102_END && versionDate < MC_228828_START) + || (versionDate >= MC_228828_END); ui->joinServerCheckBox->setEnabled(enableJoinServer); ui->joinServer->setEnabled(enableJoinServer); } diff --git a/launcher/ui/dialogs/CreateShortcutDialog.h b/launcher/ui/dialogs/CreateShortcutDialog.h index 8e6d961f..d27e94cd 100644 --- a/launcher/ui/dialogs/CreateShortcutDialog.h +++ b/launcher/ui/dialogs/CreateShortcutDialog.h @@ -10,26 +10,17 @@ #include #include "minecraft/auth/MinecraftAccount.h" #include "BaseInstance.h" +#include "minecraft/ParseUtils.h" #ifdef Q_OS_WIN #include #endif -const QString JOIN_SERVER_DISALLOWED_VERSIONS( - "(19w0[89][a-z])" - "|(19w1[0-9][a-z])" - "|(1.14.?[1-4]?-pre[0-9])" - "|(1.14.?[1-4]?)" - "|(19w[34][0-9][a-z])" - "|(1.15.?[0-9]?-pre[0-9])" - "|(1.15.?[0-9]?)" - "|(20w[01][0-9][a-z])" - "|(20w20a)" - "|(21w[12][0-9][a-z])" - "|(1.17-pre[0-9])" - "|(1.17-rc[0-9])" - "|(1.17)" - ); +// Dates when the game was affected by bugs that crashed the game when using the option to join a server on startup +const QDateTime MC_145102_START = timeFromS3Time("2019-02-20T14:56:58+00:00"); +const QDateTime MC_145102_END = timeFromS3Time("2020-05-14T08:16:26+00:00"); +const QDateTime MC_228828_START = timeFromS3Time("2021-03-10T15:24:38+00:00"); +const QDateTime MC_228828_END = timeFromS3Time("2021-06-18T12:24:40+00:00"); namespace Ui { From 0a2ad17f062b42710d111e03567f1d1f08784f42 Mon Sep 17 00:00:00 2001 From: arthomnix Date: Sun, 3 Jul 2022 18:11:18 +0100 Subject: [PATCH 18/28] NOISSUE shortcut creation: add comments and todo --- launcher/ui/dialogs/CreateShortcutDialog.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/launcher/ui/dialogs/CreateShortcutDialog.cpp b/launcher/ui/dialogs/CreateShortcutDialog.cpp index 3dc91988..3238da01 100644 --- a/launcher/ui/dialogs/CreateShortcutDialog.cpp +++ b/launcher/ui/dialogs/CreateShortcutDialog.cpp @@ -41,6 +41,8 @@ CreateShortcutDialog::CreateShortcutDialog(QWidget *parent, InstancePtr instance ui->profileComboBox->setCurrentText(accounts->defaultAccount()->profileName()); } + // check if instance is affected by a bug causing it to crash when trying to join a server on launch + // TODO: implement this check in meta if (m_instance->typeName() == "Minecraft") { try @@ -64,6 +66,7 @@ CreateShortcutDialog::CreateShortcutDialog(QWidget *parent, InstancePtr instance } } + // Macs don't have any concept of a desktop shortcut, so force-enable the option to generate a shell script instead #if defined(Q_OS_UNIX) && !defined(Q_OS_LINUX) ui->createScriptCheckBox->setEnabled(false); ui->createScriptCheckBox->setChecked(true); From 79910e3542e104e600b5dc3d2175d01509bddbf8 Mon Sep 17 00:00:00 2001 From: arthomnix Date: Sun, 3 Jul 2022 19:53:45 +0100 Subject: [PATCH 19/28] NOISSUE shortcut creation: put file dialog in save mode This makes sure that the user is prompted if they are about to overwrite a file --- launcher/ui/dialogs/CreateShortcutDialog.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/launcher/ui/dialogs/CreateShortcutDialog.cpp b/launcher/ui/dialogs/CreateShortcutDialog.cpp index 3238da01..9123d667 100644 --- a/launcher/ui/dialogs/CreateShortcutDialog.cpp +++ b/launcher/ui/dialogs/CreateShortcutDialog.cpp @@ -91,7 +91,7 @@ void CreateShortcutDialog::on_shortcutPathBrowse_clicked() #endif QFileDialog fileDialog(this, tr("Select shortcut path"), QStandardPaths::writableLocation(QStandardPaths::DesktopLocation)); fileDialog.setDefaultSuffix(linkExtension); - fileDialog.setAcceptMode(QFileDialog::AcceptOpen); + fileDialog.setAcceptMode(QFileDialog::AcceptSave); fileDialog.setFileMode(QFileDialog::AnyFile); fileDialog.selectFile(m_instance->name() + " - " + BuildConfig.LAUNCHER_DISPLAYNAME + "." + linkExtension); if (fileDialog.exec()) From 518b19e6677eb1a328f2a88daa4334fc02202dc7 Mon Sep 17 00:00:00 2001 From: arthomnix Date: Wed, 6 Jul 2022 08:03:04 +0100 Subject: [PATCH 20/28] NOISSUE shortcut creation: enclose paths in quotes --- launcher/ui/dialogs/CreateShortcutDialog.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/launcher/ui/dialogs/CreateShortcutDialog.cpp b/launcher/ui/dialogs/CreateShortcutDialog.cpp index 9123d667..f6711397 100644 --- a/launcher/ui/dialogs/CreateShortcutDialog.cpp +++ b/launcher/ui/dialogs/CreateShortcutDialog.cpp @@ -129,7 +129,7 @@ void CreateShortcutDialog::updateDialogState() QString CreateShortcutDialog::getLaunchCommand() { - return QDir::toNativeSeparators(QCoreApplication::applicationFilePath()) + return "\"" + QDir::toNativeSeparators(QCoreApplication::applicationFilePath()) + "\"" + getLaunchArgs(); } @@ -155,7 +155,7 @@ void CreateShortcutDialog::createShortcut() if (ui->createScriptCheckBox->isChecked()) { shortcutText = "#!/bin/sh\n" - "cd " + QCoreApplication::applicationDirPath() + "\n" + "cd \"" + QCoreApplication::applicationDirPath() + "\"\n" + getLaunchCommand() + " &\n"; } else // freedesktop.org desktop entry @@ -179,7 +179,7 @@ void CreateShortcutDialog::createShortcut() #ifdef Q_OS_WIN // Windows batch script implementation shortcutText = "@ECHO OFF\r\n" - "CD " + QDir::toNativeSeparators(QCoreApplication::applicationDirPath()) + "\r\n" + "CD \"" + QDir::toNativeSeparators(QCoreApplication::applicationDirPath()) + "\"\r\n" "START /B " + getLaunchCommand() + "\r\n"; #endif QFile shortcutFile(ui->shortcutPath->text()); From 00589b247a14d2f7ff549740c89f087c2dd8f0bd Mon Sep 17 00:00:00 2001 From: arthomnix Date: Mon, 11 Jul 2022 18:02:20 +0100 Subject: [PATCH 21/28] GH-4812 Prefill instance name to allow making adjustments Fills the instance name in instead of just setting a placeholder. This allows adjustments to be made to the suggested name without typing the whole thing out. The text is selected by default so that typing will overwrite the text, but users who want to adjust the default name instead of typing their own can deselect the text. The placeholder name is still set so it is still visible if the user deletes the text. Also sets the focus to the instance name textbox by default, whereas previously it was on the group name - this is required so the text gets overwritten on typing but also makes more sense generally. Closes issue #4812. --- launcher/ui/dialogs/NewInstanceDialog.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/launcher/ui/dialogs/NewInstanceDialog.cpp b/launcher/ui/dialogs/NewInstanceDialog.cpp index 0b933fb5..135e8b3d 100644 --- a/launcher/ui/dialogs/NewInstanceDialog.cpp +++ b/launcher/ui/dialogs/NewInstanceDialog.cpp @@ -151,6 +151,9 @@ void NewInstanceDialog::setSuggestedPack(const QString& name, InstanceTask* task { creationTask.reset(task); ui->instNameTextBox->setPlaceholderText(name); + ui->instNameTextBox->setText(name); + ui->instNameTextBox->selectAll(); + ui->instNameTextBox->setFocus(); if(!task) { From ec897aee95433603f490438ab2f3710c3388d979 Mon Sep 17 00:00:00 2001 From: arthomnix Date: Mon, 11 Jul 2022 19:51:31 +0100 Subject: [PATCH 22/28] GH-4812 More improvements related to instance name Selects text on focus rather than selecting text and focusing by default. Text is not selected if the user has changed the name from the default. If the user changes the instance name, don't change it when they select a new version or modpack. Add a reset button that changes the instance name back to the default for the selected version/pack, and resets the flag that stops the name from being changed upon selecting a new version/pack. --- launcher/ui/dialogs/NewInstanceDialog.cpp | 32 +++++++++++++++++++--- launcher/ui/dialogs/NewInstanceDialog.h | 6 +++++ launcher/ui/dialogs/NewInstanceDialog.ui | 33 ++++++++++++++--------- 3 files changed, 54 insertions(+), 17 deletions(-) diff --git a/launcher/ui/dialogs/NewInstanceDialog.cpp b/launcher/ui/dialogs/NewInstanceDialog.cpp index 135e8b3d..42130f49 100644 --- a/launcher/ui/dialogs/NewInstanceDialog.cpp +++ b/launcher/ui/dialogs/NewInstanceDialog.cpp @@ -103,6 +103,8 @@ NewInstanceDialog::NewInstanceDialog(const QString & initialGroup, const QString importPage->setUrl(url); } + connect(APPLICATION, &QApplication::focusChanged, this, &NewInstanceDialog::onFocusChanged); + updateDialogState(); restoreGeometry(QByteArray::fromBase64(APPLICATION->settings()->get("NewInstanceGeometry").toByteArray())); @@ -150,10 +152,14 @@ NewInstanceDialog::~NewInstanceDialog() void NewInstanceDialog::setSuggestedPack(const QString& name, InstanceTask* task) { creationTask.reset(task); - ui->instNameTextBox->setPlaceholderText(name); - ui->instNameTextBox->setText(name); - ui->instNameTextBox->selectAll(); - ui->instNameTextBox->setFocus(); + + defaultInstName = name; + + if (!instNameChanged) + { + ui->instNameTextBox->setPlaceholderText(name); + ui->instNameTextBox->setText(name); + } if(!task) { @@ -241,11 +247,29 @@ void NewInstanceDialog::on_iconButton_clicked() } } +void NewInstanceDialog::on_resetNameButton_clicked() +{ + ui->instNameTextBox->setText(defaultInstName); + instNameChanged = false; +} + void NewInstanceDialog::on_instNameTextBox_textChanged(const QString &arg1) { updateDialogState(); } +void NewInstanceDialog::on_instNameTextBox_textEdited(const QString &text) +{ + instNameChanged = true; +} + +void NewInstanceDialog::onFocusChanged(QWidget *, QWidget *newWidget) +{ + if (newWidget == ui->instNameTextBox && !instNameChanged) { + QTimer::singleShot(0, ui->instNameTextBox, &QLineEdit::selectAll); + } +} + void NewInstanceDialog::importIconNow() { if(importIcon) { diff --git a/launcher/ui/dialogs/NewInstanceDialog.h b/launcher/ui/dialogs/NewInstanceDialog.h index 3a100b77..a001acea 100644 --- a/launcher/ui/dialogs/NewInstanceDialog.h +++ b/launcher/ui/dialogs/NewInstanceDialog.h @@ -56,10 +56,13 @@ public: public slots: void accept() override; void reject() override; + void onFocusChanged(QWidget *, QWidget *newWidget); private slots: void on_iconButton_clicked(); + void on_resetNameButton_clicked(); void on_instNameTextBox_textChanged(const QString &arg1); + void on_instNameTextBox_textEdited(const QString &text); private: Ui::NewInstanceDialog *ui = nullptr; @@ -75,4 +78,7 @@ private: QString importIconName; void importIconNow(); + + QString defaultInstName; + bool instNameChanged = false; }; diff --git a/launcher/ui/dialogs/NewInstanceDialog.ui b/launcher/ui/dialogs/NewInstanceDialog.ui index 7fb19ff5..90d6bf39 100644 --- a/launcher/ui/dialogs/NewInstanceDialog.ui +++ b/launcher/ui/dialogs/NewInstanceDialog.ui @@ -26,6 +26,9 @@ + + + @@ -33,6 +36,16 @@ + + + + &Name: + + + instNameTextBox + + + @@ -43,19 +56,6 @@ - - - - - - - &Name: - - - instNameTextBox - - - @@ -66,6 +66,13 @@ + + + + Reset + + + From ffec1e1930420e1a1d0aafdabf18f3fd1e06c9a2 Mon Sep 17 00:00:00 2001 From: arthomnix Date: Mon, 11 Jul 2022 19:55:36 +0100 Subject: [PATCH 23/28] GH-4812 Set placeholder even if the user has changed the name --- launcher/ui/dialogs/NewInstanceDialog.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/launcher/ui/dialogs/NewInstanceDialog.cpp b/launcher/ui/dialogs/NewInstanceDialog.cpp index 42130f49..28be8fee 100644 --- a/launcher/ui/dialogs/NewInstanceDialog.cpp +++ b/launcher/ui/dialogs/NewInstanceDialog.cpp @@ -154,10 +154,10 @@ void NewInstanceDialog::setSuggestedPack(const QString& name, InstanceTask* task creationTask.reset(task); defaultInstName = name; + ui->instNameTextBox->setPlaceholderText(name); if (!instNameChanged) { - ui->instNameTextBox->setPlaceholderText(name); ui->instNameTextBox->setText(name); } From 81b7e5f769f49bf42432cd5f725f527b5dda6fa6 Mon Sep 17 00:00:00 2001 From: kb1000 Date: Thu, 14 Jul 2022 16:45:41 +0200 Subject: [PATCH 24/28] [NOISSUE] Unwrap InvocationTargetException and allow non-public main classes --- .../launcher/org/multimc/onesix/OneSixLauncher.java | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/libraries/launcher/org/multimc/onesix/OneSixLauncher.java b/libraries/launcher/org/multimc/onesix/OneSixLauncher.java index ea445995..d341cad7 100644 --- a/libraries/launcher/org/multimc/onesix/OneSixLauncher.java +++ b/libraries/launcher/org/multimc/onesix/OneSixLauncher.java @@ -21,6 +21,7 @@ import java.applet.Applet; import java.io.File; import java.io.IOException; import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; @@ -143,12 +144,14 @@ public class OneSixLauncher implements Launcher String[] paramsArray = mcparams.toArray(new String[mcparams.size()]); try { - mc.getMethod("main", String[].class).invoke(null, (Object) paramsArray); + Method meth = mc.getMethod("main", String[].class); + meth.setAccessible(true); + meth.invoke(null, (Object) paramsArray); return 0; } catch (Exception e) { Utils.log("Failed to invoke the Minecraft main class:", "Fatal"); - e.printStackTrace(System.err); + (e instanceof InvocationTargetException ? e.getCause() : e).printStackTrace(System.err); return -1; } } @@ -195,7 +198,8 @@ public class OneSixLauncher implements Launcher try { meth = mc.getMethod("main", String[].class); - } catch (NoSuchMethodException e) + meth.setAccessible(true); + } catch (NoSuchMethodException | SecurityException e) { System.err.println("Failed to acquire the main method:"); e.printStackTrace(System.err); @@ -211,7 +215,7 @@ public class OneSixLauncher implements Launcher } catch (Exception e) { System.err.println("Failed to start Minecraft:"); - e.printStackTrace(System.err); + (e instanceof InvocationTargetException ? e.getCause() : e).printStackTrace(System.err); return -1; } return 0; From 844ed61aa4effdd84155a593d12aeb0df9197b13 Mon Sep 17 00:00:00 2001 From: arthomnix Date: Tue, 19 Jul 2022 17:14:46 +0100 Subject: [PATCH 25/28] NOISSUE Yeet the version check --- launcher/ui/dialogs/CreateShortcutDialog.cpp | 25 +------------------- launcher/ui/dialogs/CreateShortcutDialog.h | 6 ----- 2 files changed, 1 insertion(+), 30 deletions(-) diff --git a/launcher/ui/dialogs/CreateShortcutDialog.cpp b/launcher/ui/dialogs/CreateShortcutDialog.cpp index f6711397..dbce5f18 100644 --- a/launcher/ui/dialogs/CreateShortcutDialog.cpp +++ b/launcher/ui/dialogs/CreateShortcutDialog.cpp @@ -41,30 +41,7 @@ CreateShortcutDialog::CreateShortcutDialog(QWidget *parent, InstancePtr instance ui->profileComboBox->setCurrentText(accounts->defaultAccount()->profileName()); } - // check if instance is affected by a bug causing it to crash when trying to join a server on launch - // TODO: implement this check in meta - if (m_instance->typeName() == "Minecraft") - { - try - { - MinecraftInstancePtr minecraftInstance = qobject_pointer_cast(m_instance); - minecraftInstance->getPackProfile()->reload(Net::Mode::Online); - QDateTime versionDate = minecraftInstance->getPackProfile()->getComponent("net.minecraft")->getReleaseDateTime(); - bool enableJoinServer = (versionDate < MC_145102_START) - || (versionDate >= MC_145102_END && versionDate < MC_228828_START) - || (versionDate >= MC_228828_END); - ui->joinServerCheckBox->setEnabled(enableJoinServer); - ui->joinServer->setEnabled(enableJoinServer); - } - catch (const Exception &e) - { - QMessageBox::critical(this, tr("Error"), e.cause()); - } - catch (...) - { - QMessageBox::critical(this, tr("Error"), tr("Failed to load pack profile to check version!")); - } - } + // TODO: check if version is affected by crashing when joining servers on launch, ideally in meta // Macs don't have any concept of a desktop shortcut, so force-enable the option to generate a shell script instead #if defined(Q_OS_UNIX) && !defined(Q_OS_LINUX) diff --git a/launcher/ui/dialogs/CreateShortcutDialog.h b/launcher/ui/dialogs/CreateShortcutDialog.h index d27e94cd..a2497dd6 100644 --- a/launcher/ui/dialogs/CreateShortcutDialog.h +++ b/launcher/ui/dialogs/CreateShortcutDialog.h @@ -16,12 +16,6 @@ #include #endif -// Dates when the game was affected by bugs that crashed the game when using the option to join a server on startup -const QDateTime MC_145102_START = timeFromS3Time("2019-02-20T14:56:58+00:00"); -const QDateTime MC_145102_END = timeFromS3Time("2020-05-14T08:16:26+00:00"); -const QDateTime MC_228828_START = timeFromS3Time("2021-03-10T15:24:38+00:00"); -const QDateTime MC_228828_END = timeFromS3Time("2021-06-18T12:24:40+00:00"); - namespace Ui { class CreateShortcutDialog; From e5c962b7b98f86156fc41a1214034783842b3efe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Tue, 19 Jul 2022 19:04:29 +0200 Subject: [PATCH 26/28] NOISSUE acknowledge the truth --- launcher/ui/dialogs/AboutDialog.cpp | 36 ++++++++++++++++------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/launcher/ui/dialogs/AboutDialog.cpp b/launcher/ui/dialogs/AboutDialog.cpp index 9795c38b..ae51809b 100644 --- a/launcher/ui/dialogs/AboutDialog.cpp +++ b/launcher/ui/dialogs/AboutDialog.cpp @@ -28,27 +28,30 @@ namespace { // This is a hack, but I can't think of a better way to do this easily without screwing with QTextDocument... QString getCreditsHtml(QStringList patrons) { - QString patronsHeading = QObject::tr("Patrons", "About Credits"); QString output; QTextStream stream(&output); stream.setCodec(QTextCodec::codecForName("UTF-8")); stream << "
\n"; - // TODO: possibly retrieve from git history at build time? - stream << "

" << QObject::tr("Developers", "About Credits") << "

\n"; - stream << "

Andrew Okin <forkk@forkk.net>

\n"; - stream << "

Petr Mrázek <peterix@gmail.com>

\n"; - stream << "

Sky Welch <multimc@bunnies.io>

\n"; - stream << "

Jan (02JanDal) <02jandal@gmail.com>

\n"; - stream << "

RoboSky <@RoboSky_>

\n"; - stream << "
\n"; - stream << "

" << QObject::tr("With thanks to", "About Credits") << "

\n"; - stream << "

Orochimarufan <orochimarufan.x3@gmail.com>

\n"; - stream << "

TakSuyu <taksuyu@gmail.com>

\n"; - stream << "

Kilobyte <stiepen22@gmx.de>

\n"; - stream << "

Rootbear75 <@rootbear75>

\n"; - stream << "

Zeker Zhayard <@Zeker_Zhayard>

\n"; - stream << "
\n"; + stream << "

" << QObject::tr("Original Author", "About Credits") << "

\n"; + stream << "

Andrew Okin <forkk@forkk.net>

\n"; + + stream << "

" << QObject::tr("Maintainer", "About Credits") << "

\n"; + stream << "

Petr Mrázek <peterix@gmail.com>

\n"; + + stream << "

Dedicated to Erika

\n"; + stream << "

You gave all the work put into this meaning.

\n"; + + // TODO: grab contributors from git history + /* + if(!contributors.isEmpty()) { + stream << "

" << QObject::tr("Contributors", "About Credits") << "

\n"; + for (auto &contributor : contributors) + { + stream << "

" << contributor << "

\n"; + } + } + */ if(!patrons.isEmpty()) { stream << "

" << QObject::tr("Patrons", "About Credits") << "

\n"; @@ -57,6 +60,7 @@ QString getCreditsHtml(QStringList patrons) stream << "

" << patron << "

\n"; } } + stream << "
\n"; return output; } From 251767139674bc4b5873e68f508613f51dd7f5c8 Mon Sep 17 00:00:00 2001 From: arthomnix Date: Tue, 19 Jul 2022 20:43:54 +0100 Subject: [PATCH 27/28] NOISSUE Use current working directory instead of applicationDirPath in shortcut creation This fixes issues with official Linux builds which place the executable in its own bin directory --- launcher/ui/dialogs/CreateShortcutDialog.cpp | 24 +++++++++++--------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/launcher/ui/dialogs/CreateShortcutDialog.cpp b/launcher/ui/dialogs/CreateShortcutDialog.cpp index dbce5f18..85397fea 100644 --- a/launcher/ui/dialogs/CreateShortcutDialog.cpp +++ b/launcher/ui/dialogs/CreateShortcutDialog.cpp @@ -112,7 +112,8 @@ QString CreateShortcutDialog::getLaunchCommand() QString CreateShortcutDialog::getLaunchArgs() { - return " -l " + m_instance->id() + return " -d \"" + QDir::toNativeSeparators(QDir::currentPath()) + "\"" + + " -l " + m_instance->id() + (ui->joinServerCheckBox->isChecked() ? " -s " + ui->joinServer->text() : "") + (ui->useProfileCheckBox->isChecked() ? " -a " + ui->profileComboBox->currentText() : "") + (ui->launchOfflineCheckBox->isChecked() ? " -o" : "") @@ -132,31 +133,32 @@ void CreateShortcutDialog::createShortcut() if (ui->createScriptCheckBox->isChecked()) { shortcutText = "#!/bin/sh\n" - "cd \"" + QCoreApplication::applicationDirPath() + "\"\n" + // FIXME: is there a way to use the launcher script instead of the raw binary here? + "cd \"" + QDir::currentPath() + "\"\n" + getLaunchCommand() + " &\n"; } else // freedesktop.org desktop entry { // save the launcher icon to a file so we can use it in the shortcut - if (!QFileInfo::exists(QCoreApplication::applicationDirPath() + "/icons/shortcut-icon.png")) + if (!QFileInfo::exists(QDir::currentPath() + "/icons/shortcut-icon.png")) { QPixmap iconPixmap = QIcon(":/logo.svg").pixmap(64, 64); - iconPixmap.save(QCoreApplication::applicationDirPath() + "/icons/shortcut-icon.png"); + iconPixmap.save(QDir::currentPath() + "/icons/shortcut-icon.png"); } shortcutText = "[Desktop Entry]\n" "Type=Application\n" "Name=" + m_instance->name() + " - " + BuildConfig.LAUNCHER_DISPLAYNAME + "\n" + "Exec=" + getLaunchCommand() + "\n" - + "Path=" + QCoreApplication::applicationDirPath() + "\n" - + "Icon=" + QCoreApplication::applicationDirPath() + "/icons/shortcut-icon.png\n"; + + "Path=" + QDir::currentPath() + "\n" + + "Icon=" + QDir::currentPath() + "/icons/shortcut-icon.png\n"; } #endif #ifdef Q_OS_WIN // Windows batch script implementation shortcutText = "@ECHO OFF\r\n" - "CD \"" + QDir::toNativeSeparators(QCoreApplication::applicationDirPath()) + "\"\r\n" + "CD \"" + QDir::toNativeSeparators(QDir::currentPath()) + "\"\r\n" "START /B " + getLaunchCommand() + "\r\n"; #endif QFile shortcutFile(ui->shortcutPath->text()); @@ -172,18 +174,18 @@ void CreateShortcutDialog::createShortcut() } else { - if (!QFileInfo::exists(QCoreApplication::applicationDirPath() + "/icons/shortcut-icon.ico")) + if (!QFileInfo::exists(QDir::currentPath() + "/icons/shortcut-icon.ico")) { QPixmap iconPixmap = QIcon(":/logo.svg").pixmap(64, 64); - iconPixmap.save(QCoreApplication::applicationDirPath() + "/icons/shortcut-icon.ico"); + iconPixmap.save(QDir::currentPath() + "/icons/shortcut-icon.ico"); } createWindowsLink(QDir::toNativeSeparators(QCoreApplication::applicationFilePath()).toStdString().c_str(), - QDir::toNativeSeparators(QCoreApplication::applicationDirPath()).toStdString().c_str(), + QDir::toNativeSeparators(QDir::currentPath()).toStdString().c_str(), getLaunchArgs().toStdString().c_str(), ui->shortcutPath->text().toStdString().c_str(), (m_instance->name() + " - " + BuildConfig.LAUNCHER_DISPLAYNAME).toStdString().c_str(), - QDir::toNativeSeparators(QCoreApplication::applicationDirPath() + "/icons/shortcut-icon.ico").toStdString().c_str() + QDir::toNativeSeparators(QDir::currentPath() + "/icons/shortcut-icon.ico").toStdString().c_str() ); } #endif From ec498074c125b2606b25941e75b3a6665f71ebf1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Tue, 19 Jul 2022 21:46:28 +0200 Subject: [PATCH 28/28] NOISSUE improve Modrinth description's page rendering --- launcher/CMakeLists.txt | 2 + launcher/HoeDown.h | 2 +- .../modplatform/modrinth/ModrinthDocument.cpp | 80 +++++++++++++++++++ .../modplatform/modrinth/ModrinthDocument.h | 45 +++++++++++ .../modplatform/modrinth/ModrinthPage.cpp | 18 ++--- .../pages/modplatform/modrinth/ModrinthPage.h | 1 + .../modplatform/modrinth/ModrinthPage.ui | 3 + 7 files changed, 140 insertions(+), 11 deletions(-) create mode 100644 launcher/ui/pages/modplatform/modrinth/ModrinthDocument.cpp create mode 100644 launcher/ui/pages/modplatform/modrinth/ModrinthDocument.h diff --git a/launcher/CMakeLists.txt b/launcher/CMakeLists.txt index bc0cce66..25c28063 100644 --- a/launcher/CMakeLists.txt +++ b/launcher/CMakeLists.txt @@ -730,6 +730,8 @@ SET(LAUNCHER_SOURCES ui/pages/modplatform/modrinth/ModrinthData.h ui/pages/modplatform/modrinth/ModrinthModel.cpp ui/pages/modplatform/modrinth/ModrinthModel.h + ui/pages/modplatform/modrinth/ModrinthDocument.cpp + ui/pages/modplatform/modrinth/ModrinthDocument.h ui/pages/modplatform/modrinth/ModrinthPage.cpp ui/pages/modplatform/modrinth/ModrinthPage.h diff --git a/launcher/HoeDown.h b/launcher/HoeDown.h index b9e06ffb..a8b831a1 100644 --- a/launcher/HoeDown.h +++ b/launcher/HoeDown.h @@ -57,7 +57,7 @@ public: HoeDown() { renderer = hoedown_html_renderer_new((hoedown_html_flags) 0,0); - document = hoedown_document_new(renderer, (hoedown_extensions) 0, 8); + document = hoedown_document_new(renderer, (hoedown_extensions) HOEDOWN_EXT_TABLES, 8); } ~HoeDown() { diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthDocument.cpp b/launcher/ui/pages/modplatform/modrinth/ModrinthDocument.cpp new file mode 100644 index 00000000..f734610a --- /dev/null +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthDocument.cpp @@ -0,0 +1,80 @@ +/* + * Copyright 2022 Petr Mrázek + * + * This source is subject to the Microsoft Permissive License (MS-PL). + * Please see the COPYING.md file for more information. + */ + +#include "ModrinthDocument.h" + +#include +#include +#include +#include +#include + +Modrinth::ModrinthDocument::ModrinthDocument(const QString &markdown, QObject* parent) : QTextDocument(parent) { + HoeDown hoedown; + // 100 MiB + QPixmapCache::setCacheLimit(102400); + setHtml(hoedown.process(markdown.toUtf8())); +} + +QVariant Modrinth::ModrinthDocument::loadResource(int type, const QUrl& name) { + if(type == QTextDocument::ResourceType::ImageResource) { + auto pixmap = QPixmapCache::find(name.toString()); + if(!pixmap) { + requestResource(name); + return QVariant(); + } + return QVariant(*pixmap); + } + return QTextDocument::loadResource(type, name); +} + +void Modrinth::ModrinthDocument::downloadFinished(const QString& key, const QPixmap& out) { + m_loading.remove(key); + QPixmapCache::insert(key, out); + emit layoutUpdateRequired(); +} + +void Modrinth::ModrinthDocument::downloadFailed(const QString& key) { + m_failed.append(key); + m_loading.remove(key); +} + +void Modrinth::ModrinthDocument::requestResource(const QUrl& url) { + QString key = url.toString(); + if(m_loading.contains(key) || m_failed.contains(key)) + { + return; + } + + qDebug() << "Loading resource" << key; + + ImageLoad *load = new ImageLoad; + load->job = new NetJob(QString("Modrinth Image Download %1").arg(key), APPLICATION->network()); + load->job->addNetAction(Net::Download::makeByteArray(url, &load->output)); + load->key = key; + + QObject::connect(load->job.get(), &NetJob::succeeded, this, [this, load] { + QPixmap pixmap; + if(!pixmap.loadFromData(load->output)) { + qDebug() << load->output; + downloadFailed(load->key); + } + if(pixmap.width() > 800) { + pixmap = pixmap.scaledToWidth(800); + } + downloadFinished(load->key, pixmap); + }); + + QObject::connect(load->job.get(), &NetJob::failed, this, [this, load] + { + downloadFailed(load->key); + }); + + load->job->start(); + + m_loading[key] = load; +} diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthDocument.h b/launcher/ui/pages/modplatform/modrinth/ModrinthDocument.h new file mode 100644 index 00000000..218a59a7 --- /dev/null +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthDocument.h @@ -0,0 +1,45 @@ +/* + * Copyright 2022 Petr Mrázek + * + * This source is subject to the Microsoft Permissive License (MS-PL). + * Please see the COPYING.md file for more information. + */ + +#pragma once + +#include +#include + +namespace Modrinth { + +using Callback = std::function; +struct ImageLoad { + QString key; + NetJob::Ptr job; + QByteArray output; + Callback handler; +}; + +class ModrinthDocument: public QTextDocument { + Q_OBJECT +public: + ModrinthDocument(const QString &markdown, QObject * parent = nullptr); + +signals: + void layoutUpdateRequired(); + +protected: + QVariant loadResource(int type, const QUrl & name) override; + +private: + void downloadFailed(const QString &key); + void downloadFinished(const QString &key, const QPixmap &out); + + void requestResource(const QUrl &url); + +private: + QMap m_loading; + QStringList m_failed; +}; + +} diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp index 7aebc2fa..70793185 100644 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.cpp @@ -17,12 +17,12 @@ #include "ModrinthModel.h" #include "ModrinthPage.h" +#include "ModrinthDocument.h" #include "ui/dialogs/NewInstanceDialog.h" #include "ui_ModrinthPage.h" #include -#include #include ModrinthPage::ModrinthPage(NewInstanceDialog *dialog, QWidget *parent) : QWidget(parent), ui(new Ui::ModrinthPage), dialog(dialog) @@ -133,14 +133,6 @@ void ModrinthPage::onPackDataChanged(const QString& id) } } -namespace { -QString processMarkdown(QString input) -{ - HoeDown hoedown; - return hoedown.process(input.toUtf8()); -} -} - QString versionToString(const Modrinth::Version& version) { switch(version.type) { case Modrinth::VersionType::Alpha: { @@ -171,7 +163,9 @@ void ModrinthPage::updateCurrentPackUI() break; } case Modrinth::LoadState::Loaded: { - ui->packDescription->setText(processMarkdown(current.body)); + auto document = new Modrinth::ModrinthDocument(current.body); + connect(document, &Modrinth::ModrinthDocument::layoutUpdateRequired, this, &ModrinthPage::forceDocumentLayout); + ui->packDescription->setDocument(document); break; } } @@ -199,3 +193,7 @@ void ModrinthPage::updateCurrentPackUI() } suggestCurrent(); } + +void ModrinthPage::forceDocumentLayout() { + ui->packDescription->document()->adjustSize(); +} diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.h b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.h index 8829ce2a..ddaa2db0 100644 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.h +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.h @@ -64,6 +64,7 @@ private slots: void onSelectionChanged(QModelIndex first, QModelIndex second); void onVersionSelectionChanged(const QString & version); void onPackDataChanged(const QString &id); + void forceDocumentLayout(); private: void updateCurrentPackUI(); diff --git a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.ui b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.ui index 7ef099d3..08dcc392 100644 --- a/launcher/ui/pages/modplatform/modrinth/ModrinthPage.ui +++ b/launcher/ui/pages/modplatform/modrinth/ModrinthPage.ui @@ -36,6 +36,9 @@ Qt::ScrollBarAlwaysOff + + QAbstractScrollArea::AdjustToContents + true