diff options
Diffstat (limited to 'launcher/ui/pages/instance')
25 files changed, 762 insertions, 142 deletions
diff --git a/launcher/ui/pages/instance/ExternalResourcesPage.cpp b/launcher/ui/pages/instance/ExternalResourcesPage.cpp index c66d1368..1115ddc3 100644 --- a/launcher/ui/pages/instance/ExternalResourcesPage.cpp +++ b/launcher/ui/pages/instance/ExternalResourcesPage.cpp @@ -1,4 +1,5 @@ #include "ExternalResourcesPage.h" +#include "ui/dialogs/CustomMessageBox.h" #include "ui_ExternalResourcesPage.h" #include "DesktopServices.h" @@ -128,7 +129,7 @@ bool ExternalResourcesPage::eventFilter(QObject* obj, QEvent* ev) { if (ev->type() != QEvent::KeyPress) return QWidget::eventFilter(obj, ev); - + QKeyEvent* keyEvent = static_cast<QKeyEvent*>(ev); if (obj == ui->treeView) return listFilter(keyEvent); @@ -140,7 +141,6 @@ void ExternalResourcesPage::addItem() { if (!m_controlsEnabled) return; - auto list = GuiUtil::BrowseForFiles( 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) return; - + 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()); } @@ -209,4 +251,3 @@ bool ExternalResourcesPage::onSelectionChanged(const QModelIndex& current, const return true; } - diff --git a/launcher/ui/pages/instance/ExternalResourcesPage.h b/launcher/ui/pages/instance/ExternalResourcesPage.h index 2d1a5b51..d17fbb7f 100644 --- a/launcher/ui/pages/instance/ExternalResourcesPage.h +++ b/launcher/ui/pages/instance/ExternalResourcesPage.h @@ -50,7 +50,8 @@ class ExternalResourcesPage : public QMainWindow, public BasePage { void filterTextChanged(const QString& newContents); virtual void addItem(); - virtual void removeItem(); + void removeItem(); + virtual void removeItems(const QItemSelection &selection); virtual void enableItem(); virtual void disableItem(); diff --git a/launcher/ui/pages/instance/InstanceSettingsPage.cpp b/launcher/ui/pages/instance/InstanceSettingsPage.cpp index af2ba7c8..4b4c73dc 100644 --- a/launcher/ui/pages/instance/InstanceSettingsPage.cpp +++ b/launcher/ui/pages/instance/InstanceSettingsPage.cpp @@ -48,18 +48,23 @@ #include "JavaCommon.h" #include "Application.h" +#include "minecraft/auth/AccountList.h" #include "java/JavaInstallList.h" #include "java/JavaUtils.h" #include "FileSystem.h" - InstanceSettingsPage::InstanceSettingsPage(BaseInstance *inst, QWidget *parent) : QWidget(parent), ui(new Ui::InstanceSettingsPage), m_instance(inst) { m_settings = inst->settings(); ui->setupUi(this); + accountMenu = new QMenu(this); + // Use undocumented property... https://stackoverflow.com/questions/7121718/create-a-scrollbar-in-a-submenu-qt + accountMenu->setStyleSheet("QMenu { menu-scrollable: 1; }"); + ui->instanceAccountSelector->setMenu(accountMenu); + connect(ui->openGlobalJavaSettingsButton, &QCommandLinkButton::clicked, this, &InstanceSettingsPage::globalSettingsButtonClicked); connect(APPLICATION, &Application::globalSettingsAboutToOpen, this, &InstanceSettingsPage::applySettings); connect(APPLICATION, &Application::globalSettingsClosed, this, &InstanceSettingsPage::loadSettings); @@ -275,6 +280,13 @@ void InstanceSettingsPage::applySettings() m_settings->reset("JoinServerOnLaunchAddress"); } + // Use an account for this instance + bool useAccountForInstance = ui->instanceAccountGroupBox->isChecked(); + m_settings->set("UseAccountForInstance", useAccountForInstance); + if (!useAccountForInstance) { + m_settings->reset("InstanceAccountId"); + } + // FIXME: This should probably be called by a signal instead m_instance->updateRuntimeContext(); } @@ -372,6 +384,9 @@ void InstanceSettingsPage::loadSettings() ui->serverJoinGroupBox->setChecked(m_settings->get("JoinServerOnLaunch").toBool()); ui->serverJoinAddress->setText(m_settings->get("JoinServerOnLaunchAddress").toString()); + + ui->instanceAccountGroupBox->setChecked(m_settings->get("UseAccountForInstance").toBool()); + updateAccountsMenu(); } void InstanceSettingsPage::on_javaDetectBtn_clicked() @@ -437,6 +452,65 @@ void InstanceSettingsPage::on_javaTestBtn_clicked() checker->run(); } +void InstanceSettingsPage::updateAccountsMenu() +{ + accountMenu->clear(); + + auto accounts = APPLICATION->accounts(); + int accountIndex = accounts->findAccountByProfileId(m_settings->get("InstanceAccountId").toString()); + MinecraftAccountPtr defaultAccount = accounts->defaultAccount(); + + if (accountIndex != -1 && accounts->at(accountIndex)) { + defaultAccount = accounts->at(accountIndex); + } + + if (defaultAccount) { + ui->instanceAccountSelector->setText(defaultAccount->profileName()); + ui->instanceAccountSelector->setIcon(getFaceForAccount(defaultAccount)); + } else { + ui->instanceAccountSelector->setText(tr("No default account")); + ui->instanceAccountSelector->setIcon(APPLICATION->getThemedIcon("noaccount")); + } + + for (int i = 0; i < accounts->count(); i++) { + MinecraftAccountPtr account = accounts->at(i); + QAction* action = new QAction(account->profileName(), this); + action->setData(i); + action->setCheckable(true); + if (accountIndex == i) { + action->setChecked(true); + } + action->setIcon(getFaceForAccount(account)); + accountMenu->addAction(action); + connect(action, SIGNAL(triggered(bool)), this, SLOT(changeInstanceAccount())); + } +} + +QIcon InstanceSettingsPage::getFaceForAccount(MinecraftAccountPtr account) +{ + if (auto face = account->getFace(); !face.isNull()) { + return face; + } + + return APPLICATION->getThemedIcon("noaccount"); +} + +void InstanceSettingsPage::changeInstanceAccount() +{ + QAction* sAction = (QAction*)sender(); + + Q_ASSERT(sAction->data().type() == QVariant::Type::Int); + + QVariant data = sAction->data(); + int index = data.toInt(); + auto accounts = APPLICATION->accounts(); + auto account = accounts->at(index); + m_settings->set("InstanceAccountId", account->profileId()); + + ui->instanceAccountSelector->setText(account->profileName()); + ui->instanceAccountSelector->setIcon(getFaceForAccount(account)); +} + void InstanceSettingsPage::on_maxMemSpinBox_valueChanged(int i) { updateThresholds(); diff --git a/launcher/ui/pages/instance/InstanceSettingsPage.h b/launcher/ui/pages/instance/InstanceSettingsPage.h index 7450188d..cb6fbae0 100644 --- a/launcher/ui/pages/instance/InstanceSettingsPage.h +++ b/launcher/ui/pages/instance/InstanceSettingsPage.h @@ -37,12 +37,13 @@ #include <QWidget> -#include "java/JavaChecker.h" -#include "BaseInstance.h" #include <QObjectPtr.h> -#include "ui/pages/BasePage.h" -#include "JavaCommon.h" +#include <QMenu> #include "Application.h" +#include "BaseInstance.h" +#include "JavaCommon.h" +#include "java/JavaChecker.h" +#include "ui/pages/BasePage.h" class JavaChecker; namespace Ui @@ -92,9 +93,14 @@ private slots: void globalSettingsButtonClicked(bool checked); + void updateAccountsMenu(); + QIcon getFaceForAccount(MinecraftAccountPtr account); + void changeInstanceAccount(); + private: Ui::InstanceSettingsPage *ui; BaseInstance *m_instance; SettingsObjectPtr m_settings; unique_qobject_ptr<JavaCommon::TestCheck> checker; + QMenu *accountMenu = nullptr; }; diff --git a/launcher/ui/pages/instance/InstanceSettingsPage.ui b/launcher/ui/pages/instance/InstanceSettingsPage.ui index b064367d..1b986184 100644 --- a/launcher/ui/pages/instance/InstanceSettingsPage.ui +++ b/launcher/ui/pages/instance/InstanceSettingsPage.ui @@ -609,6 +609,48 @@ </widget> </item> <item> + <widget class="QGroupBox" name="instanceAccountGroupBox"> + <property name="title"> + <string>Override default account</string> + </property> + <property name="checkable"> + <bool>true</bool> + </property> + <property name="checked"> + <bool>false</bool> + </property> + <layout class="QVBoxLayout" name="verticalLayout_15"> + <item> + <layout class="QGridLayout" name="instanceAccountLayout"> + <item row="0" column="0"> + <widget class="QLabel" name="instanceAccountNameLabel"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Preferred"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Account:</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QToolButton" name="instanceAccountSelector"> + <property name="popupMode"> + <enum>QToolButton::InstantPopup</enum> + </property> + <property name="toolButtonStyle"> + <enum>Qt::ToolButtonTextBesideIcon</enum> + </property> + </widget> + </item> + </layout> + </item> + </layout> + </widget> + </item> + <item> <spacer name="verticalSpacerMiscellaneous"> <property name="orientation"> <enum>Qt::Vertical</enum> diff --git a/launcher/ui/pages/instance/LogPage.cpp b/launcher/ui/pages/instance/LogPage.cpp index 31c3e925..639cd711 100644 --- a/launcher/ui/pages/instance/LogPage.cpp +++ b/launcher/ui/pages/instance/LogPage.cpp @@ -1,8 +1,9 @@ // 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 Sefa Eyeoglu <contact@scrumplex.net> + * Copyright (C) 2022 TheKodeToad <TheKodeToad@proton.me> * * 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 @@ -39,7 +40,7 @@ #include "Application.h" -#include <QIcon> +#include <QIdentityProxyModel> #include <QScrollBar> #include <QShortcut> @@ -277,28 +278,22 @@ void LogPage::on_btnPaste_clicked() //FIXME: turn this into a proper task and move the upload logic out of GuiUtil! m_model->append( MessageLevel::Launcher, - QString("%2: Log upload triggered at: %1").arg( - QDateTime::currentDateTime().toString(Qt::RFC2822Date), - BuildConfig.LAUNCHER_DISPLAYNAME + QString("Log upload triggered at: %1").arg( + QDateTime::currentDateTime().toString(Qt::RFC2822Date) ) ); - auto url = GuiUtil::uploadPaste(m_model->toPlainText(), this); - if(!url.isEmpty()) + auto url = GuiUtil::uploadPaste(tr("Minecraft Log"), m_model->toPlainText(), this); + if(!url.has_value()) { - m_model->append( - MessageLevel::Launcher, - QString("%2: Log uploaded to: %1").arg( - url, - BuildConfig.LAUNCHER_DISPLAYNAME - ) - ); + m_model->append(MessageLevel::Error, QString("Log upload canceled")); + } + else if (url->isNull()) + { + m_model->append(MessageLevel::Error, QString("Log upload failed!")); } else { - m_model->append( - MessageLevel::Error, - QString("%1: Log upload failed!").arg(BuildConfig.LAUNCHER_DISPLAYNAME) - ); + m_model->append(MessageLevel::Launcher, QString("Log uploaded to: %1").arg(url.value())); } } diff --git a/launcher/ui/pages/instance/ManagedPackPage.cpp b/launcher/ui/pages/instance/ManagedPackPage.cpp index 4de80468..d0701a7a 100644 --- a/launcher/ui/pages/instance/ManagedPackPage.cpp +++ b/launcher/ui/pages/instance/ManagedPackPage.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 flow <flowlnlnln@gmail.com> +// SPDX-FileCopyrightText: 2022 flowln <flowlnlnln@gmail.com> // // SPDX-License-Identifier: GPL-3.0-only @@ -9,14 +9,13 @@ #include <QProxyStyle> #include <QStyleFactory> -#include <HoeDown.h> - #include "Application.h" #include "BuildConfig.h" #include "InstanceImportTask.h" #include "InstanceList.h" #include "InstanceTask.h" #include "Json.h" +#include "Markdown.h" #include "modplatform/modrinth/ModrinthPackManifest.h" @@ -31,8 +30,6 @@ class NoBigComboBoxStyle : public QProxyStyle { Q_OBJECT public: - NoBigComboBoxStyle(QStyle* style) : QProxyStyle(style) {} - // clang-format off int styleHint(QStyle::StyleHint hint, const QStyleOption* option = nullptr, const QWidget* widget = nullptr, QStyleHintReturn* returnData = nullptr) const override { @@ -42,6 +39,37 @@ class NoBigComboBoxStyle : public QProxyStyle { return QProxyStyle::styleHint(hint, option, widget, returnData); } // clang-format on + + /** + * Something about QProxyStyle and QStyle objects means they can't be free'd just + * because all the widgets using them are gone. + * They seems to be tied to the QApplicaiton lifecycle. + * So make singletons tied to the lifetime of the application to clean them up and ensure they aren't + * being remade over and over again, thus leaking memory. + */ + public: + static NoBigComboBoxStyle* getInstance(QStyle* style) + { + static QHash<QStyle*, NoBigComboBoxStyle*> s_singleton_instances_ = {}; + static std::mutex s_singleton_instances_mutex_; + + std::lock_guard<std::mutex> lock(s_singleton_instances_mutex_); + auto inst_iter = s_singleton_instances_.constFind(style); + NoBigComboBoxStyle* inst = nullptr; + if (inst_iter == s_singleton_instances_.constEnd() || *inst_iter == nullptr) { + inst = new NoBigComboBoxStyle(style); + inst->setParent(APPLICATION); + s_singleton_instances_.insert(style, inst); + qDebug() << "QProxyStyle NoBigComboBox created for" << style->objectName() << style; + } else { + inst = *inst_iter; + } + return inst; + } + + private: + NoBigComboBoxStyle(QStyle* style) : QProxyStyle(style) {} + }; ManagedPackPage* ManagedPackPage::createPage(BaseInstance* inst, QString type, QWidget* parent) @@ -63,8 +91,10 @@ ManagedPackPage::ManagedPackPage(BaseInstance* inst, InstanceWindow* instance_wi // NOTE: GTK2 themes crash with the proxy style. // This seems like an upstream bug, so there's not much else that can be done. - if (!QStyleFactory::keys().contains("gtk2")) - ui->versionsComboBox->setStyle(new NoBigComboBoxStyle(ui->versionsComboBox->style())); + if (!QStyleFactory::keys().contains("gtk2")){ + auto comboStyle = NoBigComboBoxStyle::getInstance(ui->versionsComboBox->style()); + ui->versionsComboBox->setStyle(comboStyle); + } ui->reloadButton->setVisible(false); connect(ui->reloadButton, &QPushButton::clicked, this, [this](bool){ @@ -263,8 +293,7 @@ void ModrinthManagedPackPage::suggestVersion() auto index = ui->versionsComboBox->currentIndex(); auto version = m_pack.versions.at(index); - HoeDown md_parser; - ui->changelogTextBrowser->setHtml(md_parser.process(version.changelog.toUtf8())); + ui->changelogTextBrowser->setHtml(markdownToHTML(version.changelog.toUtf8())); ManagedPackPage::suggestVersion(); } diff --git a/launcher/ui/pages/instance/ManagedPackPage.h b/launcher/ui/pages/instance/ManagedPackPage.h index d29a5e88..1ac6fc03 100644 --- a/launcher/ui/pages/instance/ManagedPackPage.h +++ b/launcher/ui/pages/instance/ManagedPackPage.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2022 flow <flowlnlnln@gmail.com> +// SPDX-FileCopyrightText: 2022 flowln <flowlnlnln@gmail.com> // // SPDX-License-Identifier: GPL-3.0-only @@ -12,6 +12,8 @@ #include "modplatform/flame/FlameAPI.h" #include "modplatform/flame/FlamePackIndex.h" +#include "net/NetJob.h" + #include "ui/pages/BasePage.h" #include <QWidget> diff --git a/launcher/ui/pages/instance/ModFolderPage.cpp b/launcher/ui/pages/instance/ModFolderPage.cpp index 0a2e6155..4548af59 100644 --- a/launcher/ui/pages/instance/ModFolderPage.cpp +++ b/launcher/ui/pages/instance/ModFolderPage.cpp @@ -1,8 +1,9 @@ // 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 Sefa Eyeoglu <contact@scrumplex.net> + * Copyright (C) 2022 TheKodeToad <TheKodeToad@proton.me> * * 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 @@ -48,8 +49,8 @@ #include "ui/GuiUtil.h" #include "ui/dialogs/CustomMessageBox.h" -#include "ui/dialogs/ModDownloadDialog.h" #include "ui/dialogs/ModUpdateDialog.h" +#include "ui/dialogs/ResourceDownloadDialog.h" #include "DesktopServices.h" @@ -58,7 +59,7 @@ #include "minecraft/mod/Mod.h" #include "minecraft/mod/ModFolderModel.h" -#include "modplatform/ModAPI.h" +#include "modplatform/ResourceAPI.h" #include "Version.h" #include "tasks/ConcurrentTask.h" @@ -139,13 +140,8 @@ bool ModFolderPage::onSelectionChanged(const QModelIndex& current, const QModelI 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()); } @@ -157,12 +153,12 @@ void ModFolderPage::installMods() return; // this is a null instance or a legacy instance auto profile = static_cast<MinecraftInstance*>(m_instance)->getPackProfile(); - if (profile->getModLoaders() == ModAPI::Unspecified) { + if (!profile->getModLoaders().has_value()) { QMessageBox::critical(this, tr("Error"), tr("Please install a mod loader first!")); return; } - ModDownloadDialog mdownload(m_model, this, m_instance); + ResourceDownload::ModDownloadDialog mdownload(this, m_model, m_instance); if (mdownload.exec()) { ConcurrentTask* tasks = new ConcurrentTask(this); connect(tasks, &Task::failed, [this, tasks](QString reason) { @@ -277,3 +273,12 @@ bool CoreModFolderPage::shouldDisplay() const } return false; } + +NilModFolderPage::NilModFolderPage(BaseInstance* inst, std::shared_ptr<ModFolderModel> mods, QWidget* parent) + : ModFolderPage(inst, mods, parent) +{} + +bool NilModFolderPage::shouldDisplay() const +{ + return m_model->dir().exists(); +} diff --git a/launcher/ui/pages/instance/ModFolderPage.h b/launcher/ui/pages/instance/ModFolderPage.h index f20adf34..2fc7b574 100644 --- a/launcher/ui/pages/instance/ModFolderPage.h +++ b/launcher/ui/pages/instance/ModFolderPage.h @@ -1,8 +1,9 @@ // 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 Sefa Eyeoglu <contact@scrumplex.net> + * Copyright (C) 2022 TheKodeToad <TheKodeToad@proton.me> * * 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 @@ -59,7 +60,7 @@ class ModFolderPage : public ExternalResourcesPage { private slots: void runningStateChanged(bool running); - void removeItem() override; + void removeItems(const QItemSelection &selection) override; void installMods(); void updateMods(); @@ -80,3 +81,16 @@ class CoreModFolderPage : public ModFolderPage { virtual bool shouldDisplay() const override; }; + +class NilModFolderPage : public ModFolderPage { + public: + explicit NilModFolderPage(BaseInstance* inst, std::shared_ptr<ModFolderModel> mods, QWidget* parent = 0); + virtual ~NilModFolderPage() = default; + + virtual QString displayName() const override { return tr("Nilmods"); } + virtual QIcon icon() const override { return APPLICATION->getThemedIcon("coremods"); } + virtual QString id() const override { return "nilmods"; } + virtual QString helpPage() const override { return "Nilmods"; } + + virtual bool shouldDisplay() const override; +}; diff --git a/launcher/ui/pages/instance/OtherLogsPage.cpp b/launcher/ui/pages/instance/OtherLogsPage.cpp index 0c1939c6..bbdd7324 100644 --- a/launcher/ui/pages/instance/OtherLogsPage.cpp +++ b/launcher/ui/pages/instance/OtherLogsPage.cpp @@ -1,7 +1,8 @@ // 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 TheKodeToad <TheKodeToad@proton.me> * * 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 @@ -204,7 +205,7 @@ void OtherLogsPage::on_btnReload_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() @@ -219,13 +220,21 @@ void OtherLogsPage::on_btnDelete_clicked() setControlsEnabled(false); return; } - if (QMessageBox::question(this, tr("Delete"), - tr("Do you really want to delete %1?").arg(m_currentFile), - QMessageBox::Yes, QMessageBox::No) == QMessageBox::No) - { + if (QMessageBox::question(this, tr("Confirm Deletion"), + tr("You are about to delete \"%1\".\n" + "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; } QFile file(FS::PathCombine(m_path, m_currentFile)); + + if (FS::trash(file.fileName())) + { + return; + } + if (!file.remove()) { QMessageBox::critical(this, tr("Error"), tr("Unable to delete %1: %2") @@ -243,15 +252,15 @@ void OtherLogsPage::on_btnClean_clicked() return; } QMessageBox *messageBox = new QMessageBox(this); - messageBox->setWindowTitle(tr("Clean up")); + messageBox->setWindowTitle(tr("Confirm Cleanup")); 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')); } 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->setDefaultButton(QMessageBox::Ok); @@ -267,6 +276,10 @@ void OtherLogsPage::on_btnClean_clicked() for(auto item: toDelete) { QFile file(FS::PathCombine(m_path, item)); + if (FS::trash(file.fileName())) + { + continue; + } if (!file.remove()) { failed.push_back(item); diff --git a/launcher/ui/pages/instance/ResourcePackPage.cpp b/launcher/ui/pages/instance/ResourcePackPage.cpp new file mode 100644 index 00000000..24bfb38d --- /dev/null +++ b/launcher/ui/pages/instance/ResourcePackPage.cpp @@ -0,0 +1,104 @@ +// SPDX-FileCopyrightText: 2023 flowln <flowlnlnln@gmail.com> +// +// SPDX-License-Identifier: GPL-3.0-only AND Apache-2.0 +/* + * Prism Launcher - Minecraft Launcher + * Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org> + * + * 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 "ResourcePackPage.h" + +#include "ResourceDownloadTask.h" + +#include "ui/dialogs/CustomMessageBox.h" +#include "ui/dialogs/ProgressDialog.h" +#include "ui/dialogs/ResourceDownloadDialog.h" + +ResourcePackPage::ResourcePackPage(MinecraftInstance* instance, std::shared_ptr<ResourcePackFolderModel> model, QWidget* parent) + : ExternalResourcesPage(instance, model, parent) +{ + ui->actionDownloadItem->setText(tr("Download packs")); + ui->actionDownloadItem->setToolTip(tr("Download resource packs from online platforms")); + ui->actionDownloadItem->setEnabled(true); + connect(ui->actionDownloadItem, &QAction::triggered, this, &ResourcePackPage::downloadRPs); + ui->actionsToolbar->insertActionBefore(ui->actionAddItem, ui->actionDownloadItem); + + ui->actionViewConfigs->setVisible(false); +} + +bool ResourcePackPage::onSelectionChanged(const QModelIndex& current, const QModelIndex& previous) +{ + auto sourceCurrent = m_filterModel->mapToSource(current); + int row = sourceCurrent.row(); + auto& rp = static_cast<ResourcePack&>(m_model->at(row)); + ui->frame->updateWithResourcePack(rp); + + return true; +} + +void ResourcePackPage::downloadRPs() +{ + if (!m_controlsEnabled) + return; + if (m_instance->typeName() != "Minecraft") + return; // this is a null instance or a legacy instance + + ResourceDownload::ResourcePackDownloadDialog mdownload(this, std::static_pointer_cast<ResourcePackFolderModel>(m_model), m_instance); + if (mdownload.exec()) { + auto tasks = new ConcurrentTask(this); + connect(tasks, &Task::failed, [this, tasks](QString reason) { + CustomMessageBox::selectable(this, tr("Error"), reason, QMessageBox::Critical)->show(); + tasks->deleteLater(); + }); + connect(tasks, &Task::aborted, [this, tasks]() { + CustomMessageBox::selectable(this, tr("Aborted"), tr("Download stopped by user."), QMessageBox::Information)->show(); + tasks->deleteLater(); + }); + connect(tasks, &Task::succeeded, [this, tasks]() { + QStringList warnings = tasks->warnings(); + if (warnings.count()) + CustomMessageBox::selectable(this, tr("Warnings"), warnings.join('\n'), QMessageBox::Warning)->show(); + + tasks->deleteLater(); + }); + + for (auto& task : mdownload.getTasks()) { + tasks->addTask(task); + } + + ProgressDialog loadDialog(this); + loadDialog.setSkipButton(true, tr("Abort")); + loadDialog.execWithTask(tasks); + + m_model->update(); + } +} diff --git a/launcher/ui/pages/instance/ResourcePackPage.h b/launcher/ui/pages/instance/ResourcePackPage.h index 9633e3b4..b04aa2e9 100644 --- a/launcher/ui/pages/instance/ResourcePackPage.h +++ b/launcher/ui/pages/instance/ResourcePackPage.h @@ -1,6 +1,8 @@ -// SPDX-License-Identifier: GPL-3.0-only +// SPDX-FileCopyrightText: 2023 flowln <flowlnlnln@gmail.com> +// +// SPDX-License-Identifier: GPL-3.0-only AND Apache-2.0 /* - * PolyMC - Minecraft Launcher + * Prism Launcher - Minecraft Launcher * Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org> * * This program is free software: you can redistribute it and/or modify @@ -44,12 +46,7 @@ class ResourcePackPage : public ExternalResourcesPage { Q_OBJECT public: - explicit ResourcePackPage(MinecraftInstance *instance, std::shared_ptr<ResourcePackFolderModel> model, QWidget *parent = 0) - : ExternalResourcesPage(instance, model, parent) - { - ui->actionViewConfigs->setVisible(false); - } - virtual ~ResourcePackPage() {} + explicit ResourcePackPage(MinecraftInstance *instance, std::shared_ptr<ResourcePackFolderModel> model, QWidget *parent = 0); QString displayName() const override { return tr("Resource packs"); } QIcon icon() const override { return APPLICATION->getThemedIcon("resourcepacks"); } @@ -63,13 +60,7 @@ public: } public slots: - bool onSelectionChanged(const QModelIndex& current, const QModelIndex& previous) override - { - auto sourceCurrent = m_filterModel->mapToSource(current); - int row = sourceCurrent.row(); - auto& rp = static_cast<ResourcePack&>(m_model->at(row)); - ui->frame->updateWithResourcePack(rp); - - return true; - } + bool onSelectionChanged(const QModelIndex& current, const QModelIndex& previous) override; + void downloadRPs(); }; + diff --git a/launcher/ui/pages/instance/ScreenshotsPage.cpp b/launcher/ui/pages/instance/ScreenshotsPage.cpp index 0092aef3..ca368d3b 100644 --- a/launcher/ui/pages/instance/ScreenshotsPage.cpp +++ b/launcher/ui/pages/instance/ScreenshotsPage.cpp @@ -1,8 +1,9 @@ // 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 Sefa Eyeoglu <contact@scrumplex.net> + * Copyright (C) 2022 TheKodeToad <TheKodeToad@proton.me> * * 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 @@ -379,6 +380,24 @@ void ScreenshotsPage::on_actionUpload_triggered() if (selection.isEmpty()) 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; auto job = NetJob::Ptr(new NetJob("Screenshot Upload", APPLICATION->network())); if(selection.size() < 2) @@ -491,17 +510,32 @@ void ScreenshotsPage::on_actionCopy_File_s_triggered() void ScreenshotsPage::on_actionDelete_triggered() { - auto mbox = CustomMessageBox::selectable( - this, tr("Are you sure?"), tr("This will delete all selected screenshots."), - QMessageBox::Warning, QMessageBox::Yes | QMessageBox::No); - std::unique_ptr<QMessageBox> box(mbox); + auto selected = ui->listView->selectionModel()->selectedIndexes(); + + 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); - if (box->exec() != QMessageBox::Yes) + auto response = + CustomMessageBox::selectable(this, tr("Confirm Deletion"), text, QMessageBox::Warning, QMessageBox::Yes | QMessageBox::No)->exec(); + + if (response != QMessageBox::Yes) return; - auto selected = ui->listView->selectionModel()->selectedIndexes(); for (auto item : selected) { + if (FS::trash(m_model->filePath(item))) + continue; + m_model->remove(item); } } diff --git a/launcher/ui/pages/instance/ScreenshotsPage.h b/launcher/ui/pages/instance/ScreenshotsPage.h index 2eb0de04..89611b6d 100644 --- a/launcher/ui/pages/instance/ScreenshotsPage.h +++ b/launcher/ui/pages/instance/ScreenshotsPage.h @@ -44,6 +44,7 @@ class QFileSystemModel; class QIdentityProxyModel; +class QItemSelection; namespace Ui { class ScreenshotsPage; diff --git a/launcher/ui/pages/instance/ServersPage.cpp b/launcher/ui/pages/instance/ServersPage.cpp index a625e20b..4b1fa08a 100644 --- a/launcher/ui/pages/instance/ServersPage.cpp +++ b/launcher/ui/pages/instance/ServersPage.cpp @@ -1,8 +1,9 @@ // 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 Sefa Eyeoglu <contact@scrumplex.net> + * Copyright (C) 2022 TheKodeToad <TheKodeToad@proton.me> * * 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 @@ -35,6 +36,7 @@ */ #include "ServersPage.h" +#include "ui/dialogs/CustomMessageBox.h" #include "ui_ServersPage.h" #include <FileSystem.h> @@ -48,6 +50,7 @@ #include <QFileSystemWatcher> #include <QMenu> +#include <QTimer> static const int COLUMN_COUNT = 2; // 3 , TBD: latency and other nice things. @@ -799,6 +802,17 @@ void ServersPage::on_actionAdd_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); } diff --git a/launcher/ui/pages/instance/ShaderPackPage.cpp b/launcher/ui/pages/instance/ShaderPackPage.cpp new file mode 100644 index 00000000..2d0c10aa --- /dev/null +++ b/launcher/ui/pages/instance/ShaderPackPage.cpp @@ -0,0 +1,98 @@ +// SPDX-FileCopyrightText: 2023 flowln <flowlnlnln@gmail.com> +// +// SPDX-License-Identifier: GPL-3.0-only AND Apache-2.0 +/* + * Prism Launcher - Minecraft Launcher + * Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org> + * + * 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 "ShaderPackPage.h" +#include "ui_ExternalResourcesPage.h" + +#include "ResourceDownloadTask.h" + +#include "minecraft/mod/ShaderPackFolderModel.h" + +#include "ui/dialogs/CustomMessageBox.h" +#include "ui/dialogs/ProgressDialog.h" +#include "ui/dialogs/ResourceDownloadDialog.h" + + +ShaderPackPage::ShaderPackPage(MinecraftInstance* instance, std::shared_ptr<ShaderPackFolderModel> model, QWidget* parent) + : ExternalResourcesPage(instance, model, parent) +{ + ui->actionDownloadItem->setText(tr("Download shaders")); + ui->actionDownloadItem->setToolTip(tr("Download shaders from online platforms")); + ui->actionDownloadItem->setEnabled(true); + connect(ui->actionDownloadItem, &QAction::triggered, this, &ShaderPackPage::downloadShaders); + ui->actionsToolbar->insertActionBefore(ui->actionAddItem, ui->actionDownloadItem); + + ui->actionViewConfigs->setVisible(false); +} + +void ShaderPackPage::downloadShaders() +{ + if (!m_controlsEnabled) + return; + if (m_instance->typeName() != "Minecraft") + return; // this is a null instance or a legacy instance + + ResourceDownload::ShaderPackDownloadDialog mdownload(this, std::static_pointer_cast<ShaderPackFolderModel>(m_model), m_instance); + if (mdownload.exec()) { + auto tasks = new ConcurrentTask(this); + connect(tasks, &Task::failed, [this, tasks](QString reason) { + CustomMessageBox::selectable(this, tr("Error"), reason, QMessageBox::Critical)->show(); + tasks->deleteLater(); + }); + connect(tasks, &Task::aborted, [this, tasks]() { + CustomMessageBox::selectable(this, tr("Aborted"), tr("Download stopped by user."), QMessageBox::Information)->show(); + tasks->deleteLater(); + }); + connect(tasks, &Task::succeeded, [this, tasks]() { + QStringList warnings = tasks->warnings(); + if (warnings.count()) + CustomMessageBox::selectable(this, tr("Warnings"), warnings.join('\n'), QMessageBox::Warning)->show(); + + tasks->deleteLater(); + }); + + for (auto& task : mdownload.getTasks()) { + tasks->addTask(task); + } + + ProgressDialog loadDialog(this); + loadDialog.setSkipButton(true, tr("Abort")); + loadDialog.execWithTask(tasks); + + m_model->update(); + } +} diff --git a/launcher/ui/pages/instance/ShaderPackPage.h b/launcher/ui/pages/instance/ShaderPackPage.h index 7f7ff8c1..a779fd8c 100644 --- a/launcher/ui/pages/instance/ShaderPackPage.h +++ b/launcher/ui/pages/instance/ShaderPackPage.h @@ -1,6 +1,8 @@ -// SPDX-License-Identifier: GPL-3.0-only +// SPDX-FileCopyrightText: 2023 flowln <flowlnlnln@gmail.com> +// +// SPDX-License-Identifier: GPL-3.0-only AND Apache-2.0 /* - * PolyMC - Minecraft Launcher + * Prism Launcher - Minecraft Launcher * Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org> * * This program is free software: you can redistribute it and/or modify @@ -36,28 +38,21 @@ #pragma once #include "ExternalResourcesPage.h" -#include "ui_ExternalResourcesPage.h" - -#include "minecraft/mod/ShaderPackFolderModel.h" class ShaderPackPage : public ExternalResourcesPage { Q_OBJECT public: - explicit ShaderPackPage(MinecraftInstance *instance, std::shared_ptr<ShaderPackFolderModel> model, QWidget *parent = 0) - : ExternalResourcesPage(instance, model, parent) - { - ui->actionViewConfigs->setVisible(false); - } - virtual ~ShaderPackPage() {} + explicit ShaderPackPage(MinecraftInstance *instance, std::shared_ptr<ShaderPackFolderModel> model, QWidget *parent = nullptr); + ~ShaderPackPage() override = default; QString displayName() const override { return tr("Shader packs"); } QIcon icon() const override { return APPLICATION->getThemedIcon("shaderpacks"); } QString id() const override { return "shaderpacks"; } QString helpPage() const override { return "Resource-packs"; } - virtual bool shouldDisplay() const override - { - return true; - } + bool shouldDisplay() const override { return true; } + + public slots: + void downloadShaders(); }; diff --git a/launcher/ui/pages/instance/TexturePackPage.cpp b/launcher/ui/pages/instance/TexturePackPage.cpp new file mode 100644 index 00000000..427aba11 --- /dev/null +++ b/launcher/ui/pages/instance/TexturePackPage.cpp @@ -0,0 +1,106 @@ +// SPDX-FileCopyrightText: 2023 flowln <flowlnlnln@gmail.com> +// +// SPDX-License-Identifier: GPL-3.0-only AND Apache-2.0 +/* + * Prism Launcher - Minecraft Launcher + * Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org> + * + * 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 "TexturePackPage.h" + +#include "ResourceDownloadTask.h" + +#include "minecraft/mod/TexturePack.h" + +#include "ui/dialogs/CustomMessageBox.h" +#include "ui/dialogs/ProgressDialog.h" +#include "ui/dialogs/ResourceDownloadDialog.h" + +TexturePackPage::TexturePackPage(MinecraftInstance* instance, std::shared_ptr<TexturePackFolderModel> model, QWidget* parent) + : ExternalResourcesPage(instance, model, parent) +{ + ui->actionDownloadItem->setText(tr("Download packs")); + ui->actionDownloadItem->setToolTip(tr("Download texture packs from online platforms")); + ui->actionDownloadItem->setEnabled(true); + connect(ui->actionDownloadItem, &QAction::triggered, this, &TexturePackPage::downloadTPs); + ui->actionsToolbar->insertActionBefore(ui->actionAddItem, ui->actionDownloadItem); + + ui->actionViewConfigs->setVisible(false); +} + +bool TexturePackPage::onSelectionChanged(const QModelIndex& current, const QModelIndex& previous) +{ + auto sourceCurrent = m_filterModel->mapToSource(current); + int row = sourceCurrent.row(); + auto& rp = static_cast<TexturePack&>(m_model->at(row)); + ui->frame->updateWithTexturePack(rp); + + return true; +} + +void TexturePackPage::downloadTPs() +{ + if (!m_controlsEnabled) + return; + if (m_instance->typeName() != "Minecraft") + return; // this is a null instance or a legacy instance + + ResourceDownload::TexturePackDownloadDialog mdownload(this, std::static_pointer_cast<TexturePackFolderModel>(m_model), m_instance); + if (mdownload.exec()) { + auto tasks = new ConcurrentTask(this); + connect(tasks, &Task::failed, [this, tasks](QString reason) { + CustomMessageBox::selectable(this, tr("Error"), reason, QMessageBox::Critical)->show(); + tasks->deleteLater(); + }); + connect(tasks, &Task::aborted, [this, tasks]() { + CustomMessageBox::selectable(this, tr("Aborted"), tr("Download stopped by user."), QMessageBox::Information)->show(); + tasks->deleteLater(); + }); + connect(tasks, &Task::succeeded, [this, tasks]() { + QStringList warnings = tasks->warnings(); + if (warnings.count()) + CustomMessageBox::selectable(this, tr("Warnings"), warnings.join('\n'), QMessageBox::Warning)->show(); + + tasks->deleteLater(); + }); + + for (auto& task : mdownload.getTasks()) { + tasks->addTask(task); + } + + ProgressDialog loadDialog(this); + loadDialog.setSkipButton(true, tr("Abort")); + loadDialog.execWithTask(tasks); + + m_model->update(); + } +} diff --git a/launcher/ui/pages/instance/TexturePackPage.h b/launcher/ui/pages/instance/TexturePackPage.h index 69b836ca..47a8fa60 100644 --- a/launcher/ui/pages/instance/TexturePackPage.h +++ b/launcher/ui/pages/instance/TexturePackPage.h @@ -1,6 +1,8 @@ -// SPDX-License-Identifier: GPL-3.0-only +// SPDX-FileCopyrightText: 2023 flowln <flowlnlnln@gmail.com> +// +// SPDX-License-Identifier: GPL-3.0-only AND Apache-2.0 /* - * PolyMC - Minecraft Launcher + * Prism Launcher - Minecraft Launcher * Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org> * * This program is free software: you can redistribute it and/or modify @@ -39,18 +41,12 @@ #include "ui_ExternalResourcesPage.h" #include "minecraft/mod/TexturePackFolderModel.h" -#include "minecraft/mod/TexturePack.h" class TexturePackPage : public ExternalResourcesPage { Q_OBJECT public: - explicit TexturePackPage(MinecraftInstance *instance, std::shared_ptr<TexturePackFolderModel> model, QWidget *parent = 0) - : ExternalResourcesPage(instance, model, parent) - { - ui->actionViewConfigs->setVisible(false); - } - virtual ~TexturePackPage() {} + explicit TexturePackPage(MinecraftInstance *instance, std::shared_ptr<TexturePackFolderModel> model, QWidget* parent = nullptr); QString displayName() const override { return tr("Texture packs"); } QIcon icon() const override { return APPLICATION->getThemedIcon("resourcepacks"); } @@ -63,13 +59,6 @@ public: } public slots: - bool onSelectionChanged(const QModelIndex& current, const QModelIndex& previous) override - { - auto sourceCurrent = m_filterModel->mapToSource(current); - int row = sourceCurrent.row(); - auto& rp = static_cast<TexturePack&>(m_model->at(row)); - ui->frame->updateWithTexturePack(rp); - - return true; - } + bool onSelectionChanged(const QModelIndex& current, const QModelIndex& previous) override; + void downloadTPs(); }; diff --git a/launcher/ui/pages/instance/VersionPage.cpp b/launcher/ui/pages/instance/VersionPage.cpp index c8a65f10..74b7ec7c 100644 --- a/launcher/ui/pages/instance/VersionPage.cpp +++ b/launcher/ui/pages/instance/VersionPage.cpp @@ -1,8 +1,11 @@ -// SPDX-License-Identifier: GPL-3.0-only +// SPDX-FileCopyrightText: 2022-2023 Sefa Eyeoglu <contact@scrumplex.net> +// +// SPDX-License-Identifier: GPL-3.0-only AND Apache-2.0 + /* * Prism Launcher - Minecraft Launcher * Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org> - * Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net> + * Copyright (C) 2022-2023 Sefa Eyeoglu <contact@scrumplex.net> * Copyright (C) 2022 TheKodeToad <TheKodeToad@proton.me> * * This program is free software: you can redistribute it and/or modify @@ -162,7 +165,7 @@ VersionPage::VersionPage(MinecraftInstance *inst, QWidget *parent) auto proxy = new IconProxy(ui->packageView); proxy->setSourceModel(m_profile.get()); - m_filterModel = new QSortFilterProxyModel(); + m_filterModel = new QSortFilterProxyModel(this); m_filterModel->setDynamicSortFilter(true); m_filterModel->setFilterCaseSensitivity(Qt::CaseInsensitive); m_filterModel->setSortCaseSensitivity(Qt::CaseInsensitive); @@ -282,6 +285,7 @@ void VersionPage::updateButtons(int row) ui->actionRevert->setEnabled(controlsEnabled && patch && patch->isRevertible()); ui->actionDownload_All->setEnabled(controlsEnabled); ui->actionAdd_Empty->setEnabled(controlsEnabled); + ui->actionImport_Components->setEnabled(controlsEnabled); ui->actionReload->setEnabled(controlsEnabled); ui->actionInstall_mods->setEnabled(controlsEnabled); ui->actionReplace_Minecraft_jar->setEnabled(controlsEnabled); @@ -318,13 +322,29 @@ void VersionPage::on_actionReload_triggered() void VersionPage::on_actionRemove_triggered() { - if (ui->packageView->currentIndex().isValid()) + if (!ui->packageView->currentIndex().isValid()) { - // FIXME: use actual model, not reloading. - if (!m_profile->remove(ui->packageView->currentIndex().row())) - { - QMessageBox::critical(this, tr("Error"), tr("Couldn't remove file")); - } + return; + } + int index = ui->packageView->currentIndex().row(); + 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(); reloadPackProfile(); @@ -359,6 +379,20 @@ void VersionPage::on_actionReplace_Minecraft_jar_triggered() updateButtons(); } +void VersionPage::on_actionImport_Components_triggered() +{ + QStringList list = GuiUtil::BrowseForFiles("component", tr("Select components"), tr("Components (*.json)"), + APPLICATION->settings()->get("CentralModsDir").toString(), this->parentWidget()); + + if (!list.isEmpty()) { + if (!m_profile->installComponents(list)) { + QMessageBox::warning(this, tr("Failed to import components"), + tr("Some components could not be imported. Check logs for details")); + } + } + + updateButtons(); +} void VersionPage::on_actionAdd_Agents_triggered() { @@ -467,7 +501,7 @@ void VersionPage::on_actionDownload_All_triggered() return; } ProgressDialog tDialog(this); - connect(updateTask.get(), SIGNAL(failed(QString)), SLOT(onGameUpdateError(QString))); + connect(updateTask.get(), &Task::failed, this, &VersionPage::onGameUpdateError); // FIXME: unused return value tDialog.execWithTask(updateTask.get()); updateButtons(); @@ -644,7 +678,7 @@ void VersionPage::onGameUpdateError(QString error) CustomMessageBox::selectable(this, tr("Error updating instance"), error, QMessageBox::Warning)->show(); } -Component * VersionPage::current() +ComponentPtr VersionPage::current() { auto row = currentRow(); if(row < 0) @@ -707,6 +741,19 @@ void VersionPage::on_actionRevert_triggered() { 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)) { // TODO: some error box here diff --git a/launcher/ui/pages/instance/VersionPage.h b/launcher/ui/pages/instance/VersionPage.h index 166f36bb..d0087714 100644 --- a/launcher/ui/pages/instance/VersionPage.h +++ b/launcher/ui/pages/instance/VersionPage.h @@ -1,7 +1,11 @@ -// SPDX-License-Identifier: GPL-3.0-only +// SPDX-FileCopyrightText: 2022-2023 Sefa Eyeoglu <contact@scrumplex.net> +// +// SPDX-License-Identifier: GPL-3.0-only AND Apache-2.0 + /* * Prism Launcher - Minecraft Launcher * Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org> + * Copyright (C) 2022-2023 Sefa Eyeoglu <contact@scrumplex.net> * Copyright (C) 2022 TheKodeToad <TheKodeToad@proton.me> * * This program is free software: you can redistribute it and/or modify @@ -86,6 +90,7 @@ private slots: void on_actionMove_down_triggered(); void on_actionAdd_to_Minecraft_jar_triggered(); void on_actionReplace_Minecraft_jar_triggered(); + void on_actionImport_Components_triggered(); void on_actionAdd_Agents_triggered(); void on_actionRevert_triggered(); void on_actionEdit_triggered(); @@ -99,7 +104,7 @@ private slots: void updateVersionControls(); private: - Component * current(); + ComponentPtr current(); int currentRow(); void updateButtons(int row = -1); void preselect(int row = 0); diff --git a/launcher/ui/pages/instance/VersionPage.ui b/launcher/ui/pages/instance/VersionPage.ui index 4cd50885..4777eafe 100644 --- a/launcher/ui/pages/instance/VersionPage.ui +++ b/launcher/ui/pages/instance/VersionPage.ui @@ -108,6 +108,7 @@ <addaction name="actionReplace_Minecraft_jar"/> <addaction name="actionAdd_Agents"/> <addaction name="actionAdd_Empty"/> + <addaction name="actionImport_Components"/> <addaction name="separator"/> <addaction name="actionMinecraftFolder"/> <addaction name="actionLibrariesFolder"/> @@ -226,10 +227,10 @@ </action> <action name="actionAdd_Agents"> <property name="text"> - <string>Add Agents</string> + <string>Add Agents</string> </property> <property name="toolTip"> - <string>Add Java agents.</string> + <string>Add Java agents.</string> </property> </action> <action name="actionAdd_Empty"> @@ -272,6 +273,14 @@ <string>Open the instance's local libraries folder.</string> </property> </action> + <action name="actionImport_Components"> + <property name="text"> + <string>Import Components</string> + </property> + <property name="toolTip"> + <string>Import existing component JSON files.</string> + </property> + </action> </widget> <customwidgets> <customwidget> diff --git a/launcher/ui/pages/instance/WorldListPage.cpp b/launcher/ui/pages/instance/WorldListPage.cpp index 93458ce4..b6ad159e 100644 --- a/launcher/ui/pages/instance/WorldListPage.cpp +++ b/launcher/ui/pages/instance/WorldListPage.cpp @@ -1,8 +1,9 @@ // 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 Sefa Eyeoglu <contact@scrumplex.net> + * Copyright (C) 2022 TheKodeToad <TheKodeToad@proton.me> * * 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 @@ -35,6 +36,7 @@ */ #include "WorldListPage.h" +#include "ui/dialogs/CustomMessageBox.h" #include "ui_WorldListPage.h" #include "minecraft/WorldList.h" @@ -43,9 +45,9 @@ #include <QKeyEvent> #include <QClipboard> #include <QMessageBox> +#include <QSortFilterProxyModel> #include <QTreeView> #include <QInputDialog> -#include <QProcess> #include <Qt> #include "tools/MCEditTool.h" @@ -105,6 +107,7 @@ WorldListPage::WorldListPage(BaseInstance *inst, std::shared_ptr<WorldList> worl auto head = ui->worldTreeView->header(); head->setSectionResizeMode(0, QHeaderView::Stretch); head->setSectionResizeMode(1, QHeaderView::ResizeToContents); + head->setSectionResizeMode(4, QHeaderView::ResizeToContents); connect(ui->worldTreeView->selectionModel(), &QItemSelectionModel::currentChanged, this, &WorldListPage::worldChanged); worldChanged(QModelIndex(), QModelIndex()); @@ -192,12 +195,14 @@ void WorldListPage::on_actionRemove_triggered() if(!proxiedIndex.isValid()) return; - auto result = QMessageBox::question(this, - tr("Are you sure?"), - tr("This will remove the selected world permenantly.\n" - "The world will be gone forever (A LONG TIME).\n" - "\n" - "Do you want to continue?")); + auto result = CustomMessageBox::selectable(this, tr("Confirm Deletion"), + tr("You are about to delete \"%1\".\n" + "The world may be gone forever (A LONG TIME).\n\n" + "Are you sure?") + .arg(m_worlds->allWorlds().at(proxiedIndex.row()).name()), + QMessageBox::Warning, QMessageBox::Yes | QMessageBox::No, QMessageBox::No) + ->exec(); + if(result != QMessageBox::Yes) { return; diff --git a/launcher/ui/pages/instance/WorldListPage.ui b/launcher/ui/pages/instance/WorldListPage.ui index 7c68bfae..d74dd079 100644 --- a/launcher/ui/pages/instance/WorldListPage.ui +++ b/launcher/ui/pages/instance/WorldListPage.ui @@ -109,7 +109,7 @@ </action> <action name="actionRemove"> <property name="text"> - <string>Remove</string> + <string>Delete</string> </property> </action> <action name="actionMCEdit"> |