Delete shortcut when deleting instances

Signed-off-by: Yihe Li <winmikedows@hotmail.com>
This commit is contained in:
Yihe Li 2025-06-01 08:13:10 +08:00
parent 0a89f5cfaa
commit d3f337d6ef
No known key found for this signature in database
11 changed files with 168 additions and 67 deletions

View file

@ -398,6 +398,17 @@ bool BaseInstance::syncInstanceDirName(const QString& newRoot) const
return oldRoot == newRoot || QFile::rename(oldRoot, newRoot); return oldRoot == newRoot || QFile::rename(oldRoot, newRoot);
} }
void BaseInstance::registerShortcut(const ShortcutData& data)
{
m_shortcuts.append(data);
qDebug() << "Registering shortcut for instance" << id() << "with name" << data.name << "and path" << data.filePath;
}
QList<ShortcutData>& BaseInstance::getShortcuts()
{
return m_shortcuts;
}
QString BaseInstance::name() const QString BaseInstance::name() const
{ {
return m_settings->get("name").toString(); return m_settings->get("name").toString();

View file

@ -39,6 +39,7 @@
#include <cassert> #include <cassert>
#include <QDateTime> #include <QDateTime>
#include <QList>
#include <QMenu> #include <QMenu>
#include <QObject> #include <QObject>
#include <QProcess> #include <QProcess>
@ -66,6 +67,16 @@ class BaseInstance;
// pointer for lazy people // pointer for lazy people
using InstancePtr = std::shared_ptr<BaseInstance>; using InstancePtr = std::shared_ptr<BaseInstance>;
/// Shortcut saving target representations
enum class ShortcutTarget { Desktop, Applications, Other };
/// Shortcut data representation
struct ShortcutData {
QString name;
QString filePath;
ShortcutTarget target;
};
/*! /*!
* \brief Base class for instances. * \brief Base class for instances.
* This class implements many functions that are common between instances and * This class implements many functions that are common between instances and
@ -129,6 +140,10 @@ class BaseInstance : public QObject, public std::enable_shared_from_this<BaseIns
/// Sync name and rename instance dir accordingly; returns true if successful /// Sync name and rename instance dir accordingly; returns true if successful
bool syncInstanceDirName(const QString& newRoot) const; bool syncInstanceDirName(const QString& newRoot) const;
/// Register a created shortcut
void registerShortcut(const ShortcutData& data);
QList<ShortcutData>& getShortcuts();
/// Value used for instance window titles /// Value used for instance window titles
QString windowTitle() const; QString windowTitle() const;
@ -308,6 +323,8 @@ class BaseInstance : public QObject, public std::enable_shared_from_this<BaseIns
SettingsObjectWeakPtr m_global_settings; SettingsObjectWeakPtr m_global_settings;
bool m_specific_settings_loaded = false; bool m_specific_settings_loaded = false;
QList<ShortcutData> m_shortcuts;
}; };
Q_DECLARE_METATYPE(shared_qobject_ptr<BaseInstance>) Q_DECLARE_METATYPE(shared_qobject_ptr<BaseInstance>)

View file

@ -898,26 +898,26 @@ QString getApplicationsDir()
} }
// Cross-platform Shortcut creation // Cross-platform Shortcut creation
bool createShortcut(QString destination, QString target, QStringList args, QString name, QString icon) QString createShortcut(QString destination, QString target, QStringList args, QString name, QString icon)
{ {
if (destination.isEmpty()) { if (destination.isEmpty()) {
destination = PathCombine(getDesktopDir(), RemoveInvalidFilenameChars(name)); destination = PathCombine(getDesktopDir(), RemoveInvalidFilenameChars(name));
} }
if (!ensureFilePathExists(destination)) { if (!ensureFilePathExists(destination)) {
qWarning() << "Destination path can't be created!"; qWarning() << "Destination path can't be created!";
return false; return "";
} }
#if defined(Q_OS_MACOS) #if defined(Q_OS_MACOS)
QDir application = destination + ".app/"; QDir application = destination + ".app/";
if (application.exists()) { if (application.exists()) {
qWarning() << "Application already exists!"; qWarning() << "Application already exists!";
return false; return "";
} }
if (!application.mkpath(".")) { if (!application.mkpath(".")) {
qWarning() << "Couldn't create application"; qWarning() << "Couldn't create application";
return false; return "";
} }
QDir content = application.path() + "/Contents/"; QDir content = application.path() + "/Contents/";
@ -927,7 +927,7 @@ bool createShortcut(QString destination, QString target, QStringList args, QStri
if (!(content.mkpath(".") && resources.mkpath(".") && binaryDir.mkpath("."))) { if (!(content.mkpath(".") && resources.mkpath(".") && binaryDir.mkpath("."))) {
qWarning() << "Couldn't create directories within application"; qWarning() << "Couldn't create directories within application";
return false; return "";
} }
info.open(QIODevice::WriteOnly | QIODevice::Text); info.open(QIODevice::WriteOnly | QIODevice::Text);
@ -976,7 +976,7 @@ bool createShortcut(QString destination, QString target, QStringList args, QStri
"</dict>\n" "</dict>\n"
"</plist>"; "</plist>";
return true; return application.path();
#elif defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) || defined(Q_OS_OPENBSD) #elif defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) || defined(Q_OS_OPENBSD)
if (!destination.endsWith(".desktop")) // in case of isFlatpak destination is already populated if (!destination.endsWith(".desktop")) // in case of isFlatpak destination is already populated
destination += ".desktop"; destination += ".desktop";
@ -1002,32 +1002,32 @@ bool createShortcut(QString destination, QString target, QStringList args, QStri
f.setPermissions(f.permissions() | QFileDevice::ExeOwner | QFileDevice::ExeGroup | QFileDevice::ExeOther); f.setPermissions(f.permissions() | QFileDevice::ExeOwner | QFileDevice::ExeGroup | QFileDevice::ExeOther);
return true; return destination;
#elif defined(Q_OS_WIN) #elif defined(Q_OS_WIN)
QFileInfo targetInfo(target); QFileInfo targetInfo(target);
if (!targetInfo.exists()) { if (!targetInfo.exists()) {
qWarning() << "Target file does not exist!"; qWarning() << "Target file does not exist!";
return false; return "";
} }
target = targetInfo.absoluteFilePath(); target = targetInfo.absoluteFilePath();
if (target.length() >= MAX_PATH) { if (target.length() >= MAX_PATH) {
qWarning() << "Target file path is too long!"; qWarning() << "Target file path is too long!";
return false; return "";
} }
if (!icon.isEmpty() && icon.length() >= MAX_PATH) { if (!icon.isEmpty() && icon.length() >= MAX_PATH) {
qWarning() << "Icon path is too long!"; qWarning() << "Icon path is too long!";
return false; return "";
} }
destination += ".lnk"; destination += ".lnk";
if (destination.length() >= MAX_PATH) { if (destination.length() >= MAX_PATH) {
qWarning() << "Destination path is too long!"; qWarning() << "Destination path is too long!";
return false; return "";
} }
QString argStr; QString argStr;
@ -1046,7 +1046,7 @@ bool createShortcut(QString destination, QString target, QStringList args, QStri
if (argStr.length() >= MAX_PATH) { if (argStr.length() >= MAX_PATH) {
qWarning() << "Arguments string is too long!"; qWarning() << "Arguments string is too long!";
return false; return "";
} }
HRESULT hres; HRESULT hres;
@ -1055,7 +1055,7 @@ bool createShortcut(QString destination, QString target, QStringList args, QStri
hres = CoInitialize(nullptr); hres = CoInitialize(nullptr);
if (FAILED(hres)) { if (FAILED(hres)) {
qWarning() << "Failed to initialize COM!"; qWarning() << "Failed to initialize COM!";
return false; return "";
} }
WCHAR wsz[MAX_PATH]; WCHAR wsz[MAX_PATH];
@ -1109,10 +1109,12 @@ bool createShortcut(QString destination, QString target, QStringList args, QStri
// go away COM, nobody likes you // go away COM, nobody likes you
CoUninitialize(); CoUninitialize();
return SUCCEEDED(hres); if (SUCCEEDED(hres))
return destination;
return "";
#else #else
qWarning("Desktop Shortcuts not supported on your platform!"); qWarning("Desktop Shortcuts not supported on your platform!");
return false; return "";
#endif #endif
} }

View file

@ -362,8 +362,9 @@ bool overrideFolder(QString overwritten_path, QString override_path);
/** /**
* Creates a shortcut to the specified target file at the specified destination path. * Creates a shortcut to the specified target file at the specified destination path.
* Returns empty string if creation failed; otherwise returns the path to the created shortcut.
*/ */
bool createShortcut(QString destination, QString target, QStringList args, QString name, QString icon); QString createShortcut(QString destination, QString target, QStringList args, QString name, QString icon);
enum class FilesystemType { enum class FilesystemType {
FAT, FAT,

View file

@ -60,6 +60,7 @@
#include "NullInstance.h" #include "NullInstance.h"
#include "WatchLock.h" #include "WatchLock.h"
#include "minecraft/MinecraftInstance.h" #include "minecraft/MinecraftInstance.h"
#include "minecraft/ShortcutUtils.h"
#include "settings/INISettingsObject.h" #include "settings/INISettingsObject.h"
#ifdef Q_OS_WIN32 #ifdef Q_OS_WIN32
@ -333,7 +334,7 @@ bool InstanceList::trashInstance(const InstanceId& id)
{ {
auto inst = getInstanceById(id); auto inst = getInstanceById(id);
if (!inst) { if (!inst) {
qDebug() << "Cannot trash instance" << id << ". No such instance is present (deleted externally?)."; qWarning() << "Cannot trash instance" << id << ". No such instance is present (deleted externally?).";
return false; return false;
} }
@ -348,26 +349,48 @@ bool InstanceList::trashInstance(const InstanceId& id)
} }
if (!FS::trash(inst->instanceRoot(), &trashedLoc)) { if (!FS::trash(inst->instanceRoot(), &trashedLoc)) {
qDebug() << "Trash of instance" << id << "has not been completely successfully..."; qWarning() << "Trash of instance" << id << "has not been completely successful...";
return false; return false;
} }
qDebug() << "Instance" << id << "has been trashed by the launcher."; qDebug() << "Instance" << id << "has been trashed by the launcher.";
m_trashHistory.push({ id, inst->instanceRoot(), trashedLoc, cachedGroupId }); m_trashHistory.push({ id, inst->instanceRoot(), trashedLoc, cachedGroupId });
// Also trash all of its shortcuts; we remove the shortcuts if trash fails since it is invalid anyway
auto& shortcuts = inst->getShortcuts();
for (auto it = shortcuts.begin(); it != shortcuts.end();) {
const auto& [name, filePath, target] = *it;
if (!FS::trash(filePath, &trashedLoc)) {
qWarning() << "Trash of shortcut" << name << "at path" << filePath << "for instance" << id
<< "has not been successful, trying to delete it instead...";
if (!FS::deletePath(filePath)) {
qWarning() << "Deletion of shortcut" << name << "at path" << filePath << "for instance" << id
<< "has not been successful, given up...";
++it;
} else {
qDebug() << "Shortcut" << name << "at path" << filePath << "for instance" << id << "has been deleted by the launcher.";
it = shortcuts.erase(it);
}
continue;
}
qDebug() << "Shortcut" << name << "at path" << filePath << "for instance" << id << "has been trashed by the launcher.";
m_trashHistory.top().shortcuts.append({ *it, trashedLoc });
it = shortcuts.erase(it);
}
return true; return true;
} }
bool InstanceList::trashedSomething() bool InstanceList::trashedSomething() const
{ {
return !m_trashHistory.empty(); return !m_trashHistory.empty();
} }
void InstanceList::undoTrashInstance() bool InstanceList::undoTrashInstance()
{ {
if (m_trashHistory.empty()) { if (m_trashHistory.empty()) {
qWarning() << "Nothing to recover from trash."; qWarning() << "Nothing to recover from trash.";
return; return true;
} }
auto top = m_trashHistory.pop(); auto top = m_trashHistory.pop();
@ -377,21 +400,41 @@ void InstanceList::undoTrashInstance()
top.path += "1"; top.path += "1";
} }
if (!QFile(top.trashPath).rename(top.path)) {
qWarning() << "Moving" << top.trashPath << "back to" << top.path << "failed!";
return false;
}
qDebug() << "Moving" << top.trashPath << "back to" << top.path; qDebug() << "Moving" << top.trashPath << "back to" << top.path;
QFile(top.trashPath).rename(top.path);
bool ok = true;
for (const auto& [data, trashPath] : top.shortcuts) {
if (QDir(data.filePath).exists()) {
// Don't try to append 1 here as the shortcut may have suffixes like .app, just warn and skip it
qWarning() << "Shortcut" << trashPath << "original directory" << data.filePath << "already exists!";
ok = false;
continue;
}
if (!QFile(trashPath).rename(data.filePath)) {
qWarning() << "Moving shortcut from" << trashPath << "back to" << data.filePath << "failed!";
ok = false;
continue;
}
qDebug() << "Moving shortcut from" << trashPath << "back to" << data.filePath;
}
m_instanceGroupIndex[top.id] = top.groupName; m_instanceGroupIndex[top.id] = top.groupName;
increaseGroupCount(top.groupName); increaseGroupCount(top.groupName);
saveGroupList(); saveGroupList();
emit instancesChanged(); emit instancesChanged();
return ok;
} }
void InstanceList::deleteInstance(const InstanceId& id) void InstanceList::deleteInstance(const InstanceId& id)
{ {
auto inst = getInstanceById(id); auto inst = getInstanceById(id);
if (!inst) { if (!inst) {
qDebug() << "Cannot delete instance" << id << ". No such instance is present (deleted externally?)."; qWarning() << "Cannot delete instance" << id << ". No such instance is present (deleted externally?).";
return; return;
} }
@ -409,6 +452,14 @@ void InstanceList::deleteInstance(const InstanceId& id)
} }
qDebug() << "Instance" << id << "has been deleted by the launcher."; qDebug() << "Instance" << id << "has been deleted by the launcher.";
for (const auto& [name, filePath, target] : inst->getShortcuts()) {
if (!FS::deletePath(filePath)) {
qWarning() << "Deletion of shortcut" << name << "at path" << filePath << "for instance" << id << "has not been successful...";
continue;
}
qDebug() << "Shortcut" << name << "at path" << filePath << "for instance" << id << "has been deleted by the launcher.";
}
} }
static QMap<InstanceId, InstanceLocator> getIdMapping(const QList<InstancePtr>& list) static QMap<InstanceId, InstanceLocator> getIdMapping(const QList<InstancePtr>& list)

