Merge pull request #618 from TheKodeToad/safer-destructive-actions

Fixes https://github.com/PolyMC/PolyMC/issues/948
This commit is contained in:
Sefa Eyeoglu 2022-12-26 17:48:43 +01:00 committed by GitHub
commit 6ea1234a3b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 254 additions and 88 deletions

View File

@ -1,7 +1,8 @@
// SPDX-License-Identifier: GPL-3.0-only // SPDX-License-Identifier: GPL-3.0-only
/* /*
* PolyMC - Minecraft Launcher * Prism Launcher - Minecraft Launcher
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net> * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
* Copyright (C) 2022 TheKodeToad <TheKodeToad@proton.me>
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -226,7 +227,7 @@ bool deletePath(QString path)
return err.value() == 0; return err.value() == 0;
} }
bool trash(QString path, QString *pathInTrash = nullptr) bool trash(QString path, QString *pathInTrash)
{ {
#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0) #if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
return false; return false;

View File

@ -1,7 +1,8 @@
// SPDX-License-Identifier: GPL-3.0-only // SPDX-License-Identifier: GPL-3.0-only
/* /*
* PolyMC - Minecraft Launcher * Prism Launcher - Minecraft Launcher
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net> * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
* Copyright (C) 2022 TheKodeToad <TheKodeToad@proton.me>
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -129,7 +130,7 @@ bool deletePath(QString path);
/** /**
* Trash a folder / file * Trash a folder / file
*/ */
bool trash(QString path, QString *pathInTrash); bool trash(QString path, QString *pathInTrash = nullptr);
QString PathCombine(const QString& path1, const QString& path2); QString PathCombine(const QString& path1, const QString& path2);
QString PathCombine(const QString& path1, const QString& path2, const QString& path3); QString PathCombine(const QString& path1, const QString& path2, const QString& path3);

View File

