Allow creating shortcuts to individual worlds and servers with Quick Play (#3767)
This commit is contained in:
commit
c300db1a24
9 changed files with 847 additions and 254 deletions
|
@ -310,6 +310,8 @@ set(MINECRAFT_SOURCES
|
||||||
minecraft/ParseUtils.h
|
minecraft/ParseUtils.h
|
||||||
minecraft/ProfileUtils.cpp
|
minecraft/ProfileUtils.cpp
|
||||||
minecraft/ProfileUtils.h
|
minecraft/ProfileUtils.h
|
||||||
|
minecraft/ShortcutUtils.cpp
|
||||||
|
minecraft/ShortcutUtils.h
|
||||||
minecraft/Library.cpp
|
minecraft/Library.cpp
|
||||||
minecraft/Library.h
|
minecraft/Library.h
|
||||||
minecraft/MojangDownloadInfo.h
|
minecraft/MojangDownloadInfo.h
|
||||||
|
@ -1048,6 +1050,8 @@ SET(LAUNCHER_SOURCES
|
||||||
ui/dialogs/ProfileSetupDialog.h
|
ui/dialogs/ProfileSetupDialog.h
|
||||||
ui/dialogs/CopyInstanceDialog.cpp
|
ui/dialogs/CopyInstanceDialog.cpp
|
||||||
ui/dialogs/CopyInstanceDialog.h
|
ui/dialogs/CopyInstanceDialog.h
|
||||||
|
ui/dialogs/CreateShortcutDialog.cpp
|
||||||
|
ui/dialogs/CreateShortcutDialog.h
|
||||||
ui/dialogs/CustomMessageBox.cpp
|
ui/dialogs/CustomMessageBox.cpp
|
||||||
ui/dialogs/CustomMessageBox.h
|
ui/dialogs/CustomMessageBox.h
|
||||||
ui/dialogs/ExportInstanceDialog.cpp
|
ui/dialogs/ExportInstanceDialog.cpp
|
||||||
|
@ -1230,6 +1234,7 @@ qt_wrap_ui(LAUNCHER_UI
|
||||||
ui/widgets/MinecraftSettingsWidget.ui
|
ui/widgets/MinecraftSettingsWidget.ui
|
||||||
ui/widgets/JavaSettingsWidget.ui
|
ui/widgets/JavaSettingsWidget.ui
|
||||||
ui/dialogs/CopyInstanceDialog.ui
|
ui/dialogs/CopyInstanceDialog.ui
|
||||||
|
ui/dialogs/CreateShortcutDialog.ui
|
||||||
ui/dialogs/ProfileSetupDialog.ui
|
ui/dialogs/ProfileSetupDialog.ui
|
||||||
ui/dialogs/ProgressDialog.ui
|
ui/dialogs/ProgressDialog.ui
|
||||||
ui/dialogs/NewInstanceDialog.ui
|
ui/dialogs/NewInstanceDialog.ui
|
||||||
|
|
237
launcher/minecraft/ShortcutUtils.cpp
Normal file
237
launcher/minecraft/ShortcutUtils.cpp
Normal file
|
@ -0,0 +1,237 @@
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
/*
|
||||||
|
* Prism Launcher - Minecraft Launcher
|
||||||
|
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||||
|
* Copyright (C) 2023 TheKodeToad <TheKodeToad@proton.me>
|
||||||
|
* Copyright (C) 2025 Yihe Li <winmikedows@hotmail.com>
|
||||||
|
*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* 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 <QApplication>
|
||||||
|
#include <QFileDialog>
|
||||||
|
|
||||||
|
#include <BuildConfig.h>
|
||||||
|
#include <DesktopServices.h>
|
||||||
|
#include <icons/IconList.h>
|
||||||
|
|
||||||
|
namespace ShortcutUtils {
|
||||||
|
|
||||||
|
void createInstanceShortcut(const Shortcut& shortcut, const QString& filePath)
|
||||||
|
{
|
||||||
|
if (!shortcut.instance)
|
||||||
|
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)
|
||||||
|
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."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
iconPath = FS::PathCombine(shortcut.instance->instanceRoot(), "Icon.icns");
|
||||||
|
|
||||||
|
QFile iconFile(iconPath);
|
||||||
|
if (!iconFile.open(QFile::WriteOnly)) {
|
||||||
|
QMessageBox::critical(shortcut.parent, QObject::tr("Create Shortcut"), QObject::tr("Failed to create icon for application."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QIcon iconObj = icon->icon();
|
||||||
|
bool success = iconObj.pixmap(1024, 1024).save(iconPath, "ICNS");
|
||||||
|
iconFile.close();
|
||||||
|
|
||||||
|
if (!success) {
|
||||||
|
iconFile.remove();
|
||||||
|
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)
|
||||||
|
if (appPath.startsWith("/tmp/.mount_")) {
|
||||||
|
// AppImage!
|
||||||
|
appPath = QProcessEnvironment::systemEnvironment().value(QStringLiteral("APPIMAGE"));
|
||||||
|
if (appPath.isEmpty()) {
|
||||||
|
QMessageBox::critical(
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
iconPath = FS::PathCombine(shortcut.instance->instanceRoot(), "icon.png");
|
||||||
|
|
||||||
|
QFile iconFile(iconPath);
|
||||||
|
if (!iconFile.open(QFile::WriteOnly)) {
|
||||||
|
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");
|
||||||
|
iconFile.close();
|
||||||
|
|
||||||
|
if (!success) {
|
||||||
|
iconFile.remove();
|
||||||
|
QMessageBox::critical(shortcut.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)
|
||||||
|
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
|
||||||
|
auto appIcon = APPLICATION->getThemedIcon("logo");
|
||||||
|
|
||||||
|
QFile iconFile(iconPath);
|
||||||
|
if (!iconFile.open(QFile::WriteOnly)) {
|
||||||
|
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");
|
||||||
|
iconFile.close();
|
||||||
|
|
||||||
|
// restore original window icon
|
||||||
|
QGuiApplication::setWindowIcon(appIcon);
|
||||||
|
|
||||||
|
if (!success) {
|
||||||
|
iconFile.remove();
|
||||||
|
QMessageBox::critical(shortcut.parent, QObject::tr("Create Shortcut"), QObject::tr("Failed to create icon for shortcut."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
QMessageBox::critical(shortcut.parent, QObject::tr("Create Shortcut"), QObject::tr("Not supported on your platform!"));
|
||||||
|
return;
|
||||||
|
#endif
|
||||||
|
args.append({ "--launch", shortcut.instance->id() });
|
||||||
|
args.append(shortcut.extraArgs);
|
||||||
|
|
||||||
|
if (!FS::createShortcut(filePath, appPath, args, shortcut.name, iconPath)) {
|
||||||
|
#if not defined(Q_OS_MACOS)
|
||||||
|
iconFile.remove();
|
||||||
|
#endif
|
||||||
|
QMessageBox::critical(shortcut.parent, QObject::tr("Create Shortcut"),
|
||||||
|
QObject::tr("Failed to create %1 shortcut!").arg(shortcut.targetString));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void createInstanceShortcutOnDesktop(const Shortcut& shortcut)
|
||||||
|
{
|
||||||
|
if (!shortcut.instance)
|
||||||
|
return;
|
||||||
|
|
||||||
|
QString desktopDir = FS::getDesktopDir();
|
||||||
|
if (desktopDir.isEmpty()) {
|
||||||
|
QMessageBox::critical(shortcut.parent, QObject::tr("Create Shortcut"), QObject::tr("Couldn't find desktop?!"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
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(const Shortcut& shortcut)
|
||||||
|
{
|
||||||
|
if (!shortcut.instance)
|
||||||
|
return;
|
||||||
|
|
||||||
|
QString applicationsDir = FS::getApplicationsDir();
|
||||||
|
if (applicationsDir.isEmpty()) {
|
||||||
|
QMessageBox::critical(shortcut.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(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(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(const Shortcut& shortcut)
|
||||||
|
{
|
||||||
|
if (!shortcut.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(shortcut.name) + extension);
|
||||||
|
QFileDialog fileDialog;
|
||||||
|
// workaround to make sure the portal file dialog opens in the desktop directory
|
||||||
|
fileDialog.setDirectoryUrl(defaultedDir);
|
||||||
|
|
||||||
|
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(shortcut, shortcutFilePath);
|
||||||
|
QMessageBox::information(shortcut.parent, QObject::tr("Create Shortcut"),
|
||||||
|
QObject::tr("Created a shortcut to this %1!").arg(shortcut.targetString));
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace ShortcutUtils
|
66
launcher/minecraft/ShortcutUtils.h
Normal file
66
launcher/minecraft/ShortcutUtils.h
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
/*
|
||||||
|
* Prism Launcher - Minecraft Launcher
|
||||||
|
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||||
|
* Copyright (C) 2023 TheKodeToad <TheKodeToad@proton.me>
|
||||||
|
* Copyright (C) 2025 Yihe Li <winmikedows@hotmail.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* This file incorporates work covered by the following copyright and
|
||||||
|
* permission notice:
|
||||||
|
*
|
||||||
|
* Copyright 2013-2021 MultiMC Contributors
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "Application.h"
|
||||||
|
|
||||||
|
#include <QMessageBox>
|
||||||
|
|
||||||
|
namespace ShortcutUtils {
|
||||||
|
/// A struct to hold parameters for creating a shortcut
|
||||||
|
struct Shortcut {
|
||||||
|
BaseInstance* instance;
|
||||||
|
QString name;
|
||||||
|
QString targetString;
|
||||||
|
QWidget* parent = nullptr;
|
||||||
|
QStringList extraArgs = {};
|
||||||
|
QString iconKey = "";
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Create an instance shortcut on the specified file path
|
||||||
|
void createInstanceShortcut(const Shortcut& shortcut, const QString& filePath);
|
||||||
|
|
||||||
|
/// Create an instance shortcut on the desktop
|
||||||
|
void createInstanceShortcutOnDesktop(const Shortcut& shortcut);
|
||||||
|
|
||||||
|
/// Create an instance shortcut in the Applications directory
|
||||||
|
void createInstanceShortcutInApplications(const Shortcut& shortcut);
|
||||||
|
|
||||||
|
/// Create an instance shortcut in other directories
|
||||||
|
void createInstanceShortcutInOther(const Shortcut& shortcut);
|
||||||
|
|
||||||
|
} // namespace ShortcutUtils
|
|
@ -93,6 +93,7 @@
|
||||||
#include "ui/GuiUtil.h"
|
#include "ui/GuiUtil.h"
|
||||||
#include "ui/dialogs/AboutDialog.h"
|
#include "ui/dialogs/AboutDialog.h"
|
||||||
#include "ui/dialogs/CopyInstanceDialog.h"
|
#include "ui/dialogs/CopyInstanceDialog.h"
|
||||||
|
#include "ui/dialogs/CreateShortcutDialog.h"
|
||||||
#include "ui/dialogs/CustomMessageBox.h"
|
#include "ui/dialogs/CustomMessageBox.h"
|
||||||
#include "ui/dialogs/ExportInstanceDialog.h"
|
#include "ui/dialogs/ExportInstanceDialog.h"
|
||||||
#include "ui/dialogs/ExportPackDialog.h"
|
#include "ui/dialogs/ExportPackDialog.h"
|
||||||
|
@ -207,26 +208,6 @@ MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent), ui(new Ui::MainWi
|
||||||
exportInstanceMenu->addAction(ui->actionExportInstanceMrPack);
|
exportInstanceMenu->addAction(ui->actionExportInstanceMrPack);
|
||||||
exportInstanceMenu->addAction(ui->actionExportInstanceFlamePack);
|
exportInstanceMenu->addAction(ui->actionExportInstanceFlamePack);
|
||||||
ui->actionExportInstance->setMenu(exportInstanceMenu);
|
ui->actionExportInstance->setMenu(exportInstanceMenu);
|
||||||
|
|
||||||
QList<QAction*> 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
|
// hide, disable and show stuff
|
||||||
|
@ -1545,208 +1526,15 @@ 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()
|
void MainWindow::on_actionCreateInstanceShortcut_triggered()
|
||||||
{
|
{
|
||||||
if (!m_selectedInstance)
|
if (!m_selectedInstance)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (DesktopServices::isFlatpak())
|
CreateShortcutDialog shortcutDlg(m_selectedInstance, this);
|
||||||
on_actionCreateInstanceShortcutOther_triggered();
|
if (!shortcutDlg.exec())
|
||||||
else
|
|
||||||
on_actionCreateInstanceShortcutDesktop_triggered();
|
|
||||||
}
|
|
||||||
|
|
||||||
void MainWindow::on_actionCreateInstanceShortcutDesktop_triggered()
|
|
||||||
{
|
|
||||||
if (!m_selectedInstance)
|
|
||||||
return;
|
return;
|
||||||
|
shortcutDlg.createShortcut();
|
||||||
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!"));
|
|
||||||
}
|
|
||||||
|
|
||||||
void MainWindow::on_actionCreateInstanceShortcutApplications_triggered()
|
|
||||||
{
|
|
||||||
if (!m_selectedInstance)
|
|
||||||
return;
|
|
||||||
|
|
||||||
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::taskEnd()
|
void MainWindow::taskEnd()
|
||||||
|
|
|
@ -167,10 +167,6 @@ class MainWindow : public QMainWindow {
|
||||||
|
|
||||||
void on_actionCreateInstanceShortcut_triggered();
|
void on_actionCreateInstanceShortcut_triggered();
|
||||||
|
|
||||||
void on_actionCreateInstanceShortcutDesktop_triggered();
|
|
||||||
void on_actionCreateInstanceShortcutApplications_triggered();
|
|
||||||
void on_actionCreateInstanceShortcutOther_triggered();
|
|
||||||
|
|
||||||
void taskEnd();
|
void taskEnd();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -230,7 +226,6 @@ class MainWindow : public QMainWindow {
|
||||||
void setSelectedInstanceById(const QString& id);
|
void setSelectedInstanceById(const QString& id);
|
||||||
void updateStatusCenter();
|
void updateStatusCenter();
|
||||||
void setInstanceActionsEnabled(bool enabled);
|
void setInstanceActionsEnabled(bool enabled);
|
||||||
void createInstanceShortcut(QString shortcutDirPath);
|
|
||||||
|
|
||||||
void runModalTask(Task* task);
|
void runModalTask(Task* task);
|
||||||
void instanceFromInstanceTask(InstanceTask* task);
|
void instanceFromInstanceTask(InstanceTask* task);
|
||||||
|
|
|
@ -771,39 +771,6 @@
|
||||||
<string>Open the Java folder in a file browser. Only available if the built-in Java downloader is used.</string>
|
<string>Open the Java folder in a file browser. Only available if the built-in Java downloader is used.</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
<action name="actionCreateInstanceShortcutDesktop">
|
|
||||||
<property name="text">
|
|
||||||
<string>Desktop</string>
|
|
||||||
</property>
|
|
||||||
<property name="toolTip">
|
|
||||||
<string>Creates an shortcut to this instance on your desktop</string>
|
|
||||||
</property>
|
|
||||||
<property name="menuRole">
|
|
||||||
<enum>QAction::TextHeuristicRole</enum>
|
|
||||||
</property>
|
|
||||||
</action>
|
|
||||||
<action name="actionCreateInstanceShortcutApplications">
|
|
||||||
<property name="text">
|
|
||||||
<string>Applications</string>
|
|
||||||
</property>
|
|
||||||
<property name="toolTip">
|
|
||||||
<string>Create a shortcut of this instance on your start menu</string>
|
|
||||||
</property>
|
|
||||||
<property name="menuRole">
|
|
||||||
<enum>QAction::TextHeuristicRole</enum>
|
|
||||||
</property>
|
|
||||||
</action>
|
|
||||||
<action name="actionCreateInstanceShortcutOther">
|
|
||||||
<property name="text">
|
|
||||||
<string>Other...</string>
|
|
||||||
</property>
|
|
||||||
<property name="toolTip">
|
|
||||||
<string>Creates a shortcut in a folder selected by you</string>
|
|
||||||
</property>
|
|
||||||
<property name="menuRole">
|
|
||||||
<enum>QAction::TextHeuristicRole</enum>
|
|
||||||
</property>
|
|
||||||
</action>
|
|
||||||
</widget>
|
</widget>
|
||||||
<customwidgets>
|
<customwidgets>
|
||||||
<customwidget>
|
<customwidget>
|
||||||
|
|
223
launcher/ui/dialogs/CreateShortcutDialog.cpp
Normal file
223
launcher/ui/dialogs/CreateShortcutDialog.cpp
Normal file
|
@ -0,0 +1,223 @@
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
/*
|
||||||
|
* Prism Launcher - Minecraft Launcher
|
||||||
|
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||||
|
* Copyright (C) 2023 TheKodeToad <TheKodeToad@proton.me>
|
||||||
|
* Copyright (C) 2025 Yihe Li <winmikedows@hotmail.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, version 3.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*
|
||||||
|
* This file incorporates work covered by the following copyright and
|
||||||
|
* permission notice:
|
||||||
|
*
|
||||||
|
* Copyright 2013-2021 MultiMC Contributors
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <QLayout>
|
||||||
|
#include <QPushButton>
|
||||||
|
|
||||||
|
#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"
|
||||||
|
|
||||||
|
#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)
|
||||||
|
{
|
||||||
|
ui->setupUi(this);
|
||||||
|
|
||||||
|
InstIconKey = instance->iconKey();
|
||||||
|
ui->iconButton->setIcon(APPLICATION->icons()->getIcon(InstIconKey));
|
||||||
|
ui->instNameTextBox->setPlaceholderText(instance->name());
|
||||||
|
|
||||||
|
auto mInst = std::dynamic_pointer_cast<MinecraftInstance>(instance);
|
||||||
|
m_QuickJoinSupported = mInst && mInst->traits().contains("feature:is_quick_play_singleplayer");
|
||||||
|
auto worldList = mInst->worldList();
|
||||||
|
worldList->update();
|
||||||
|
if (!m_QuickJoinSupported || worldList->empty()) {
|
||||||
|
ui->worldTarget->hide();
|
||||||
|
ui->worldSelectionBox->hide();
|
||||||
|
ui->serverTarget->setChecked(true);
|
||||||
|
ui->serverTarget->hide();
|
||||||
|
ui->serverLabel->show();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Populate save targets
|
||||||
|
if (!DesktopServices::isFlatpak()) {
|
||||||
|
QString desktopDir = FS::getDesktopDir();
|
||||||
|
QString applicationDir = FS::getApplicationsDir();
|
||||||
|
|
||||||
|
if (!desktopDir.isEmpty())
|
||||||
|
ui->saveTargetSelectionBox->addItem(tr("Desktop"), QVariant::fromValue(SaveTarget::Desktop));
|
||||||
|
|
||||||
|
if (!applicationDir.isEmpty())
|
||||||
|
ui->saveTargetSelectionBox->addItem(tr("Applications"), QVariant::fromValue(SaveTarget::Applications));
|
||||||
|
}
|
||||||
|
ui->saveTargetSelectionBox->addItem(tr("Other..."), QVariant::fromValue(SaveTarget::Other));
|
||||||
|
|
||||||
|
// Populate worlds
|
||||||
|
if (m_QuickJoinSupported) {
|
||||||
|
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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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()
|
||||||
|
{
|
||||||
|
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_overrideAccountCheckbox_stateChanged(int state)
|
||||||
|
{
|
||||||
|
ui->accountOptionsGroup->setEnabled(state == Qt::Checked);
|
||||||
|
}
|
||||||
|
|
||||||
|
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_worldTarget_toggled(bool checked)
|
||||||
|
{
|
||||||
|
ui->worldSelectionBox->setEnabled(checked);
|
||||||
|
stateChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CreateShortcutDialog::on_serverTarget_toggled(bool checked)
|
||||||
|
{
|
||||||
|
ui->serverAddressBox->setEnabled(checked);
|
||||||
|
stateChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
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->worldSelectionBox->currentIndex() != -1) ||
|
||||||
|
(ui->serverTarget->isChecked() && !ui->serverAddressBox->text().isEmpty()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Real work
|
||||||
|
void CreateShortcutDialog::createShortcut()
|
||||||
|
{
|
||||||
|
QString targetString = tr("instance");
|
||||||
|
QStringList extraArgs;
|
||||||
|
if (ui->targetCheckbox->isChecked()) {
|
||||||
|
if (ui->worldTarget->isChecked()) {
|
||||||
|
targetString = tr("world");
|
||||||
|
extraArgs = { "--world", ui->worldSelectionBox->currentData().toString() };
|
||||||
|
} else if (ui->serverTarget->isChecked()) {
|
||||||
|
targetString = tr("server");
|
||||||
|
extraArgs = { "--server", ui->serverAddressBox->text() };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto target = ui->saveTargetSelectionBox->currentData().value<SaveTarget>();
|
||||||
|
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(args);
|
||||||
|
else if (target == SaveTarget::Applications)
|
||||||
|
ShortcutUtils::createInstanceShortcutInApplications(args);
|
||||||
|
else
|
||||||
|
ShortcutUtils::createInstanceShortcutInOther(args);
|
||||||
|
}
|
62
launcher/ui/dialogs/CreateShortcutDialog.h
Normal file
62
launcher/ui/dialogs/CreateShortcutDialog.h
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
/* 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 <QDialog>
|
||||||
|
#include "BaseInstance.h"
|
||||||
|
|
||||||
|
class BaseInstance;
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
class CreateShortcutDialog;
|
||||||
|
}
|
||||||
|
|
||||||
|
class CreateShortcutDialog : public QDialog {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit CreateShortcutDialog(InstancePtr instance, QWidget* parent = nullptr);
|
||||||
|
~CreateShortcutDialog();
|
||||||
|
|
||||||
|
void createShortcut();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
// Icon, target and name
|
||||||
|
void on_iconButton_clicked();
|
||||||
|
|
||||||
|
// Override account
|
||||||
|
void on_overrideAccountCheckbox_stateChanged(int state);
|
||||||
|
|
||||||
|
// 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& text);
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Data
|
||||||
|
Ui::CreateShortcutDialog* ui;
|
||||||
|
QString InstIconKey;
|
||||||
|
InstancePtr m_instance;
|
||||||
|
bool m_QuickJoinSupported = false;
|
||||||
|
|
||||||
|
// Index representations
|
||||||
|
enum class SaveTarget { Desktop, Applications, Other };
|
||||||
|
|
||||||
|
// Functions
|
||||||
|
void stateChanged();
|
||||||
|
};
|
250
launcher/ui/dialogs/CreateShortcutDialog.ui
Normal file
250
launcher/ui/dialogs/CreateShortcutDialog.ui
Normal file
|
@ -0,0 +1,250 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>CreateShortcutDialog</class>
|
||||||
|
<widget class="QDialog" name="CreateShortcutDialog">
|
||||||
|
<property name="windowModality">
|
||||||
|
<enum>Qt::WindowModality::ApplicationModal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>450</width>
|
||||||
|
<height>370</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Create Instance Shortcut</string>
|
||||||
|
</property>
|
||||||
|
<property name="modal">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="iconBtnLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QToolButton" name="iconButton">
|
||||||
|
<property name="icon">
|
||||||
|
<iconset>
|
||||||
|
<normaloff>:/icons/instances/grass</normaloff>:/icons/instances/grass</iconset>
|
||||||
|
</property>
|
||||||
|
<property name="iconSize">
|
||||||
|
<size>
|
||||||
|
<width>80</width>
|
||||||
|
<height>80</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QGridLayout" name="iconBtnGridLayout">
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QLabel" name="saveToLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>Save To:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1">
|
||||||
|
<widget class="QComboBox" name="saveTargetSelectionBox">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QLabel" name="nameLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>Name:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="1">
|
||||||
|
<widget class="QLineEdit" name="instNameTextBox">
|
||||||
|
<property name="placeholderText">
|
||||||
|
<string>Name</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="overrideAccountCheckbox">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Use a different account than the default specified.</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Override the default account</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox" name="accountOptionsGroup">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="accountOptionsLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QComboBox" name="accountSelectionBox">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="targetCheckbox">
|
||||||
|
<property name="toolTip">
|
||||||
|
<string>Specify a world or server to automatically join on launch.</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Select a target to join on launch</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox" name="targetOptionsGroup">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<layout class="QGridLayout" name="targetOptionsGridLayout">
|
||||||
|
<item row="0" column="0">
|
||||||
|
<layout class="QVBoxLayout" name="worldOverlap">
|
||||||
|
<property name="spacing">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<widget class="QRadioButton" name="worldTarget">
|
||||||
|
<property name="text">
|
||||||
|
<string>World:</string>
|
||||||
|
</property>
|
||||||
|
<attribute name="buttonGroup">
|
||||||
|
<string notr="true">targetBtnGroup</string>
|
||||||
|
</attribute>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1">
|
||||||
|
<widget class="QComboBox" name="worldSelectionBox">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<layout class="QVBoxLayout" name="serverOverlap">
|
||||||
|
<property name="spacing">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<widget class="QRadioButton" name="serverTarget">
|
||||||
|
<property name="text">
|
||||||
|
<string>Server Address:</string>
|
||||||
|
</property>
|
||||||
|
<attribute name="buttonGroup">
|
||||||
|
<string notr="true">targetBtnGroup</string>
|
||||||
|
</attribute>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="serverLabel">
|
||||||
|
<property name="visible">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Server Address:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="1">
|
||||||
|
<widget class="QLineEdit" name="serverAddressBox">
|
||||||
|
<property name="placeholderText">
|
||||||
|
<string>Server Address</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QDialogButtonBox" name="buttonBox">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Orientation::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="standardButtons">
|
||||||
|
<set>QDialogButtonBox::StandardButton::Cancel|QDialogButtonBox::StandardButton::Ok</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<tabstops>
|
||||||
|
<tabstop>iconButton</tabstop>
|
||||||
|
</tabstops>
|
||||||
|
<resources/>
|
||||||
|
<connections>
|
||||||
|
<connection>
|
||||||
|
<sender>buttonBox</sender>
|
||||||
|
<signal>accepted()</signal>
|
||||||
|
<receiver>CreateShortcutDialog</receiver>
|
||||||
|
<slot>accept()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>20</x>
|
||||||
|
<y>20</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>20</x>
|
||||||
|
<y>20</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
<connection>
|
||||||
|
<sender>buttonBox</sender>
|
||||||
|
<signal>rejected()</signal>
|
||||||
|
<receiver>CreateShortcutDialog</receiver>
|
||||||
|
<slot>reject()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>20</x>
|
||||||
|
<y>20</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>20</x>
|
||||||
|
<y>20</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
</connections>
|
||||||
|
<buttongroups>
|
||||||
|
<buttongroup name="targetBtnGroup"/>
|
||||||
|
</buttongroups>
|
||||||
|
</ui>
|
Loading…
Add table
Add a link
Reference in a new issue