added instance shortcut feature

Signed-off-by: sshcrack <34072808+sshcrack@users.noreply.github.com>
This commit is contained in:
sshcrack 2024-10-22 20:53:57 +02:00
parent 79439a0217
commit a737d5df42
No known key found for this signature in database
GPG Key ID: 1DA55560745A2F13
6 changed files with 238 additions and 149 deletions

View File

@ -701,6 +701,9 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv)
m_settings->registerSetting("InstSortMode", "Name"); m_settings->registerSetting("InstSortMode", "Name");
m_settings->registerSetting("SelectedInstance", QString()); m_settings->registerSetting("SelectedInstance", QString());
// Shortcut creation
m_settings->registerSetting("ShortcutCreationMode", "Desktop");
// Window state and geometry // Window state and geometry
m_settings->registerSetting("MainWindowState", ""); m_settings->registerSetting("MainWindowState", "");
m_settings->registerSetting("MainWindowGeometry", ""); m_settings->registerSetting("MainWindowGeometry", "");

View File

@ -915,6 +915,11 @@ QString getDesktopDir()
return QStandardPaths::writableLocation(QStandardPaths::DesktopLocation); return QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);
} }
QString getApplicationsDir()
{
return QStandardPaths::writableLocation(QStandardPaths::ApplicationsLocation);
}
// Cross-platform Shortcut creation // Cross-platform Shortcut creation
bool createShortcut(QString destination, QString target, QStringList args, QString name, QString icon) bool createShortcut(QString destination, QString target, QStringList args, QString name, QString icon)
{ {

View File

@ -353,6 +353,9 @@ bool checkProblemticPathJava(QDir folder);
// Get the Directory representing the User's Desktop // Get the Directory representing the User's Desktop
QString getDesktopDir(); QString getDesktopDir();
// Get the Directory representing the User's Applications directory
QString getApplicationsDir();
// Overrides one folder with the contents of another, preserving items exclusive to the first folder // Overrides one folder with the contents of another, preserving items exclusive to the first folder
// Equivalent to doing QDir::rename, but allowing for overrides // Equivalent to doing QDir::rename, but allowing for overrides
bool overrideFolder(QString overwritten_path, QString override_path); bool overrideFolder(QString overwritten_path, QString override_path);

View File

@ -1495,141 +1495,158 @@ void MainWindow::on_actionCreateInstanceShortcut_triggered()
{ {
if (!m_selectedInstance) if (!m_selectedInstance)
return; return;
auto desktopPath = FS::getDesktopDir();
if (desktopPath.isEmpty()) { std::vector<QString> paths;
// TODO come up with an alternative solution (open "save file" dialog) QString mode = APPLICATION->settings()->get("ShortcutCreationMode").toString();
QMessageBox::critical(this, tr("Create instance shortcut"), tr("Couldn't find desktop?!")); if (mode == "Applications") {
return; paths.push_back(FS::getApplicationsDir());
} else if (mode == "Both") {
paths.push_back(FS::getDesktopDir());
paths.push_back(FS::getApplicationsDir());
} else {
// Default to desktop
paths.push_back(FS::getDesktopDir());
} }
QString desktopFilePath; for (const QString& shortcutDirPath : paths) {
QString appPath = QApplication::applicationFilePath(); if (shortcutDirPath.isEmpty()) {
QString iconPath; // TODO come up with an alternative solution (open "save file" dialog)
QStringList args; QMessageBox::critical(this, tr("Create instance shortcut"), tr("Couldn't find desktop?!"));
#if defined(Q_OS_MACOS) return;
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()); QString shortcutFilePath;
if (icon == nullptr) { QString appPath = QApplication::applicationFilePath();
icon = APPLICATION->icons()->icon("grass"); 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;
}
iconPath = FS::PathCombine(m_selectedInstance->instanceRoot(), "icon.png"); auto pIcon = APPLICATION->icons()->icon(m_selectedInstance->iconKey());
if (pIcon == nullptr) {
pIcon = APPLICATION->icons()->icon("grass");
}
QFile iconFile(iconPath); iconPath = FS::PathCombine(m_selectedInstance->instanceRoot(), "Icon.icns");
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) { QFile iconFile(iconPath);
iconFile.remove(); if (!iconFile.open(QFile::WriteOnly)) {
QMessageBox::critical(this, tr("Create instance shortcut"), tr("Failed to create icon for shortcut.")); QMessageBox::critical(this, tr("Create instance Application"), tr("Failed to create icon for Application."));
return; return;
} }
if (DesktopServices::isFlatpak()) { QIcon icon = pIcon->icon();
desktopFilePath = FS::PathCombine(desktopPath, FS::RemoveInvalidFilenameChars(m_selectedInstance->name()) + ".desktop");
QFileDialog fileDialog; bool success = icon.pixmap(1024, 1024).save(iconPath, "ICNS");
// workaround to make sure the portal file dialog opens in the desktop directory iconFile.close();
fileDialog.setDirectoryUrl(desktopPath);
desktopFilePath = fileDialog.getSaveFileName(this, tr("Create Shortcut"), desktopFilePath, tr("Desktop Entries") + " (*.desktop)"); if (!success) {
if (desktopFilePath.isEmpty()) iconFile.remove();
return; // file dialog canceled by user QMessageBox::critical(this, tr("Create instance Application"), tr("Failed to create icon for Application."));
appPath = "flatpak"; return;
QString flatpakAppId = BuildConfig.LAUNCHER_DESKTOPFILENAME; }
flatpakAppId.remove(".desktop"); #elif defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) || defined(Q_OS_OPENBSD)
args.append({ "run", flatpakAppId }); 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()) {
shortcutFilePath = FS::PathCombine(shortcutDirPath, FS::RemoveInvalidFilenameChars(m_selectedInstance->name()) + ".desktop");
QFileDialog fileDialog;
// workaround to make sure the portal file dialog opens in the desktop directory
fileDialog.setDirectoryUrl(shortcutDirPath);
shortcutFilePath =
fileDialog.getSaveFileName(this, tr("Create Shortcut"), shortcutFilePath, tr("Desktop Entries") + " (*.desktop)");
if (shortcutFilePath.isEmpty())
return; // file dialog canceled by user
appPath = "flatpak";
QString flatpakAppId = BuildConfig.LAUNCHER_DESKTOPFILENAME;
flatpakAppId.remove(".desktop");
args.append({ "run", flatpakAppId });
}
#elif defined(Q_OS_WIN) #elif defined(Q_OS_WIN)
auto icon = APPLICATION->icons()->icon(m_selectedInstance->iconKey()); auto icon = APPLICATION->icons()->icon(m_selectedInstance->iconKey());
if (icon == nullptr) { if (icon == nullptr) {
icon = APPLICATION->icons()->icon("grass"); icon = APPLICATION->icons()->icon("grass");
} }
iconPath = FS::PathCombine(m_selectedInstance->instanceRoot(), "icon.ico"); iconPath = FS::PathCombine(m_selectedInstance->instanceRoot(), "icon.ico");
// part of fix for weird bug involving the window icon being replaced // 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 // dunno why it happens, but this 2-line fix seems to be enough, so w/e
auto appIcon = APPLICATION->getThemedIcon("logo"); auto appIcon = APPLICATION->getThemedIcon("logo");
QFile iconFile(iconPath); QFile iconFile(iconPath);
if (!iconFile.open(QFile::WriteOnly)) { if (!iconFile.open(QFile::WriteOnly)) {
QMessageBox::critical(this, tr("Create instance shortcut"), tr("Failed to create icon for shortcut.")); QMessageBox::critical(this, tr("Create instance shortcut"), tr("Failed to create icon for shortcut."));
return; return;
} }
bool success = icon->icon().pixmap(64, 64).save(&iconFile, "ICO"); bool success = icon->icon().pixmap(64, 64).save(&iconFile, "ICO");
iconFile.close(); iconFile.close();
// restore original window icon // restore original window icon
QGuiApplication::setWindowIcon(appIcon); QGuiApplication::setWindowIcon(appIcon);
if (!success) { if (!success) {
iconFile.remove(); iconFile.remove();
QMessageBox::critical(this, tr("Create instance shortcut"), tr("Failed to create icon for shortcut.")); QMessageBox::critical(this, tr("Create instance shortcut"), tr("Failed to create icon for shortcut."));
return; return;
} }
#else #else
QMessageBox::critical(this, tr("Create instance shortcut"), tr("Not supported on your platform!")); QMessageBox::critical(this, tr("Create instance shortcut"), tr("Not supported on your platform!"));
return; return;
#endif #endif
args.append({ "--launch", m_selectedInstance->id() }); args.append({ "--launch", m_selectedInstance->id() });
if (FS::createShortcut(desktopFilePath, appPath, args, m_selectedInstance->name(), iconPath)) {
if (shortcutFilePath.isEmpty())
shortcutFilePath = FS::PathCombine(shortcutDirPath, FS::RemoveInvalidFilenameChars(m_selectedInstance->name()));
if (!FS::createShortcut(shortcutFilePath, appPath, args, m_selectedInstance->name(), iconPath)) {
#if not defined(Q_OS_MACOS) #if not defined(Q_OS_MACOS)
QMessageBox::information(this, tr("Create instance shortcut"), tr("Created a shortcut to this instance on your desktop!")); iconFile.remove();
#else
QMessageBox::information(this, tr("Create instance shortcut"), tr("Created a shortcut to this instance!"));
#endif #endif
} else { QMessageBox::critical(this, tr("Create instance shortcut"), tr("Failed to create instance shortcut!"));
#if not defined(Q_OS_MACOS) }
iconFile.remove();
#endif
QMessageBox::critical(this, tr("Create instance shortcut"), tr("Failed to create instance shortcut!"));
} }
#if not defined(Q_OS_MACOS)
QMessageBox::information(this, tr("Create instance shortcut"), tr("Created a shortcut to this instance!"));
#else
QMessageBox::information(this, tr("Create instance shortcut"), tr("Created a shortcut to this instance!"));
#endif
} }
void MainWindow::taskEnd() void MainWindow::taskEnd()

View File

@ -65,6 +65,15 @@ enum InstSortMode {
Sort_LastLaunch Sort_LastLaunch
}; };
enum ShortcutCreationMode {
// Create a shortcut in the applications
Shortcut_OnlyApplications,
// Create a shortcut in both locations
Shortcut_Both,
// Create a shortcut on the desktop
Shortcut_OnlyDesktop
};
LauncherPage::LauncherPage(QWidget* parent) : QWidget(parent), ui(new Ui::LauncherPage) LauncherPage::LauncherPage(QWidget* parent) : QWidget(parent), ui(new Ui::LauncherPage)
{ {
ui->setupUi(this); ui->setupUi(this);
@ -254,6 +263,19 @@ void LauncherPage::applySettings()
s->set("ModMetadataDisabled", ui->metadataDisableBtn->isChecked()); s->set("ModMetadataDisabled", ui->metadataDisableBtn->isChecked());
s->set("ModDependenciesDisabled", ui->dependenciesDisableBtn->isChecked()); s->set("ModDependenciesDisabled", ui->dependenciesDisableBtn->isChecked());
s->set("SkipModpackUpdatePrompt", ui->skipModpackUpdatePromptBtn->isChecked()); s->set("SkipModpackUpdatePrompt", ui->skipModpackUpdatePromptBtn->isChecked());
auto shortcutMode = (ShortcutCreationMode) ui->createShortcutActionComboBox->currentIndex();
switch (shortcutMode) {
case Shortcut_OnlyApplications:
s->set("ShortcutCreationMode", "Applications");
break;
case Shortcut_Both:
s->set("ShortcutCreationMode", "Both");
break;
case Shortcut_OnlyDesktop:
s->set("ShortcutCreationMode", "Desktop");
break;
}
} }
void LauncherPage::loadSettings() void LauncherPage::loadSettings()
{ {
@ -319,6 +341,19 @@ void LauncherPage::loadSettings()
ui->metadataWarningLabel->setHidden(!ui->metadataDisableBtn->isChecked()); ui->metadataWarningLabel->setHidden(!ui->metadataDisableBtn->isChecked());
ui->dependenciesDisableBtn->setChecked(s->get("ModDependenciesDisabled").toBool()); ui->dependenciesDisableBtn->setChecked(s->get("ModDependenciesDisabled").toBool());
ui->skipModpackUpdatePromptBtn->setChecked(s->get("SkipModpackUpdatePrompt").toBool()); ui->skipModpackUpdatePromptBtn->setChecked(s->get("SkipModpackUpdatePrompt").toBool());
QString shortcutModeStr = s->get("ShortcutCreationMode").toString();
ShortcutCreationMode shortcutMode = Shortcut_OnlyDesktop;
if(shortcutModeStr == "Applications") {
shortcutMode = Shortcut_OnlyApplications;
} else if(shortcutModeStr == "Desktop") {
// Guess we don't need that, but it's here for completeness
shortcutMode = Shortcut_OnlyDesktop;
} else if(shortcutModeStr == "Both") {
shortcutMode = Shortcut_Both;
}
ui->createShortcutActionComboBox->setCurrentIndex(shortcutMode);
} }
void LauncherPage::refreshFontPreview() void LauncherPage::refreshFontPreview()

View File

@ -282,41 +282,6 @@
<string>Miscellaneous</string> <string>Miscellaneous</string>
</property> </property>
<layout class="QGridLayout" name="gridLayout"> <layout class="QGridLayout" name="gridLayout">
<item row="1" column="1">
<widget class="QSpinBox" name="numberOfConcurrentDownloadsSpinBox">
<property name="minimum">
<number>1</number>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="numberOfConcurrentTasksLabel">
<property name="text">
<string>Number of concurrent tasks</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QSpinBox" name="numberOfConcurrentTasksSpinBox">
<property name="minimum">
<number>1</number>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="numberOfConcurrentDownloadsLabel">
<property name="text">
<string>Number of concurrent downloads</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="numberOfManualRetriesLabel">
<property name="text">
<string>Number of manual retries</string>
</property>
</widget>
</item>
<item row="2" column="1"> <item row="2" column="1">
<widget class="QSpinBox" name="numberOfManualRetriesSpinBox"> <widget class="QSpinBox" name="numberOfManualRetriesSpinBox">
<property name="minimum"> <property name="minimum">
@ -334,6 +299,13 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="1" column="1">
<widget class="QSpinBox" name="numberOfConcurrentDownloadsSpinBox">
<property name="minimum">
<number>1</number>
</property>
</widget>
</item>
<item row="3" column="1"> <item row="3" column="1">
<widget class="QSpinBox" name="timeoutSecondsSpinBox"> <widget class="QSpinBox" name="timeoutSecondsSpinBox">
<property name="suffix"> <property name="suffix">
@ -341,6 +313,60 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="1" column="0">
<widget class="QLabel" name="numberOfConcurrentDownloadsLabel">
<property name="text">
<string>Number of concurrent downloads</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="numberOfManualRetriesLabel">
<property name="text">
<string>Number of manual retries</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="numberOfConcurrentTasksLabel">
<property name="text">
<string>Number of concurrent tasks</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QSpinBox" name="numberOfConcurrentTasksSpinBox">
<property name="minimum">
<number>1</number>
</property>
</widget>
</item>
<item row="5" column="0">
<widget class="QLabel" name="createShortcutActionLabel">
<property name="text">
<string>Create shortcut action</string>
</property>
</widget>
</item>
<item row="5" column="1">
<widget class="QComboBox" name="createShortcutActionComboBox">
<item>
<property name="text">
<string>Applications only</string>
</property>
</item>
<item>
<property name="text">
<string>Applications &amp; Desktop</string>
</property>
</item>
<item>
<property name="text">
<string>Desktop only</string>
</property>
</item>
</widget>
</item>
</layout> </layout>
</widget> </widget>
</item> </item>