From 69469b4484b88459a2fa74358197ac1dba4896ff Mon Sep 17 00:00:00 2001 From: Yihe Li Date: Sun, 11 May 2025 03:33:03 +0800 Subject: [PATCH 01/24] Refactor shortcut creation logic into its own file Signed-off-by: Yihe Li --- launcher/CMakeLists.txt | 2 + launcher/minecraft/ShortcutUtils.cpp | 264 +++++++++++++++++++++++++++ launcher/minecraft/ShortcutUtils.h | 71 +++++++ launcher/ui/MainWindow.cpp | 191 +------------------ launcher/ui/MainWindow.h | 2 - launcher/ui/MainWindow.ui | 2 +- 6 files changed, 345 insertions(+), 187 deletions(-) create mode 100644 launcher/minecraft/ShortcutUtils.cpp create mode 100644 launcher/minecraft/ShortcutUtils.h diff --git a/launcher/CMakeLists.txt b/launcher/CMakeLists.txt index dbd9dc0bb..918e38df0 100644 --- a/launcher/CMakeLists.txt +++ b/launcher/CMakeLists.txt @@ -310,6 +310,8 @@ set(MINECRAFT_SOURCES minecraft/ParseUtils.h minecraft/ProfileUtils.cpp minecraft/ProfileUtils.h + minecraft/ShortcutUtils.cpp + minecraft/ShortcutUtils.h minecraft/Library.cpp minecraft/Library.h minecraft/MojangDownloadInfo.h diff --git a/launcher/minecraft/ShortcutUtils.cpp b/launcher/minecraft/ShortcutUtils.cpp new file mode 100644 index 000000000..7d4faf231 --- /dev/null +++ b/launcher/minecraft/ShortcutUtils.cpp @@ -0,0 +1,264 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* + * Prism Launcher - Minecraft Launcher + * Copyright (C) 2022 Sefa Eyeoglu + * + * parent 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. + * + * parent 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 parent program. If not, see . + * + * parent 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 parent 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 "ShortcutUtils.h" + +#include "FileSystem.h" + +#include +#include + +#include +#include +#include + +namespace ShortcutUtils { + +void createInstanceShortcut(BaseInstance* instance, + QString shortcutName, + QString shortcutFilePath, + QString targetString, + QWidget* parent, + const QStringList& extraArgs) +{ + if (!instance) + return; + + QString appPath = QApplication::applicationFilePath(); + QString iconPath; + QStringList args; +#if defined(Q_OS_MACOS) + appPath = QApplication::applicationFilePath(); + if (appPath.startsWith("/private/var/")) { + QMessageBox::critical(parent, QObject::tr("Create Shortcut"), + QObject::tr("The launcher is in the folder it was extracted from, therefore it cannot create shortcuts.")); + return; + } + + auto pIcon = APPLICATION->icons()->icon(instance->iconKey()); + if (pIcon == nullptr) { + pIcon = APPLICATION->icons()->icon("grass"); + } + + iconPath = FS::PathCombine(instance->instanceRoot(), "Icon.icns"); + + QFile iconFile(iconPath); + if (!iconFile.open(QFile::WriteOnly)) { + QMessageBox::critical(parent, QObject::tr("Create Shortcut"), QObject::tr("Failed to create icon for application.")); + return; + } + + QIcon icon = pIcon->icon(); + + bool success = icon.pixmap(1024, 1024).save(iconPath, "ICNS"); + iconFile.close(); + + if (!success) { + iconFile.remove(); + QMessageBox::critical(parent, QObject::tr("Create Shortcut"), QObject::tr("Failed to create icon for application.")); + return; + } +#elif defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) || defined(Q_OS_OPENBSD) + if (appPath.startsWith("/tmp/.mount_")) { + // AppImage! + appPath = QProcessEnvironment::systemEnvironment().value(QStringLiteral("APPIMAGE")); + if (appPath.isEmpty()) { + QMessageBox::critical( + parent, QObject::tr("Create Shortcut"), + QObject::tr("Launcher is running as misconfigured AppImage? ($APPIMAGE environment variable is missing)")); + } else if (appPath.endsWith("/")) { + appPath.chop(1); + } + } + + auto icon = APPLICATION->icons()->icon(instance->iconKey()); + if (icon == nullptr) { + icon = APPLICATION->icons()->icon("grass"); + } + + iconPath = FS::PathCombine(instance->instanceRoot(), "icon.png"); + + QFile iconFile(iconPath); + if (!iconFile.open(QFile::WriteOnly)) { + QMessageBox::critical(parent, QObject::tr("Create Shortcut"), QObject::tr("Failed to create icon for shortcut.")); + return; + } + bool success = icon->icon().pixmap(64, 64).save(&iconFile, "PNG"); + iconFile.close(); + + if (!success) { + iconFile.remove(); + QMessageBox::critical(parent, QObject::tr("Create Shortcut"), QObject::tr("Failed to create icon for shortcut.")); + return; + } + + if (DesktopServices::isFlatpak()) { + appPath = "flatpak"; + args.append({ "run", BuildConfig.LAUNCHER_APPID }); + } + +#elif defined(Q_OS_WIN) + auto icon = APPLICATION->icons()->icon(instance->iconKey()); + if (icon == nullptr) { + icon = APPLICATION->icons()->icon("grass"); + } + + iconPath = FS::PathCombine(instance->instanceRoot(), "icon.ico"); + + // part of fix for weird bug involving the window icon being replaced + // dunno why it happens, but parent 2-line fix seems to be enough, so w/e + auto appIcon = APPLICATION->getThemedIcon("logo"); + + QFile iconFile(iconPath); + if (!iconFile.open(QFile::WriteOnly)) { + QMessageBox::critical(parent, QObject::tr("Create Shortcut"), QObject::tr("Failed to create icon for shortcut.")); + return; + } + bool success = icon->icon().pixmap(64, 64).save(&iconFile, "ICO"); + iconFile.close(); + + // restore original window icon + QGuiApplication::setWindowIcon(appIcon); + + if (!success) { + iconFile.remove(); + QMessageBox::critical(parent, QObject::tr("Create Shortcut"), QObject::tr("Failed to create icon for shortcut.")); + return; + } + +#else + QMessageBox::critical(parent, QObject::tr("Create Shortcut"), QObject::tr("Not supported on your platform!")); + return; +#endif + args.append({ "--launch", instance->id() }); + args.append(extraArgs); + + if (!FS::createShortcut(std::move(shortcutFilePath), appPath, args, shortcutName, iconPath)) { +#if not defined(Q_OS_MACOS) + iconFile.remove(); +#endif + QMessageBox::critical(parent, QObject::tr("Create Shortcut"), QObject::tr("Failed to create %1 shortcut!").arg(targetString)); + return; + } +} + +void createInstanceShortcutOnDesktop(BaseInstance* instance, + QString shortcutName, + QString targetString, + QWidget* parent, + const QStringList& extraArgs) +{ + if (!instance) + return; + + QString desktopDir = FS::getDesktopDir(); + if (desktopDir.isEmpty()) { + QMessageBox::critical(parent, QObject::tr("Create Shortcut"), QObject::tr("Couldn't find desktop?!")); + return; + } + + QString shortcutFilePath = FS::PathCombine(FS::getDesktopDir(), FS::RemoveInvalidFilenameChars(shortcutName)); + createInstanceShortcut(instance, shortcutName, shortcutFilePath, targetString, parent, extraArgs); + QMessageBox::information(parent, QObject::tr("Create Shortcut"), + QObject::tr("Created a shortcut to this %1 on your desktop!").arg(targetString)); +} + +void createInstanceShortcutInApplications(BaseInstance* instance, + QString shortcutName, + QString targetString, + QWidget* parent, + const QStringList& extraArgs) +{ + if (!instance) + return; + + QString applicationsDir = FS::getApplicationsDir(); + if (applicationsDir.isEmpty()) { + QMessageBox::critical(parent, QObject::tr("Create Shortcut"), QObject::tr("Couldn't find applications folder?!")); + return; + } + +#if defined(Q_OS_MACOS) || defined(Q_OS_WIN) + applicationsDir = FS::PathCombine(applicationsDir, BuildConfig.LAUNCHER_DISPLAYNAME + " Instances"); + + QDir applicationsDirQ(applicationsDir); + if (!applicationsDirQ.mkpath(".")) { + QMessageBox::critical(parent, QObject::tr("Create Shortcut"), + QObject::tr("Failed to create instances folder in applications folder!")); + return; + } +#endif + + QString shortcutFilePath = FS::PathCombine(applicationsDir, FS::RemoveInvalidFilenameChars(shortcutName)); + createInstanceShortcut(instance, shortcutName, shortcutFilePath, targetString, parent, extraArgs); + QMessageBox::information(parent, QObject::tr("Create Shortcut"), + QObject::tr("Created a shortcut to this %1 in your applications folder!").arg(targetString)); +} + +void createInstanceShortcutInOther(BaseInstance* instance, + QString shortcutName, + QString targetString, + QWidget* parent, + const QStringList& extraArgs) +{ + if (!instance) + return; + + QString defaultedDir = FS::getDesktopDir(); +#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) || defined(Q_OS_OPENBSD) + QString extension = ".desktop"; +#elif defined(Q_OS_WINDOWS) + QString extension = ".lnk"; +#else + QString extension = ""; +#endif + + QString shortcutFilePath = FS::PathCombine(defaultedDir, FS::RemoveInvalidFilenameChars(shortcutName) + extension); + QFileDialog fileDialog; + // workaround to make sure the portal file dialog opens in the desktop directory + fileDialog.setDirectoryUrl(defaultedDir); + + shortcutFilePath = fileDialog.getSaveFileName(parent, QObject::tr("Create Shortcut"), shortcutFilePath, + QObject::tr("Desktop Entries") + " (*" + extension + ")"); + if (shortcutFilePath.isEmpty()) + return; // file dialog canceled by user + + if (shortcutFilePath.endsWith(extension)) + shortcutFilePath = shortcutFilePath.mid(0, shortcutFilePath.length() - extension.length()); + createInstanceShortcut(instance, shortcutName, shortcutFilePath, targetString, parent, extraArgs); + QMessageBox::information(parent, QObject::tr("Create Shortcut"), QObject::tr("Created a shortcut to this %1!").arg(targetString)); +} + +} // namespace ShortcutUtils diff --git a/launcher/minecraft/ShortcutUtils.h b/launcher/minecraft/ShortcutUtils.h new file mode 100644 index 000000000..88800f5e6 --- /dev/null +++ b/launcher/minecraft/ShortcutUtils.h @@ -0,0 +1,71 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* + * Prism Launcher - Minecraft Launcher + * Copyright (C) 2022 Sefa Eyeoglu + * + * 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 . + * + * 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 +#include "Application.h" + +#include + +namespace ShortcutUtils { +/// Create an instance shortcut on the specified file path +void createInstanceShortcut(BaseInstance* instance, + QString shortcutName, + QString shortcutFilePath, + QString targetString, + QWidget* parent = nullptr, + const QStringList& extraArgs = {}); + +/// Create an instance shortcut on the desktop +void createInstanceShortcutOnDesktop(BaseInstance* instance, + QString shortcutName, + QString targetString, + QWidget* parent = nullptr, + const QStringList& extraArgs = {}); + +/// Create an instance shortcut in the Applications directory +void createInstanceShortcutInApplications(BaseInstance* instance, + QString shortcutName, + QString targetString, + QWidget* parent = nullptr, + const QStringList& extraArgs = {}); + +/// Create an instance shortcut in other directories +void createInstanceShortcutInOther(BaseInstance* instance, + QString shortcutName, + QString targetString, + QWidget* parent = nullptr, + const QStringList& extraArgs = {}); + +} // namespace ShortcutUtils diff --git a/launcher/ui/MainWindow.cpp b/launcher/ui/MainWindow.cpp index 232ba45cd..ed9961975 100644 --- a/launcher/ui/MainWindow.cpp +++ b/launcher/ui/MainWindow.cpp @@ -109,6 +109,7 @@ #include "ui/widgets/LabeledToolButton.h" #include "minecraft/PackProfile.h" +#include "minecraft/ShortcutUtils.h" #include "minecraft/VersionFile.h" #include "minecraft/WorldList.h" #include "minecraft/mod/ModFolderModel.h" @@ -1545,157 +1546,6 @@ void MainWindow::on_actionKillInstance_triggered() } } -void MainWindow::createInstanceShortcut(QString shortcutFilePath) -{ - if (!m_selectedInstance) - return; - - QString appPath = QApplication::applicationFilePath(); - QString iconPath; - QStringList args; -#if defined(Q_OS_MACOS) - appPath = QApplication::applicationFilePath(); - if (appPath.startsWith("/private/var/")) { - QMessageBox::critical(this, tr("Create instance shortcut"), - tr("The launcher is in the folder it was extracted from, therefore it cannot create shortcuts.")); - return; - } - - auto pIcon = APPLICATION->icons()->icon(m_selectedInstance->iconKey()); - if (pIcon == nullptr) { - pIcon = APPLICATION->icons()->icon("grass"); - } - - iconPath = FS::PathCombine(m_selectedInstance->instanceRoot(), "Icon.icns"); - - QFile iconFile(iconPath); - if (!iconFile.open(QFile::WriteOnly)) { - QMessageBox::critical(this, tr("Create instance Application"), tr("Failed to create icon for Application.")); - return; - } - - QIcon icon = pIcon->icon(); - - bool success = icon.pixmap(1024, 1024).save(iconPath, "ICNS"); - iconFile.close(); - - if (!success) { - iconFile.remove(); - QMessageBox::critical(this, tr("Create instance Application"), tr("Failed to create icon for Application.")); - return; - } -#elif defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) || defined(Q_OS_OPENBSD) - if (appPath.startsWith("/tmp/.mount_")) { - // AppImage! - appPath = QProcessEnvironment::systemEnvironment().value(QStringLiteral("APPIMAGE")); - if (appPath.isEmpty()) { - QMessageBox::critical(this, tr("Create instance shortcut"), - tr("Launcher is running as misconfigured AppImage? ($APPIMAGE environment variable is missing)")); - } else if (appPath.endsWith("/")) { - appPath.chop(1); - } - } - - auto icon = APPLICATION->icons()->icon(m_selectedInstance->iconKey()); - if (icon == nullptr) { - icon = APPLICATION->icons()->icon("grass"); - } - - iconPath = FS::PathCombine(m_selectedInstance->instanceRoot(), "icon.png"); - - QFile iconFile(iconPath); - if (!iconFile.open(QFile::WriteOnly)) { - QMessageBox::critical(this, tr("Create instance shortcut"), tr("Failed to create icon for shortcut.")); - return; - } - bool success = icon->icon().pixmap(64, 64).save(&iconFile, "PNG"); - iconFile.close(); - - if (!success) { - iconFile.remove(); - QMessageBox::critical(this, tr("Create instance shortcut"), tr("Failed to create icon for shortcut.")); - return; - } - - if (DesktopServices::isFlatpak()) { - appPath = "flatpak"; - args.append({ "run", BuildConfig.LAUNCHER_APPID }); - } - -#elif defined(Q_OS_WIN) - auto icon = APPLICATION->icons()->icon(m_selectedInstance->iconKey()); - if (icon == nullptr) { - icon = APPLICATION->icons()->icon("grass"); - } - - iconPath = FS::PathCombine(m_selectedInstance->instanceRoot(), "icon.ico"); - - // part of fix for weird bug involving the window icon being replaced - // dunno why it happens, but this 2-line fix seems to be enough, so w/e - auto appIcon = APPLICATION->getThemedIcon("logo"); - - QFile iconFile(iconPath); - if (!iconFile.open(QFile::WriteOnly)) { - QMessageBox::critical(this, tr("Create instance shortcut"), tr("Failed to create icon for shortcut.")); - return; - } - bool success = icon->icon().pixmap(64, 64).save(&iconFile, "ICO"); - iconFile.close(); - - // restore original window icon - QGuiApplication::setWindowIcon(appIcon); - - if (!success) { - iconFile.remove(); - QMessageBox::critical(this, tr("Create instance shortcut"), tr("Failed to create icon for shortcut.")); - return; - } - -#else - QMessageBox::critical(this, tr("Create instance shortcut"), tr("Not supported on your platform!")); - return; -#endif - args.append({ "--launch", m_selectedInstance->id() }); - - if (!FS::createShortcut(std::move(shortcutFilePath), appPath, args, m_selectedInstance->name(), iconPath)) { -#if not defined(Q_OS_MACOS) - iconFile.remove(); -#endif - QMessageBox::critical(this, tr("Create instance shortcut"), tr("Failed to create instance shortcut!")); - return; - } -} - -void MainWindow::on_actionCreateInstanceShortcutOther_triggered() -{ - if (!m_selectedInstance) - return; - - QString defaultedDir = FS::getDesktopDir(); -#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) || defined(Q_OS_OPENBSD) - QString extension = ".desktop"; -#elif defined(Q_OS_WINDOWS) - QString extension = ".lnk"; -#else - QString extension = ""; -#endif - - QString shortcutFilePath = FS::PathCombine(defaultedDir, FS::RemoveInvalidFilenameChars(m_selectedInstance->name()) + extension); - QFileDialog fileDialog; - // workaround to make sure the portal file dialog opens in the desktop directory - fileDialog.setDirectoryUrl(defaultedDir); - - shortcutFilePath = - fileDialog.getSaveFileName(this, tr("Create Shortcut"), shortcutFilePath, tr("Desktop Entries") + " (*" + extension + ")"); - if (shortcutFilePath.isEmpty()) - return; // file dialog canceled by user - - if(shortcutFilePath.endsWith(extension)) - shortcutFilePath = shortcutFilePath.mid(0, shortcutFilePath.length() - extension.length()); - createInstanceShortcut(shortcutFilePath); - QMessageBox::information(this, tr("Create instance shortcut"), tr("Created a shortcut to this instance!")); -} - void MainWindow::on_actionCreateInstanceShortcut_triggered() { if (!m_selectedInstance) @@ -1709,44 +1559,17 @@ void MainWindow::on_actionCreateInstanceShortcut_triggered() void MainWindow::on_actionCreateInstanceShortcutDesktop_triggered() { - if (!m_selectedInstance) - return; - - QString desktopDir = FS::getDesktopDir(); - if (desktopDir.isEmpty()) { - QMessageBox::critical(this, tr("Create instance shortcut"), tr("Couldn't find desktop?!")); - return; - } - - QString shortcutFilePath = FS::PathCombine(FS::getDesktopDir(), FS::RemoveInvalidFilenameChars(m_selectedInstance->name())); - createInstanceShortcut(shortcutFilePath); - QMessageBox::information(this, tr("Create instance shortcut"), tr("Created a shortcut to this instance on your desktop!")); + ShortcutUtils::createInstanceShortcutOnDesktop(m_selectedInstance.get(), m_selectedInstance->name(), tr("instance"), this); } void MainWindow::on_actionCreateInstanceShortcutApplications_triggered() { - if (!m_selectedInstance) - return; + ShortcutUtils::createInstanceShortcutInApplications(m_selectedInstance.get(), m_selectedInstance->name(), tr("instance"), this); +} - QString applicationsDir = FS::getApplicationsDir(); - if (applicationsDir.isEmpty()) { - QMessageBox::critical(this, tr("Create instance shortcut"), tr("Couldn't find applications folder?!")); - return; - } - -#if defined(Q_OS_MACOS) || defined(Q_OS_WIN) - applicationsDir = FS::PathCombine(applicationsDir, BuildConfig.LAUNCHER_DISPLAYNAME + " Instances"); - - QDir applicationsDirQ(applicationsDir); - if (!applicationsDirQ.mkpath(".")) { - QMessageBox::critical(this, tr("Create instance shortcut"), tr("Failed to create instances folder in applications folder!")); - return; - } -#endif - - QString shortcutFilePath = FS::PathCombine(applicationsDir, FS::RemoveInvalidFilenameChars(m_selectedInstance->name())); - createInstanceShortcut(shortcutFilePath); - QMessageBox::information(this, tr("Create instance shortcut"), tr("Created a shortcut to this instance in your applications folder!")); +void MainWindow::on_actionCreateInstanceShortcutOther_triggered() +{ + ShortcutUtils::createInstanceShortcutInOther(m_selectedInstance.get(), m_selectedInstance->name(), tr("instance"), this); } void MainWindow::taskEnd() diff --git a/launcher/ui/MainWindow.h b/launcher/ui/MainWindow.h index f3f2de730..20ab21e67 100644 --- a/launcher/ui/MainWindow.h +++ b/launcher/ui/MainWindow.h @@ -166,7 +166,6 @@ class MainWindow : public QMainWindow { void on_actionEditInstance_triggered(); void on_actionCreateInstanceShortcut_triggered(); - void on_actionCreateInstanceShortcutDesktop_triggered(); void on_actionCreateInstanceShortcutApplications_triggered(); void on_actionCreateInstanceShortcutOther_triggered(); @@ -230,7 +229,6 @@ class MainWindow : public QMainWindow { void setSelectedInstanceById(const QString& id); void updateStatusCenter(); void setInstanceActionsEnabled(bool enabled); - void createInstanceShortcut(QString shortcutDirPath); void runModalTask(Task* task); void instanceFromInstanceTask(InstanceTask* task); diff --git a/launcher/ui/MainWindow.ui b/launcher/ui/MainWindow.ui index 69d31589b..6530e2c5a 100644 --- a/launcher/ui/MainWindow.ui +++ b/launcher/ui/MainWindow.ui @@ -776,7 +776,7 @@ Desktop - Creates an shortcut to this instance on your desktop + Creates a shortcut to this instance on your desktop QAction::TextHeuristicRole From 37213ecc34797dd4388e1c8e97f22e407d8dfef5 Mon Sep 17 00:00:00 2001 From: Yihe Li Date: Sun, 11 May 2025 19:01:37 +0800 Subject: [PATCH 02/24] Add create shortcut button for worlds Signed-off-by: Yihe Li --- launcher/minecraft/WorldList.cpp | 38 +++++++++++++ launcher/minecraft/WorldList.h | 5 ++ launcher/ui/MainWindow.cpp | 8 +-- launcher/ui/pages/instance/WorldListPage.cpp | 58 ++++++++++++++++++++ launcher/ui/pages/instance/WorldListPage.h | 4 ++ launcher/ui/pages/instance/WorldListPage.ui | 44 ++++++++++++++- 6 files changed, 152 insertions(+), 5 deletions(-) diff --git a/launcher/minecraft/WorldList.cpp b/launcher/minecraft/WorldList.cpp index 6a821ba60..9a5cf042c 100644 --- a/launcher/minecraft/WorldList.cpp +++ b/launcher/minecraft/WorldList.cpp @@ -46,6 +46,9 @@ #include #include +#include +#include "minecraft/ShortcutUtils.h" + WorldList::WorldList(const QString& dir, BaseInstance* instance) : QAbstractListModel(), m_instance(instance), m_dir(dir) { FS::ensureFolderPathExists(m_dir.absolutePath()); @@ -454,4 +457,39 @@ void WorldList::loadWorldsAsync() } } +void WorldList::createWorldShortcut(const QModelIndex& index, QWidget* parent) const +{ + if (!m_instance) + return; + + if (DesktopServices::isFlatpak()) + createWorldShortcutInOther(index, parent); + else + createWorldShortcutOnDesktop(index, parent); +} + +void WorldList::createWorldShortcutOnDesktop(const QModelIndex& index, QWidget* parent) const +{ + auto world = static_cast(data(index, ObjectRole).value()); + QString name = QString(tr("%1 - %2")).arg(m_instance->name(), world->name()); + QStringList extraArgs{ "--world", world->name() }; + ShortcutUtils::createInstanceShortcutOnDesktop(m_instance, name, tr("world"), parent, extraArgs); +} + +void WorldList::createWorldShortcutInApplications(const QModelIndex& index, QWidget* parent) const +{ + auto world = static_cast(data(index, ObjectRole).value()); + QString name = QString(tr("%1 - %2")).arg(m_instance->name(), world->name()); + QStringList extraArgs{ "--world", world->name() }; + ShortcutUtils::createInstanceShortcutInApplications(m_instance, name, tr("world"), parent, extraArgs); +} + +void WorldList::createWorldShortcutInOther(const QModelIndex& index, QWidget* parent) const +{ + auto world = static_cast(data(index, ObjectRole).value()); + QString name = QString(tr("%1 - %2")).arg(m_instance->name(), world->name()); + QStringList extraArgs{ "--world", world->name() }; + ShortcutUtils::createInstanceShortcutInOther(m_instance, name, tr("world"), parent, extraArgs); +} + #include "WorldList.moc" diff --git a/launcher/minecraft/WorldList.h b/launcher/minecraft/WorldList.h index 93fecf1f5..4f54e0737 100644 --- a/launcher/minecraft/WorldList.h +++ b/launcher/minecraft/WorldList.h @@ -84,6 +84,11 @@ class WorldList : public QAbstractListModel { const QList& allWorlds() const { return m_worlds; } + void createWorldShortcut(const QModelIndex& index, QWidget* parent = nullptr) const; + void createWorldShortcutOnDesktop(const QModelIndex& index, QWidget* parent = nullptr) const; + void createWorldShortcutInApplications(const QModelIndex& index, QWidget* parent = nullptr) const; + void createWorldShortcutInOther(const QModelIndex& index, QWidget* parent = nullptr) const; + private slots: void directoryChanged(QString path); void loadWorldsAsync(); diff --git a/launcher/ui/MainWindow.cpp b/launcher/ui/MainWindow.cpp index ed9961975..4f03d14da 100644 --- a/launcher/ui/MainWindow.cpp +++ b/launcher/ui/MainWindow.cpp @@ -214,17 +214,17 @@ MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent), ui(new Ui::MainWi QString desktopDir = FS::getDesktopDir(); QString applicationDir = FS::getApplicationsDir(); - if(!applicationDir.isEmpty()) + if (!applicationDir.isEmpty()) shortcutActions.push_front(ui->actionCreateInstanceShortcutApplications); - if(!desktopDir.isEmpty()) + if (!desktopDir.isEmpty()) shortcutActions.push_front(ui->actionCreateInstanceShortcutDesktop); } - if(shortcutActions.length() > 1) { + if (shortcutActions.length() > 1) { auto shortcutInstanceMenu = new QMenu(this); - for(auto action : shortcutActions) + for (auto action : shortcutActions) shortcutInstanceMenu->addAction(action); ui->actionCreateInstanceShortcut->setMenu(shortcutInstanceMenu); } diff --git a/launcher/ui/pages/instance/WorldListPage.cpp b/launcher/ui/pages/instance/WorldListPage.cpp index 9e1a0fb55..f6a1e0e5f 100644 --- a/launcher/ui/pages/instance/WorldListPage.cpp +++ b/launcher/ui/pages/instance/WorldListPage.cpp @@ -345,6 +345,28 @@ void WorldListPage::worldChanged([[maybe_unused]] const QModelIndex& current, [[ if (!supportsJoin) { ui->toolBar->removeAction(ui->actionJoin); + ui->toolBar->removeAction(ui->actionCreateWorldShortcut); + } else { + QList shortcutActions = { ui->actionCreateWorldShortcutOther }; + if (!DesktopServices::isFlatpak()) { + QString desktopDir = FS::getDesktopDir(); + QString applicationDir = FS::getApplicationsDir(); + + if (!applicationDir.isEmpty()) + shortcutActions.push_front(ui->actionCreateWorldShortcutApplications); + + if (!desktopDir.isEmpty()) + shortcutActions.push_front(ui->actionCreateWorldShortcutDesktop); + } + + if (shortcutActions.length() > 1) { + auto shortcutInstanceMenu = new QMenu(this); + + for (auto action : shortcutActions) + shortcutInstanceMenu->addAction(action); + ui->actionCreateWorldShortcut->setMenu(shortcutInstanceMenu); + } + ui->actionCreateWorldShortcut->setEnabled(enable); } } @@ -420,6 +442,42 @@ void WorldListPage::on_actionRename_triggered() } } +void WorldListPage::on_actionCreateWorldShortcut_triggered() +{ + QModelIndex index = getSelectedWorld(); + if (!index.isValid()) { + return; + } + m_worlds->createWorldShortcut(index, this); +} + +void WorldListPage::on_actionCreateWorldShortcutDesktop_triggered() +{ + QModelIndex index = getSelectedWorld(); + if (!index.isValid()) { + return; + } + m_worlds->createWorldShortcutOnDesktop(index, this); +} + +void WorldListPage::on_actionCreateWorldShortcutApplications_triggered() +{ + QModelIndex index = getSelectedWorld(); + if (!index.isValid()) { + return; + } + m_worlds->createWorldShortcutInApplications(index, this); +} + +void WorldListPage::on_actionCreateWorldShortcutOther_triggered() +{ + QModelIndex index = getSelectedWorld(); + if (!index.isValid()) { + return; + } + m_worlds->createWorldShortcutInOther(index, this); +} + void WorldListPage::on_actionRefresh_triggered() { m_worlds->update(); diff --git a/launcher/ui/pages/instance/WorldListPage.h b/launcher/ui/pages/instance/WorldListPage.h index 84d9cd075..f2c081bc5 100644 --- a/launcher/ui/pages/instance/WorldListPage.h +++ b/launcher/ui/pages/instance/WorldListPage.h @@ -95,6 +95,10 @@ class WorldListPage : public QMainWindow, public BasePage { void on_actionAdd_triggered(); void on_actionCopy_triggered(); void on_actionRename_triggered(); + void on_actionCreateWorldShortcut_triggered(); + void on_actionCreateWorldShortcutDesktop_triggered(); + void on_actionCreateWorldShortcutApplications_triggered(); + void on_actionCreateWorldShortcutOther_triggered(); void on_actionRefresh_triggered(); void on_actionView_Folder_triggered(); void on_actionDatapacks_triggered(); diff --git a/launcher/ui/pages/instance/WorldListPage.ui b/launcher/ui/pages/instance/WorldListPage.ui index 04344b453..f4664d503 100644 --- a/launcher/ui/pages/instance/WorldListPage.ui +++ b/launcher/ui/pages/instance/WorldListPage.ui @@ -85,10 +85,11 @@ + + - @@ -118,6 +119,14 @@ Delete + + + Create Shortcut + + + Creates a shortcut on a selected folder to join the selected world. + + MCEdit @@ -154,6 +163,39 @@ Manage datapacks inside the world. + + + Desktop + + + Creates a shortcut to this world on your desktop + + + QAction::TextHeuristicRole + + + + + Applications + + + Create a shortcut of this world on your start menu + + + QAction::TextHeuristicRole + + + + + Other... + + + Creates a shortcut in a folder selected by you + + + QAction::TextHeuristicRole + + From dbdc9bea7a53ac0e26e69476d7a016f92afb8dff Mon Sep 17 00:00:00 2001 From: Yihe Li Date: Sun, 11 May 2025 19:16:37 +0800 Subject: [PATCH 03/24] Add create shortcut button for servers Signed-off-by: Yihe Li --- launcher/minecraft/ShortcutUtils.cpp | 1 - launcher/ui/pages/instance/ServersPage.cpp | 75 ++++++++++++++++++++++ launcher/ui/pages/instance/ServersPage.h | 4 ++ launcher/ui/pages/instance/ServersPage.ui | 45 ++++++++++++- 4 files changed, 123 insertions(+), 2 deletions(-) diff --git a/launcher/minecraft/ShortcutUtils.cpp b/launcher/minecraft/ShortcutUtils.cpp index 7d4faf231..c579368c2 100644 --- a/launcher/minecraft/ShortcutUtils.cpp +++ b/launcher/minecraft/ShortcutUtils.cpp @@ -170,7 +170,6 @@ void createInstanceShortcut(BaseInstance* instance, iconFile.remove(); #endif QMessageBox::critical(parent, QObject::tr("Create Shortcut"), QObject::tr("Failed to create %1 shortcut!").arg(targetString)); - return; } } diff --git a/launcher/ui/pages/instance/ServersPage.cpp b/launcher/ui/pages/instance/ServersPage.cpp index 245bbffe2..88b21a787 100644 --- a/launcher/ui/pages/instance/ServersPage.cpp +++ b/launcher/ui/pages/instance/ServersPage.cpp @@ -40,8 +40,10 @@ #include "ui/dialogs/CustomMessageBox.h" #include "ui_ServersPage.h" +#include #include #include +#include #include #include #include @@ -102,6 +104,38 @@ struct Server { } } + void createServerShortcut(BaseInstance* instance, QWidget* parent = nullptr) const + { + if (!instance) + return; + + if (DesktopServices::isFlatpak()) + createServerShortcutInOther(instance, parent); + else + createServerShortcutOnDesktop(instance, parent); + } + + void createServerShortcutOnDesktop(BaseInstance* instance, QWidget* parent = nullptr) const + { + QString name = QString(QObject::tr("%1 - Server %2")).arg(instance->name(), m_name); + QStringList extraArgs{ "--server", m_address }; + ShortcutUtils::createInstanceShortcutOnDesktop(instance, name, QObject::tr("server"), parent, extraArgs); + } + + void createServerShortcutInApplications(BaseInstance* instance, QWidget* parent = nullptr) const + { + QString name = QString(QObject::tr("%1 - Server %2")).arg(instance->name(), m_name); + QStringList extraArgs{ "--server", m_address }; + ShortcutUtils::createInstanceShortcutInApplications(instance, name, QObject::tr("server"), parent, extraArgs); + } + + void createServerShortcutInOther(BaseInstance* instance, QWidget* parent = nullptr) const + { + QString name = QString(QObject::tr("%1 - Server %2")).arg(instance->name(), m_name); + QStringList extraArgs{ "--server", m_address }; + ShortcutUtils::createInstanceShortcutInOther(instance, name, QObject::tr("server"), parent, extraArgs); + } + // Data - persistent and user changeable QString m_name; QString m_address; @@ -696,6 +730,27 @@ void ServersPage::updateState() } ui->actionAdd->setDisabled(m_locked); + + QList shortcutActions = { ui->actionCreateServerShortcutOther }; + if (!DesktopServices::isFlatpak()) { + QString desktopDir = FS::getDesktopDir(); + QString applicationDir = FS::getApplicationsDir(); + + if (!applicationDir.isEmpty()) + shortcutActions.push_front(ui->actionCreateServerShortcutApplications); + + if (!desktopDir.isEmpty()) + shortcutActions.push_front(ui->actionCreateServerShortcutDesktop); + } + + if (shortcutActions.length() > 1) { + auto shortcutInstanceMenu = new QMenu(this); + + for (auto action : shortcutActions) + shortcutInstanceMenu->addAction(action); + ui->actionCreateServerShortcut->setMenu(shortcutInstanceMenu); + } + ui->actionCreateServerShortcut->setEnabled(serverEditEnabled); } void ServersPage::openedImpl() @@ -767,6 +822,26 @@ void ServersPage::on_actionJoin_triggered() APPLICATION->launch(m_inst, true, false, std::make_shared(MinecraftTarget::parse(address, false))); } +void ServersPage::on_actionCreateServerShortcut_triggered() +{ + m_model->at(currentServer)->createServerShortcut(m_inst.get(), this); +} + +void ServersPage::on_actionCreateServerShortcutDesktop_triggered() +{ + m_model->at(currentServer)->createServerShortcutOnDesktop(m_inst.get(), this); +} + +void ServersPage::on_actionCreateServerShortcutApplications_triggered() +{ + m_model->at(currentServer)->createServerShortcutInApplications(m_inst.get(), this); +} + +void ServersPage::on_actionCreateServerShortcutOther_triggered() +{ + m_model->at(currentServer)->createServerShortcutInOther(m_inst.get(), this); +} + void ServersPage::on_actionRefresh_triggered() { m_model->queryServersStatus(); diff --git a/launcher/ui/pages/instance/ServersPage.h b/launcher/ui/pages/instance/ServersPage.h index 77710d6cc..94baaa004 100644 --- a/launcher/ui/pages/instance/ServersPage.h +++ b/launcher/ui/pages/instance/ServersPage.h @@ -85,6 +85,10 @@ class ServersPage : public QMainWindow, public BasePage { void on_actionMove_Up_triggered(); void on_actionMove_Down_triggered(); void on_actionJoin_triggered(); + void on_actionCreateServerShortcut_triggered(); + void on_actionCreateServerShortcutDesktop_triggered(); + void on_actionCreateServerShortcutApplications_triggered(); + void on_actionCreateServerShortcutOther_triggered(); void on_actionRefresh_triggered(); void runningStateChanged(bool running); diff --git a/launcher/ui/pages/instance/ServersPage.ui b/launcher/ui/pages/instance/ServersPage.ui index d330835c8..e26152242 100644 --- a/launcher/ui/pages/instance/ServersPage.ui +++ b/launcher/ui/pages/instance/ServersPage.ui @@ -145,10 +145,12 @@ false + + - + @@ -177,6 +179,47 @@ Join + + + Create Shortcut + + + Creates a shortcut on a selected folder to join the selected server. + + + + + Desktop + + + Creates a shortcut to this server on your desktop + + + QAction::TextHeuristicRole + + + + + Applications + + + Create a shortcut of this server on your start menu + + + QAction::TextHeuristicRole + + + + + Other... + + + Creates a shortcut in a folder selected by you + + + QAction::TextHeuristicRole + + Refresh From 039682b7dc70b7d5d9c6d5b7694444010e1b0574 Mon Sep 17 00:00:00 2001 From: Yihe Li Date: Tue, 13 May 2025 03:09:49 +0800 Subject: [PATCH 04/24] Remove inappropriate comments Signed-off-by: Yihe Li --- launcher/minecraft/ShortcutUtils.cpp | 1 - launcher/minecraft/ShortcutUtils.h | 1 - 2 files changed, 2 deletions(-) diff --git a/launcher/minecraft/ShortcutUtils.cpp b/launcher/minecraft/ShortcutUtils.cpp index c579368c2..de8bd3cb3 100644 --- a/launcher/minecraft/ShortcutUtils.cpp +++ b/launcher/minecraft/ShortcutUtils.cpp @@ -1,7 +1,6 @@ // SPDX-License-Identifier: GPL-3.0-only /* * Prism Launcher - Minecraft Launcher - * Copyright (C) 2022 Sefa Eyeoglu * * parent 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/minecraft/ShortcutUtils.h b/launcher/minecraft/ShortcutUtils.h index 88800f5e6..0bc18b61e 100644 --- a/launcher/minecraft/ShortcutUtils.h +++ b/launcher/minecraft/ShortcutUtils.h @@ -1,7 +1,6 @@ // SPDX-License-Identifier: GPL-3.0-only /* * Prism Launcher - Minecraft Launcher - * Copyright (C) 2022 Sefa Eyeoglu * * 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 From bae0ac7ad6bdcd1299c8fdacd91796176308e0ac Mon Sep 17 00:00:00 2001 From: Yihe Li Date: Tue, 13 May 2025 03:12:20 +0800 Subject: [PATCH 05/24] Use index.row() directly Signed-off-by: Yihe Li --- launcher/minecraft/WorldList.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/launcher/minecraft/WorldList.cpp b/launcher/minecraft/WorldList.cpp index 9a5cf042c..ec6328018 100644 --- a/launcher/minecraft/WorldList.cpp +++ b/launcher/minecraft/WorldList.cpp @@ -470,25 +470,25 @@ void WorldList::createWorldShortcut(const QModelIndex& index, QWidget* parent) c void WorldList::createWorldShortcutOnDesktop(const QModelIndex& index, QWidget* parent) const { - auto world = static_cast(data(index, ObjectRole).value()); - QString name = QString(tr("%1 - %2")).arg(m_instance->name(), world->name()); - QStringList extraArgs{ "--world", world->name() }; + const auto& world = allWorlds().at(index.row()); + QString name = QString(tr("%1 - %2")).arg(m_instance->name(), world.name()); + QStringList extraArgs{ "--world", world.name() }; ShortcutUtils::createInstanceShortcutOnDesktop(m_instance, name, tr("world"), parent, extraArgs); } void WorldList::createWorldShortcutInApplications(const QModelIndex& index, QWidget* parent) const { - auto world = static_cast(data(index, ObjectRole).value()); - QString name = QString(tr("%1 - %2")).arg(m_instance->name(), world->name()); - QStringList extraArgs{ "--world", world->name() }; + const auto& world = allWorlds().at(index.row()); + QString name = QString(tr("%1 - %2")).arg(m_instance->name(), world.name()); + QStringList extraArgs{ "--world", world.name() }; ShortcutUtils::createInstanceShortcutInApplications(m_instance, name, tr("world"), parent, extraArgs); } void WorldList::createWorldShortcutInOther(const QModelIndex& index, QWidget* parent) const { - auto world = static_cast(data(index, ObjectRole).value()); - QString name = QString(tr("%1 - %2")).arg(m_instance->name(), world->name()); - QStringList extraArgs{ "--world", world->name() }; + const auto& world = allWorlds().at(index.row()); + QString name = QString(tr("%1 - %2")).arg(m_instance->name(), world.name()); + QStringList extraArgs{ "--world", world.name() }; ShortcutUtils::createInstanceShortcutInOther(m_instance, name, tr("world"), parent, extraArgs); } From db82988943a0f98dda5adbd2463239623226a5b0 Mon Sep 17 00:00:00 2001 From: Yihe Li Date: Tue, 13 May 2025 03:23:28 +0800 Subject: [PATCH 06/24] Re-add an appropriate copyright comment Signed-off-by: Yihe Li --- launcher/minecraft/ShortcutUtils.cpp | 3 +++ launcher/minecraft/ShortcutUtils.h | 3 +++ 2 files changed, 6 insertions(+) diff --git a/launcher/minecraft/ShortcutUtils.cpp b/launcher/minecraft/ShortcutUtils.cpp index de8bd3cb3..ac3a60614 100644 --- a/launcher/minecraft/ShortcutUtils.cpp +++ b/launcher/minecraft/ShortcutUtils.cpp @@ -1,6 +1,9 @@ // SPDX-License-Identifier: GPL-3.0-only /* * Prism Launcher - Minecraft Launcher + * Copyright (C) 2022 Sefa Eyeoglu + * Copyright (C) 2023 TheKodeToad + * Copyright (C) 2025 Yihe Li * * parent 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/minecraft/ShortcutUtils.h b/launcher/minecraft/ShortcutUtils.h index 0bc18b61e..7c0eeea5d 100644 --- a/launcher/minecraft/ShortcutUtils.h +++ b/launcher/minecraft/ShortcutUtils.h @@ -1,6 +1,9 @@ // SPDX-License-Identifier: GPL-3.0-only /* * Prism Launcher - Minecraft Launcher + * Copyright (C) 2022 Sefa Eyeoglu + * Copyright (C) 2023 TheKodeToad + * Copyright (C) 2025 Yihe Li * * 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 From 31dc84653d454e8b913d7bf06609096e335c8318 Mon Sep 17 00:00:00 2001 From: Yihe Li Date: Tue, 13 May 2025 05:14:45 +0800 Subject: [PATCH 07/24] Refactor shortcut parameter into its own struct Signed-off-by: Yihe Li --- launcher/minecraft/ShortcutUtils.cpp | 103 +++++++++------------ launcher/minecraft/ShortcutUtils.h | 34 +++---- launcher/minecraft/WorldList.cpp | 6 +- launcher/ui/MainWindow.cpp | 6 +- launcher/ui/pages/instance/ServersPage.cpp | 6 +- 5 files changed, 66 insertions(+), 89 deletions(-) diff --git a/launcher/minecraft/ShortcutUtils.cpp b/launcher/minecraft/ShortcutUtils.cpp index ac3a60614..2bbeacb08 100644 --- a/launcher/minecraft/ShortcutUtils.cpp +++ b/launcher/minecraft/ShortcutUtils.cpp @@ -48,14 +48,9 @@ namespace ShortcutUtils { -void createInstanceShortcut(BaseInstance* instance, - QString shortcutName, - QString shortcutFilePath, - QString targetString, - QWidget* parent, - const QStringList& extraArgs) +void createInstanceShortcut(const Shortcut& shortcut, const QString& filePath) { - if (!instance) + if (!shortcut.instance) return; QString appPath = QApplication::applicationFilePath(); @@ -64,21 +59,21 @@ void createInstanceShortcut(BaseInstance* instance, #if defined(Q_OS_MACOS) appPath = QApplication::applicationFilePath(); if (appPath.startsWith("/private/var/")) { - QMessageBox::critical(parent, QObject::tr("Create Shortcut"), + QMessageBox::critical(shortcut.parent, QObject::tr("Create Shortcut"), QObject::tr("The launcher is in the folder it was extracted from, therefore it cannot create shortcuts.")); return; } - auto pIcon = APPLICATION->icons()->icon(instance->iconKey()); + auto pIcon = APPLICATION->icons()->icon(shortcut.instance->iconKey()); if (pIcon == nullptr) { pIcon = APPLICATION->icons()->icon("grass"); } - iconPath = FS::PathCombine(instance->instanceRoot(), "Icon.icns"); + iconPath = FS::PathCombine(shortcut.instance->instanceRoot(), "Icon.icns"); QFile iconFile(iconPath); if (!iconFile.open(QFile::WriteOnly)) { - QMessageBox::critical(parent, QObject::tr("Create Shortcut"), QObject::tr("Failed to create icon for application.")); + QMessageBox::critical(shortcut.parent, QObject::tr("Create Shortcut"), QObject::tr("Failed to create icon for application.")); return; } @@ -89,7 +84,7 @@ void createInstanceShortcut(BaseInstance* instance, if (!success) { iconFile.remove(); - QMessageBox::critical(parent, QObject::tr("Create Shortcut"), QObject::tr("Failed to create icon for application.")); + QMessageBox::critical(shortcut.parent, QObject::tr("Create Shortcut"), QObject::tr("Failed to create icon for application.")); return; } #elif defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) || defined(Q_OS_OPENBSD) @@ -98,23 +93,23 @@ void createInstanceShortcut(BaseInstance* instance, appPath = QProcessEnvironment::systemEnvironment().value(QStringLiteral("APPIMAGE")); if (appPath.isEmpty()) { QMessageBox::critical( - parent, QObject::tr("Create Shortcut"), + shortcut.parent, QObject::tr("Create Shortcut"), QObject::tr("Launcher is running as misconfigured AppImage? ($APPIMAGE environment variable is missing)")); } else if (appPath.endsWith("/")) { appPath.chop(1); } } - auto icon = APPLICATION->icons()->icon(instance->iconKey()); + auto icon = APPLICATION->icons()->icon(shortcut.instance->iconKey()); if (icon == nullptr) { icon = APPLICATION->icons()->icon("grass"); } - iconPath = FS::PathCombine(instance->instanceRoot(), "icon.png"); + iconPath = FS::PathCombine(shortcut.instance->instanceRoot(), "icon.png"); QFile iconFile(iconPath); if (!iconFile.open(QFile::WriteOnly)) { - QMessageBox::critical(parent, QObject::tr("Create Shortcut"), QObject::tr("Failed to create icon for shortcut.")); + QMessageBox::critical(shortcut.parent, QObject::tr("Create Shortcut"), QObject::tr("Failed to create icon for shortcut.")); return; } bool success = icon->icon().pixmap(64, 64).save(&iconFile, "PNG"); @@ -122,7 +117,7 @@ void createInstanceShortcut(BaseInstance* instance, if (!success) { iconFile.remove(); - QMessageBox::critical(parent, QObject::tr("Create Shortcut"), QObject::tr("Failed to create icon for shortcut.")); + QMessageBox::critical(shortcut.parent, QObject::tr("Create Shortcut"), QObject::tr("Failed to create icon for shortcut.")); return; } @@ -132,12 +127,12 @@ void createInstanceShortcut(BaseInstance* instance, } #elif defined(Q_OS_WIN) - auto icon = APPLICATION->icons()->icon(instance->iconKey()); + auto icon = APPLICATION->icons()->icon(shortcut.instance->iconKey()); if (icon == nullptr) { icon = APPLICATION->icons()->icon("grass"); } - iconPath = FS::PathCombine(instance->instanceRoot(), "icon.ico"); + iconPath = FS::PathCombine(shortcut.instance->instanceRoot(), "icon.ico"); // part of fix for weird bug involving the window icon being replaced // dunno why it happens, but parent 2-line fix seems to be enough, so w/e @@ -145,7 +140,7 @@ void createInstanceShortcut(BaseInstance* instance, QFile iconFile(iconPath); if (!iconFile.open(QFile::WriteOnly)) { - QMessageBox::critical(parent, QObject::tr("Create Shortcut"), QObject::tr("Failed to create icon for shortcut.")); + QMessageBox::critical(shortcut.parent, QObject::tr("Create Shortcut"), QObject::tr("Failed to create icon for shortcut.")); return; } bool success = icon->icon().pixmap(64, 64).save(&iconFile, "ICO"); @@ -156,58 +151,51 @@ void createInstanceShortcut(BaseInstance* instance, if (!success) { iconFile.remove(); - QMessageBox::critical(parent, QObject::tr("Create Shortcut"), QObject::tr("Failed to create icon for shortcut.")); + QMessageBox::critical(shortcut.parent, QObject::tr("Create Shortcut"), QObject::tr("Failed to create icon for shortcut.")); return; } #else - QMessageBox::critical(parent, QObject::tr("Create Shortcut"), QObject::tr("Not supported on your platform!")); + QMessageBox::critical(shortcut.parent, QObject::tr("Create Shortcut"), QObject::tr("Not supported on your platform!")); return; #endif - args.append({ "--launch", instance->id() }); - args.append(extraArgs); + args.append({ "--launch", shortcut.instance->id() }); + args.append(shortcut.extraArgs); - if (!FS::createShortcut(std::move(shortcutFilePath), appPath, args, shortcutName, iconPath)) { + if (!FS::createShortcut(std::move(filePath), appPath, args, shortcut.name, iconPath)) { #if not defined(Q_OS_MACOS) iconFile.remove(); #endif - QMessageBox::critical(parent, QObject::tr("Create Shortcut"), QObject::tr("Failed to create %1 shortcut!").arg(targetString)); + QMessageBox::critical(shortcut.parent, QObject::tr("Create Shortcut"), + QObject::tr("Failed to create %1 shortcut!").arg(shortcut.targetString)); } } -void createInstanceShortcutOnDesktop(BaseInstance* instance, - QString shortcutName, - QString targetString, - QWidget* parent, - const QStringList& extraArgs) +void createInstanceShortcutOnDesktop(const Shortcut& shortcut) { - if (!instance) + if (!shortcut.instance) return; QString desktopDir = FS::getDesktopDir(); if (desktopDir.isEmpty()) { - QMessageBox::critical(parent, QObject::tr("Create Shortcut"), QObject::tr("Couldn't find desktop?!")); + QMessageBox::critical(shortcut.parent, QObject::tr("Create Shortcut"), QObject::tr("Couldn't find desktop?!")); return; } - QString shortcutFilePath = FS::PathCombine(FS::getDesktopDir(), FS::RemoveInvalidFilenameChars(shortcutName)); - createInstanceShortcut(instance, shortcutName, shortcutFilePath, targetString, parent, extraArgs); - QMessageBox::information(parent, QObject::tr("Create Shortcut"), - QObject::tr("Created a shortcut to this %1 on your desktop!").arg(targetString)); + QString shortcutFilePath = FS::PathCombine(desktopDir, FS::RemoveInvalidFilenameChars(shortcut.name)); + createInstanceShortcut(shortcut, shortcutFilePath); + QMessageBox::information(shortcut.parent, QObject::tr("Create Shortcut"), + QObject::tr("Created a shortcut to this %1 on your desktop!").arg(shortcut.targetString)); } -void createInstanceShortcutInApplications(BaseInstance* instance, - QString shortcutName, - QString targetString, - QWidget* parent, - const QStringList& extraArgs) +void createInstanceShortcutInApplications(const Shortcut& shortcut) { - if (!instance) + if (!shortcut.instance) return; QString applicationsDir = FS::getApplicationsDir(); if (applicationsDir.isEmpty()) { - QMessageBox::critical(parent, QObject::tr("Create Shortcut"), QObject::tr("Couldn't find applications folder?!")); + QMessageBox::critical(shortcut.parent, QObject::tr("Create Shortcut"), QObject::tr("Couldn't find applications folder?!")); return; } @@ -216,25 +204,21 @@ void createInstanceShortcutInApplications(BaseInstance* instance, QDir applicationsDirQ(applicationsDir); if (!applicationsDirQ.mkpath(".")) { - QMessageBox::critical(parent, QObject::tr("Create Shortcut"), + QMessageBox::critical(shortcut.parent, QObject::tr("Create Shortcut"), QObject::tr("Failed to create instances folder in applications folder!")); return; } #endif - QString shortcutFilePath = FS::PathCombine(applicationsDir, FS::RemoveInvalidFilenameChars(shortcutName)); - createInstanceShortcut(instance, shortcutName, shortcutFilePath, targetString, parent, extraArgs); - QMessageBox::information(parent, QObject::tr("Create Shortcut"), - QObject::tr("Created a shortcut to this %1 in your applications folder!").arg(targetString)); + QString shortcutFilePath = FS::PathCombine(applicationsDir, FS::RemoveInvalidFilenameChars(shortcut.name)); + createInstanceShortcut(shortcut, shortcutFilePath); + QMessageBox::information(shortcut.parent, QObject::tr("Create Shortcut"), + QObject::tr("Created a shortcut to this %1 in your applications folder!").arg(shortcut.targetString)); } -void createInstanceShortcutInOther(BaseInstance* instance, - QString shortcutName, - QString targetString, - QWidget* parent, - const QStringList& extraArgs) +void createInstanceShortcutInOther(const Shortcut& shortcut) { - if (!instance) + if (!shortcut.instance) return; QString defaultedDir = FS::getDesktopDir(); @@ -246,20 +230,21 @@ void createInstanceShortcutInOther(BaseInstance* instance, QString extension = ""; #endif - QString shortcutFilePath = FS::PathCombine(defaultedDir, FS::RemoveInvalidFilenameChars(shortcutName) + extension); + QString shortcutFilePath = FS::PathCombine(defaultedDir, FS::RemoveInvalidFilenameChars(shortcut.name) + extension); QFileDialog fileDialog; // workaround to make sure the portal file dialog opens in the desktop directory fileDialog.setDirectoryUrl(defaultedDir); - shortcutFilePath = fileDialog.getSaveFileName(parent, QObject::tr("Create Shortcut"), shortcutFilePath, + shortcutFilePath = fileDialog.getSaveFileName(shortcut.parent, QObject::tr("Create Shortcut"), shortcutFilePath, QObject::tr("Desktop Entries") + " (*" + extension + ")"); if (shortcutFilePath.isEmpty()) return; // file dialog canceled by user if (shortcutFilePath.endsWith(extension)) shortcutFilePath = shortcutFilePath.mid(0, shortcutFilePath.length() - extension.length()); - createInstanceShortcut(instance, shortcutName, shortcutFilePath, targetString, parent, extraArgs); - QMessageBox::information(parent, QObject::tr("Create Shortcut"), QObject::tr("Created a shortcut to this %1!").arg(targetString)); + createInstanceShortcut(shortcut, shortcutFilePath); + QMessageBox::information(shortcut.parent, QObject::tr("Create Shortcut"), + QObject::tr("Created a shortcut to this %1!").arg(shortcut.targetString)); } } // namespace ShortcutUtils diff --git a/launcher/minecraft/ShortcutUtils.h b/launcher/minecraft/ShortcutUtils.h index 7c0eeea5d..a21ccf06a 100644 --- a/launcher/minecraft/ShortcutUtils.h +++ b/launcher/minecraft/ShortcutUtils.h @@ -41,33 +41,25 @@ #include namespace ShortcutUtils { +/// A struct to hold parameters for creating a shortcut +struct Shortcut { + BaseInstance* instance; + QString name; + QString targetString; + QWidget* parent = nullptr; + QStringList extraArgs = {}; +}; + /// Create an instance shortcut on the specified file path -void createInstanceShortcut(BaseInstance* instance, - QString shortcutName, - QString shortcutFilePath, - QString targetString, - QWidget* parent = nullptr, - const QStringList& extraArgs = {}); +void createInstanceShortcut(const Shortcut& shortcut, const QString& filePath); /// Create an instance shortcut on the desktop -void createInstanceShortcutOnDesktop(BaseInstance* instance, - QString shortcutName, - QString targetString, - QWidget* parent = nullptr, - const QStringList& extraArgs = {}); +void createInstanceShortcutOnDesktop(const Shortcut& shortcut); /// Create an instance shortcut in the Applications directory -void createInstanceShortcutInApplications(BaseInstance* instance, - QString shortcutName, - QString targetString, - QWidget* parent = nullptr, - const QStringList& extraArgs = {}); +void createInstanceShortcutInApplications(const Shortcut& shortcut); /// Create an instance shortcut in other directories -void createInstanceShortcutInOther(BaseInstance* instance, - QString shortcutName, - QString targetString, - QWidget* parent = nullptr, - const QStringList& extraArgs = {}); +void createInstanceShortcutInOther(const Shortcut& shortcut); } // namespace ShortcutUtils diff --git a/launcher/minecraft/WorldList.cpp b/launcher/minecraft/WorldList.cpp index ec6328018..582531577 100644 --- a/launcher/minecraft/WorldList.cpp +++ b/launcher/minecraft/WorldList.cpp @@ -473,7 +473,7 @@ void WorldList::createWorldShortcutOnDesktop(const QModelIndex& index, QWidget* const auto& world = allWorlds().at(index.row()); QString name = QString(tr("%1 - %2")).arg(m_instance->name(), world.name()); QStringList extraArgs{ "--world", world.name() }; - ShortcutUtils::createInstanceShortcutOnDesktop(m_instance, name, tr("world"), parent, extraArgs); + ShortcutUtils::createInstanceShortcutOnDesktop({ m_instance, name, tr("world"), parent, extraArgs }); } void WorldList::createWorldShortcutInApplications(const QModelIndex& index, QWidget* parent) const @@ -481,7 +481,7 @@ void WorldList::createWorldShortcutInApplications(const QModelIndex& index, QWid const auto& world = allWorlds().at(index.row()); QString name = QString(tr("%1 - %2")).arg(m_instance->name(), world.name()); QStringList extraArgs{ "--world", world.name() }; - ShortcutUtils::createInstanceShortcutInApplications(m_instance, name, tr("world"), parent, extraArgs); + ShortcutUtils::createInstanceShortcutInApplications({ m_instance, name, tr("world"), parent, extraArgs }); } void WorldList::createWorldShortcutInOther(const QModelIndex& index, QWidget* parent) const @@ -489,7 +489,7 @@ void WorldList::createWorldShortcutInOther(const QModelIndex& index, QWidget* pa const auto& world = allWorlds().at(index.row()); QString name = QString(tr("%1 - %2")).arg(m_instance->name(), world.name()); QStringList extraArgs{ "--world", world.name() }; - ShortcutUtils::createInstanceShortcutInOther(m_instance, name, tr("world"), parent, extraArgs); + ShortcutUtils::createInstanceShortcutInOther({ m_instance, name, tr("world"), parent, extraArgs }); } #include "WorldList.moc" diff --git a/launcher/ui/MainWindow.cpp b/launcher/ui/MainWindow.cpp index 4f03d14da..d64e92124 100644 --- a/launcher/ui/MainWindow.cpp +++ b/launcher/ui/MainWindow.cpp @@ -1559,17 +1559,17 @@ void MainWindow::on_actionCreateInstanceShortcut_triggered() void MainWindow::on_actionCreateInstanceShortcutDesktop_triggered() { - ShortcutUtils::createInstanceShortcutOnDesktop(m_selectedInstance.get(), m_selectedInstance->name(), tr("instance"), this); + ShortcutUtils::createInstanceShortcutOnDesktop({ m_selectedInstance.get(), m_selectedInstance->name(), tr("instance"), this }); } void MainWindow::on_actionCreateInstanceShortcutApplications_triggered() { - ShortcutUtils::createInstanceShortcutInApplications(m_selectedInstance.get(), m_selectedInstance->name(), tr("instance"), this); + ShortcutUtils::createInstanceShortcutInApplications({ m_selectedInstance.get(), m_selectedInstance->name(), tr("instance"), this }); } void MainWindow::on_actionCreateInstanceShortcutOther_triggered() { - ShortcutUtils::createInstanceShortcutInOther(m_selectedInstance.get(), m_selectedInstance->name(), tr("instance"), this); + ShortcutUtils::createInstanceShortcutInOther({ m_selectedInstance.get(), m_selectedInstance->name(), tr("instance"), this }); } void MainWindow::taskEnd() diff --git a/launcher/ui/pages/instance/ServersPage.cpp b/launcher/ui/pages/instance/ServersPage.cpp index 88b21a787..b29cc1137 100644 --- a/launcher/ui/pages/instance/ServersPage.cpp +++ b/launcher/ui/pages/instance/ServersPage.cpp @@ -119,21 +119,21 @@ struct Server { { QString name = QString(QObject::tr("%1 - Server %2")).arg(instance->name(), m_name); QStringList extraArgs{ "--server", m_address }; - ShortcutUtils::createInstanceShortcutOnDesktop(instance, name, QObject::tr("server"), parent, extraArgs); + ShortcutUtils::createInstanceShortcutOnDesktop({ instance, name, QObject::tr("server"), parent, extraArgs }); } void createServerShortcutInApplications(BaseInstance* instance, QWidget* parent = nullptr) const { QString name = QString(QObject::tr("%1 - Server %2")).arg(instance->name(), m_name); QStringList extraArgs{ "--server", m_address }; - ShortcutUtils::createInstanceShortcutInApplications(instance, name, QObject::tr("server"), parent, extraArgs); + ShortcutUtils::createInstanceShortcutInApplications({ instance, name, QObject::tr("server"), parent, extraArgs }); } void createServerShortcutInOther(BaseInstance* instance, QWidget* parent = nullptr) const { QString name = QString(QObject::tr("%1 - Server %2")).arg(instance->name(), m_name); QStringList extraArgs{ "--server", m_address }; - ShortcutUtils::createInstanceShortcutInOther(instance, name, QObject::tr("server"), parent, extraArgs); + ShortcutUtils::createInstanceShortcutInOther({ instance, name, QObject::tr("server"), parent, extraArgs }); } // Data - persistent and user changeable From f3c253d7086e669aa7d56488cf0ad3227cc28368 Mon Sep 17 00:00:00 2001 From: Yihe Li Date: Thu, 15 May 2025 19:05:40 +0800 Subject: [PATCH 08/24] Fix menu issues Signed-off-by: Yihe Li --- launcher/ui/pages/instance/ServersPage.ui | 3 +++ launcher/ui/pages/instance/WorldListPage.ui | 3 +++ 2 files changed, 6 insertions(+) diff --git a/launcher/ui/pages/instance/ServersPage.ui b/launcher/ui/pages/instance/ServersPage.ui index e26152242..bb8bff5aa 100644 --- a/launcher/ui/pages/instance/ServersPage.ui +++ b/launcher/ui/pages/instance/ServersPage.ui @@ -135,6 +135,9 @@ Qt::ToolButtonTextOnly + + true + false diff --git a/launcher/ui/pages/instance/WorldListPage.ui b/launcher/ui/pages/instance/WorldListPage.ui index f4664d503..6d951cbdd 100644 --- a/launcher/ui/pages/instance/WorldListPage.ui +++ b/launcher/ui/pages/instance/WorldListPage.ui @@ -70,6 +70,9 @@ Qt::ToolButtonTextOnly + + true + false From bc1d1b41c0c8c8718fb175790d458744a5c9fe42 Mon Sep 17 00:00:00 2001 From: Yihe Li Date: Thu, 15 May 2025 19:12:15 +0800 Subject: [PATCH 09/24] Move menu creation to constructors to avoid performance issues Signed-off-by: Yihe Li --- launcher/ui/pages/instance/ServersPage.cpp | 42 ++++++++++---------- launcher/ui/pages/instance/WorldListPage.cpp | 39 +++++++++--------- 2 files changed, 41 insertions(+), 40 deletions(-) diff --git a/launcher/ui/pages/instance/ServersPage.cpp b/launcher/ui/pages/instance/ServersPage.cpp index b29cc1137..36844d92a 100644 --- a/launcher/ui/pages/instance/ServersPage.cpp +++ b/launcher/ui/pages/instance/ServersPage.cpp @@ -615,6 +615,26 @@ ServersPage::ServersPage(InstancePtr inst, QWidget* parent) : QMainWindow(parent connect(ui->resourceComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(resourceIndexChanged(int))); connect(m_model, &QAbstractItemModel::rowsRemoved, this, &ServersPage::rowsRemoved); + QList shortcutActions = { ui->actionCreateServerShortcutOther }; + if (!DesktopServices::isFlatpak()) { + QString desktopDir = FS::getDesktopDir(); + QString applicationDir = FS::getApplicationsDir(); + + if (!applicationDir.isEmpty()) + shortcutActions.push_front(ui->actionCreateServerShortcutApplications); + + if (!desktopDir.isEmpty()) + shortcutActions.push_front(ui->actionCreateServerShortcutDesktop); + } + + if (shortcutActions.length() > 1) { + auto shortcutInstanceMenu = new QMenu(this); + + for (auto action : shortcutActions) + shortcutInstanceMenu->addAction(action); + ui->actionCreateServerShortcut->setMenu(shortcutInstanceMenu); + } + m_locked = m_inst->isRunning(); if (m_locked) { m_model->lock(); @@ -718,6 +738,7 @@ void ServersPage::updateState() ui->actionMove_Up->setEnabled(serverEditEnabled); ui->actionRemove->setEnabled(serverEditEnabled); ui->actionJoin->setEnabled(serverEditEnabled); + ui->actionCreateServerShortcut->setEnabled(serverEditEnabled); if (server) { ui->addressLine->setText(server->m_address); @@ -730,27 +751,6 @@ void ServersPage::updateState() } ui->actionAdd->setDisabled(m_locked); - - QList shortcutActions = { ui->actionCreateServerShortcutOther }; - if (!DesktopServices::isFlatpak()) { - QString desktopDir = FS::getDesktopDir(); - QString applicationDir = FS::getApplicationsDir(); - - if (!applicationDir.isEmpty()) - shortcutActions.push_front(ui->actionCreateServerShortcutApplications); - - if (!desktopDir.isEmpty()) - shortcutActions.push_front(ui->actionCreateServerShortcutDesktop); - } - - if (shortcutActions.length() > 1) { - auto shortcutInstanceMenu = new QMenu(this); - - for (auto action : shortcutActions) - shortcutInstanceMenu->addAction(action); - ui->actionCreateServerShortcut->setMenu(shortcutInstanceMenu); - } - ui->actionCreateServerShortcut->setEnabled(serverEditEnabled); } void ServersPage::openedImpl() diff --git a/launcher/ui/pages/instance/WorldListPage.cpp b/launcher/ui/pages/instance/WorldListPage.cpp index f6a1e0e5f..c770f9f23 100644 --- a/launcher/ui/pages/instance/WorldListPage.cpp +++ b/launcher/ui/pages/instance/WorldListPage.cpp @@ -89,6 +89,26 @@ WorldListPage::WorldListPage(InstancePtr inst, std::shared_ptr worlds ui->toolBar->insertSpacer(ui->actionRefresh); + QList shortcutActions = { ui->actionCreateWorldShortcutOther }; + if (!DesktopServices::isFlatpak()) { + QString desktopDir = FS::getDesktopDir(); + QString applicationDir = FS::getApplicationsDir(); + + if (!applicationDir.isEmpty()) + shortcutActions.push_front(ui->actionCreateWorldShortcutApplications); + + if (!desktopDir.isEmpty()) + shortcutActions.push_front(ui->actionCreateWorldShortcutDesktop); + } + + if (shortcutActions.length() > 1) { + auto shortcutInstanceMenu = new QMenu(this); + + for (auto action : shortcutActions) + shortcutInstanceMenu->addAction(action); + ui->actionCreateWorldShortcut->setMenu(shortcutInstanceMenu); + } + WorldListProxyModel* proxy = new WorldListProxyModel(this); proxy->setSortCaseSensitivity(Qt::CaseInsensitive); proxy->setSourceModel(m_worlds.get()); @@ -347,25 +367,6 @@ void WorldListPage::worldChanged([[maybe_unused]] const QModelIndex& current, [[ ui->toolBar->removeAction(ui->actionJoin); ui->toolBar->removeAction(ui->actionCreateWorldShortcut); } else { - QList shortcutActions = { ui->actionCreateWorldShortcutOther }; - if (!DesktopServices::isFlatpak()) { - QString desktopDir = FS::getDesktopDir(); - QString applicationDir = FS::getApplicationsDir(); - - if (!applicationDir.isEmpty()) - shortcutActions.push_front(ui->actionCreateWorldShortcutApplications); - - if (!desktopDir.isEmpty()) - shortcutActions.push_front(ui->actionCreateWorldShortcutDesktop); - } - - if (shortcutActions.length() > 1) { - auto shortcutInstanceMenu = new QMenu(this); - - for (auto action : shortcutActions) - shortcutInstanceMenu->addAction(action); - ui->actionCreateWorldShortcut->setMenu(shortcutInstanceMenu); - } ui->actionCreateWorldShortcut->setEnabled(enable); } } From d9c9eb6521fceb8a9555758633a4b4a5633ebc07 Mon Sep 17 00:00:00 2001 From: Yihe Li Date: Sun, 18 May 2025 20:41:11 +0800 Subject: [PATCH 10/24] Remove redundant assignment Signed-off-by: Yihe Li --- launcher/minecraft/ShortcutUtils.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/launcher/minecraft/ShortcutUtils.cpp b/launcher/minecraft/ShortcutUtils.cpp index 2bbeacb08..cbf4f00e0 100644 --- a/launcher/minecraft/ShortcutUtils.cpp +++ b/launcher/minecraft/ShortcutUtils.cpp @@ -57,7 +57,6 @@ void createInstanceShortcut(const Shortcut& shortcut, const QString& filePath) QString iconPath; QStringList args; #if defined(Q_OS_MACOS) - appPath = QApplication::applicationFilePath(); if (appPath.startsWith("/private/var/")) { QMessageBox::critical(shortcut.parent, QObject::tr("Create Shortcut"), QObject::tr("The launcher is in the folder it was extracted from, therefore it cannot create shortcuts.")); From 183f3d4e9a21ca0491dc0aa474020376dcb297cb Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Sun, 11 May 2025 00:28:34 +0000 Subject: [PATCH 11/24] chore(nix): update lockfile MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Flake lock file updates: • Updated input 'nixpkgs': 'github:NixOS/nixpkgs/f771eb401a46846c1aebd20552521b233dd7e18b?narHash=sha256-ITSpPDwvLBZBnPRS2bUcHY3gZSwis/uTe255QgMtTLA%3D' (2025-04-24) → 'github:NixOS/nixpkgs/dda3dcd3fe03e991015e9a74b22d35950f264a54?narHash=sha256-Ua0drDHawlzNqJnclTJGf87dBmaO/tn7iZ%2BTCkTRpRc%3D' (2025-05-08) --- flake.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/flake.lock b/flake.lock index 5418557a3..d0cc6f54c 100644 --- a/flake.lock +++ b/flake.lock @@ -18,11 +18,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1745526057, - "narHash": "sha256-ITSpPDwvLBZBnPRS2bUcHY3gZSwis/uTe255QgMtTLA=", + "lastModified": 1746663147, + "narHash": "sha256-Ua0drDHawlzNqJnclTJGf87dBmaO/tn7iZ+TCkTRpRc=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "f771eb401a46846c1aebd20552521b233dd7e18b", + "rev": "dda3dcd3fe03e991015e9a74b22d35950f264a54", "type": "github" }, "original": { From 91e9e49d2ce637f8bca4f4cfd9570cff6d3d4b07 Mon Sep 17 00:00:00 2001 From: Sefa Eyeoglu Date: Tue, 13 May 2025 15:51:52 +0200 Subject: [PATCH 12/24] chore(readme): update Jetbrains logo Signed-off-by: Sefa Eyeoglu --- README.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 9c4909509..361864dfe 100644 --- a/README.md +++ b/README.md @@ -76,7 +76,13 @@ We thank all the wonderful backers over at Open Collective! Support Prism Launch Thanks to JetBrains for providing us a few licenses for all their products, as part of their [Open Source program](https://www.jetbrains.com/opensource/). -[![JetBrains](https://resources.jetbrains.com/storage/products/company/brand/logos/jb_beam.svg)](https://www.jetbrains.com/opensource/) + + + + + JetBrains logo + + Thanks to Weblate for hosting our translation efforts. From 8a60ec1c4a7779a78521a438b0e607959bba8fcb Mon Sep 17 00:00:00 2001 From: Trial97 Date: Wed, 14 May 2025 09:55:55 +0300 Subject: [PATCH 13/24] chore: replace foreach macro Signed-off-by: Trial97 --- launcher/java/JavaUtils.cpp | 8 ++++---- launcher/ui/widgets/CheckComboBox.cpp | 2 +- launcher/ui/widgets/InfoFrame.cpp | 4 ++-- launcher/updater/MacSparkleUpdater.mm | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/launcher/java/JavaUtils.cpp b/launcher/java/JavaUtils.cpp index 072cb1d16..2d0560049 100644 --- a/launcher/java/JavaUtils.cpp +++ b/launcher/java/JavaUtils.cpp @@ -365,13 +365,13 @@ QList JavaUtils::FindJavaPaths() javas.append("/System/Library/Frameworks/JavaVM.framework/Versions/Current/Commands/java"); QDir libraryJVMDir("/Library/Java/JavaVirtualMachines/"); QStringList libraryJVMJavas = libraryJVMDir.entryList(QDir::Dirs | QDir::NoDotAndDotDot); - foreach (const QString& java, libraryJVMJavas) { + for (const QString& java : libraryJVMJavas) { javas.append(libraryJVMDir.absolutePath() + "/" + java + "/Contents/Home/bin/java"); javas.append(libraryJVMDir.absolutePath() + "/" + java + "/Contents/Home/jre/bin/java"); } QDir systemLibraryJVMDir("/System/Library/Java/JavaVirtualMachines/"); QStringList systemLibraryJVMJavas = systemLibraryJVMDir.entryList(QDir::Dirs | QDir::NoDotAndDotDot); - foreach (const QString& java, systemLibraryJVMJavas) { + for (const QString& java : systemLibraryJVMJavas) { javas.append(systemLibraryJVMDir.absolutePath() + "/" + java + "/Contents/Home/bin/java"); javas.append(systemLibraryJVMDir.absolutePath() + "/" + java + "/Contents/Commands/java"); } @@ -381,14 +381,14 @@ QList JavaUtils::FindJavaPaths() // javas downloaded by sdkman QDir sdkmanDir(FS::PathCombine(home, ".sdkman/candidates/java")); QStringList sdkmanJavas = sdkmanDir.entryList(QDir::Dirs | QDir::NoDotAndDotDot); - foreach (const QString& java, sdkmanJavas) { + for (const QString& java : sdkmanJavas) { javas.append(sdkmanDir.absolutePath() + "/" + java + "/bin/java"); } // java in user library folder (like from intellij downloads) QDir userLibraryJVMDir(FS::PathCombine(home, "Library/Java/JavaVirtualMachines/")); QStringList userLibraryJVMJavas = userLibraryJVMDir.entryList(QDir::Dirs | QDir::NoDotAndDotDot); - foreach (const QString& java, userLibraryJVMJavas) { + for (const QString& java : userLibraryJVMJavas) { javas.append(userLibraryJVMDir.absolutePath() + "/" + java + "/Contents/Home/bin/java"); javas.append(userLibraryJVMDir.absolutePath() + "/" + java + "/Contents/Commands/java"); } diff --git a/launcher/ui/widgets/CheckComboBox.cpp b/launcher/ui/widgets/CheckComboBox.cpp index 02b629162..57d98ea7f 100644 --- a/launcher/ui/widgets/CheckComboBox.cpp +++ b/launcher/ui/widgets/CheckComboBox.cpp @@ -178,7 +178,7 @@ QStringList CheckComboBox::checkedItems() const void CheckComboBox::setCheckedItems(const QStringList& items) { - foreach (auto text, items) { + for (auto text : items) { auto index = findText(text); setItemCheckState(index, index != -1 ? Qt::Checked : Qt::Unchecked); } diff --git a/launcher/ui/widgets/InfoFrame.cpp b/launcher/ui/widgets/InfoFrame.cpp index 3ef5dcb88..93520f611 100644 --- a/launcher/ui/widgets/InfoFrame.cpp +++ b/launcher/ui/widgets/InfoFrame.cpp @@ -287,7 +287,7 @@ void InfoFrame::setDescription(QString text) QChar rem('\n'); QString finaltext; finaltext.reserve(intermediatetext.size()); - foreach (const QChar& c, intermediatetext) { + for (const QChar& c : intermediatetext) { if (c == rem && prev) { continue; } @@ -341,7 +341,7 @@ void InfoFrame::setLicense(QString text) QChar rem('\n'); QString finaltext; finaltext.reserve(intermediatetext.size()); - foreach (const QChar& c, intermediatetext) { + for (const QChar& c : intermediatetext) { if (c == rem && prev) { continue; } diff --git a/launcher/updater/MacSparkleUpdater.mm b/launcher/updater/MacSparkleUpdater.mm index b2b631593..07862c9a3 100644 --- a/launcher/updater/MacSparkleUpdater.mm +++ b/launcher/updater/MacSparkleUpdater.mm @@ -166,7 +166,7 @@ void MacSparkleUpdater::setAllowedChannels(const QSet& channels) { QString channelsConfig = ""; // Convert QSet -> NSSet NSMutableSet* nsChannels = [NSMutableSet setWithCapacity:channels.count()]; - foreach (const QString channel, channels) { + for (const QString channel : channels) { [nsChannels addObject:channel.toNSString()]; channelsConfig += channel + " "; } From 1c288543f2c05f0a9969da2e17c957566bf28584 Mon Sep 17 00:00:00 2001 From: Yihe Li Date: Sun, 18 May 2025 22:32:30 +0800 Subject: [PATCH 14/24] Initial UI for shortcut dialog Signed-off-by: Yihe Li --- launcher/ui/dialogs/CreateShortcutDialog.ui | 217 ++++++++++++++++++++ 1 file changed, 217 insertions(+) create mode 100644 launcher/ui/dialogs/CreateShortcutDialog.ui diff --git a/launcher/ui/dialogs/CreateShortcutDialog.ui b/launcher/ui/dialogs/CreateShortcutDialog.ui new file mode 100644 index 000000000..26e34ecde --- /dev/null +++ b/launcher/ui/dialogs/CreateShortcutDialog.ui @@ -0,0 +1,217 @@ + + + CreateShortcutDialog + + + Qt::WindowModality::ApplicationModal + + + + 0 + 0 + 450 + 365 + + + + Create Instance Shortcut + + + true + + + + + + + + + :/icons/instances/grass:/icons/instances/grass + + + + 80 + 80 + + + + + + + + + + Save To: + + + + + + + + 0 + 0 + + + + + + + + Name: + + + + + + + Name + + + + + + + + + + + Use a different account than the default specified. + + + Override the default account + + + + + + + false + + + + 0 + 0 + + + + + + + + 0 + 0 + + + + + + + + + + + Specify a world or server to automatically join on launch. + + + Select a target to join on launch + + + + + + + false + + + + 0 + 0 + + + + + + + World: + + + + + + + + 0 + 0 + + + + + + + + Server Address: + + + + + + + Server Address + + + + + + + + + + Qt::Orientation::Horizontal + + + QDialogButtonBox::StandardButton::Cancel|QDialogButtonBox::StandardButton::Ok + + + + + + + iconButton + + + + + buttonBox + accepted() + CreateShortcutDialog + accept() + + + 20 + 20 + + + 20 + 20 + + + + + buttonBox + rejected() + CreateShortcutDialog + reject() + + + 20 + 20 + + + 20 + 20 + + + + + From 0a5013ff9f795c74f293d43c092fceb88bb378aa Mon Sep 17 00:00:00 2001 From: Yihe Li Date: Sun, 18 May 2025 22:54:57 +0800 Subject: [PATCH 15/24] Add source files for UI Signed-off-by: Yihe Li --- launcher/CMakeLists.txt | 3 + launcher/ui/MainWindow.cpp | 1 + launcher/ui/dialogs/CreateShortcutDialog.cpp | 70 ++++++++++++++++++++ launcher/ui/dialogs/CreateShortcutDialog.h | 56 ++++++++++++++++ launcher/ui/dialogs/CreateShortcutDialog.ui | 9 +++ 5 files changed, 139 insertions(+) create mode 100644 launcher/ui/dialogs/CreateShortcutDialog.cpp create mode 100644 launcher/ui/dialogs/CreateShortcutDialog.h diff --git a/launcher/CMakeLists.txt b/launcher/CMakeLists.txt index 918e38df0..90a2093b6 100644 --- a/launcher/CMakeLists.txt +++ b/launcher/CMakeLists.txt @@ -1050,6 +1050,8 @@ SET(LAUNCHER_SOURCES ui/dialogs/ProfileSetupDialog.h ui/dialogs/CopyInstanceDialog.cpp ui/dialogs/CopyInstanceDialog.h + ui/dialogs/CreateShortcutDialog.cpp + ui/dialogs/CreateShortcutDialog.h ui/dialogs/CustomMessageBox.cpp ui/dialogs/CustomMessageBox.h ui/dialogs/ExportInstanceDialog.cpp @@ -1232,6 +1234,7 @@ qt_wrap_ui(LAUNCHER_UI ui/widgets/MinecraftSettingsWidget.ui ui/widgets/JavaSettingsWidget.ui ui/dialogs/CopyInstanceDialog.ui + ui/dialogs/CreateShortcutDialog.ui ui/dialogs/ProfileSetupDialog.ui ui/dialogs/ProgressDialog.ui ui/dialogs/NewInstanceDialog.ui diff --git a/launcher/ui/MainWindow.cpp b/launcher/ui/MainWindow.cpp index d64e92124..7cc28917a 100644 --- a/launcher/ui/MainWindow.cpp +++ b/launcher/ui/MainWindow.cpp @@ -93,6 +93,7 @@ #include "ui/GuiUtil.h" #include "ui/dialogs/AboutDialog.h" #include "ui/dialogs/CopyInstanceDialog.h" +#include "ui/dialogs/CreateShortcutDialog.h" #include "ui/dialogs/CustomMessageBox.h" #include "ui/dialogs/ExportInstanceDialog.h" #include "ui/dialogs/ExportPackDialog.h" diff --git a/launcher/ui/dialogs/CreateShortcutDialog.cpp b/launcher/ui/dialogs/CreateShortcutDialog.cpp new file mode 100644 index 000000000..eda8eb214 --- /dev/null +++ b/launcher/ui/dialogs/CreateShortcutDialog.cpp @@ -0,0 +1,70 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* + * Prism Launcher - Minecraft Launcher + * Copyright (C) 2022 Sefa Eyeoglu + * Copyright (C) 2023 TheKodeToad + * Copyright (C) 2025 Yihe Li + * + * 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 . + * + * 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 +#include + +#include "Application.h" +#include "BuildConfig.h" +#include "CreateShortcutDialog.h" +#include "ui_CreateShortcutDialog.h" + +#include "ui/dialogs/IconPickerDialog.h" + +#include "BaseInstance.h" +#include "DesktopServices.h" +#include "FileSystem.h" +#include "InstanceList.h" +#include "icons/IconList.h" + +CreateShortcutDialog::CreateShortcutDialog(InstancePtr instance, QWidget* parent) + : QDialog(parent), ui(new Ui::CreateShortcutDialog), m_instance(instance) +{ + ui->setupUi(this); + resize(minimumSizeHint()); + layout()->setSizeConstraint(QLayout::SetFixedSize); + + InstIconKey = instance->iconKey(); + ui->iconButton->setIcon(APPLICATION->icons()->getIcon(InstIconKey)); + ui->instNameTextBox->setText(instance->name()); + ui->instNameTextBox->setFocus(); +} + +CreateShortcutDialog::~CreateShortcutDialog() +{ + delete ui; +} diff --git a/launcher/ui/dialogs/CreateShortcutDialog.h b/launcher/ui/dialogs/CreateShortcutDialog.h new file mode 100644 index 000000000..5fba78931 --- /dev/null +++ b/launcher/ui/dialogs/CreateShortcutDialog.h @@ -0,0 +1,56 @@ +/* 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 + +#include +#include "BaseInstance.h" + +class BaseInstance; + +namespace Ui { +class CreateShortcutDialog; +} + +class CreateShortcutDialog : public QDialog { + Q_OBJECT + + public: + explicit CreateShortcutDialog(InstancePtr instance, QWidget* parent = nullptr); + ~CreateShortcutDialog(); + + private slots: + // Icon, target and name + void on_iconButton_clicked(); + void on_saveTargetSelectionBox_currentIndexChanged(int index); + void on_instNameTextBox_textChanged(const QString& arg1); + + // Override account + void on_overrideAccountCheckbox_stateChanged(int state); + void on_accountSelectionBox_currentIndexChanged(int index); + + // Override target (world, server) + void on_targetCheckbox_stateChanged(int state); + void on_worldSelectionBox_currentIndexChanged(int index); + void on_serverAddressTextBox_textChanged(const QString& arg1); + void targetChanged(); + + private: + /* data */ + Ui::CreateShortcutDialog* ui; + QString InstIconKey; + InstancePtr m_instance; + bool m_QuickJoinSupported = false; +}; diff --git a/launcher/ui/dialogs/CreateShortcutDialog.ui b/launcher/ui/dialogs/CreateShortcutDialog.ui index 26e34ecde..364c42b15 100644 --- a/launcher/ui/dialogs/CreateShortcutDialog.ui +++ b/launcher/ui/dialogs/CreateShortcutDialog.ui @@ -135,6 +135,9 @@ World: + + targetBtnGroup + @@ -152,6 +155,9 @@ Server Address: + + targetBtnGroup + @@ -214,4 +220,7 @@ + + + From ea8f105292058289ec7350d61ab5fec1c3e94306 Mon Sep 17 00:00:00 2001 From: Yihe Li Date: Sun, 18 May 2025 23:03:14 +0800 Subject: [PATCH 16/24] Add stubs and b asic integration with MainWindow Signed-off-by: Yihe Li --- launcher/ui/MainWindow.cpp | 44 ++------------------ launcher/ui/MainWindow.h | 3 -- launcher/ui/MainWindow.ui | 33 --------------- launcher/ui/dialogs/CreateShortcutDialog.cpp | 44 ++++++++++++++++++-- launcher/ui/dialogs/CreateShortcutDialog.h | 2 + 5 files changed, 47 insertions(+), 79 deletions(-) diff --git a/launcher/ui/MainWindow.cpp b/launcher/ui/MainWindow.cpp index 7cc28917a..062175ece 100644 --- a/launcher/ui/MainWindow.cpp +++ b/launcher/ui/MainWindow.cpp @@ -110,7 +110,6 @@ #include "ui/widgets/LabeledToolButton.h" #include "minecraft/PackProfile.h" -#include "minecraft/ShortcutUtils.h" #include "minecraft/VersionFile.h" #include "minecraft/WorldList.h" #include "minecraft/mod/ModFolderModel.h" @@ -209,26 +208,6 @@ MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent), ui(new Ui::MainWi exportInstanceMenu->addAction(ui->actionExportInstanceMrPack); exportInstanceMenu->addAction(ui->actionExportInstanceFlamePack); ui->actionExportInstance->setMenu(exportInstanceMenu); - - QList shortcutActions = { ui->actionCreateInstanceShortcutOther }; - if (!DesktopServices::isFlatpak()) { - QString desktopDir = FS::getDesktopDir(); - QString applicationDir = FS::getApplicationsDir(); - - if (!applicationDir.isEmpty()) - shortcutActions.push_front(ui->actionCreateInstanceShortcutApplications); - - if (!desktopDir.isEmpty()) - shortcutActions.push_front(ui->actionCreateInstanceShortcutDesktop); - } - - if (shortcutActions.length() > 1) { - auto shortcutInstanceMenu = new QMenu(this); - - for (auto action : shortcutActions) - shortcutInstanceMenu->addAction(action); - ui->actionCreateInstanceShortcut->setMenu(shortcutInstanceMenu); - } } // hide, disable and show stuff @@ -1552,25 +1531,10 @@ void MainWindow::on_actionCreateInstanceShortcut_triggered() if (!m_selectedInstance) return; - if (DesktopServices::isFlatpak()) - on_actionCreateInstanceShortcutOther_triggered(); - else - on_actionCreateInstanceShortcutDesktop_triggered(); -} - -void MainWindow::on_actionCreateInstanceShortcutDesktop_triggered() -{ - ShortcutUtils::createInstanceShortcutOnDesktop({ m_selectedInstance.get(), m_selectedInstance->name(), tr("instance"), this }); -} - -void MainWindow::on_actionCreateInstanceShortcutApplications_triggered() -{ - ShortcutUtils::createInstanceShortcutInApplications({ m_selectedInstance.get(), m_selectedInstance->name(), tr("instance"), this }); -} - -void MainWindow::on_actionCreateInstanceShortcutOther_triggered() -{ - ShortcutUtils::createInstanceShortcutInOther({ m_selectedInstance.get(), m_selectedInstance->name(), tr("instance"), this }); + CreateShortcutDialog shortcutDlg(m_selectedInstance, this); + if (!shortcutDlg.exec()) + return; + shortcutDlg.createShortcut(); } void MainWindow::taskEnd() diff --git a/launcher/ui/MainWindow.h b/launcher/ui/MainWindow.h index 20ab21e67..0e692eda7 100644 --- a/launcher/ui/MainWindow.h +++ b/launcher/ui/MainWindow.h @@ -166,9 +166,6 @@ class MainWindow : public QMainWindow { void on_actionEditInstance_triggered(); void on_actionCreateInstanceShortcut_triggered(); - void on_actionCreateInstanceShortcutDesktop_triggered(); - void on_actionCreateInstanceShortcutApplications_triggered(); - void on_actionCreateInstanceShortcutOther_triggered(); void taskEnd(); diff --git a/launcher/ui/MainWindow.ui b/launcher/ui/MainWindow.ui index 6530e2c5a..1499ec872 100644 --- a/launcher/ui/MainWindow.ui +++ b/launcher/ui/MainWindow.ui @@ -771,39 +771,6 @@ Open the Java folder in a file browser. Only available if the built-in Java downloader is used. - - - Desktop - - - Creates a shortcut to this instance on your desktop - - - QAction::TextHeuristicRole - - - - - Applications - - - Create a shortcut of this instance on your start menu - - - QAction::TextHeuristicRole - - - - - Other... - - - Creates a shortcut in a folder selected by you - - - QAction::TextHeuristicRole - - diff --git a/launcher/ui/dialogs/CreateShortcutDialog.cpp b/launcher/ui/dialogs/CreateShortcutDialog.cpp index eda8eb214..8b6ce8a04 100644 --- a/launcher/ui/dialogs/CreateShortcutDialog.cpp +++ b/launcher/ui/dialogs/CreateShortcutDialog.cpp @@ -50,21 +50,59 @@ #include "FileSystem.h" #include "InstanceList.h" #include "icons/IconList.h" +#include "minecraft/ShortcutUtils.h" CreateShortcutDialog::CreateShortcutDialog(InstancePtr instance, QWidget* parent) : QDialog(parent), ui(new Ui::CreateShortcutDialog), m_instance(instance) { ui->setupUi(this); - resize(minimumSizeHint()); - layout()->setSizeConstraint(QLayout::SetFixedSize); InstIconKey = instance->iconKey(); ui->iconButton->setIcon(APPLICATION->icons()->getIcon(InstIconKey)); ui->instNameTextBox->setText(instance->name()); - ui->instNameTextBox->setFocus(); } CreateShortcutDialog::~CreateShortcutDialog() { delete ui; } + +void CreateShortcutDialog::on_iconButton_clicked() +{ + IconPickerDialog dlg(this); + dlg.execWithSelection(InstIconKey); + + if (dlg.result() == QDialog::Accepted) { + InstIconKey = dlg.selectedIconKey; + ui->iconButton->setIcon(APPLICATION->icons()->getIcon(InstIconKey)); + } +} + +void CreateShortcutDialog::on_saveTargetSelectionBox_currentIndexChanged(int index) +{} + +void CreateShortcutDialog::on_instNameTextBox_textChanged(const QString& arg1) +{} + +void CreateShortcutDialog::on_overrideAccountCheckbox_stateChanged(int state) +{} + +void CreateShortcutDialog::on_accountSelectionBox_currentIndexChanged(int index) +{} + +void CreateShortcutDialog::on_targetCheckbox_stateChanged(int state) +{} + +void CreateShortcutDialog::on_worldSelectionBox_currentIndexChanged(int index) +{} + +void CreateShortcutDialog::on_serverAddressTextBox_textChanged(const QString& arg1) +{} + +void CreateShortcutDialog::targetChanged() +{} + +// Real work +void CreateShortcutDialog::createShortcut() const +{} + diff --git a/launcher/ui/dialogs/CreateShortcutDialog.h b/launcher/ui/dialogs/CreateShortcutDialog.h index 5fba78931..be0a5e792 100644 --- a/launcher/ui/dialogs/CreateShortcutDialog.h +++ b/launcher/ui/dialogs/CreateShortcutDialog.h @@ -31,6 +31,8 @@ class CreateShortcutDialog : public QDialog { explicit CreateShortcutDialog(InstancePtr instance, QWidget* parent = nullptr); ~CreateShortcutDialog(); + void createShortcut() const; + private slots: // Icon, target and name void on_iconButton_clicked(); From b296085ea064f22cc21c32ff9d90e3c850dc56de Mon Sep 17 00:00:00 2001 From: Yihe Li Date: Sun, 18 May 2025 23:32:23 +0800 Subject: [PATCH 17/24] Small adjustments Signed-off-by: Yihe Li --- launcher/ui/dialogs/CreateShortcutDialog.cpp | 47 ++++++++++++-------- launcher/ui/dialogs/CreateShortcutDialog.h | 8 ++-- launcher/ui/dialogs/CreateShortcutDialog.ui | 14 ++++-- 3 files changed, 43 insertions(+), 26 deletions(-) diff --git a/launcher/ui/dialogs/CreateShortcutDialog.cpp b/launcher/ui/dialogs/CreateShortcutDialog.cpp index 8b6ce8a04..38c22d861 100644 --- a/launcher/ui/dialogs/CreateShortcutDialog.cpp +++ b/launcher/ui/dialogs/CreateShortcutDialog.cpp @@ -60,6 +60,11 @@ CreateShortcutDialog::CreateShortcutDialog(InstancePtr instance, QWidget* parent InstIconKey = instance->iconKey(); ui->iconButton->setIcon(APPLICATION->icons()->getIcon(InstIconKey)); ui->instNameTextBox->setText(instance->name()); + + m_QuickJoinSupported = instance->traits().contains("feature:is_quick_play_singleplayer"); + if (!m_QuickJoinSupported) { + // TODO: Remove radio box and add a single server address textbox instead + } } CreateShortcutDialog::~CreateShortcutDialog() @@ -78,31 +83,35 @@ void CreateShortcutDialog::on_iconButton_clicked() } } -void CreateShortcutDialog::on_saveTargetSelectionBox_currentIndexChanged(int index) -{} +void CreateShortcutDialog::on_saveTargetSelectionBox_currentIndexChanged(int index) {} -void CreateShortcutDialog::on_instNameTextBox_textChanged(const QString& arg1) -{} +void CreateShortcutDialog::on_instNameTextBox_textChanged(const QString& arg1) {} -void CreateShortcutDialog::on_overrideAccountCheckbox_stateChanged(int state) -{} +void CreateShortcutDialog::on_overrideAccountCheckbox_stateChanged(int state) {} -void CreateShortcutDialog::on_accountSelectionBox_currentIndexChanged(int index) -{} +void CreateShortcutDialog::on_accountSelectionBox_currentIndexChanged(int index) {} -void CreateShortcutDialog::on_targetCheckbox_stateChanged(int state) -{} +void CreateShortcutDialog::on_targetCheckbox_stateChanged(int state) {} -void CreateShortcutDialog::on_worldSelectionBox_currentIndexChanged(int index) -{} +void CreateShortcutDialog::on_worldSelectionBox_currentIndexChanged(int index) {} -void CreateShortcutDialog::on_serverAddressTextBox_textChanged(const QString& arg1) -{} +void CreateShortcutDialog::on_serverAddressBox_textChanged(const QString& arg1) {} -void CreateShortcutDialog::targetChanged() -{} +void CreateShortcutDialog::targetChanged() {} // Real work -void CreateShortcutDialog::createShortcut() const -{} - +void CreateShortcutDialog::createShortcut() +{ + QString targetString = tr("instance"); + QStringList extraArgs; + if (ui->targetCheckbox->isChecked()) { + if (ui->worldTarget->isChecked()) { + targetString = tr("world"); + extraArgs = { "--world", /* world ID */ }; + } else if (ui->serverTarget->isChecked()) { + targetString = tr("server"); + extraArgs = { "--server", /* server address */ }; + } + } + ShortcutUtils::createInstanceShortcutOnDesktop({ m_instance.get(), m_instance->name(), targetString, this, extraArgs }); +} diff --git a/launcher/ui/dialogs/CreateShortcutDialog.h b/launcher/ui/dialogs/CreateShortcutDialog.h index be0a5e792..7be6b339c 100644 --- a/launcher/ui/dialogs/CreateShortcutDialog.h +++ b/launcher/ui/dialogs/CreateShortcutDialog.h @@ -31,7 +31,7 @@ class CreateShortcutDialog : public QDialog { explicit CreateShortcutDialog(InstancePtr instance, QWidget* parent = nullptr); ~CreateShortcutDialog(); - void createShortcut() const; + void createShortcut(); private slots: // Icon, target and name @@ -46,13 +46,15 @@ class CreateShortcutDialog : public QDialog { // Override target (world, server) void on_targetCheckbox_stateChanged(int state); void on_worldSelectionBox_currentIndexChanged(int index); - void on_serverAddressTextBox_textChanged(const QString& arg1); + void on_serverAddressBox_textChanged(const QString& arg1); void targetChanged(); private: - /* data */ + // Data Ui::CreateShortcutDialog* ui; QString InstIconKey; InstancePtr m_instance; bool m_QuickJoinSupported = false; + + // Index representations }; diff --git a/launcher/ui/dialogs/CreateShortcutDialog.ui b/launcher/ui/dialogs/CreateShortcutDialog.ui index 364c42b15..e45a8428a 100644 --- a/launcher/ui/dialogs/CreateShortcutDialog.ui +++ b/launcher/ui/dialogs/CreateShortcutDialog.ui @@ -10,7 +10,7 @@ 0 0 450 - 365 + 370 @@ -161,9 +161,15 @@ - - - Server Address + + + + 0 + 0 + + + + true From 2e6981977b3b457b1e25b1d6d55fb8ad89d72632 Mon Sep 17 00:00:00 2001 From: Yihe Li Date: Mon, 19 May 2025 00:00:39 +0800 Subject: [PATCH 18/24] Add basic shortcut creation integration Signed-off-by: Yihe Li --- launcher/minecraft/ShortcutUtils.cpp | 24 +++--------- launcher/minecraft/ShortcutUtils.h | 1 + launcher/ui/dialogs/CreateShortcutDialog.cpp | 40 ++++++++++++++++---- launcher/ui/dialogs/CreateShortcutDialog.h | 3 +- 4 files changed, 40 insertions(+), 28 deletions(-) diff --git a/launcher/minecraft/ShortcutUtils.cpp b/launcher/minecraft/ShortcutUtils.cpp index cbf4f00e0..ea2a988be 100644 --- a/launcher/minecraft/ShortcutUtils.cpp +++ b/launcher/minecraft/ShortcutUtils.cpp @@ -54,6 +54,10 @@ void createInstanceShortcut(const Shortcut& shortcut, const QString& filePath) return; QString appPath = QApplication::applicationFilePath(); + auto icon = APPLICATION->icons()->icon(shortcut.iconKey.isEmpty() ? shortcut.instance->iconKey() : shortcut.iconKey); + if (icon == nullptr) { + icon = APPLICATION->icons()->icon("grass"); + } QString iconPath; QStringList args; #if defined(Q_OS_MACOS) @@ -63,11 +67,6 @@ void createInstanceShortcut(const Shortcut& shortcut, const QString& filePath) return; } - auto pIcon = APPLICATION->icons()->icon(shortcut.instance->iconKey()); - if (pIcon == nullptr) { - pIcon = APPLICATION->icons()->icon("grass"); - } - iconPath = FS::PathCombine(shortcut.instance->instanceRoot(), "Icon.icns"); QFile iconFile(iconPath); @@ -76,9 +75,8 @@ void createInstanceShortcut(const Shortcut& shortcut, const QString& filePath) return; } - QIcon icon = pIcon->icon(); - - bool success = icon.pixmap(1024, 1024).save(iconPath, "ICNS"); + QIcon iconObj = icon->icon(); + bool success = iconObj.pixmap(1024, 1024).save(iconPath, "ICNS"); iconFile.close(); if (!success) { @@ -99,11 +97,6 @@ void createInstanceShortcut(const Shortcut& shortcut, const QString& filePath) } } - auto icon = APPLICATION->icons()->icon(shortcut.instance->iconKey()); - if (icon == nullptr) { - icon = APPLICATION->icons()->icon("grass"); - } - iconPath = FS::PathCombine(shortcut.instance->instanceRoot(), "icon.png"); QFile iconFile(iconPath); @@ -126,11 +119,6 @@ void createInstanceShortcut(const Shortcut& shortcut, const QString& filePath) } #elif defined(Q_OS_WIN) - auto icon = APPLICATION->icons()->icon(shortcut.instance->iconKey()); - if (icon == nullptr) { - icon = APPLICATION->icons()->icon("grass"); - } - iconPath = FS::PathCombine(shortcut.instance->instanceRoot(), "icon.ico"); // part of fix for weird bug involving the window icon being replaced diff --git a/launcher/minecraft/ShortcutUtils.h b/launcher/minecraft/ShortcutUtils.h index a21ccf06a..e3d2e283a 100644 --- a/launcher/minecraft/ShortcutUtils.h +++ b/launcher/minecraft/ShortcutUtils.h @@ -48,6 +48,7 @@ struct Shortcut { QString targetString; QWidget* parent = nullptr; QStringList extraArgs = {}; + QString iconKey = ""; }; /// Create an instance shortcut on the specified file path diff --git a/launcher/ui/dialogs/CreateShortcutDialog.cpp b/launcher/ui/dialogs/CreateShortcutDialog.cpp index 38c22d861..83057619e 100644 --- a/launcher/ui/dialogs/CreateShortcutDialog.cpp +++ b/launcher/ui/dialogs/CreateShortcutDialog.cpp @@ -63,8 +63,22 @@ CreateShortcutDialog::CreateShortcutDialog(InstancePtr instance, QWidget* parent m_QuickJoinSupported = instance->traits().contains("feature:is_quick_play_singleplayer"); if (!m_QuickJoinSupported) { - // TODO: Remove radio box and add a single server address textbox instead + ui->worldTarget->hide(); + ui->worldSelectionBox->hide(); } + + // Populate save targets + if (!DesktopServices::isFlatpak()) { + QString desktopDir = FS::getDesktopDir(); + QString applicationDir = FS::getApplicationsDir(); + + if (!desktopDir.isEmpty()) + ui->saveTargetSelectionBox->addItem("Desktop", QVariant::fromValue(SaveTarget::Desktop)); + + if (!applicationDir.isEmpty()) + ui->saveTargetSelectionBox->addItem("Applications", QVariant::fromValue(SaveTarget::Applications)); + } + ui->saveTargetSelectionBox->addItem("Other...", QVariant::fromValue(SaveTarget::Other)); } CreateShortcutDialog::~CreateShortcutDialog() @@ -83,15 +97,17 @@ void CreateShortcutDialog::on_iconButton_clicked() } } -void CreateShortcutDialog::on_saveTargetSelectionBox_currentIndexChanged(int index) {} - -void CreateShortcutDialog::on_instNameTextBox_textChanged(const QString& arg1) {} - -void CreateShortcutDialog::on_overrideAccountCheckbox_stateChanged(int state) {} +void CreateShortcutDialog::on_overrideAccountCheckbox_stateChanged(int state) +{ + ui->accountOptionsGroup->setEnabled(state == Qt::Checked); +} void CreateShortcutDialog::on_accountSelectionBox_currentIndexChanged(int index) {} -void CreateShortcutDialog::on_targetCheckbox_stateChanged(int state) {} +void CreateShortcutDialog::on_targetCheckbox_stateChanged(int state) +{ + ui->targetOptionsGroup->setEnabled(state == Qt::Checked); +} void CreateShortcutDialog::on_worldSelectionBox_currentIndexChanged(int index) {} @@ -113,5 +129,13 @@ void CreateShortcutDialog::createShortcut() extraArgs = { "--server", /* server address */ }; } } - ShortcutUtils::createInstanceShortcutOnDesktop({ m_instance.get(), m_instance->name(), targetString, this, extraArgs }); + + auto target = ui->saveTargetSelectionBox->currentData().value(); + auto name = ui->instNameTextBox->text(); + if (target == SaveTarget::Desktop) + ShortcutUtils::createInstanceShortcutOnDesktop({ m_instance.get(), name, targetString, this, extraArgs, InstIconKey }); + else if (target == SaveTarget::Applications) + ShortcutUtils::createInstanceShortcutInApplications({ m_instance.get(), name, targetString, this, extraArgs, InstIconKey }); + else + ShortcutUtils::createInstanceShortcutInOther({ m_instance.get(), m_instance->name(), targetString, this, extraArgs, InstIconKey }); } diff --git a/launcher/ui/dialogs/CreateShortcutDialog.h b/launcher/ui/dialogs/CreateShortcutDialog.h index 7be6b339c..04849ebfa 100644 --- a/launcher/ui/dialogs/CreateShortcutDialog.h +++ b/launcher/ui/dialogs/CreateShortcutDialog.h @@ -36,8 +36,6 @@ class CreateShortcutDialog : public QDialog { private slots: // Icon, target and name void on_iconButton_clicked(); - void on_saveTargetSelectionBox_currentIndexChanged(int index); - void on_instNameTextBox_textChanged(const QString& arg1); // Override account void on_overrideAccountCheckbox_stateChanged(int state); @@ -57,4 +55,5 @@ class CreateShortcutDialog : public QDialog { bool m_QuickJoinSupported = false; // Index representations + enum class SaveTarget { Desktop, Applications, Other }; }; From 3529d295843812796d191c79bbbc3d3e08df4ed9 Mon Sep 17 00:00:00 2001 From: Yihe Li Date: Mon, 19 May 2025 01:05:08 +0800 Subject: [PATCH 19/24] Implement world and server selection Signed-off-by: Yihe Li --- launcher/ui/dialogs/CreateShortcutDialog.cpp | 70 +++++++++++++++++--- launcher/ui/dialogs/CreateShortcutDialog.h | 8 ++- launcher/ui/dialogs/CreateShortcutDialog.ui | 12 +--- 3 files changed, 71 insertions(+), 19 deletions(-) diff --git a/launcher/ui/dialogs/CreateShortcutDialog.cpp b/launcher/ui/dialogs/CreateShortcutDialog.cpp index 83057619e..9a41a7961 100644 --- a/launcher/ui/dialogs/CreateShortcutDialog.cpp +++ b/launcher/ui/dialogs/CreateShortcutDialog.cpp @@ -50,7 +50,9 @@ #include "FileSystem.h" #include "InstanceList.h" #include "icons/IconList.h" +#include "minecraft/MinecraftInstance.h" #include "minecraft/ShortcutUtils.h" +#include "minecraft/WorldList.h" CreateShortcutDialog::CreateShortcutDialog(InstancePtr instance, QWidget* parent) : QDialog(parent), ui(new Ui::CreateShortcutDialog), m_instance(instance) @@ -59,12 +61,14 @@ CreateShortcutDialog::CreateShortcutDialog(InstancePtr instance, QWidget* parent InstIconKey = instance->iconKey(); ui->iconButton->setIcon(APPLICATION->icons()->getIcon(InstIconKey)); - ui->instNameTextBox->setText(instance->name()); + ui->instNameTextBox->setPlaceholderText(instance->name()); - m_QuickJoinSupported = instance->traits().contains("feature:is_quick_play_singleplayer"); + auto mInst = std::dynamic_pointer_cast(instance); + m_QuickJoinSupported = mInst && mInst->traits().contains("feature:is_quick_play_singleplayer"); if (!m_QuickJoinSupported) { ui->worldTarget->hide(); ui->worldSelectionBox->hide(); + ui->serverTarget->setChecked(true); } // Populate save targets @@ -79,6 +83,18 @@ CreateShortcutDialog::CreateShortcutDialog(InstancePtr instance, QWidget* parent ui->saveTargetSelectionBox->addItem("Applications", QVariant::fromValue(SaveTarget::Applications)); } ui->saveTargetSelectionBox->addItem("Other...", QVariant::fromValue(SaveTarget::Other)); + + // Populate worlds + if (m_QuickJoinSupported) { + auto worldList = mInst->worldList(); + worldList->update(); + for (const auto& world : worldList->allWorlds()) { + // Entry name: World Name [Game Mode] - Last Played: DateTime + QString entry_name = tr("%1 [%2] - Last Played: %3") + .arg(world.name(), world.gameType().toTranslatedString(), world.lastPlayed().toString(Qt::ISODate)); + ui->worldSelectionBox->addItem(entry_name, world.name()); + } + } } CreateShortcutDialog::~CreateShortcutDialog() @@ -107,13 +123,49 @@ void CreateShortcutDialog::on_accountSelectionBox_currentIndexChanged(int index) void CreateShortcutDialog::on_targetCheckbox_stateChanged(int state) { ui->targetOptionsGroup->setEnabled(state == Qt::Checked); + ui->worldSelectionBox->setEnabled(ui->worldTarget->isChecked()); + ui->serverAddressBox->setEnabled(ui->serverTarget->isChecked()); + stateChanged(); } -void CreateShortcutDialog::on_worldSelectionBox_currentIndexChanged(int index) {} +void CreateShortcutDialog::on_worldTarget_toggled(bool checked) +{ + ui->worldSelectionBox->setEnabled(checked); + stateChanged(); +} -void CreateShortcutDialog::on_serverAddressBox_textChanged(const QString& arg1) {} +void CreateShortcutDialog::on_serverTarget_toggled(bool checked) +{ + ui->serverAddressBox->setEnabled(checked); + stateChanged(); +} -void CreateShortcutDialog::targetChanged() {} +void CreateShortcutDialog::on_worldSelectionBox_currentIndexChanged(int index) +{ + stateChanged(); +} + +void CreateShortcutDialog::on_serverAddressBox_textChanged(const QString& text) +{ + stateChanged(); +} + +void CreateShortcutDialog::stateChanged() +{ + QString result = m_instance->name(); + if (ui->targetCheckbox->isChecked()) { + if (ui->worldTarget->isChecked()) + result = tr("%1 - %2").arg(result, ui->worldSelectionBox->currentData().toString()); + else if (ui->serverTarget->isChecked()) + result = tr("%1 - Server %2").arg(result, ui->serverAddressBox->text()); + } + ui->instNameTextBox->setPlaceholderText(result); + if (!ui->targetCheckbox->isChecked()) + ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(true); + else + ui->buttonBox->button(QDialogButtonBox::Ok) + ->setEnabled(ui->worldTarget->isChecked() || (ui->serverTarget->isChecked() && !ui->serverAddressBox->text().isEmpty())); +} // Real work void CreateShortcutDialog::createShortcut() @@ -123,19 +175,21 @@ void CreateShortcutDialog::createShortcut() if (ui->targetCheckbox->isChecked()) { if (ui->worldTarget->isChecked()) { targetString = tr("world"); - extraArgs = { "--world", /* world ID */ }; + extraArgs = { "--world", ui->worldSelectionBox->currentData().toString() }; } else if (ui->serverTarget->isChecked()) { targetString = tr("server"); - extraArgs = { "--server", /* server address */ }; + extraArgs = { "--server", ui->serverAddressBox->text() }; } } auto target = ui->saveTargetSelectionBox->currentData().value(); auto name = ui->instNameTextBox->text(); + if (name.isEmpty()) + name = ui->instNameTextBox->placeholderText(); if (target == SaveTarget::Desktop) ShortcutUtils::createInstanceShortcutOnDesktop({ m_instance.get(), name, targetString, this, extraArgs, InstIconKey }); else if (target == SaveTarget::Applications) ShortcutUtils::createInstanceShortcutInApplications({ m_instance.get(), name, targetString, this, extraArgs, InstIconKey }); else - ShortcutUtils::createInstanceShortcutInOther({ m_instance.get(), m_instance->name(), targetString, this, extraArgs, InstIconKey }); + ShortcutUtils::createInstanceShortcutInOther({ m_instance.get(), name, targetString, this, extraArgs, InstIconKey }); } diff --git a/launcher/ui/dialogs/CreateShortcutDialog.h b/launcher/ui/dialogs/CreateShortcutDialog.h index 04849ebfa..c26005304 100644 --- a/launcher/ui/dialogs/CreateShortcutDialog.h +++ b/launcher/ui/dialogs/CreateShortcutDialog.h @@ -43,9 +43,10 @@ class CreateShortcutDialog : public QDialog { // Override target (world, server) void on_targetCheckbox_stateChanged(int state); + void on_worldTarget_toggled(bool checked); + void on_serverTarget_toggled(bool checked); void on_worldSelectionBox_currentIndexChanged(int index); - void on_serverAddressBox_textChanged(const QString& arg1); - void targetChanged(); + void on_serverAddressBox_textChanged(const QString& text); private: // Data @@ -56,4 +57,7 @@ class CreateShortcutDialog : public QDialog { // Index representations enum class SaveTarget { Desktop, Applications, Other }; + + // Functions + void stateChanged(); }; diff --git a/launcher/ui/dialogs/CreateShortcutDialog.ui b/launcher/ui/dialogs/CreateShortcutDialog.ui index e45a8428a..2a90f43ab 100644 --- a/launcher/ui/dialogs/CreateShortcutDialog.ui +++ b/launcher/ui/dialogs/CreateShortcutDialog.ui @@ -161,15 +161,9 @@ - - - - 0 - 0 - - - - true + + + Server Address From 4839595a117ee65e952f7c18ffb4231136b7a084 Mon Sep 17 00:00:00 2001 From: Yihe Li Date: Mon, 19 May 2025 01:29:23 +0800 Subject: [PATCH 20/24] Implement account override Signed-off-by: Yihe Li --- launcher/ui/dialogs/CreateShortcutDialog.cpp | 33 +++++++++++++++++--- launcher/ui/dialogs/CreateShortcutDialog.h | 1 - 2 files changed, 28 insertions(+), 6 deletions(-) diff --git a/launcher/ui/dialogs/CreateShortcutDialog.cpp b/launcher/ui/dialogs/CreateShortcutDialog.cpp index 9a41a7961..6bc2b80cf 100644 --- a/launcher/ui/dialogs/CreateShortcutDialog.cpp +++ b/launcher/ui/dialogs/CreateShortcutDialog.cpp @@ -50,9 +50,11 @@ #include "FileSystem.h" #include "InstanceList.h" #include "icons/IconList.h" + #include "minecraft/MinecraftInstance.h" #include "minecraft/ShortcutUtils.h" #include "minecraft/WorldList.h" +#include "minecraft/auth/AccountList.h" CreateShortcutDialog::CreateShortcutDialog(InstancePtr instance, QWidget* parent) : QDialog(parent), ui(new Ui::CreateShortcutDialog), m_instance(instance) @@ -95,6 +97,25 @@ CreateShortcutDialog::CreateShortcutDialog(InstancePtr instance, QWidget* parent ui->worldSelectionBox->addItem(entry_name, world.name()); } } + + // Populate accounts + auto accounts = APPLICATION->accounts(); + MinecraftAccountPtr defaultAccount = accounts->defaultAccount(); + if (accounts->count() <= 0) { + ui->overrideAccountCheckbox->setEnabled(false); + } else + for (int i = 0; i < accounts->count(); i++) { + MinecraftAccountPtr account = accounts->at(i); + auto profileLabel = account->profileName(); + if (account->isInUse()) + profileLabel = tr("%1 (in use)").arg(profileLabel); + auto face = account->getFace(); + QIcon icon = face.isNull() ? APPLICATION->getThemedIcon("noaccount") : face; + ui->accountSelectionBox->addItem(profileLabel, account->profileName()); + ui->accountSelectionBox->setItemIcon(i, icon); + if (defaultAccount == account) + ui->accountSelectionBox->setCurrentIndex(i); + } } CreateShortcutDialog::~CreateShortcutDialog() @@ -118,8 +139,6 @@ void CreateShortcutDialog::on_overrideAccountCheckbox_stateChanged(int state) ui->accountOptionsGroup->setEnabled(state == Qt::Checked); } -void CreateShortcutDialog::on_accountSelectionBox_currentIndexChanged(int index) {} - void CreateShortcutDialog::on_targetCheckbox_stateChanged(int state) { ui->targetOptionsGroup->setEnabled(state == Qt::Checked); @@ -186,10 +205,14 @@ void CreateShortcutDialog::createShortcut() auto name = ui->instNameTextBox->text(); if (name.isEmpty()) name = ui->instNameTextBox->placeholderText(); + if (ui->overrideAccountCheckbox->isChecked()) + extraArgs.append({ "--profile", ui->accountSelectionBox->currentData().toString() }); + + ShortcutUtils::Shortcut args{ m_instance.get(), name, targetString, this, extraArgs, InstIconKey }; if (target == SaveTarget::Desktop) - ShortcutUtils::createInstanceShortcutOnDesktop({ m_instance.get(), name, targetString, this, extraArgs, InstIconKey }); + ShortcutUtils::createInstanceShortcutOnDesktop(args); else if (target == SaveTarget::Applications) - ShortcutUtils::createInstanceShortcutInApplications({ m_instance.get(), name, targetString, this, extraArgs, InstIconKey }); + ShortcutUtils::createInstanceShortcutInApplications(args); else - ShortcutUtils::createInstanceShortcutInOther({ m_instance.get(), name, targetString, this, extraArgs, InstIconKey }); + ShortcutUtils::createInstanceShortcutInOther(args); } diff --git a/launcher/ui/dialogs/CreateShortcutDialog.h b/launcher/ui/dialogs/CreateShortcutDialog.h index c26005304..cfedbf017 100644 --- a/launcher/ui/dialogs/CreateShortcutDialog.h +++ b/launcher/ui/dialogs/CreateShortcutDialog.h @@ -39,7 +39,6 @@ class CreateShortcutDialog : public QDialog { // Override account void on_overrideAccountCheckbox_stateChanged(int state); - void on_accountSelectionBox_currentIndexChanged(int index); // Override target (world, server) void on_targetCheckbox_stateChanged(int state); From 46c9eb1d5fb2df8ebe10f4a57d41e9172b3aca84 Mon Sep 17 00:00:00 2001 From: Yihe Li Date: Mon, 19 May 2025 01:33:15 +0800 Subject: [PATCH 21/24] Remove button additions Signed-off-by: Yihe Li --- launcher/minecraft/WorldList.cpp | 38 ---------- launcher/minecraft/WorldList.h | 5 -- launcher/ui/pages/instance/ServersPage.cpp | 75 -------------------- launcher/ui/pages/instance/ServersPage.h | 4 -- launcher/ui/pages/instance/ServersPage.ui | 48 +------------ launcher/ui/pages/instance/WorldListPage.cpp | 59 --------------- launcher/ui/pages/instance/WorldListPage.h | 4 -- launcher/ui/pages/instance/WorldListPage.ui | 47 +----------- 8 files changed, 2 insertions(+), 278 deletions(-) diff --git a/launcher/minecraft/WorldList.cpp b/launcher/minecraft/WorldList.cpp index 582531577..6a821ba60 100644 --- a/launcher/minecraft/WorldList.cpp +++ b/launcher/minecraft/WorldList.cpp @@ -46,9 +46,6 @@ #include #include -#include -#include "minecraft/ShortcutUtils.h" - WorldList::WorldList(const QString& dir, BaseInstance* instance) : QAbstractListModel(), m_instance(instance), m_dir(dir) { FS::ensureFolderPathExists(m_dir.absolutePath()); @@ -457,39 +454,4 @@ void WorldList::loadWorldsAsync() } } -void WorldList::createWorldShortcut(const QModelIndex& index, QWidget* parent) const -{ - if (!m_instance) - return; - - if (DesktopServices::isFlatpak()) - createWorldShortcutInOther(index, parent); - else - createWorldShortcutOnDesktop(index, parent); -} - -void WorldList::createWorldShortcutOnDesktop(const QModelIndex& index, QWidget* parent) const -{ - const auto& world = allWorlds().at(index.row()); - QString name = QString(tr("%1 - %2")).arg(m_instance->name(), world.name()); - QStringList extraArgs{ "--world", world.name() }; - ShortcutUtils::createInstanceShortcutOnDesktop({ m_instance, name, tr("world"), parent, extraArgs }); -} - -void WorldList::createWorldShortcutInApplications(const QModelIndex& index, QWidget* parent) const -{ - const auto& world = allWorlds().at(index.row()); - QString name = QString(tr("%1 - %2")).arg(m_instance->name(), world.name()); - QStringList extraArgs{ "--world", world.name() }; - ShortcutUtils::createInstanceShortcutInApplications({ m_instance, name, tr("world"), parent, extraArgs }); -} - -void WorldList::createWorldShortcutInOther(const QModelIndex& index, QWidget* parent) const -{ - const auto& world = allWorlds().at(index.row()); - QString name = QString(tr("%1 - %2")).arg(m_instance->name(), world.name()); - QStringList extraArgs{ "--world", world.name() }; - ShortcutUtils::createInstanceShortcutInOther({ m_instance, name, tr("world"), parent, extraArgs }); -} - #include "WorldList.moc" diff --git a/launcher/minecraft/WorldList.h b/launcher/minecraft/WorldList.h index 4f54e0737..93fecf1f5 100644 --- a/launcher/minecraft/WorldList.h +++ b/launcher/minecraft/WorldList.h @@ -84,11 +84,6 @@ class WorldList : public QAbstractListModel { const QList& allWorlds() const { return m_worlds; } - void createWorldShortcut(const QModelIndex& index, QWidget* parent = nullptr) const; - void createWorldShortcutOnDesktop(const QModelIndex& index, QWidget* parent = nullptr) const; - void createWorldShortcutInApplications(const QModelIndex& index, QWidget* parent = nullptr) const; - void createWorldShortcutInOther(const QModelIndex& index, QWidget* parent = nullptr) const; - private slots: void directoryChanged(QString path); void loadWorldsAsync(); diff --git a/launcher/ui/pages/instance/ServersPage.cpp b/launcher/ui/pages/instance/ServersPage.cpp index 36844d92a..245bbffe2 100644 --- a/launcher/ui/pages/instance/ServersPage.cpp +++ b/launcher/ui/pages/instance/ServersPage.cpp @@ -40,10 +40,8 @@ #include "ui/dialogs/CustomMessageBox.h" #include "ui_ServersPage.h" -#include #include #include -#include #include #include #include @@ -104,38 +102,6 @@ struct Server { } } - void createServerShortcut(BaseInstance* instance, QWidget* parent = nullptr) const - { - if (!instance) - return; - - if (DesktopServices::isFlatpak()) - createServerShortcutInOther(instance, parent); - else - createServerShortcutOnDesktop(instance, parent); - } - - void createServerShortcutOnDesktop(BaseInstance* instance, QWidget* parent = nullptr) const - { - QString name = QString(QObject::tr("%1 - Server %2")).arg(instance->name(), m_name); - QStringList extraArgs{ "--server", m_address }; - ShortcutUtils::createInstanceShortcutOnDesktop({ instance, name, QObject::tr("server"), parent, extraArgs }); - } - - void createServerShortcutInApplications(BaseInstance* instance, QWidget* parent = nullptr) const - { - QString name = QString(QObject::tr("%1 - Server %2")).arg(instance->name(), m_name); - QStringList extraArgs{ "--server", m_address }; - ShortcutUtils::createInstanceShortcutInApplications({ instance, name, QObject::tr("server"), parent, extraArgs }); - } - - void createServerShortcutInOther(BaseInstance* instance, QWidget* parent = nullptr) const - { - QString name = QString(QObject::tr("%1 - Server %2")).arg(instance->name(), m_name); - QStringList extraArgs{ "--server", m_address }; - ShortcutUtils::createInstanceShortcutInOther({ instance, name, QObject::tr("server"), parent, extraArgs }); - } - // Data - persistent and user changeable QString m_name; QString m_address; @@ -615,26 +581,6 @@ ServersPage::ServersPage(InstancePtr inst, QWidget* parent) : QMainWindow(parent connect(ui->resourceComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(resourceIndexChanged(int))); connect(m_model, &QAbstractItemModel::rowsRemoved, this, &ServersPage::rowsRemoved); - QList shortcutActions = { ui->actionCreateServerShortcutOther }; - if (!DesktopServices::isFlatpak()) { - QString desktopDir = FS::getDesktopDir(); - QString applicationDir = FS::getApplicationsDir(); - - if (!applicationDir.isEmpty()) - shortcutActions.push_front(ui->actionCreateServerShortcutApplications); - - if (!desktopDir.isEmpty()) - shortcutActions.push_front(ui->actionCreateServerShortcutDesktop); - } - - if (shortcutActions.length() > 1) { - auto shortcutInstanceMenu = new QMenu(this); - - for (auto action : shortcutActions) - shortcutInstanceMenu->addAction(action); - ui->actionCreateServerShortcut->setMenu(shortcutInstanceMenu); - } - m_locked = m_inst->isRunning(); if (m_locked) { m_model->lock(); @@ -738,7 +684,6 @@ void ServersPage::updateState() ui->actionMove_Up->setEnabled(serverEditEnabled); ui->actionRemove->setEnabled(serverEditEnabled); ui->actionJoin->setEnabled(serverEditEnabled); - ui->actionCreateServerShortcut->setEnabled(serverEditEnabled); if (server) { ui->addressLine->setText(server->m_address); @@ -822,26 +767,6 @@ void ServersPage::on_actionJoin_triggered() APPLICATION->launch(m_inst, true, false, std::make_shared(MinecraftTarget::parse(address, false))); } -void ServersPage::on_actionCreateServerShortcut_triggered() -{ - m_model->at(currentServer)->createServerShortcut(m_inst.get(), this); -} - -void ServersPage::on_actionCreateServerShortcutDesktop_triggered() -{ - m_model->at(currentServer)->createServerShortcutOnDesktop(m_inst.get(), this); -} - -void ServersPage::on_actionCreateServerShortcutApplications_triggered() -{ - m_model->at(currentServer)->createServerShortcutInApplications(m_inst.get(), this); -} - -void ServersPage::on_actionCreateServerShortcutOther_triggered() -{ - m_model->at(currentServer)->createServerShortcutInOther(m_inst.get(), this); -} - void ServersPage::on_actionRefresh_triggered() { m_model->queryServersStatus(); diff --git a/launcher/ui/pages/instance/ServersPage.h b/launcher/ui/pages/instance/ServersPage.h index 94baaa004..77710d6cc 100644 --- a/launcher/ui/pages/instance/ServersPage.h +++ b/launcher/ui/pages/instance/ServersPage.h @@ -85,10 +85,6 @@ class ServersPage : public QMainWindow, public BasePage { void on_actionMove_Up_triggered(); void on_actionMove_Down_triggered(); void on_actionJoin_triggered(); - void on_actionCreateServerShortcut_triggered(); - void on_actionCreateServerShortcutDesktop_triggered(); - void on_actionCreateServerShortcutApplications_triggered(); - void on_actionCreateServerShortcutOther_triggered(); void on_actionRefresh_triggered(); void runningStateChanged(bool running); diff --git a/launcher/ui/pages/instance/ServersPage.ui b/launcher/ui/pages/instance/ServersPage.ui index bb8bff5aa..d330835c8 100644 --- a/launcher/ui/pages/instance/ServersPage.ui +++ b/launcher/ui/pages/instance/ServersPage.ui @@ -135,9 +135,6 @@ Qt::ToolButtonTextOnly - - true - false @@ -148,12 +145,10 @@ false - - - + @@ -182,47 +177,6 @@ Join - - - Create Shortcut - - - Creates a shortcut on a selected folder to join the selected server. - - - - - Desktop - - - Creates a shortcut to this server on your desktop - - - QAction::TextHeuristicRole - - - - - Applications - - - Create a shortcut of this server on your start menu - - - QAction::TextHeuristicRole - - - - - Other... - - - Creates a shortcut in a folder selected by you - - - QAction::TextHeuristicRole - - Refresh diff --git a/launcher/ui/pages/instance/WorldListPage.cpp b/launcher/ui/pages/instance/WorldListPage.cpp index c770f9f23..9e1a0fb55 100644 --- a/launcher/ui/pages/instance/WorldListPage.cpp +++ b/launcher/ui/pages/instance/WorldListPage.cpp @@ -89,26 +89,6 @@ WorldListPage::WorldListPage(InstancePtr inst, std::shared_ptr worlds ui->toolBar->insertSpacer(ui->actionRefresh); - QList shortcutActions = { ui->actionCreateWorldShortcutOther }; - if (!DesktopServices::isFlatpak()) { - QString desktopDir = FS::getDesktopDir(); - QString applicationDir = FS::getApplicationsDir(); - - if (!applicationDir.isEmpty()) - shortcutActions.push_front(ui->actionCreateWorldShortcutApplications); - - if (!desktopDir.isEmpty()) - shortcutActions.push_front(ui->actionCreateWorldShortcutDesktop); - } - - if (shortcutActions.length() > 1) { - auto shortcutInstanceMenu = new QMenu(this); - - for (auto action : shortcutActions) - shortcutInstanceMenu->addAction(action); - ui->actionCreateWorldShortcut->setMenu(shortcutInstanceMenu); - } - WorldListProxyModel* proxy = new WorldListProxyModel(this); proxy->setSortCaseSensitivity(Qt::CaseInsensitive); proxy->setSourceModel(m_worlds.get()); @@ -365,9 +345,6 @@ void WorldListPage::worldChanged([[maybe_unused]] const QModelIndex& current, [[ if (!supportsJoin) { ui->toolBar->removeAction(ui->actionJoin); - ui->toolBar->removeAction(ui->actionCreateWorldShortcut); - } else { - ui->actionCreateWorldShortcut->setEnabled(enable); } } @@ -443,42 +420,6 @@ void WorldListPage::on_actionRename_triggered() } } -void WorldListPage::on_actionCreateWorldShortcut_triggered() -{ - QModelIndex index = getSelectedWorld(); - if (!index.isValid()) { - return; - } - m_worlds->createWorldShortcut(index, this); -} - -void WorldListPage::on_actionCreateWorldShortcutDesktop_triggered() -{ - QModelIndex index = getSelectedWorld(); - if (!index.isValid()) { - return; - } - m_worlds->createWorldShortcutOnDesktop(index, this); -} - -void WorldListPage::on_actionCreateWorldShortcutApplications_triggered() -{ - QModelIndex index = getSelectedWorld(); - if (!index.isValid()) { - return; - } - m_worlds->createWorldShortcutInApplications(index, this); -} - -void WorldListPage::on_actionCreateWorldShortcutOther_triggered() -{ - QModelIndex index = getSelectedWorld(); - if (!index.isValid()) { - return; - } - m_worlds->createWorldShortcutInOther(index, this); -} - void WorldListPage::on_actionRefresh_triggered() { m_worlds->update(); diff --git a/launcher/ui/pages/instance/WorldListPage.h b/launcher/ui/pages/instance/WorldListPage.h index f2c081bc5..84d9cd075 100644 --- a/launcher/ui/pages/instance/WorldListPage.h +++ b/launcher/ui/pages/instance/WorldListPage.h @@ -95,10 +95,6 @@ class WorldListPage : public QMainWindow, public BasePage { void on_actionAdd_triggered(); void on_actionCopy_triggered(); void on_actionRename_triggered(); - void on_actionCreateWorldShortcut_triggered(); - void on_actionCreateWorldShortcutDesktop_triggered(); - void on_actionCreateWorldShortcutApplications_triggered(); - void on_actionCreateWorldShortcutOther_triggered(); void on_actionRefresh_triggered(); void on_actionView_Folder_triggered(); void on_actionDatapacks_triggered(); diff --git a/launcher/ui/pages/instance/WorldListPage.ui b/launcher/ui/pages/instance/WorldListPage.ui index 6d951cbdd..04344b453 100644 --- a/launcher/ui/pages/instance/WorldListPage.ui +++ b/launcher/ui/pages/instance/WorldListPage.ui @@ -70,9 +70,6 @@ Qt::ToolButtonTextOnly - - true - false @@ -88,11 +85,10 @@ - - + @@ -122,14 +118,6 @@ Delete - - - Create Shortcut - - - Creates a shortcut on a selected folder to join the selected world. - - MCEdit @@ -166,39 +154,6 @@ Manage datapacks inside the world. - - - Desktop - - - Creates a shortcut to this world on your desktop - - - QAction::TextHeuristicRole - - - - - Applications - - - Create a shortcut of this world on your start menu - - - QAction::TextHeuristicRole - - - - - Other... - - - Creates a shortcut in a folder selected by you - - - QAction::TextHeuristicRole - - From 3745bdb6f2725d51e24692f25fc4965a325ecde9 Mon Sep 17 00:00:00 2001 From: Yihe Li Date: Mon, 19 May 2025 01:46:23 +0800 Subject: [PATCH 22/24] Special treatment of non-Quick Join worlds Signed-off-by: Yihe Li --- launcher/ui/dialogs/CreateShortcutDialog.cpp | 2 + launcher/ui/dialogs/CreateShortcutDialog.ui | 52 ++++++++++++++------ 2 files changed, 40 insertions(+), 14 deletions(-) diff --git a/launcher/ui/dialogs/CreateShortcutDialog.cpp b/launcher/ui/dialogs/CreateShortcutDialog.cpp index 6bc2b80cf..6fb6e7050 100644 --- a/launcher/ui/dialogs/CreateShortcutDialog.cpp +++ b/launcher/ui/dialogs/CreateShortcutDialog.cpp @@ -71,6 +71,8 @@ CreateShortcutDialog::CreateShortcutDialog(InstancePtr instance, QWidget* parent ui->worldTarget->hide(); ui->worldSelectionBox->hide(); ui->serverTarget->setChecked(true); + ui->serverTarget->hide(); + ui->serverLabel->show(); } // Populate save targets diff --git a/launcher/ui/dialogs/CreateShortcutDialog.ui b/launcher/ui/dialogs/CreateShortcutDialog.ui index 2a90f43ab..9e2bdd747 100644 --- a/launcher/ui/dialogs/CreateShortcutDialog.ui +++ b/launcher/ui/dialogs/CreateShortcutDialog.ui @@ -131,14 +131,21 @@ - - - World: + + + 0 - - targetBtnGroup - - + + + + World: + + + targetBtnGroup + + + + @@ -151,14 +158,31 @@ - - - Server Address: + + + 0 - - targetBtnGroup - - + + + + Server Address: + + + targetBtnGroup + + + + + + + false + + + Server Address: + + + + From a89caf7362d595a66c37d06a77f56270042784f4 Mon Sep 17 00:00:00 2001 From: Yihe Li Date: Thu, 22 May 2025 23:09:29 +0800 Subject: [PATCH 23/24] Apply suggestions from review Signed-off-by: Yihe Li --- launcher/minecraft/ShortcutUtils.cpp | 2 +- launcher/ui/dialogs/CreateShortcutDialog.cpp | 15 +++++++++------ 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/launcher/minecraft/ShortcutUtils.cpp b/launcher/minecraft/ShortcutUtils.cpp index ea2a988be..43954aa6a 100644 --- a/launcher/minecraft/ShortcutUtils.cpp +++ b/launcher/minecraft/ShortcutUtils.cpp @@ -149,7 +149,7 @@ void createInstanceShortcut(const Shortcut& shortcut, const QString& filePath) args.append({ "--launch", shortcut.instance->id() }); args.append(shortcut.extraArgs); - if (!FS::createShortcut(std::move(filePath), appPath, args, shortcut.name, iconPath)) { + if (!FS::createShortcut(filePath, appPath, args, shortcut.name, iconPath)) { #if not defined(Q_OS_MACOS) iconFile.remove(); #endif diff --git a/launcher/ui/dialogs/CreateShortcutDialog.cpp b/launcher/ui/dialogs/CreateShortcutDialog.cpp index 6fb6e7050..581ac29e3 100644 --- a/launcher/ui/dialogs/CreateShortcutDialog.cpp +++ b/launcher/ui/dialogs/CreateShortcutDialog.cpp @@ -81,12 +81,12 @@ CreateShortcutDialog::CreateShortcutDialog(InstancePtr instance, QWidget* parent QString applicationDir = FS::getApplicationsDir(); if (!desktopDir.isEmpty()) - ui->saveTargetSelectionBox->addItem("Desktop", QVariant::fromValue(SaveTarget::Desktop)); + ui->saveTargetSelectionBox->addItem(tr("Desktop"), QVariant::fromValue(SaveTarget::Desktop)); if (!applicationDir.isEmpty()) - ui->saveTargetSelectionBox->addItem("Applications", QVariant::fromValue(SaveTarget::Applications)); + ui->saveTargetSelectionBox->addItem(tr("Applications"), QVariant::fromValue(SaveTarget::Applications)); } - ui->saveTargetSelectionBox->addItem("Other...", QVariant::fromValue(SaveTarget::Other)); + ui->saveTargetSelectionBox->addItem(tr("Other..."), QVariant::fromValue(SaveTarget::Other)); // Populate worlds if (m_QuickJoinSupported) { @@ -105,7 +105,7 @@ CreateShortcutDialog::CreateShortcutDialog(InstancePtr instance, QWidget* parent MinecraftAccountPtr defaultAccount = accounts->defaultAccount(); if (accounts->count() <= 0) { ui->overrideAccountCheckbox->setEnabled(false); - } else + } else { for (int i = 0; i < accounts->count(); i++) { MinecraftAccountPtr account = accounts->at(i); auto profileLabel = account->profileName(); @@ -118,6 +118,7 @@ CreateShortcutDialog::CreateShortcutDialog(InstancePtr instance, QWidget* parent if (defaultAccount == account) ui->accountSelectionBox->setCurrentIndex(i); } + } } CreateShortcutDialog::~CreateShortcutDialog() @@ -183,9 +184,11 @@ void CreateShortcutDialog::stateChanged() ui->instNameTextBox->setPlaceholderText(result); if (!ui->targetCheckbox->isChecked()) ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(true); - else + else { ui->buttonBox->button(QDialogButtonBox::Ok) - ->setEnabled(ui->worldTarget->isChecked() || (ui->serverTarget->isChecked() && !ui->serverAddressBox->text().isEmpty())); + ->setEnabled((ui->worldTarget->isChecked() && ui->worldSelectionBox->currentIndex() != -1) || + (ui->serverTarget->isChecked() && !ui->serverAddressBox->text().isEmpty())); + } } // Real work From 8425861fb14f1c47ea60a9d99d79ee9c857c3f26 Mon Sep 17 00:00:00 2001 From: Yihe Li Date: Fri, 23 May 2025 00:53:03 +0800 Subject: [PATCH 24/24] Just disable world selection when there is no world Signed-off-by: Yihe Li --- 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 581ac29e3..278573a22 100644 --- a/launcher/ui/dialogs/CreateShortcutDialog.cpp +++ b/launcher/ui/dialogs/CreateShortcutDialog.cpp @@ -67,7 +67,9 @@ CreateShortcutDialog::CreateShortcutDialog(InstancePtr instance, QWidget* parent auto mInst = std::dynamic_pointer_cast(instance); m_QuickJoinSupported = mInst && mInst->traits().contains("feature:is_quick_play_singleplayer"); - if (!m_QuickJoinSupported) { + auto worldList = mInst->worldList(); + worldList->update(); + if (!m_QuickJoinSupported || worldList->empty()) { ui->worldTarget->hide(); ui->worldSelectionBox->hide(); ui->serverTarget->setChecked(true); @@ -90,8 +92,6 @@ CreateShortcutDialog::CreateShortcutDialog(InstancePtr instance, QWidget* parent // Populate worlds if (m_QuickJoinSupported) { - auto worldList = mInst->worldList(); - worldList->update(); for (const auto& world : worldList->allWorlds()) { // Entry name: World Name [Game Mode] - Last Played: DateTime QString entry_name = tr("%1 [%2] - Last Played: %3")