Merge pull request #1246 from Trial97/export

This commit is contained in:
Sefa Eyeoglu 2023-07-16 12:24:42 +02:00 committed by GitHub
commit fcdd9ea986
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 1034 additions and 373 deletions

View File

@ -487,6 +487,9 @@ set(API_SOURCES
modplatform/helpers/HashUtils.cpp
modplatform/helpers/OverrideUtils.h
modplatform/helpers/OverrideUtils.cpp
modplatform/helpers/ExportToModList.h
modplatform/helpers/ExportToModList.cpp
)
set(FTB_SOURCES
@ -911,6 +914,8 @@ SET(LAUNCHER_SOURCES
ui/dialogs/ExportInstanceDialog.h
ui/dialogs/ExportPackDialog.cpp
ui/dialogs/ExportPackDialog.h
ui/dialogs/ExportToModListDialog.cpp
ui/dialogs/ExportToModListDialog.h
ui/dialogs/IconPickerDialog.cpp
ui/dialogs/IconPickerDialog.h
ui/dialogs/ImportResourceDialog.cpp
@ -1058,6 +1063,7 @@ qt_wrap_ui(LAUNCHER_UI
ui/dialogs/SkinUploadDialog.ui
ui/dialogs/ExportInstanceDialog.ui
ui/dialogs/ExportPackDialog.ui
ui/dialogs/ExportToModListDialog.ui
ui/dialogs/IconPickerDialog.ui
ui/dialogs/ImportResourceDialog.ui
ui/dialogs/MSALoginDialog.ui

View File

@ -0,0 +1,200 @@
// SPDX-License-Identifier: GPL-3.0-only
/*
* Prism Launcher - Minecraft Launcher
* Copyright (c) 2023 Trial97 <alexandru.tripon97@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "ExportToModList.h"
#include <QJsonArray>
#include <QJsonDocument>
#include <QJsonObject>
namespace ExportToModList {
QString toHTML(QList<Mod*> mods, OptionalData extraData)
{
QStringList lines;
for (auto mod : mods) {
auto meta = mod->metadata();
auto modName = mod->name().toHtmlEscaped();
if (extraData & Url) {
auto url = mod->metaurl().toHtmlEscaped();
if (!url.isEmpty())
modName = QString("<a href=\"%1\">%2</a>").arg(url, modName);
}
auto line = modName;
if (extraData & Version) {
auto ver = mod->version();
if (ver.isEmpty() && meta != nullptr)
ver = meta->version().toString();
if (!ver.isEmpty())
line += QString(" [%1]").arg(ver.toHtmlEscaped());
}
if (extraData & Authors && !mod->authors().isEmpty())
line += " by " + mod->authors().join(", ").toHtmlEscaped();
lines.append(QString("<li>%1</li>").arg(line));
}
return QString("<html><body><ul>\n\t%1\n</ul></body></html>").arg(lines.join("\n\t"));
}
QString toMarkdown(QList<Mod*> mods, OptionalData extraData)
{
QStringList lines;
for (auto mod : mods) {
auto meta = mod->metadata();
auto modName = mod->name();
if (extraData & Url) {
auto url = mod->metaurl();
if (!url.isEmpty())
modName = QString("[%1](%2)").arg(modName, url);
}
auto line = modName;
if (extraData & Version) {
auto ver = mod->version();
if (ver.isEmpty() && meta != nullptr)
ver = meta->version().toString();
if (!ver.isEmpty())
line += QString(" [%1]").arg(ver);
}
if (extraData & Authors && !mod->authors().isEmpty())
line += " by " + mod->authors().join(", ");
lines << "- " + line;
}
return lines.join("\n");
}
QString toPlainTXT(QList<Mod*> mods, OptionalData extraData)
{
QStringList lines;
for (auto mod : mods) {
auto meta = mod->metadata();
auto modName = mod->name();
auto line = modName;
if (extraData & Url) {
auto url = mod->metaurl();
if (!url.isEmpty())
line += QString(" (%1)").arg(url);
}
if (extraData & Version) {
auto ver = mod->version();
if (ver.isEmpty() && meta != nullptr)
ver = meta->version().toString();
if (!ver.isEmpty())
line += QString(" [%1]").arg(ver);
}
if (extraData & Authors && !mod->authors().isEmpty())
line += " by " + mod->authors().join(", ");
lines << line;
}
return lines.join("\n");
}
QString toJSON(QList<Mod*> mods, OptionalData extraData)
{
QJsonArray lines;
for (auto mod : mods) {
auto meta = mod->metadata();
auto modName = mod->name();
QJsonObject line;
line["name"] = modName;
if (extraData & Url) {
auto url = mod->metaurl();
if (!url.isEmpty())
line["url"] = url;
}
if (extraData & Version) {
auto ver = mod->version();
if (ver.isEmpty() && meta != nullptr)
ver = meta->version().toString();
if (!ver.isEmpty())
line["version"] = ver;
}
if (extraData & Authors && !mod->authors().isEmpty())
line["authors"] = QJsonArray::fromStringList(mod->authors());
lines << line;
}
QJsonDocument doc;
doc.setArray(lines);
return doc.toJson();
}
QString toCSV(QList<Mod*> mods, OptionalData extraData)
{
QStringList lines;
for (auto mod : mods) {
QStringList data;
auto meta = mod->metadata();
auto modName = mod->name();
data << modName;
if (extraData & Url)
data << mod->metaurl();
if (extraData & Version) {
auto ver = mod->version();
if (ver.isEmpty() && meta != nullptr)
ver = meta->version().toString();
data << ver;
}
if (extraData & Authors) {
QString authors;
if (mod->authors().length() == 1)
authors = mod->authors().back();
else if (mod->authors().length() > 1)
authors = QString("\"%1\"").arg(mod->authors().join(","));
data << authors;
}
lines << data.join(",");
}
return lines.join("\n");
}
QString exportToModList(QList<Mod*> mods, Formats format, OptionalData extraData)
{
switch (format) {
case HTML:
return toHTML(mods, extraData);
case MARKDOWN:
return toMarkdown(mods, extraData);
case PLAINTXT:
return toPlainTXT(mods, extraData);
case JSON:
return toJSON(mods, extraData);
case CSV:
return toCSV(mods, extraData);
default: {
return QString("unknown format:%1").arg(format);
}
}
}
QString exportToModList(QList<Mod*> mods, QString lineTemplate)
{
QStringList lines;
for (auto mod : mods) {
auto meta = mod->metadata();
auto modName = mod->name();
auto url = mod->metaurl();
auto ver = mod->version();
if (ver.isEmpty() && meta != nullptr)
ver = meta->version().toString();
auto authors = mod->authors().join(", ");
lines << QString(lineTemplate)
.replace("{name}", modName)
.replace("{url}", url)
.replace("{version}", ver)
.replace("{authors}", authors);
}
return lines.join("\n");
}
} // namespace ExportToModList

View File

@ -0,0 +1,33 @@
// SPDX-License-Identifier: GPL-3.0-only
/*
* Prism Launcher - Minecraft Launcher
* Copyright (c) 2023 Trial97 <alexandru.tripon97@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#include <QList>
#include <QString>
#include "minecraft/mod/Mod.h"
namespace ExportToModList {
enum Formats { HTML, MARKDOWN, PLAINTXT, JSON, CSV, CUSTOM };
enum OptionalData {
Authors = 1 << 0,
Url = 1 << 1,
Version = 1 << 2,
};
QString exportToModList(QList<Mod*> mods, Formats format, OptionalData extraData);
QString exportToModList(QList<Mod*> mods, QString lineTemplate);
} // namespace ExportToModList

View File

@ -43,100 +43,98 @@
#include "FileSystem.h"
#include "MainWindow.h"
#include "ui/dialogs/ExportToModListDialog.h"
#include "ui_MainWindow.h"
#include <QVariant>
#include <QUrl>
#include <QDir>
#include <QFileInfo>
#include <QUrl>
#include <QVariant>
#include <QKeyEvent>
#include <QAction>
#include <QActionGroup>
#include <QApplication>
#include <QButtonGroup>
#include <QFileDialog>
#include <QHBoxLayout>
#include <QHeaderView>
#include <QInputDialog>
#include <QKeyEvent>
#include <QLabel>
#include <QMainWindow>
#include <QStatusBar>
#include <QToolBar>
#include <QWidget>
#include <QMenu>
#include <QMenuBar>
#include <QMessageBox>
#include <QFileDialog>
#include <QInputDialog>
#include <QLabel>
#include <QToolButton>
#include <QWidgetAction>
#include <QProgressDialog>
#include <QShortcut>
#include <QStatusBar>
#include <QToolBar>
#include <QToolButton>
#include <QWidget>
#include <QWidgetAction>
#include <BaseInstance.h>
#include <InstanceList.h>
#include <minecraft/MinecraftInstance.h>
#include <MMCZip.h>
#include <icons/IconList.h>
#include <java/JavaUtils.h>
#include <java/JavaInstallList.h>
#include <launch/LaunchTask.h>
#include <minecraft/auth/AccountList.h>
#include <SkinUtils.h>
#include <BuildConfig.h>
#include <net/NetJob.h>
#include <DesktopServices.h>
#include <InstanceList.h>
#include <MMCZip.h>
#include <SkinUtils.h>
#include <icons/IconList.h>
#include <java/JavaInstallList.h>
#include <java/JavaUtils.h>
#include <launch/LaunchTask.h>
#include <minecraft/MinecraftInstance.h>
#include <minecraft/auth/AccountList.h>
#include <net/Download.h>
#include <net/NetJob.h>
#include <news/NewsChecker.h>
#include <tools/BaseProfiler.h>
#include <updater/ExternalUpdater.h>
#include <DesktopServices.h>
#include "InstanceWindow.h"
#include "InstancePageProvider.h"
#include "InstanceWindow.h"
#include "JavaCommon.h"
#include "LaunchController.h"
#include "ui/instanceview/InstanceProxyModel.h"
#include "ui/instanceview/InstanceView.h"
#include "ui/instanceview/InstanceDelegate.h"
#include "ui/widgets/LabeledToolButton.h"
#include "ui/dialogs/NewInstanceDialog.h"
#include "ui/dialogs/NewsDialog.h"
#include "ui/dialogs/ProgressDialog.h"
#include "ui/dialogs/AboutDialog.h"
#include "ui/dialogs/CustomMessageBox.h"
#include "ui/dialogs/IconPickerDialog.h"
#include "ui/dialogs/CopyInstanceDialog.h"
#include "ui/dialogs/CustomMessageBox.h"
#include "ui/dialogs/EditAccountDialog.h"
#include "ui/dialogs/ExportInstanceDialog.h"
#include "ui/dialogs/ExportPackDialog.h"
#include "ui/dialogs/IconPickerDialog.h"
#include "ui/dialogs/ImportResourceDialog.h"
#include "ui/dialogs/NewInstanceDialog.h"
#include "ui/dialogs/NewsDialog.h"
#include "ui/dialogs/ProgressDialog.h"
#include "ui/instanceview/InstanceDelegate.h"
#include "ui/instanceview/InstanceProxyModel.h"
#include "ui/instanceview/InstanceView.h"
#include "ui/themes/ITheme.h"
#include "ui/themes/ThemeManager.h"
#include "ui/widgets/LabeledToolButton.h"
#include "minecraft/mod/tasks/LocalResourceParse.h"
#include "minecraft/WorldList.h"
#include "minecraft/mod/ModFolderModel.h"
#include "minecraft/mod/ShaderPackFolderModel.h"
#include "minecraft/WorldList.h"
#include "minecraft/mod/tasks/LocalResourceParse.h"
#include "KonamiCode.h"
#include "InstanceImportTask.h"
#include "InstanceCopyTask.h"
#include "InstanceImportTask.h"
#include "MMCTime.h"
namespace {
QString profileInUseFilter(const QString& profile, bool used)
{
if(used)
{
if (used) {
return QObject::tr("%1 (in use)").arg(profile);
}
else
{
} else {
return profile;
}
}
}
} // namespace
MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent), ui(new Ui::MainWindow)
{
@ -184,7 +182,6 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWi
ui->instanceToolBar->addContextMenuAction(ui->newsToolBar->toggleViewAction());
ui->instanceToolBar->addContextMenuAction(ui->instanceToolBar->toggleViewAction());
ui->instanceToolBar->addContextMenuAction(ui->actionLockToolbars);
}
// set the menu for the folders help, accounts, and export tool buttons
@ -206,6 +203,7 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWi
exportInstanceMenu->addAction(ui->actionExportInstanceZip);
exportInstanceMenu->addAction(ui->actionExportInstanceMrPack);
exportInstanceMenu->addAction(ui->actionExportInstanceFlamePack);
exportInstanceMenu->addAction(ui->actionExportInstanceToModList);
ui->actionExportInstance->setMenu(exportInstanceMenu);
}
@ -231,7 +229,6 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWi
if (qgetenv("XDG_CURRENT_DESKTOP") == "gamescope") {
ui->mainToolBar->addAction(ui->actionCloseWindow);
}
}
// add the toolbar toggles to the view menu
@ -301,9 +298,8 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWi
connect(proxymodel, &InstanceProxyModel::dataChanged, this, &MainWindow::instanceDataChanged);
view->setModel(proxymodel);
view->setSourceOfGroupCollapseStatus([](const QString & groupName)->bool {
return APPLICATION->instances()->isGroupCollapsed(groupName);
});
view->setSourceOfGroupCollapseStatus(
[](const QString& groupName) -> bool { return APPLICATION->instances()->isGroupCollapsed(groupName); });
connect(view, &InstanceView::groupStateChanged, APPLICATION->instances().get(), &InstanceList::on_GroupStateChanged);
ui->horizontalLayout->addWidget(view);
}
@ -361,21 +357,8 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWi
// Update the menu when the active account changes.
// Shouldn't have to use lambdas here like this, but if I don't, the compiler throws a fit.
// Template hell sucks...
connect(
APPLICATION->accounts().get(),
&AccountList::defaultAccountChanged,
[this] {
defaultAccountChanged();
}
);
connect(
APPLICATION->accounts().get(),
&AccountList::listChanged,
[this]
{
repopulateAccountsMenu();
}
);
connect(APPLICATION->accounts().get(), &AccountList::defaultAccountChanged, [this] { defaultAccountChanged(); });
connect(APPLICATION->accounts().get(), &AccountList::listChanged, [this] { repopulateAccountsMenu(); });
// Show initial account
defaultAccountChanged();
@ -427,7 +410,6 @@ void MainWindow::keyReleaseEvent(QKeyEvent *event)
void MainWindow::retranslateUi()
{
if (m_selectedInstance) {
m_statusLeft->setText(m_selectedInstance->getStatusbarDescription());
} else {
@ -457,9 +439,7 @@ void MainWindow::retranslateUi()
}
}
MainWindow::~MainWindow()
{
}
MainWindow::~MainWindow() {}
QMenu* MainWindow::createPopupMenu()
{
@ -478,10 +458,11 @@ void MainWindow::lockToolbars(bool state)
APPLICATION->settings()->set("ToolbarsLocked", state);
}
void MainWindow::konamiTriggered()
{
QString gradient = " stop:0 rgba(125, 0, 0, 255), stop:0.166 rgba(125, 125, 0, 255), stop:0.333 rgba(0, 125, 0, 255), stop:0.5 rgba(0, 125, 125, 255), stop:0.666 rgba(0, 0, 125, 255), stop:0.833 rgba(125, 0, 125, 255), stop:1 rgba(125, 0, 0, 255));";
QString gradient =
" stop:0 rgba(125, 0, 0, 255), stop:0.166 rgba(125, 125, 0, 255), stop:0.333 rgba(0, 125, 0, 255), stop:0.5 rgba(0, 125, 125, "
"255), stop:0.666 rgba(0, 0, 125, 255), stop:0.833 rgba(125, 0, 125, 255), stop:1 rgba(125, 0, 0, 255));";
QString stylesheet = "background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0," + gradient;
if (ui->mainToolBar->styleSheet() == stylesheet) {
ui->mainToolBar->setStyleSheet("");
@ -508,8 +489,7 @@ void MainWindow::showInstanceContextMenu(const QPoint &pos)
actionSep->setSeparator(true);
bool onInstance = view->indexAt(pos).isValid();
if (onInstance)
{
if (onInstance) {
// reuse the file menu actions
actions = ui->fileMenu->actions();
@ -526,9 +506,7 @@ void MainWindow::showInstanceContextMenu(const QPoint &pos)
QAction* actionVoid = new QAction(m_selectedInstance->name(), this);
actionVoid->setEnabled(false);
actions.prepend(actionVoid);
}
else
{
} else {
auto group = view->groupNameAt(pos);
QAction* actionVoid = new QAction(BuildConfig.LAUNCHER_DISPLAYNAME, this);
@ -536,8 +514,7 @@ void MainWindow::showInstanceContextMenu(const QPoint &pos)
QAction* actionCreateInstance = new QAction(tr("Create instance"), this);
actionCreateInstance->setToolTip(ui->actionAddInstance->toolTip());
if(!group.isNull())
{
if (!group.isNull()) {
QVariantMap data;
data["group"] = group;
actionCreateInstance->setData(data);
@ -548,8 +525,7 @@ void MainWindow::showInstanceContextMenu(const QPoint &pos)
actions.prepend(actionSep);
actions.prepend(actionVoid);
actions.append(actionCreateInstance);
if(!group.isNull())
{
if (!group.isNull()) {
QAction* actionDeleteGroup = new QAction(tr("Delete group '%1'").arg(group), this);
QVariantMap data;
data["group"] = group;
@ -582,12 +558,9 @@ void MainWindow::updateToolsMenu()
ui->actionLaunchInstanceDemo->setDisabled(!m_selectedInstance || currentInstanceRunning);
QMenu* launchMenu = ui->actionLaunchInstance->menu();
if (launchMenu)
{
if (launchMenu) {
launchMenu->clear();
}
else
{
} else {
launchMenu = new QMenu(this);
}
QAction* normalLaunch = launchMenu->addAction(tr("Launch"));
@ -596,24 +569,15 @@ void MainWindow::updateToolsMenu()
normalLaunchOffline->setShortcut(QKeySequence(tr("Ctrl+Shift+O")));
QAction* normalLaunchDemo = launchMenu->addAction(tr("Launch Demo"));
normalLaunchDemo->setShortcut(QKeySequence(tr("Ctrl+Alt+O")));
if (m_selectedInstance)
{
if (m_selectedInstance) {
normalLaunch->setEnabled(m_selectedInstance->canLaunch());
normalLaunchOffline->setEnabled(m_selectedInstance->canLaunch());
normalLaunchDemo->setEnabled(m_selectedInstance->canLaunch());
connect(normalLaunch, &QAction::triggered, [this]() {
APPLICATION->launch(m_selectedInstance, true, false);
});
connect(normalLaunchOffline, &QAction::triggered, [this]() {
APPLICATION->launch(m_selectedInstance, false, false);
});
connect(normalLaunchDemo, &QAction::triggered, [this]() {
APPLICATION->launch(m_selectedInstance, false, true);
});
}
else
{
connect(normalLaunch, &QAction::triggered, [this]() { APPLICATION->launch(m_selectedInstance, true, false); });
connect(normalLaunchOffline, &QAction::triggered, [this]() { APPLICATION->launch(m_selectedInstance, false, false); });
connect(normalLaunchDemo, &QAction::triggered, [this]() { APPLICATION->launch(m_selectedInstance, false, true); });
} else {
normalLaunch->setDisabled(true);
normalLaunchOffline->setDisabled(true);
normalLaunchDemo->setDisabled(true);
@ -627,35 +591,25 @@ void MainWindow::updateToolsMenu()
QString profilersTitle = tr("Profilers");
launchMenu->addSeparator()->setText(profilersTitle);
for (auto profiler : APPLICATION->profilers().values())
{
for (auto profiler : APPLICATION->profilers().values()) {
QAction* profilerAction = launchMenu->addAction(profiler->name());
QAction* profilerOfflineAction = launchMenu->addAction(tr("%1 Offline").arg(profiler->name()));
QString error;
if (!profiler->check(&error))
{
if (!profiler->check(&error)) {
profilerAction->setDisabled(true);
profilerOfflineAction->setDisabled(true);
QString profilerToolTip = tr("Profiler not setup correctly. Go into settings, \"External Tools\".");
profilerAction->setToolTip(profilerToolTip);
profilerOfflineAction->setToolTip(profilerToolTip);
}
else if (m_selectedInstance)
{
} else if (m_selectedInstance) {
profilerAction->setEnabled(m_selectedInstance->canLaunch());
profilerOfflineAction->setEnabled(m_selectedInstance->canLaunch());
connect(profilerAction, &QAction::triggered, [this, profiler]()
{
APPLICATION->launch(m_selectedInstance, true, false, profiler.get());
});
connect(profilerOfflineAction, &QAction::triggered, [this, profiler]()
{
APPLICATION->launch(m_selectedInstance, false, false, profiler.get());
});
}
else
{
connect(profilerAction, &QAction::triggered,
[this, profiler]() { APPLICATION->launch(m_selectedInstance, true, false, profiler.get()); });
connect(profilerOfflineAction, &QAction::triggered,
[this, profiler]() { APPLICATION->launch(m_selectedInstance, false, false, profiler.get()); });
} else {
profilerAction->setDisabled(true);
profilerOfflineAction->setDisabled(true);
}
@ -712,11 +666,9 @@ void MainWindow::repopulateAccountsMenu()
MinecraftAccountPtr defaultAccount = accounts->defaultAccount();
QString active_profileId = "";
if (defaultAccount)
{
if (defaultAccount) {
// this can be called before accountMenuButton exists
if (ui->actionAccountsButton)
{
if (ui->actionAccountsButton) {
auto profileLabel = profileInUseFilter(defaultAccount->profileName(), defaultAccount->isInUse());
ui->actionAccountsButton->setText(profileLabel);
}
@ -724,38 +676,31 @@ void MainWindow::repopulateAccountsMenu()
QActionGroup* accountsGroup = new QActionGroup(this);
if (accounts->count() <= 0)
{
if (accounts->count() <= 0) {
ui->actionNoAccountsAdded->setEnabled(false);
ui->accountsMenu->addAction(ui->actionNoAccountsAdded);
}
else
{
} else {
// TODO: Nicer way to iterate?
for (int i = 0; i < accounts->count(); i++)
{
for (int i = 0; i < accounts->count(); i++) {
MinecraftAccountPtr account = accounts->at(i);
auto profileLabel = profileInUseFilter(account->profileName(), account->isInUse());
QAction* action = new QAction(profileLabel, this);
action->setData(i);
action->setCheckable(true);
action->setActionGroup(accountsGroup);
if (defaultAccount == account)
{
if (defaultAccount == account) {
action->setChecked(true);
}
auto face = account->getFace();
if (!face.isNull()) {
action->setIcon(face);
}
else {
} else {
action->setIcon(APPLICATION->getThemedIcon("noaccount"));
}
const int highestNumberKey = 9;
if(i<highestNumberKey)
{
if (i < highestNumberKey) {
action->setShortcut(QKeySequence(tr("Ctrl+%1").arg(i + 1)));
}
@ -782,8 +727,7 @@ void MainWindow::repopulateAccountsMenu()
void MainWindow::updatesAllowedChanged(bool allowed)
{
if(!BuildConfig.UPDATER_ENABLED)
{
if (!BuildConfig.UPDATER_ENABLED) {
return;
}
ui->actionCheckUpdate->setEnabled(allowed);
@ -818,15 +762,13 @@ void MainWindow::defaultAccountChanged()
MinecraftAccountPtr account = APPLICATION->accounts()->defaultAccount();
// FIXME: this needs adjustment for MSA
if (account && account->profileName() != "")
{
if (account && account->profileName() != "") {
auto profileLabel = profileInUseFilter(account->profileName(), account->isInUse());
ui->actionAccountsButton->setText(profileLabel);
auto face = account->getFace();
if (face.isNull()) {
ui->actionAccountsButton->setIcon(APPLICATION->getThemedIcon("noaccount"));
}
else {
} else {
ui->actionAccountsButton->setIcon(face);
}
return;
@ -839,14 +781,11 @@ void MainWindow::defaultAccountChanged()
bool MainWindow::eventFilter(QObject* obj, QEvent* ev)
{
if (obj == view)
{
if (ev->type() == QEvent::KeyPress)
{
if (obj == view) {
if (ev->type() == QEvent::KeyPress) {
secretEventFilter->input(ev);
QKeyEvent* keyEvent = static_cast<QKeyEvent*>(ev);
switch (keyEvent->key())
{
switch (keyEvent->key()) {
/*
case Qt::Key_Enter:
case Qt::Key_Return:
@ -872,23 +811,17 @@ bool MainWindow::eventFilter(QObject *obj, QEvent *ev)
void MainWindow::updateNewsLabel()
{
if (m_newsChecker->isLoadingNews())
{
if (m_newsChecker->isLoadingNews()) {
newsLabel->setText(tr("Loading news..."));
newsLabel->setEnabled(false);
ui->actionMoreNews->setVisible(false);
}
else
{
} else {
QList<NewsEntryPtr> entries = m_newsChecker->getNewsEntries();
if (entries.length() > 0)
{
if (entries.length() > 0) {
newsLabel->setText(entries[0]->title);
newsLabel->setEnabled(true);
ui->actionMoreNews->setVisible(true);
}
else
{
} else {
newsLabel->setText(tr("No news available."));
newsLabel->setEnabled(false);
ui->actionMoreNews->setVisible(false);
@ -904,8 +837,7 @@ QList<int> stringToIntList(const QString &string)
QStringList split = string.split(',', QString::SkipEmptyParts);
#endif
QList<int> out;
for (int i = 0; i < split.size(); ++i)
{
for (int i = 0; i < split.size(); ++i) {
out.append(split.at(i).toInt());
}
return out;
@ -913,8 +845,7 @@ QList<int> stringToIntList(const QString &string)
QString intListToString(const QList<int>& list)
{
QStringList slist;
for (int i = 0; i < list.size(); ++i)
{
for (int i = 0; i < list.size(); ++i) {
slist.append(QString::number(list.at(i)));
}
return slist.join(',');
@ -934,21 +865,17 @@ void MainWindow::setCatBackground(bool enabled)
void MainWindow::runModalTask(Task* task)
{
connect(task, &Task::failed, [this](QString reason)
{
CustomMessageBox::selectable(this, tr("Error"), reason, QMessageBox::Critical)->show();
});
connect(task, &Task::succeeded, [this, task]()
{
connect(task, &Task::failed,
[this](QString reason) { CustomMessageBox::selectable(this, tr("Error"), reason, QMessageBox::Critical)->show(); });
connect(task, &Task::succeeded, [this, task]() {
QStringList warnings = task->warnings();
if(warnings.count())
{
if (warnings.count()) {
CustomMessageBox::selectable(this, tr("Warnings"), warnings.join('\n'), QMessageBox::Warning)->show();
}
});
connect(task, &Task::aborted, [this]
{
CustomMessageBox::selectable(this, tr("Task aborted"), tr("The task has been aborted by the user."), QMessageBox::Information)->show();
connect(task, &Task::aborted, [this] {
CustomMessageBox::selectable(this, tr("Task aborted"), tr("The task has been aborted by the user."), QMessageBox::Information)
->show();
});
ProgressDialog loadDialog(this);
loadDialog.setSkipButton(true, tr("Abort"));
@ -982,38 +909,30 @@ void MainWindow::finalizeInstance(InstancePtr inst)
{
view->updateGeometries();
setSelectedInstanceById(inst->id());
if (APPLICATION->accounts()->anyAccountIsValid())
{
if (APPLICATION->accounts()->anyAccountIsValid()) {
ProgressDialog loadDialog(this);
auto update = inst->createUpdateTask(Net::Mode::Online);
connect(update.get(), &Task::failed, [this](QString reason)
{
connect(update.get(), &Task::failed, [this](QString reason) {
QString error = QString("Instance load failed: %1").arg(reason);
CustomMessageBox::selectable(this, tr("Error"), error, QMessageBox::Warning)->show();
});
if(update)
{
if (update) {
loadDialog.setSkipButton(true, tr("Abort"));
loadDialog.execWithTask(update.get());
}
}
else
{
CustomMessageBox::selectable(
this,
tr("Error"),
} else {
CustomMessageBox::selectable(this, tr("Error"),
tr("The launcher cannot download Minecraft or update instances unless you have at least "
"one account added.\nPlease add your Mojang or Minecraft account."),
QMessageBox::Warning
)->show();
QMessageBox::Warning)
->show();
}
}
void MainWindow::addInstance(QString url)
{
QString groupName;
do
{
do {
QObject* obj = sender();
if (!obj)
break;
@ -1026,8 +945,7 @@ void MainWindow::addInstance(QString url)
groupName = map["group"].toString();
} while (0);
if(groupName.isEmpty())
{
if (groupName.isEmpty()) {
groupName = APPLICATION->settings()->get("LastUsedGroupForNewInstance").toString();
}
@ -1038,8 +956,7 @@ void MainWindow::addInstance(QString url)
APPLICATION->settings()->set("LastUsedGroupForNewInstance", newInstDlg.instGroup());
InstanceTask* creationTask = newInstDlg.extractTask();
if(creationTask)
{
if (creationTask) {
instanceFromInstanceTask(creationTask);
}
}
@ -1133,8 +1050,7 @@ void MainWindow::on_actionChangeInstIcon_triggered()
IconPickerDialog dlg(this);
dlg.execWithSelection(m_selectedInstance->iconKey());
if (dlg.result() == QDialog::Accepted)
{
if (dlg.result() == QDialog::Accepted) {
m_selectedInstance->setIconKey(dlg.selectedIconKey);
auto icon = APPLICATION->icons()->getIcon(dlg.selectedIconKey);
ui->actionChangeInstIcon->setIcon(icon);
@ -1144,8 +1060,7 @@ void MainWindow::on_actionChangeInstIcon_triggered()
void MainWindow::iconUpdated(QString icon)
{
if (icon == m_currentInstIcon)
{
if (icon == m_currentInstIcon) {
auto icon = APPLICATION->icons()->getIcon(m_currentInstIcon);
ui->actionChangeInstIcon->setIcon(icon);
changeIconButton->setIcon(icon);
@ -1165,8 +1080,7 @@ void MainWindow::setSelectedInstanceById(const QString &id)
if (id.isNull())
return;
const QModelIndex index = APPLICATION->instances()->getInstanceIndexById(id);
if (index.isValid())
{
if (index.isValid()) {
QModelIndex selectionIndex = proxymodel->mapFromSource(index);
view->selectionModel()->setCurrentIndex(selectionIndex, QItemSelectionModel::ClearAndSelect);
updateStatusCenter();
@ -1188,8 +1102,7 @@ void MainWindow::on_actionChangeInstGroup_triggered()
name = QInputDialog::getItem(this, tr("Group name"), tr("Enter a new group name."), groups, foo, true, &ok);
name = name.simplified();
if (ok)
{
if (ok) {
APPLICATION->instances()->setInstanceGroup(instId, name);
}
}
@ -1206,12 +1119,10 @@ void MainWindow::deleteGroup()
if (!map.contains("group"))
return;
QString groupName = map["group"].toString();
if(!groupName.isEmpty())
{
auto reply = QMessageBox::question(this, tr("Delete group"), tr("Are you sure you want to delete the group %1?")
.arg(groupName), QMessageBox::Yes | QMessageBox::No);
if(reply == QMessageBox::Yes)
{
if (!groupName.isEmpty()) {
auto reply = QMessageBox::question(this, tr("Delete group"), tr("Are you sure you want to delete the group %1?").arg(groupName),
QMessageBox::Yes | QMessageBox::No);
if (reply == QMessageBox::Yes) {
APPLICATION->instances()->deleteGroup(groupName);
}
}
@ -1247,12 +1158,9 @@ void MainWindow::on_actionViewCentralModsFolder_triggered()
void MainWindow::checkForUpdates()
{
if(BuildConfig.UPDATER_ENABLED)
{
if (BuildConfig.UPDATER_ENABLED) {
APPLICATION->triggerUpdateCheck();
}
else
{
} else {
qWarning() << "Updater not set up. Cannot check for updates.";
}
}
@ -1280,7 +1188,6 @@ void MainWindow::globalSettingsClosed()
void MainWindow::on_actionEditInstance_triggered()
{
if (!m_selectedInstance)
return;
@ -1289,7 +1196,8 @@ void MainWindow::on_actionEditInstance_triggered()
} else {
CustomMessageBox::selectable(this, tr("Instance not editable"),
tr("This instance is not editable. It may be broken, invalid, or too old. Check logs for details."),
QMessageBox::Critical)->show();
QMessageBox::Critical)
->show();
}
}
@ -1352,7 +1260,8 @@ void MainWindow::newsButtonClicked()
news_dialog.exec();
}
void MainWindow::onCatChanged(int) {
void MainWindow::onCatChanged(int)
{
setCatBackground(APPLICATION->settings()->get("TheCat").toBool());
}
@ -1383,14 +1292,15 @@ void MainWindow::on_actionDeleteInstance_triggered()
auto linkedInstances = APPLICATION->instances()->getLinkedInstancesById(id);
if (!linkedInstances.empty()) {
response = CustomMessageBox::selectable(
this, tr("There are linked instances"),
response = CustomMessageBox::selectable(this, tr("There are linked instances"),
tr("The following instance(s) might reference files in this instance:\n\n"
"%1\n\n"
"Deleting it could break the other instance(s), \n\n"
"Do you wish to proceed?", nullptr, linkedInstances.count()).arg(linkedInstances.join("\n")),
QMessageBox::Warning, QMessageBox::Yes | QMessageBox::No, QMessageBox::No
)->exec();
"Do you wish to proceed?",
nullptr, linkedInstances.count())
.arg(linkedInstances.join("\n")),
QMessageBox::Warning, QMessageBox::Yes | QMessageBox::No, QMessageBox::No)
->exec();
if (response != QMessageBox::Yes)
return;
}
@ -1405,8 +1315,7 @@ void MainWindow::on_actionDeleteInstance_triggered()
void MainWindow::on_actionExportInstanceZip_triggered()
{
if (m_selectedInstance)
{
if (m_selectedInstance) {
ExportInstanceDialog dlg(m_selectedInstance, this);
dlg.exec();
}
@ -1414,13 +1323,20 @@ void MainWindow::on_actionExportInstanceZip_triggered()
void MainWindow::on_actionExportInstanceMrPack_triggered()
{
if (m_selectedInstance)
{
if (m_selectedInstance) {
ExportPackDialog dlg(m_selectedInstance, this);
dlg.exec();
}
}
void MainWindow::on_actionExportInstanceToModList_triggered()
{
if (m_selectedInstance) {
ExportToModListDialog dlg(m_selectedInstance, this);
dlg.exec();
}
}
void MainWindow::on_actionExportInstanceFlamePack_triggered()
{
if (m_selectedInstance) {
@ -1447,16 +1363,14 @@ void MainWindow::on_actionExportInstanceFlamePack_triggered()
void MainWindow::on_actionRenameInstance_triggered()
{
if (m_selectedInstance)
{
if (m_selectedInstance) {
view->edit(view->currentIndex());
}
}
void MainWindow::on_actionViewSelectedInstFolder_triggered()
{
if (m_selectedInstance)
{
if (m_selectedInstance) {
QString str = m_selectedInstance->instanceRoot();
DesktopServices::openDirectory(QDir(str).absolutePath());
}
@ -1474,8 +1388,7 @@ void MainWindow::closeEvent(QCloseEvent *event)
void MainWindow::changeEvent(QEvent* event)
{
if (event->type() == QEvent::LanguageChange)
{
if (event->type() == QEvent::LanguageChange) {
retranslateUi();
}
QMainWindow::changeEvent(event);
@ -1495,8 +1408,7 @@ void MainWindow::instanceActivated(QModelIndex index)
void MainWindow::on_actionLaunchInstance_triggered()
{
if(m_selectedInstance && !m_selectedInstance->isRunning())
{
if (m_selectedInstance && !m_selectedInstance->isRunning()) {
APPLICATION->launch(m_selectedInstance);
}
}
@ -1508,24 +1420,21 @@ void MainWindow::activateInstance(InstancePtr instance)
void MainWindow::on_actionLaunchInstanceOffline_triggered()
{
if (m_selectedInstance)
{
if (m_selectedInstance) {
APPLICATION->launch(m_selectedInstance, false);
}
}
void MainWindow::on_actionLaunchInstanceDemo_triggered()
{
if (m_selectedInstance)
{
if (m_selectedInstance) {
APPLICATION->launch(m_selectedInstance, false, true);
}
}
void MainWindow::on_actionKillInstance_triggered()
{
if(m_selectedInstance && m_selectedInstance->isRunning())
{
if (m_selectedInstance && m_selectedInstance->isRunning()) {
APPLICATION->kill(m_selectedInstance);
}
}
@ -1554,16 +1463,14 @@ void MainWindow::on_actionCreateInstanceShortcut_triggered()
}
auto pIcon = APPLICATION->icons()->icon(m_selectedInstance->iconKey());
if (pIcon == nullptr)
{
if (pIcon == nullptr) {
pIcon = APPLICATION->icons()->icon("grass");
}
iconPath = FS::PathCombine(m_selectedInstance->instanceRoot(), "Icon.icns");
QFile iconFile(iconPath);
if (!iconFile.open(QFile::WriteOnly))
{
if (!iconFile.open(QFile::WriteOnly)) {
QMessageBox::critical(this, tr("Create instance Application"), tr("Failed to create icon for Application."));
return;
}
@ -1573,8 +1480,7 @@ void MainWindow::on_actionCreateInstanceShortcut_triggered()
bool success = icon.pixmap(1024, 1024).save(iconPath, "ICNS");
iconFile.close();
if (!success)
{
if (!success) {
iconFile.remove();
QMessageBox::critical(this, tr("Create instance Application"), tr("Failed to create icon for Application."));
return;
@ -1692,8 +1598,7 @@ void MainWindow::startTask(Task *task)
void MainWindow::instanceChanged(const QModelIndex& current, const QModelIndex& previous)
{
if (!current.isValid())
{
if (!current.isValid()) {
APPLICATION->settings()->set("SelectedInstance", QString());
selectionBad();
return;
@ -1703,8 +1608,7 @@ void MainWindow::instanceChanged(const QModelIndex &current, const QModelIndex &
}
QString id = current.data(InstanceList::InstanceIDRole).toString();
m_selectedInstance = APPLICATION->instances()->getInstanceById(id);
if (m_selectedInstance)
{
if (m_selectedInstance) {
ui->instanceToolBar->setEnabled(true);
setInstanceActionsEnabled(true);
ui->actionLaunchInstance->setEnabled(m_selectedInstance->canLaunch());
@ -1729,9 +1633,7 @@ void MainWindow::instanceChanged(const QModelIndex &current, const QModelIndex &
APPLICATION->settings()->set("SelectedInstance", m_selectedInstance->id());
connect(m_selectedInstance.get(), &BaseInstance::runningStatusChanged, this, &MainWindow::refreshCurrentInstance);
}
else
{
} else {
ui->instanceToolBar->setEnabled(false);
setInstanceActionsEnabled(false);
ui->actionLaunchInstance->setEnabled(false);
@ -1753,8 +1655,7 @@ void MainWindow::instanceDataChanged(const QModelIndex &topLeft, const QModelInd
{
auto current = view->selectionModel()->currentIndex();
QItemSelection test(topLeft, bottomRight);
if (test.contains(current))
{
if (test.contains(current)) {
instanceChanged(current, current);
}
}
@ -1778,34 +1679,28 @@ void MainWindow::selectionBad()
void MainWindow::checkInstancePathForProblems()
{
QString instanceFolder = APPLICATION->settings()->get("InstanceDir").toString();
if (FS::checkProblemticPathJava(QDir(instanceFolder)))
{
if (FS::checkProblemticPathJava(QDir(instanceFolder))) {
QMessageBox warning(this);
warning.setText(tr("Your instance folder contains \'!\' and this is known to cause Java problems!"));
warning.setInformativeText(
tr(
"You have now two options: <br/>"
warning.setInformativeText(tr("You have now two options: <br/>"
" - change the instance folder in the settings <br/>"
" - move this installation of %1 to a different folder"
).arg(BuildConfig.LAUNCHER_DISPLAYNAME)
);
" - move this installation of %1 to a different folder")
.arg(BuildConfig.LAUNCHER_DISPLAYNAME));
warning.setDefaultButton(QMessageBox::Ok);
warning.exec();
}
auto tempFolderText = tr("This is a problem: <br/>"
auto tempFolderText =
tr("This is a problem: <br/>"
" - The launcher will likely be deleted without warning by the operating system <br/>"
" - close the launcher now and extract it to a real location, not a temporary folder");
QString pathfoldername = QDir(instanceFolder).absolutePath();
if (pathfoldername.contains("Rar$", Qt::CaseInsensitive))
{
if (pathfoldername.contains("Rar$", Qt::CaseInsensitive)) {
QMessageBox warning(this);
warning.setText(tr("Your instance folder contains \'Rar$\' - that means you haven't extracted the launcher archive!"));
warning.setInformativeText(tempFolderText);
warning.setDefaultButton(QMessageBox::Ok);
warning.exec();
}
else if (pathfoldername.startsWith(QDir::tempPath()) || pathfoldername.contains("/TempState/"))
{
} else if (pathfoldername.startsWith(QDir::tempPath()) || pathfoldername.contains("/TempState/")) {
QMessageBox warning(this);
warning.setText(tr("Your instance folder is in a temporary folder: \'%1\'!").arg(QDir::tempPath()));
warning.setInformativeText(tempFolderText);

View File

@ -158,6 +158,7 @@ private slots:
void on_actionExportInstanceZip_triggered();
void on_actionExportInstanceMrPack_triggered();
void on_actionExportInstanceFlamePack_triggered();
void on_actionExportInstanceToModList_triggered();
void on_actionRenameInstance_triggered();

View File

@ -487,6 +487,14 @@
<string>CurseForge (zip)</string>
</property>
</action>
<action name="actionExportInstanceToModList">
<property name="icon">
<iconset theme="new"/>
</property>
<property name="text">
<string>Mod List</string>
</property>
</action>
<action name="actionCreateInstanceShortcut">
<property name="icon">
<iconset theme="shortcut">

View File

@ -0,0 +1,223 @@
// SPDX-License-Identifier: GPL-3.0-only
/*
* Prism Launcher - Minecraft Launcher
* Copyright (c) 2023 Trial97 <alexandru.tripon97@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include "ExportToModListDialog.h"
#include <QCheckBox>
#include <QComboBox>
#include <QTextEdit>
#include "FileSystem.h"
#include "Markdown.h"
#include "minecraft/MinecraftInstance.h"
#include "minecraft/mod/ModFolderModel.h"
#include "modplatform/helpers/ExportToModList.h"
#include "ui_ExportToModListDialog.h"
#include <QFileDialog>
#include <QFileSystemModel>
#include <QJsonDocument>
#include <QMessageBox>
#include <QPushButton>
const QHash<ExportToModList::Formats, QString> ExportToModListDialog::exampleLines = {
{ ExportToModList::HTML, "<li><a href=\"{url}\">{name}</a> [{version}] by {authors}</li>" },
{ ExportToModList::MARKDOWN, "[{name}]({url}) [{version}] by {authors}" },
{ ExportToModList::PLAINTXT, "{name} ({url}) [{version}] by {authors}" },
{ ExportToModList::JSON, "{\"name\":\"{name}\",\"url\":\"{url}\",\"version\":\"{version}\",\"authors\":\"{authors}\"}," },
{ ExportToModList::CSV, "{name},{url},{version},\"{authors}\"" },
};
ExportToModListDialog::ExportToModListDialog(InstancePtr instance, QWidget* parent)
: QDialog(parent), m_template_changed(false), name(instance->name()), ui(new Ui::ExportToModListDialog)
{
ui->setupUi(this);
enableCustom(false);
MinecraftInstance* mcInstance = dynamic_cast<MinecraftInstance*>(instance.get());
if (mcInstance) {
mcInstance->loaderModList()->update();
connect(mcInstance->loaderModList().get(), &ModFolderModel::updateFinished, this, [this, mcInstance]() {
m_allMods = mcInstance->loaderModList()->allMods();
triggerImp();
});
}
connect(ui->formatComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &ExportToModListDialog::formatChanged);
connect(ui->authorsCheckBox, &QCheckBox::stateChanged, this, &ExportToModListDialog::trigger);
connect(ui->versionCheckBox, &QCheckBox::stateChanged, this, &ExportToModListDialog::trigger);
connect(ui->urlCheckBox, &QCheckBox::stateChanged, this, &ExportToModListDialog::trigger);
connect(ui->authorsButton, &QPushButton::clicked, this, [this](bool) { addExtra(ExportToModList::Authors); });
connect(ui->versionButton, &QPushButton::clicked, this, [this](bool) { addExtra(ExportToModList::Version); });
connect(ui->urlButton, &QPushButton::clicked, this, [this](bool) { addExtra(ExportToModList::Url); });
connect(ui->templateText, &QTextEdit::textChanged, this, [this] {
if (ui->templateText->toPlainText() != exampleLines[format])
ui->formatComboBox->setCurrentIndex(5);
else
triggerImp();
});
connect(ui->copyButton, &QPushButton::clicked, this, [this](bool) {
this->ui->finalText->selectAll();
this->ui->finalText->copy();
});
}
ExportToModListDialog::~ExportToModListDialog()
{
delete ui;
}
void ExportToModListDialog::formatChanged(int index)
{
switch (index) {
case 0: {
enableCustom(false);
ui->resultText->show();
format = ExportToModList::HTML;
break;
}
case 1: {
enableCustom(false);
ui->resultText->show();
format = ExportToModList::MARKDOWN;
break;
}
case 2: {
enableCustom(false);
ui->resultText->hide();
format = ExportToModList::PLAINTXT;
break;
}
case 3: {
enableCustom(false);
ui->resultText->hide();
format = ExportToModList::JSON;
break;
}
case 4: {
enableCustom(false);
ui->resultText->hide();
format = ExportToModList::CSV;
break;
}
case 5: {
m_template_changed = true;
enableCustom(true);
ui->resultText->hide();
format = ExportToModList::CUSTOM;
break;
}
}
triggerImp();
}
void ExportToModListDialog::triggerImp()
{
if (format == ExportToModList::CUSTOM) {
ui->finalText->setPlainText(ExportToModList::exportToModList(m_allMods, ui->templateText->toPlainText()));
return;
}
auto opt = 0;
if (ui->authorsCheckBox->isChecked())
opt |= ExportToModList::Authors;
if (ui->versionCheckBox->isChecked())
opt |= ExportToModList::Version;
if (ui->urlCheckBox->isChecked())
opt |= ExportToModList::Url;
auto txt = ExportToModList::exportToModList(m_allMods, format, static_cast<ExportToModList::OptionalData>(opt));
ui->finalText->setPlainText(txt);
switch (format) {
case ExportToModList::CUSTOM:
return;
case ExportToModList::HTML:
ui->resultText->setHtml(txt);
break;
case ExportToModList::MARKDOWN:
ui->resultText->setHtml(markdownToHTML(txt));
break;
case ExportToModList::PLAINTXT:
break;
case ExportToModList::JSON:
break;
case ExportToModList::CSV:
break;
}
auto exampleLine = exampleLines[format];
if (!m_template_changed && ui->templateText->toPlainText() != exampleLine)
ui->templateText->setPlainText(exampleLine);
}
void ExportToModListDialog::done(int result)
{
if (result == Accepted) {
const QString filename = FS::RemoveInvalidFilenameChars(name);
const QString output =
QFileDialog::getSaveFileName(this, tr("Export %1").arg(name), FS::PathCombine(QDir::homePath(), filename + extension()),
"File (*.txt *.html *.md *.json *.csv)", nullptr);
if (output.isEmpty())
return;
FS::write(output, ui->finalText->toPlainText().toUtf8());
}
QDialog::done(result);
}
QString ExportToModListDialog::extension()
{
switch (format) {
case ExportToModList::HTML:
return ".html";
case ExportToModList::MARKDOWN:
return ".md";
case ExportToModList::PLAINTXT:
return ".txt";
case ExportToModList::CUSTOM:
return ".txt";
case ExportToModList::JSON:
return ".json";
case ExportToModList::CSV:
return ".csv";
}
return ".txt";
}
void ExportToModListDialog::addExtra(ExportToModList::OptionalData option)
{
if (format != ExportToModList::CUSTOM)
return;
switch (option) {
case ExportToModList::Authors:
ui->templateText->insertPlainText("{authors}");
break;
case ExportToModList::Url:
ui->templateText->insertPlainText("{url}");
break;
case ExportToModList::Version:
ui->templateText->insertPlainText("{version}");
break;
}
}
void ExportToModListDialog::enableCustom(bool enabled)
{
ui->authorsCheckBox->setHidden(enabled);
ui->versionCheckBox->setHidden(enabled);
ui->urlCheckBox->setHidden(enabled);
ui->authorsButton->setHidden(!enabled);
ui->versionButton->setHidden(!enabled);
ui->urlButton->setHidden(!enabled);
}

View File

@ -0,0 +1,55 @@
// SPDX-License-Identifier: GPL-3.0-only
/*
* Prism Launcher - Minecraft Launcher
* Copyright (c) 2023 Trial97 <alexandru.tripon97@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#pragma once
#include <QDialog>
#include <QList>
#include "BaseInstance.h"
#include "minecraft/mod/Mod.h"
#include "modplatform/helpers/ExportToModList.h"
namespace Ui {
class ExportToModListDialog;
}
class ExportToModListDialog : public QDialog {
Q_OBJECT
public:
explicit ExportToModListDialog(InstancePtr instance, QWidget* parent = nullptr);
~ExportToModListDialog();
void done(int result) override;
protected slots:
void formatChanged(int index);
void triggerImp();
void trigger(int) { triggerImp(); };
void addExtra(ExportToModList::OptionalData option);
private:
QString extension();
void enableCustom(bool enabled);
QList<Mod*> m_allMods;
bool m_template_changed;
QString name;
ExportToModList::Formats format = ExportToModList::Formats::HTML;
Ui::ExportToModListDialog* ui;
static const QHash<ExportToModList::Formats, QString> exampleLines;
};

View File

@ -0,0 +1,240 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ExportToModListDialog</class>
<widget class="QDialog" name="ExportToModListDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>650</width>
<height>446</height>
</rect>
</property>
<property name="windowTitle">
<string>Export Pack to ModList</string>
</property>
<property name="sizeGripEnabled">
<bool>true</bool>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<layout class="QVBoxLayout" name="verticalLayout" stretch="0,0,0">
<item>
<widget class="QGroupBox" name="groupBox_3">
<property name="title">
<string>Settings</string>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="1">
<widget class="QComboBox" name="formatComboBox">
<item>
<property name="text">
<string>HTML</string>
</property>
</item>
<item>
<property name="text">
<string>Markdown</string>
</property>
</item>
<item>
<property name="text">
<string>Plaintext</string>
</property>
</item>
<item>
<property name="text">
<string>JSON</string>
</property>
</item>
<item>
<property name="text">
<string>CSV</string>
</property>
</item>
<item>
<property name="text">
<string>Custom</string>
</property>
</item>
</widget>
</item>
<item row="1" column="0">
<widget class="QGroupBox" name="templateGroup">
<property name="title">
<string>Template</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
<widget class="QTextEdit" name="templateText"/>
</item>
</layout>
</widget>
</item>
<item row="1" column="1">
<widget class="QGroupBox" name="optionsGroup">
<property name="title">
<string>Optional Info</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_5">
<item>
<widget class="QCheckBox" name="versionCheckBox">
<property name="text">
<string>Version</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="authorsCheckBox">
<property name="text">
<string>Authors</string>
</property>
</widget>
</item>
<item>
<widget class="QCheckBox" name="urlCheckBox">
<property name="text">
<string>URL</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="versionButton">
<property name="text">
<string>Version</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="authorsButton">
<property name="text">
<string>Authors</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="urlButton">
<property name="text">
<string>URL</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="label">
<property name="frameShape">
<enum>QFrame::NoFrame</enum>
</property>
<property name="frameShadow">
<enum>QFrame::Plain</enum>
</property>
<property name="lineWidth">
<number>1</number>
</property>
<property name="text">
<string>Format</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_4">
<property name="title">
<string>Result</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QPlainTextEdit" name="finalText">
<property name="minimumSize">
<size>
<width>0</width>
<height>143</height>
</size>
</property>
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QTextBrowser" name="resultText">
<property name="openExternalLinks">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QLabel" name="warningLabel">
<property name="text">
<string>This depends on the mods' metadata. To ensure it is available, run an update on the instance. Installing the updates isn't necessary.</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QPushButton" name="copyButton">
<property name="text">
<string>Copy</string>
</property>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Save</set>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>ExportToModListDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>334</x>
<y>435</y>
</hint>
<hint type="destinationlabel">
<x>324</x>
<y>206</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>ExportToModListDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>324</x>
<y>390</y>
</hint>
<hint type="destinationlabel">
<x>324</x>
<y>206</y>
</hint>
</hints>
</connection>
</connections>
</ui>