View file

@ -56,11 +56,17 @@ enum class InstCreateError { NoCreateError = 0, NoSuchVersion, UnknownCreateErro
enum class GroupsState { NotLoaded, Steady, Dirty }; enum class GroupsState { NotLoaded, Steady, Dirty };
struct TrashShortcutItem {
ShortcutData data;
QString trashPath;
};
struct TrashHistoryItem { struct TrashHistoryItem {
QString id; QString id;
QString path; QString path;
QString trashPath; QString trashPath;
QString groupName; QString groupName;
QList<TrashShortcutItem> shortcuts;
}; };
class InstanceList : public QAbstractListModel { class InstanceList : public QAbstractListModel {
@ -111,8 +117,8 @@ class InstanceList : public QAbstractListModel {
void deleteGroup(const GroupId& name); void deleteGroup(const GroupId& name);
void renameGroup(const GroupId& src, const GroupId& dst); void renameGroup(const GroupId& src, const GroupId& dst);
bool trashInstance(const InstanceId& id); bool trashInstance(const InstanceId& id);
bool trashedSomething(); bool trashedSomething() const;
void undoTrashInstance(); bool undoTrashInstance();
void deleteInstance(const InstanceId& id); void deleteInstance(const InstanceId& id);
// Wrap an instance creation task in some more task machinery and make it ready to be used // Wrap an instance creation task in some more task machinery and make it ready to be used

View file

@ -48,10 +48,10 @@
namespace ShortcutUtils { namespace ShortcutUtils {
void createInstanceShortcut(const Shortcut& shortcut, const QString& filePath) bool createInstanceShortcut(const Shortcut& shortcut, const QString& filePath)
{ {
if (!shortcut.instance) if (!shortcut.instance)
return; return false;
QString appPath = QApplication::applicationFilePath(); QString appPath = QApplication::applicationFilePath();
auto icon = APPLICATION->icons()->icon(shortcut.iconKey.isEmpty() ? shortcut.instance->iconKey() : shortcut.iconKey); auto icon = APPLICATION->icons()->icon(shortcut.iconKey.isEmpty() ? shortcut.instance->iconKey() : shortcut.iconKey);
@ -64,7 +64,7 @@ void createInstanceShortcut(const Shortcut& shortcut, const QString& filePath)
if (appPath.startsWith("/private/var/")) { if (appPath.startsWith("/private/var/")) {
QMessageBox::critical(shortcut.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.")); QObject::tr("The launcher is in the folder it was extracted from, therefore it cannot create shortcuts."));
return; return false;
} }
iconPath = FS::PathCombine(shortcut.instance->instanceRoot(), "Icon.icns"); iconPath = FS::PathCombine(shortcut.instance->instanceRoot(), "Icon.icns");
@ -72,7 +72,7 @@ void createInstanceShortcut(const Shortcut& shortcut, const QString& filePath)
QFile iconFile(iconPath); QFile iconFile(iconPath);
if (!iconFile.open(QFile::WriteOnly)) { if (!iconFile.open(QFile::WriteOnly)) {
QMessageBox::critical(shortcut.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; return false;
} }
QIcon iconObj = icon->icon(); QIcon iconObj = icon->icon();
@ -82,7 +82,7 @@ void createInstanceShortcut(const Shortcut& shortcut, const QString& filePath)
if (!success) { if (!success) {
iconFile.remove(); iconFile.remove();
QMessageBox::critical(shortcut.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; return false;
} }
#elif defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) || defined(Q_OS_OPENBSD) #elif defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) || defined(Q_OS_OPENBSD)
if (appPath.startsWith("/tmp/.mount_")) { if (appPath.startsWith("/tmp/.mount_")) {
@ -102,7 +102,7 @@ void createInstanceShortcut(const Shortcut& shortcut, const QString& filePath)
QFile iconFile(iconPath); QFile iconFile(iconPath);
if (!iconFile.open(QFile::WriteOnly)) { if (!iconFile.open(QFile::WriteOnly)) {
QMessageBox::critical(shortcut.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; return false;
} }
bool success = icon->icon().pixmap(64, 64).save(&iconFile, "PNG"); bool success = icon->icon().pixmap(64, 64).save(&iconFile, "PNG");
iconFile.close(); iconFile.close();
@ -110,7 +110,7 @@ void createInstanceShortcut(const Shortcut& shortcut, const QString& filePath)
if (!success) { if (!success) {
iconFile.remove(); iconFile.remove();
QMessageBox::critical(shortcut.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; return false;
} }
if (DesktopServices::isFlatpak()) { if (DesktopServices::isFlatpak()) {
@ -128,7 +128,7 @@ void createInstanceShortcut(const Shortcut& shortcut, const QString& filePath)
QFile iconFile(iconPath); QFile iconFile(iconPath);
if (!iconFile.open(QFile::WriteOnly)) { if (!iconFile.open(QFile::WriteOnly)) {
QMessageBox::critical(shortcut.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; return false;
} }
bool success = icon->icon().pixmap(64, 64).save(&iconFile, "ICO"); bool success = icon->icon().pixmap(64, 64).save(&iconFile, "ICO");
iconFile.close(); iconFile.close();
@ -139,51 +139,58 @@ void createInstanceShortcut(const Shortcut& shortcut, const QString& filePath)
if (!success) { if (!success) {
iconFile.remove(); iconFile.remove();
QMessageBox::critical(shortcut.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; return false;
} }
#else #else
QMessageBox::critical(shortcut.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; return false;
#endif #endif
args.append({ "--launch", shortcut.instance->id() }); args.append({ "--launch", shortcut.instance->id() });
args.append(shortcut.extraArgs); args.append(shortcut.extraArgs);
if (!FS::createShortcut(filePath, appPath, args, shortcut.name, iconPath)) { QString shortcutPath = FS::createShortcut(filePath, appPath, args, shortcut.name, iconPath);
if (shortcutPath.isEmpty()) {
#if not defined(Q_OS_MACOS) #if not defined(Q_OS_MACOS)
iconFile.remove(); iconFile.remove();
#endif #endif
QMessageBox::critical(shortcut.parent, QObject::tr("Create Shortcut"), QMessageBox::critical(shortcut.parent, QObject::tr("Create Shortcut"),
QObject::tr("Failed to create %1 shortcut!").arg(shortcut.targetString)); QObject::tr("Failed to create %1 shortcut!").arg(shortcut.targetString));
} return false;
} }
void createInstanceShortcutOnDesktop(const Shortcut& shortcut) shortcut.instance->registerShortcut({ shortcut.name, shortcutPath, shortcut.target });
return true;
}
bool createInstanceShortcutOnDesktop(const Shortcut& shortcut)
{ {
if (!shortcut.instance) if (!shortcut.instance)
return; return false;
QString desktopDir = FS::getDesktopDir(); QString desktopDir = FS::getDesktopDir();
if (desktopDir.isEmpty()) { if (desktopDir.isEmpty()) {
QMessageBox::critical(shortcut.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; return false;
} }
QString shortcutFilePath = FS::PathCombine(desktopDir, FS::RemoveInvalidFilenameChars(shortcut.name)); QString shortcutFilePath = FS::PathCombine(desktopDir, FS::RemoveInvalidFilenameChars(shortcut.name));
createInstanceShortcut(shortcut, shortcutFilePath); if (!createInstanceShortcut(shortcut, shortcutFilePath))
return false;
QMessageBox::information(shortcut.parent, QObject::tr("Create Shortcut"), QMessageBox::information(shortcut.parent, QObject::tr("Create Shortcut"),
QObject::tr("Created a shortcut to this %1 on your desktop!").arg(shortcut.targetString)); QObject::tr("Created a shortcut to this %1 on your desktop!").arg(shortcut.targetString));
return true;
} }
void createInstanceShortcutInApplications(const Shortcut& shortcut) bool createInstanceShortcutInApplications(const Shortcut& shortcut)
{ {
if (!shortcut.instance) if (!shortcut.instance)
return; return false;
QString applicationsDir = FS::getApplicationsDir(); QString applicationsDir = FS::getApplicationsDir();
if (applicationsDir.isEmpty()) { if (applicationsDir.isEmpty()) {
QMessageBox::critical(shortcut.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; return false;
} }
#if defined(Q_OS_MACOS) || defined(Q_OS_WIN) #if defined(Q_OS_MACOS) || defined(Q_OS_WIN)
@ -193,20 +200,22 @@ void createInstanceShortcutInApplications(const Shortcut& shortcut)
if (!applicationsDirQ.mkpath(".")) { if (!applicationsDirQ.mkpath(".")) {
QMessageBox::critical(shortcut.parent, QObject::tr("Create Shortcut"), QMessageBox::critical(shortcut.parent, QObject::tr("Create Shortcut"),
QObject::tr("Failed to create instances folder in applications folder!")); QObject::tr("Failed to create instances folder in applications folder!"));
return; return false;
} }
#endif #endif
QString shortcutFilePath = FS::PathCombine(applicationsDir, FS::RemoveInvalidFilenameChars(shortcut.name)); QString shortcutFilePath = FS::PathCombine(applicationsDir, FS::RemoveInvalidFilenameChars(shortcut.name));
createInstanceShortcut(shortcut, shortcutFilePath); if (!createInstanceShortcut(shortcut, shortcutFilePath))
return false;
QMessageBox::information(shortcut.parent, QObject::tr("Create Shortcut"), QMessageBox::information(shortcut.parent, QObject::tr("Create Shortcut"),
QObject::tr("Created a shortcut to this %1 in your applications folder!").arg(shortcut.targetString)); QObject::tr("Created a shortcut to this %1 in your applications folder!").arg(shortcut.targetString));
return true;
} }
void createInstanceShortcutInOther(const Shortcut& shortcut) bool createInstanceShortcutInOther(const Shortcut& shortcut)
{ {
if (!shortcut.instance) if (!shortcut.instance)
return; return false;
QString defaultedDir = FS::getDesktopDir(); QString defaultedDir = FS::getDesktopDir();
#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) || defined(Q_OS_OPENBSD) #if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) || defined(Q_OS_OPENBSD)
@ -225,13 +234,15 @@ void createInstanceShortcutInOther(const Shortcut& shortcut)
shortcutFilePath = fileDialog.getSaveFileName(shortcut.parent, QObject::tr("Create Shortcut"), shortcutFilePath, shortcutFilePath = fileDialog.getSaveFileName(shortcut.parent, QObject::tr("Create Shortcut"), shortcutFilePath,
QObject::tr("Desktop Entries") + " (*" + extension + ")"); QObject::tr("Desktop Entries") + " (*" + extension + ")");
if (shortcutFilePath.isEmpty()) if (shortcutFilePath.isEmpty())
return; // file dialog canceled by user return false; // file dialog canceled by user
if (shortcutFilePath.endsWith(extension)) if (shortcutFilePath.endsWith(extension))
shortcutFilePath = shortcutFilePath.mid(0, shortcutFilePath.length() - extension.length()); shortcutFilePath = shortcutFilePath.mid(0, shortcutFilePath.length() - extension.length());
createInstanceShortcut(shortcut, shortcutFilePath); if (!createInstanceShortcut(shortcut, shortcutFilePath))
return false;
QMessageBox::information(shortcut.parent, QObject::tr("Create Shortcut"), QMessageBox::information(shortcut.parent, QObject::tr("Create Shortcut"),
QObject::tr("Created a shortcut to this %1!").arg(shortcut.targetString)); QObject::tr("Created a shortcut to this %1!").arg(shortcut.targetString));
return true;
} }
} // namespace ShortcutUtils } // namespace ShortcutUtils

View file

@ -38,6 +38,7 @@
#pragma once #pragma once
#include "Application.h" #include "Application.h"
#include <QList>
#include <QMessageBox> #include <QMessageBox>
namespace ShortcutUtils { namespace ShortcutUtils {
@ -49,18 +50,19 @@ struct Shortcut {
QWidget* parent = nullptr; QWidget* parent = nullptr;
QStringList extraArgs = {}; QStringList extraArgs = {};
QString iconKey = ""; QString iconKey = "";
ShortcutTarget target;
}; };
/// Create an instance shortcut on the specified file path /// Create an instance shortcut on the specified file path
void createInstanceShortcut(const Shortcut& shortcut, const QString& filePath); bool createInstanceShortcut(const Shortcut& shortcut, const QString& filePath);
/// Create an instance shortcut on the desktop /// Create an instance shortcut on the desktop
void createInstanceShortcutOnDesktop(const Shortcut& shortcut); bool createInstanceShortcutOnDesktop(const Shortcut& shortcut);
/// Create an instance shortcut in the Applications directory /// Create an instance shortcut in the Applications directory
void createInstanceShortcutInApplications(const Shortcut& shortcut); bool createInstanceShortcutInApplications(const Shortcut& shortcut);
/// Create an instance shortcut in other directories /// Create an instance shortcut in other directories
void createInstanceShortcutInOther(const Shortcut& shortcut); bool createInstanceShortcutInOther(const Shortcut& shortcut);
} // namespace ShortcutUtils } // namespace ShortcutUtils

View file

@ -1207,7 +1207,10 @@ void MainWindow::renameGroup(QString group)
void MainWindow::undoTrashInstance() void MainWindow::undoTrashInstance()
{ {
APPLICATION->instances()->undoTrashInstance(); if (!APPLICATION->instances()->undoTrashInstance())
QMessageBox::warning(
this, tr("Failed to undo trashing instance"),
tr("Some instances and shortcuts could not be restored.\nPlease check your trashbin to manually restore them."));
ui->actionUndoTrashInstance->setEnabled(APPLICATION->instances()->trashedSomething()); ui->actionUndoTrashInstance->setEnabled(APPLICATION->instances()->trashedSomething());
} }
@ -1407,7 +1410,7 @@ void MainWindow::on_actionDeleteInstance_triggered()
auto id = m_selectedInstance->id(); auto id = m_selectedInstance->id();
auto response = CustomMessageBox::selectable(this, tr("Confirm Deletion"), auto response = CustomMessageBox::selectable(this, tr("Confirm Deletion"),
tr("You are about to delete \"%1\".\n" tr("You are about to delete \"%1\" and all of its shortcut(s).\n"
"This may be permanent and will completely delete the instance.\n\n" "This may be permanent and will completely delete the instance.\n\n"
"Are you sure?") "Are you sure?")
.arg(m_selectedInstance->name()), .arg(m_selectedInstance->name()),

View file

@ -83,12 +83,12 @@ CreateShortcutDialog::CreateShortcutDialog(InstancePtr instance, QWidget* parent
QString applicationDir = FS::getApplicationsDir(); QString applicationDir = FS::getApplicationsDir();
if (!desktopDir.isEmpty()) if (!desktopDir.isEmpty())
ui->saveTargetSelectionBox->addItem(tr("Desktop"), QVariant::fromValue(SaveTarget::Desktop)); ui->saveTargetSelectionBox->addItem(tr("Desktop"), QVariant::fromValue(ShortcutTarget::Desktop));
if (!applicationDir.isEmpty()) if (!applicationDir.isEmpty())
ui->saveTargetSelectionBox->addItem(tr("Applications"), QVariant::fromValue(SaveTarget::Applications)); ui->saveTargetSelectionBox->addItem(tr("Applications"), QVariant::fromValue(ShortcutTarget::Applications));
} }
ui->saveTargetSelectionBox->addItem(tr("Other..."), QVariant::fromValue(SaveTarget::Other)); ui->saveTargetSelectionBox->addItem(tr("Other..."), QVariant::fromValue(ShortcutTarget::Other));
// Populate worlds // Populate worlds
if (m_QuickJoinSupported) { if (m_QuickJoinSupported) {
@ -206,17 +206,17 @@ void CreateShortcutDialog::createShortcut()
} }
} }
auto target = ui->saveTargetSelectionBox->currentData().value<SaveTarget>(); auto target = ui->saveTargetSelectionBox->currentData().value<ShortcutTarget>();
auto name = ui->instNameTextBox->text(); auto name = ui->instNameTextBox->text();
if (name.isEmpty()) if (name.isEmpty())
name = ui->instNameTextBox->placeholderText(); name = ui->instNameTextBox->placeholderText();
if (ui->overrideAccountCheckbox->isChecked()) if (ui->overrideAccountCheckbox->isChecked())
extraArgs.append({ "--profile", ui->accountSelectionBox->currentData().toString() }); extraArgs.append({ "--profile", ui->accountSelectionBox->currentData().toString() });
ShortcutUtils::Shortcut args{ m_instance.get(), name, targetString, this, extraArgs, InstIconKey }; ShortcutUtils::Shortcut args{ m_instance.get(), name, targetString, this, extraArgs, InstIconKey, target };
if (target == SaveTarget::Desktop) if (target == ShortcutTarget::Desktop)
ShortcutUtils::createInstanceShortcutOnDesktop(args); ShortcutUtils::createInstanceShortcutOnDesktop(args);
else if (target == SaveTarget::Applications) else if (target == ShortcutTarget::Applications)
ShortcutUtils::createInstanceShortcutInApplications(args); ShortcutUtils::createInstanceShortcutInApplications(args);
else else
ShortcutUtils::createInstanceShortcutInOther(args); ShortcutUtils::createInstanceShortcutInOther(args);

View file

@ -54,9 +54,6 @@ class CreateShortcutDialog : public QDialog {
InstancePtr m_instance; InstancePtr m_instance;
bool m_QuickJoinSupported = false; bool m_QuickJoinSupported = false;
// Index representations
enum class SaveTarget { Desktop, Applications, Other };
// Functions // Functions
void stateChanged(); void stateChanged();
}; };