@ -1,7 +1,8 @@
// SPDX-License-Identifier: GPL-3.0-only // SPDX-License-Identifier: GPL-3.0-only
/* /*
* PolyMC - Minecraft Launcher * Prism Launcher - Minecraft Launcher
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net> * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
* Copyright (C) 2022 TheKodeToad <TheKodeToad@proton.me>
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -545,6 +546,10 @@ bool World::replace(World &with)
bool World::destroy() bool World::destroy()
{ {
if(!is_valid) return false; if(!is_valid) return false;
if (FS::trash(m_containerFile.filePath()))
return true;
if (m_containerFile.isDir()) if (m_containerFile.isDir())
{ {
QDir d(m_containerFile.filePath()); QDir d(m_containerFile.filePath());

View File

@ -143,5 +143,9 @@ bool Resource::enable(EnableAction action)
bool Resource::destroy() bool Resource::destroy()
{ {
m_type = ResourceType::UNKNOWN; m_type = ResourceType::UNKNOWN;
if (FS::trash(m_file_info.filePath()))
return true;
return FS::deletePath(m_file_info.filePath()); return FS::deletePath(m_file_info.filePath());
} }

View File

@ -1,8 +1,9 @@
// SPDX-License-Identifier: GPL-3.0-only // SPDX-License-Identifier: GPL-3.0-only
/* /*
* PolyMC - Minecraft Launcher * Prism Launcher - Minecraft Launcher
* Copyright (C) 2022 Lenny McLennington <lenny@sneed.church> * Copyright (C) 2022 Lenny McLennington <lenny@sneed.church>
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net> * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
* Copyright (C) 2022 TheKodeToad <TheKodeToad@proton.me>
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -49,11 +50,34 @@
#include <DesktopServices.h> #include <DesktopServices.h>
#include <BuildConfig.h> #include <BuildConfig.h>
QString GuiUtil::uploadPaste(const QString &text, QWidget *parentWidget) std::optional<QString> GuiUtil::uploadPaste(const QString &name, const QString &text, QWidget *parentWidget)
{ {
ProgressDialog dialog(parentWidget); ProgressDialog dialog(parentWidget);
auto pasteTypeSetting = static_cast<PasteUpload::PasteType>(APPLICATION->settings()->get("PastebinType").toInt()); auto pasteTypeSetting = static_cast<PasteUpload::PasteType>(APPLICATION->settings()->get("PastebinType").toInt());
auto pasteCustomAPIBaseSetting = APPLICATION->settings()->get("PastebinCustomAPIBase").toString(); auto pasteCustomAPIBaseSetting = APPLICATION->settings()->get("PastebinCustomAPIBase").toString();
{
QUrl baseUrl;
if (pasteCustomAPIBaseSetting.isEmpty())
baseUrl = PasteUpload::PasteTypes[pasteTypeSetting].defaultBase;
else
baseUrl = pasteCustomAPIBaseSetting;
if (baseUrl.isValid())
{
auto response = CustomMessageBox::selectable(parentWidget, QObject::tr("Confirm Upload"),
QObject::tr("You are about to upload \"%1\" to %2.\n"
"You should double-check for personal information.\n\n"
"Are you sure?")
.arg(name, baseUrl.host()),
QMessageBox::Warning, QMessageBox::Yes | QMessageBox::No, QMessageBox::No)
->exec();
if (response != QMessageBox::Yes)
return {};
}
}
std::unique_ptr<PasteUpload> paste(new PasteUpload(parentWidget, text, pasteCustomAPIBaseSetting, pasteTypeSetting)); std::unique_ptr<PasteUpload> paste(new PasteUpload(parentWidget, text, pasteCustomAPIBaseSetting, pasteTypeSetting));
dialog.execWithTask(paste.get()); dialog.execWithTask(paste.get());

View File

@ -1,10 +1,11 @@
#pragma once #pragma once
#include <QWidget> #include <QWidget>
#include <optional>
namespace GuiUtil namespace GuiUtil
{ {
QString uploadPaste(const QString &text, QWidget *parentWidget); std::optional<QString> uploadPaste(const QString &name, const QString &text, QWidget *parentWidget);
void setClipboardText(const QString &text); void setClipboardText(const QString &text);
QStringList BrowseForFiles(QString context, QString caption, QString filter, QString defaultPath, QWidget *parentWidget); QStringList BrowseForFiles(QString context, QString caption, QString filter, QString defaultPath, QWidget *parentWidget);
QString BrowseForFile(QString context, QString caption, QString filter, QString defaultPath, QWidget *parentWidget); QString BrowseForFile(QString context, QString caption, QString filter, QString defaultPath, QWidget *parentWidget);

View File

@ -1,7 +1,8 @@
// SPDX-License-Identifier: GPL-3.0-only // SPDX-License-Identifier: GPL-3.0-only
/* /*
* PolyMC - Minecraft Launcher * Prism Launcher - Minecraft Launcher
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net> * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
* Copyright (C) 2022 TheKodeToad <TheKodeToad@proton.me>
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -490,7 +491,7 @@ public:
if (!BuildConfig.BUG_TRACKER_URL.isEmpty()) { if (!BuildConfig.BUG_TRACKER_URL.isEmpty()) {
helpMenu->addAction(actionReportBug); helpMenu->addAction(actionReportBug);
} }
if(!BuildConfig.MATRIX_URL.isEmpty()) { if(!BuildConfig.MATRIX_URL.isEmpty()) {
helpMenu->addAction(actionMATRIX); helpMenu->addAction(actionMATRIX);
} }
@ -2093,21 +2094,23 @@ void MainWindow::on_actionDeleteInstance_triggered()
auto id = m_selectedInstance->id(); auto id = m_selectedInstance->id();
auto response = auto response = CustomMessageBox::selectable(this, tr("Confirm Deletion"),
CustomMessageBox::selectable(this, tr("CAREFUL!"), tr("You are about to delete \"%1\".\n"
tr("About to delete: %1\nThis may be permanent and will completely delete the instance.\n\nAre you sure?") "This may be permanent and will completely delete the instance.\n\n"
.arg(m_selectedInstance->name()), "Are you sure?")
QMessageBox::Warning, QMessageBox::Yes | QMessageBox::No, QMessageBox::No) .arg(m_selectedInstance->name()),
->exec(); QMessageBox::Warning, QMessageBox::Yes | QMessageBox::No, QMessageBox::No)
->exec();
if (response == QMessageBox::Yes) { if (response != QMessageBox::Yes)
if (APPLICATION->instances()->trashInstance(id)) { return;
ui->actionUndoTrashInstance->setEnabled(APPLICATION->instances()->trashedSomething());
return;
}
APPLICATION->instances()->deleteInstance(id); if (APPLICATION->instances()->trashInstance(id)) {
ui->actionUndoTrashInstance->setEnabled(APPLICATION->instances()->trashedSomething());
return;
} }
APPLICATION->instances()->deleteInstance(id);
} }
void MainWindow::on_actionExportInstance_triggered() void MainWindow::on_actionExportInstance_triggered()
@ -2252,7 +2255,7 @@ void MainWindow::on_actionCreateInstanceShortcut_triggered()
} }
QString iconPath = FS::PathCombine(m_selectedInstance->instanceRoot(), "icon.png"); QString iconPath = FS::PathCombine(m_selectedInstance->instanceRoot(), "icon.png");
QFile iconFile(iconPath); QFile iconFile(iconPath);
if (!iconFile.open(QFile::WriteOnly)) if (!iconFile.open(QFile::WriteOnly))
{ {
@ -2261,7 +2264,7 @@ void MainWindow::on_actionCreateInstanceShortcut_triggered()
} }
bool success = icon->icon().pixmap(64, 64).save(&iconFile, "PNG"); bool success = icon->icon().pixmap(64, 64).save(&iconFile, "PNG");
iconFile.close(); iconFile.close();
if (!success) if (!success)
{ {
iconFile.remove(); iconFile.remove();
@ -2302,7 +2305,7 @@ void MainWindow::on_actionCreateInstanceShortcut_triggered()
} }
QString iconPath = FS::PathCombine(m_selectedInstance->instanceRoot(), "icon.ico"); QString 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");
@ -2325,7 +2328,7 @@ void MainWindow::on_actionCreateInstanceShortcut_triggered()
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;
} }
if (FS::createShortcut(FS::PathCombine(desktopPath, m_selectedInstance->name()), if (FS::createShortcut(FS::PathCombine(desktopPath, m_selectedInstance->name()),
QApplication::applicationFilePath(), { "--launch", m_selectedInstance->id() }, QApplication::applicationFilePath(), { "--launch", m_selectedInstance->id() },
m_selectedInstance->name(), iconPath)) { m_selectedInstance->name(), iconPath)) {

View File

@ -1,4 +1,5 @@
#include "ExternalResourcesPage.h" #include "ExternalResourcesPage.h"
#include "ui/dialogs/CustomMessageBox.h"
#include "ui_ExternalResourcesPage.h" #include "ui_ExternalResourcesPage.h"
#include "DesktopServices.h" #include "DesktopServices.h"
@ -128,7 +129,7 @@ bool ExternalResourcesPage::eventFilter(QObject* obj, QEvent* ev)
{ {
if (ev->type() != QEvent::KeyPress) if (ev->type() != QEvent::KeyPress)
return QWidget::eventFilter(obj, ev); return QWidget::eventFilter(obj, ev);
QKeyEvent* keyEvent = static_cast<QKeyEvent*>(ev); QKeyEvent* keyEvent = static_cast<QKeyEvent*>(ev);
if (obj == ui->treeView) if (obj == ui->treeView)
return listFilter(keyEvent); return listFilter(keyEvent);
@ -140,7 +141,6 @@ void ExternalResourcesPage::addItem()
{ {
if (!m_controlsEnabled) if (!m_controlsEnabled)
return; return;
auto list = GuiUtil::BrowseForFiles( auto list = GuiUtil::BrowseForFiles(
helpPage(), tr("Select %1", "Select whatever type of files the page contains. Example: 'Loader Mods'").arg(displayName()), helpPage(), tr("Select %1", "Select whatever type of files the page contains. Example: 'Loader Mods'").arg(displayName()),
@ -157,8 +157,50 @@ void ExternalResourcesPage::removeItem()
{ {
if (!m_controlsEnabled) if (!m_controlsEnabled)
return; return;
auto selection = m_filterModel->mapSelectionToSource(ui->treeView->selectionModel()->selection()); auto selection = m_filterModel->mapSelectionToSource(ui->treeView->selectionModel()->selection());
int count = 0;
bool folder = false;
for (auto& i : selection.indexes()) {
if (i.column() == 0) {
count++;
// if a folder is selected, show the confirmation dialog
if (m_model->at(i.row()).fileinfo().isDir())
folder = true;
}
}
QString text;
bool multiple = count > 1;
if (multiple) {
text = tr("You are about to remove %1 items.\n"
"This may be permanent and they will be gone from the folder.\n\n"
"Are you sure?")
.arg(count);
} else if (folder) {
text = tr("You are about to remove the folder \"%1\".\n"
"This may be permanent and it will be gone from the parent folder.\n\n"
"Are you sure?")
.arg(m_model->at(selection.indexes().at(0).row()).fileinfo().fileName());
}
if (!text.isEmpty()) {
auto response = CustomMessageBox::selectable(this, tr("Confirm Removal"), text, QMessageBox::Warning,
QMessageBox::Yes | QMessageBox::No, QMessageBox::No)
->exec();
if (response != QMessageBox::Yes)
return;
}
removeItems(selection);
}
void ExternalResourcesPage::removeItems(const QItemSelection& selection)
{
m_model->deleteResources(selection.indexes()); m_model->deleteResources(selection.indexes());
} }
@ -209,4 +251,3 @@ bool ExternalResourcesPage::onSelectionChanged(const QModelIndex& current, const
return true; return true;
} }

View File

@ -50,7 +50,8 @@ class ExternalResourcesPage : public QMainWindow, public BasePage {
void filterTextChanged(const QString& newContents); void filterTextChanged(const QString& newContents);
virtual void addItem(); virtual void addItem();
virtual void removeItem(); void removeItem();
virtual void removeItems(const QItemSelection &selection);
virtual void enableItem(); virtual void enableItem();
virtual void disableItem(); virtual void disableItem();

View File

@ -1,8 +1,9 @@
// SPDX-License-Identifier: GPL-3.0-only // SPDX-License-Identifier: GPL-3.0-only
/* /*
* PolyMC - Minecraft Launcher * Prism Launcher - Minecraft Launcher
* Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org> * Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net> * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
* Copyright (C) 2022 TheKodeToad <TheKodeToad@proton.me>
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -277,28 +278,22 @@ void LogPage::on_btnPaste_clicked()
//FIXME: turn this into a proper task and move the upload logic out of GuiUtil! //FIXME: turn this into a proper task and move the upload logic out of GuiUtil!
m_model->append( m_model->append(
MessageLevel::Launcher, MessageLevel::Launcher,
QString("%2: Log upload triggered at: %1").arg( QString("Log upload triggered at: %1").arg(
QDateTime::currentDateTime().toString(Qt::RFC2822Date), QDateTime::currentDateTime().toString(Qt::RFC2822Date)
BuildConfig.LAUNCHER_DISPLAYNAME
) )
); );
auto url = GuiUtil::uploadPaste(m_model->toPlainText(), this); auto url = GuiUtil::uploadPaste(tr("Minecraft Log"), m_model->toPlainText(), this);
if(!url.isEmpty()) if(!url.has_value())
{ {
m_model->append( m_model->append(MessageLevel::Error, QString("Log upload canceled"));
MessageLevel::Launcher, }
QString("%2: Log uploaded to: %1").arg( else if (url->isNull())
url, {
BuildConfig.LAUNCHER_DISPLAYNAME m_model->append(MessageLevel::Error, QString("Log upload failed!"));
)
);
} }
else else
{ {
m_model->append( m_model->append(MessageLevel::Launcher, QString("Log uploaded to: %1").arg(url.value()));
MessageLevel::Error,
QString("%1: Log upload failed!").arg(BuildConfig.LAUNCHER_DISPLAYNAME)
);
} }
} }

View File

@ -1,8 +1,9 @@
// SPDX-License-Identifier: GPL-3.0-only // SPDX-License-Identifier: GPL-3.0-only
/* /*
* PolyMC - Minecraft Launcher * Prism Launcher - Minecraft Launcher
* Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org> * Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net> * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
* Copyright (C) 2022 TheKodeToad <TheKodeToad@proton.me>
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -139,13 +140,8 @@ bool ModFolderPage::onSelectionChanged(const QModelIndex& current, const QModelI
return true; return true;
} }
void ModFolderPage::removeItem() void ModFolderPage::removeItems(const QItemSelection &selection)
{ {
if (!m_controlsEnabled)
return;
auto selection = m_filterModel->mapSelectionToSource(ui->treeView->selectionModel()->selection());
m_model->deleteMods(selection.indexes()); m_model->deleteMods(selection.indexes());
} }

View File

@ -1,8 +1,9 @@
// SPDX-License-Identifier: GPL-3.0-only // SPDX-License-Identifier: GPL-3.0-only
/* /*
* PolyMC - Minecraft Launcher * Prism Launcher - Minecraft Launcher
* Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org> * Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net> * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
* Copyright (C) 2022 TheKodeToad <TheKodeToad@proton.me>
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -59,7 +60,7 @@ class ModFolderPage : public ExternalResourcesPage {
private slots: private slots:
void runningStateChanged(bool running); void runningStateChanged(bool running);
void removeItem() override; void removeItems(const QItemSelection &selection) override;
void installMods(); void installMods();
void updateMods(); void updateMods();

View File

@ -1,7 +1,8 @@
// SPDX-License-Identifier: GPL-3.0-only // SPDX-License-Identifier: GPL-3.0-only
/* /*
* PolyMC - Minecraft Launcher * Prism Launcher - Minecraft Launcher
* Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org> * Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
* Copyright (C) 2022 TheKodeToad <TheKodeToad@proton.me>
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -204,7 +205,7 @@ void OtherLogsPage::on_btnReload_clicked()
void OtherLogsPage::on_btnPaste_clicked() void OtherLogsPage::on_btnPaste_clicked()
{ {
GuiUtil::uploadPaste(ui->text->toPlainText(), this); GuiUtil::uploadPaste(m_currentFile, ui->text->toPlainText(), this);
} }
void OtherLogsPage::on_btnCopy_clicked() void OtherLogsPage::on_btnCopy_clicked()
@ -219,13 +220,21 @@ void OtherLogsPage::on_btnDelete_clicked()
setControlsEnabled(false); setControlsEnabled(false);
return; return;
} }
if (QMessageBox::question(this, tr("Delete"), if (QMessageBox::question(this, tr("Confirm Deletion"),
tr("Do you really want to delete %1?").arg(m_currentFile), tr("You are about to delete \"%1\".\n"
QMessageBox::Yes, QMessageBox::No) == QMessageBox::No) "This may be permanent and it will be gone from the logs folder.\n\n"
{ "Are you sure?")
.arg(m_currentFile),
QMessageBox::Yes, QMessageBox::No) == QMessageBox::No) {
return; return;
} }
QFile file(FS::PathCombine(m_path, m_currentFile)); QFile file(FS::PathCombine(m_path, m_currentFile));
if (FS::trash(file.fileName()))
{
return;
}
if (!file.remove()) if (!file.remove())
{ {
QMessageBox::critical(this, tr("Error"), tr("Unable to delete %1: %2") QMessageBox::critical(this, tr("Error"), tr("Unable to delete %1: %2")
@ -243,15 +252,15 @@ void OtherLogsPage::on_btnClean_clicked()
return; return;
} }
QMessageBox *messageBox = new QMessageBox(this); QMessageBox *messageBox = new QMessageBox(this);
messageBox->setWindowTitle(tr("Clean up")); messageBox->setWindowTitle(tr("Confirm Cleanup"));
if(toDelete.size() > 5) if(toDelete.size() > 5)
{ {
messageBox->setText(tr("Do you really want to delete all log files?")); messageBox->setText(tr("Are you sure you want to delete all log files?"));
messageBox->setDetailedText(toDelete.join('\n')); messageBox->setDetailedText(toDelete.join('\n'));
} }
else else
{ {
messageBox->setText(tr("Do you really want to delete these files?\n%1").arg(toDelete.join('\n'))); messageBox->setText(tr("Are you sure you want to delete all these files?\n%1").arg(toDelete.join('\n')));
} }
messageBox->setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel); messageBox->setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);
messageBox->setDefaultButton(QMessageBox::Ok); messageBox->setDefaultButton(QMessageBox::Ok);
@ -267,6 +276,10 @@ void OtherLogsPage::on_btnClean_clicked()
for(auto item: toDelete) for(auto item: toDelete)
{ {
QFile file(FS::PathCombine(m_path, item)); QFile file(FS::PathCombine(m_path, item));
if (FS::trash(file.fileName()))
{
continue;
}
if (!file.remove()) if (!file.remove())
{ {
failed.push_back(item); failed.push_back(item);

View File

@ -1,8 +1,9 @@
// SPDX-License-Identifier: GPL-3.0-only // SPDX-License-Identifier: GPL-3.0-only
/* /*
* PolyMC - Minecraft Launcher * Prism Launcher - Minecraft Launcher
* Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org> * Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net> * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
* Copyright (C) 2022 TheKodeToad <TheKodeToad@proton.me>
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -379,6 +380,24 @@ void ScreenshotsPage::on_actionUpload_triggered()
if (selection.isEmpty()) if (selection.isEmpty())
return; return;
QString text;
if (selection.size() > 1)
text = tr("You are about to upload %1 screenshots.\n\n"
"Are you sure?")
.arg(selection.size());
else
text =
tr("You are about to upload the selected screenshot.\n\n"
"Are you sure?");
auto response = CustomMessageBox::selectable(this, "Confirm Upload", text, QMessageBox::Warning, QMessageBox::Yes | QMessageBox::No,
QMessageBox::No)
->exec();
if (response != QMessageBox::Yes)
return;
QList<ScreenShot::Ptr> uploaded; QList<ScreenShot::Ptr> uploaded;
auto job = NetJob::Ptr(new NetJob("Screenshot Upload", APPLICATION->network())); auto job = NetJob::Ptr(new NetJob("Screenshot Upload", APPLICATION->network()));
if(selection.size() < 2) if(selection.size() < 2)
@ -491,17 +510,32 @@ void ScreenshotsPage::on_actionCopy_File_s_triggered()
void ScreenshotsPage::on_actionDelete_triggered() void ScreenshotsPage::on_actionDelete_triggered()
{ {
auto mbox = CustomMessageBox::selectable( auto selected = ui->listView->selectionModel()->selectedIndexes();
this, tr("Are you sure?"), tr("This will delete all selected screenshots."),
QMessageBox::Warning, QMessageBox::Yes | QMessageBox::No);
std::unique_ptr<QMessageBox> box(mbox);
if (box->exec() != QMessageBox::Yes) int count = ui->listView->selectionModel()->selectedRows().size();
QString text;
if (count > 1)
text = tr("You are about to delete %1 screenshots.\n"
"This may be permanent and they will be gone from the folder.\n\n"
"Are you sure?")
.arg(count);
else
text = tr("You are about to delete the selected screenshot.\n"
"This may be permanent and it will be gone from the folder.\n\n"
"Are you sure?")
.arg(count);
auto response =
CustomMessageBox::selectable(this, tr("Confirm Deletion"), text, QMessageBox::Warning, QMessageBox::Yes | QMessageBox::No)->exec();
if (response != QMessageBox::Yes)
return; return;
auto selected = ui->listView->selectionModel()->selectedIndexes();
for (auto item : selected) for (auto item : selected)
{ {
if (FS::trash(m_model->filePath(item)))
continue;
m_model->remove(item); m_model->remove(item);
} }
} }

View File

@ -1,8 +1,9 @@
// SPDX-License-Identifier: GPL-3.0-only // SPDX-License-Identifier: GPL-3.0-only
/* /*
* PolyMC - Minecraft Launcher * Prism Launcher - Minecraft Launcher
* Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org> * Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net> * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
* Copyright (C) 2022 TheKodeToad <TheKodeToad@proton.me>
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -35,6 +36,7 @@
*/ */
#include "ServersPage.h" #include "ServersPage.h"
#include "ui/dialogs/CustomMessageBox.h"
#include "ui_ServersPage.h" #include "ui_ServersPage.h"
#include <FileSystem.h> #include <FileSystem.h>
@ -799,6 +801,17 @@ void ServersPage::on_actionAdd_triggered()
void ServersPage::on_actionRemove_triggered() void ServersPage::on_actionRemove_triggered()
{ {
auto response = CustomMessageBox::selectable(this, tr("Confirm Removal"),
tr("You are about to remove \"%1\".\n"
"This is permanent and the server will be gone from your list forever (A LONG TIME).\n\n"
"Are you sure?")
.arg(m_model->at(currentServer)->m_name),
QMessageBox::Warning, QMessageBox::Yes | QMessageBox::No, QMessageBox::No)
->exec();
if (response != QMessageBox::Yes)
return;
m_model->removeRow(currentServer); m_model->removeRow(currentServer);
} }

View File

@ -318,13 +318,29 @@ void VersionPage::on_actionReload_triggered()
void VersionPage::on_actionRemove_triggered() void VersionPage::on_actionRemove_triggered()
{ {
if (ui->packageView->currentIndex().isValid()) if (!ui->packageView->currentIndex().isValid())
{ {
// FIXME: use actual model, not reloading. return;
if (!m_profile->remove(ui->packageView->currentIndex().row())) }
{ int index = ui->packageView->currentIndex().row();
QMessageBox::critical(this, tr("Error"), tr("Couldn't remove file")); auto component = m_profile->getComponent(index);
} if (component->isCustom())
{
auto response = CustomMessageBox::selectable(this, tr("Confirm Removal"),
tr("You are about to remove \"%1\".\n"
"This is permanent and will completely remove the custom component.\n\n"
"Are you sure?")
.arg(component->getName()),
QMessageBox::Warning, QMessageBox::Yes | QMessageBox::No, QMessageBox::No)
->exec();
if (response != QMessageBox::Yes)
return;
}
// FIXME: use actual model, not reloading.
if (!m_profile->remove(index))
{
QMessageBox::critical(this, tr("Error"), tr("Couldn't remove file"));
} }
updateButtons(); updateButtons();
reloadPackProfile(); reloadPackProfile();
@ -707,6 +723,19 @@ void VersionPage::on_actionRevert_triggered()
{ {
return; return;
} }
auto component = m_profile->getComponent(version);
auto response = CustomMessageBox::selectable(this, tr("Confirm Reversion"),
tr("You are about to revert \"%1\".\n"
"This is permanent and will completely revert your customizations.\n\n"
"Are you sure?")
.arg(component->getName()),
QMessageBox::Warning, QMessageBox::Yes | QMessageBox::No, QMessageBox::No)
->exec();
if (response != QMessageBox::Yes)
return;
if(!m_profile->revertToBase(version)) if(!m_profile->revertToBase(version))
{ {
// TODO: some error box here // TODO: some error box here

View File

@ -1,8 +1,9 @@
// SPDX-License-Identifier: GPL-3.0-only // SPDX-License-Identifier: GPL-3.0-only
/* /*
* PolyMC - Minecraft Launcher * Prism Launcher - Minecraft Launcher
* Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org> * Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net> * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
* Copyright (C) 2022 TheKodeToad <TheKodeToad@proton.me>
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
@ -35,6 +36,7 @@
*/ */
#include "WorldListPage.h" #include "WorldListPage.h"
#include "ui/dialogs/CustomMessageBox.h"
#include "ui_WorldListPage.h" #include "ui_WorldListPage.h"
#include "minecraft/WorldList.h" #include "minecraft/WorldList.h"
@ -192,12 +194,14 @@ void WorldListPage::on_actionRemove_triggered()
if(!proxiedIndex.isValid()) if(!proxiedIndex.isValid())
return; return;
auto result = QMessageBox::question(this, auto result = CustomMessageBox::selectable(this, tr("Confirm Deletion"),
tr("Are you sure?"), tr("You are about to delete \"%1\".\n"
tr("This will remove the selected world permenantly.\n" "The world may be gone forever (A LONG TIME).\n\n"
"The world will be gone forever (A LONG TIME).\n" "Are you sure?")
"\n" .arg(m_worlds->allWorlds().at(proxiedIndex.row()).name()),
"Do you want to continue?")); QMessageBox::Warning, QMessageBox::Yes | QMessageBox::No, QMessageBox::No)
->exec();
if(result != QMessageBox::Yes) if(result != QMessageBox::Yes)
{ {
return; return;

View File

@ -109,7 +109,7 @@
</action> </action>
<action name="actionRemove"> <action name="actionRemove">
<property name="text"> <property name="text">
<string>Remove</string> <string>Delete</string>
</property> </property>
</action> </action>
<action name="actionMCEdit"> <action name="actionMCEdit">