Merge remote-tracking branch 'upstream/develop' into resource-meta

Signed-off-by: TheKodeToad <TheKodeToad@proton.me>
This commit is contained in:
TheKodeToad
2024-10-08 17:15:42 +01:00
534 changed files with 14803 additions and 8430 deletions

View File

@@ -98,6 +98,7 @@ ExternalResourcesPage::ExternalResourcesPage(BaseInstance* instance, std::shared
connect(selection_model, &QItemSelectionModel::selectionChanged, this, updateExtra);
connect(model.get(), &ResourceFolderModel::updateFinished, this, updateExtra);
connect(model.get(), &ResourceFolderModel::parseFinished, this, updateExtra);
connect(selection_model, &QItemSelectionModel::selectionChanged, this, [this] { updateActions(); });
connect(m_model.get(), &ResourceFolderModel::rowsInserted, this, [this] { updateActions(); });

View File

@@ -60,7 +60,7 @@
<bool>true</bool>
</property>
<property name="dragDropMode">
<enum>QAbstractItemView::DropOnly</enum>
<enum>QAbstractItemView::DragDropMode::DropOnly</enum>
</property>
<property name="uniformRowHeights">
<bool>true</bool>
@@ -74,7 +74,7 @@
<string>Actions</string>
</property>
<property name="toolButtonStyle">
<enum>Qt::ToolButtonTextOnly</enum>
<enum>Qt::ToolButtonStyle::ToolButtonTextOnly</enum>
</property>
<property name="useDefaultAction" stdset="0">
<bool>true</bool>
@@ -177,7 +177,7 @@
<string>Reset Update Metadata</string>
</property>
<property name="menuRole">
<enum>QAction::NoRole</enum>
<enum>QAction::MenuRole::NoRole</enum>
</property>
</action>
<action name="actionVerifyItemDependencies">
@@ -185,7 +185,29 @@
<string>Verify Dependencies</string>
</property>
<property name="menuRole">
<enum>QAction::NoRole</enum>
<enum>QAction::MenuRole::NoRole</enum>
</property>
</action>
<action name="actionExportMetadata">
<property name="enabled">
<bool>true</bool>
</property>
<property name="text">
<string>Export List</string>
</property>
<property name="toolTip">
<string>Export resource's metadata to text.</string>
</property>
</action>
<action name="actionChangeVersion">
<property name="text">
<string>Change Version</string>
</property>
<property name="toolTip">
<string>Change a resource's version.</string>
</property>
<property name="menuRole">
<enum>QAction::MenuRole::NoRole</enum>
</property>
</action>
</widget>

View File

@@ -36,6 +36,11 @@
*/
#include "InstanceSettingsPage.h"
#include "minecraft/MinecraftInstance.h"
#include "minecraft/WorldList.h"
#include "settings/Setting.h"
#include "ui/dialogs/CustomMessageBox.h"
#include "ui/java/InstallJavaDialog.h"
#include "ui_InstanceSettingsPage.h"
#include <QDialog>
@@ -62,6 +67,8 @@ InstanceSettingsPage::InstanceSettingsPage(BaseInstance* inst, QWidget* parent)
m_settings = inst->settings();
ui->setupUi(this);
ui->javaDownloadBtn->setHidden(!BuildConfig.JAVA_DOWNLOADER_ENABLED);
connect(ui->openGlobalJavaSettingsButton, &QCommandLinkButton::clicked, this, &InstanceSettingsPage::globalSettingsButtonClicked);
connect(APPLICATION, &Application::globalSettingsAboutToOpen, this, &InstanceSettingsPage::applySettings);
connect(APPLICATION, &Application::globalSettingsClosed, this, &InstanceSettingsPage::loadSettings);
@@ -71,6 +78,22 @@ InstanceSettingsPage::InstanceSettingsPage(BaseInstance* inst, QWidget* parent)
connect(ui->useNativeGLFWCheck, &QAbstractButton::toggled, this, &InstanceSettingsPage::onUseNativeGLFWChanged);
connect(ui->useNativeOpenALCheck, &QAbstractButton::toggled, this, &InstanceSettingsPage::onUseNativeOpenALChanged);
auto mInst = dynamic_cast<MinecraftInstance*>(inst);
m_world_quickplay_supported = mInst && mInst->traits().contains("feature:is_quick_play_singleplayer");
if (m_world_quickplay_supported) {
auto worlds = mInst->worldList();
worlds->update();
for (const auto& world : worlds->allWorlds()) {
ui->worldsCb->addItem(world.folderName());
}
} else {
ui->worldsCb->hide();
ui->worldJoinButton->hide();
ui->serverJoinAddressButton->setChecked(true);
ui->serverJoinAddress->setEnabled(true);
ui->serverJoinAddressButton->setStyleSheet("QRadioButton::indicator { width: 0px; height: 0px; }");
}
loadSettings();
updateThresholds();
@@ -186,9 +209,6 @@ void InstanceSettingsPage::applySettings()
m_settings->reset("JvmArgs");
}
// old generic 'override both' is removed.
m_settings->reset("OverrideJava");
// Custom Commands
bool custcmd = ui->customCommands->checked();
m_settings->set("OverrideCommands", custcmd);
@@ -256,9 +276,16 @@ void InstanceSettingsPage::applySettings()
bool joinServerOnLaunch = ui->serverJoinGroupBox->isChecked();
m_settings->set("JoinServerOnLaunch", joinServerOnLaunch);
if (joinServerOnLaunch) {
m_settings->set("JoinServerOnLaunchAddress", ui->serverJoinAddress->text());
if (ui->serverJoinAddressButton->isChecked() || !m_world_quickplay_supported) {
m_settings->set("JoinServerOnLaunchAddress", ui->serverJoinAddress->text());
m_settings->reset("JoinWorldOnLaunch");
} else {
m_settings->set("JoinWorldOnLaunch", ui->worldsCb->currentText());
m_settings->reset("JoinServerOnLaunchAddress");
}
} else {
m_settings->reset("JoinServerOnLaunchAddress");
m_settings->reset("JoinWorldOnLaunch");
}
// Use an account for this instance
@@ -317,12 +344,16 @@ void InstanceSettingsPage::loadSettings()
ui->labelPermgenNote->setVisible(permGenVisible);
// Java Settings
bool overrideJava = m_settings->get("OverrideJava").toBool();
bool overrideLocation = m_settings->get("OverrideJavaLocation").toBool() || overrideJava;
bool overrideArgs = m_settings->get("OverrideJavaArgs").toBool() || overrideJava;
bool overrideLocation = m_settings->get("OverrideJavaLocation").toBool();
bool overrideArgs = m_settings->get("OverrideJavaArgs").toBool();
connect(m_settings->getSetting("OverrideJavaLocation").get(), &Setting::SettingChanged, ui->javaSettingsGroupBox,
[this] { ui->javaSettingsGroupBox->setChecked(m_settings->get("OverrideJavaLocation").toBool()); });
ui->javaSettingsGroupBox->setChecked(overrideLocation);
ui->javaPathTextBox->setText(m_settings->get("JavaPath").toString());
connect(m_settings->getSetting("JavaPath").get(), &Setting::SettingChanged, ui->javaSettingsGroupBox,
[this] { ui->javaPathTextBox->setText(m_settings->get("JavaPath").toString()); });
ui->skipCompatibilityCheckbox->setChecked(m_settings->get("IgnoreJavaCompatibility").toBool());
ui->javaArgumentsGroupBox->setChecked(overrideArgs);
@@ -379,7 +410,25 @@ void InstanceSettingsPage::loadSettings()
ui->recordGameTime->setChecked(m_settings->get("RecordGameTime").toBool());
ui->serverJoinGroupBox->setChecked(m_settings->get("JoinServerOnLaunch").toBool());
ui->serverJoinAddress->setText(m_settings->get("JoinServerOnLaunchAddress").toString());
if (auto server = m_settings->get("JoinServerOnLaunchAddress").toString(); !server.isEmpty()) {
ui->serverJoinAddress->setText(server);
ui->serverJoinAddressButton->setChecked(true);
ui->worldJoinButton->setChecked(false);
ui->serverJoinAddress->setEnabled(true);
ui->worldsCb->setEnabled(false);
} else if (auto world = m_settings->get("JoinWorldOnLaunch").toString(); !world.isEmpty() && m_world_quickplay_supported) {
ui->worldsCb->setCurrentText(world);
ui->serverJoinAddressButton->setChecked(false);
ui->worldJoinButton->setChecked(true);
ui->serverJoinAddress->setEnabled(false);
ui->worldsCb->setEnabled(true);
} else {
ui->serverJoinAddressButton->setChecked(true);
ui->worldJoinButton->setChecked(false);
ui->serverJoinAddress->setEnabled(true);
ui->worldsCb->setEnabled(false);
}
ui->instanceAccountGroupBox->setChecked(m_settings->get("UseAccountForInstance").toBool());
updateAccountsMenu();
@@ -388,6 +437,12 @@ void InstanceSettingsPage::loadSettings()
ui->onlineFixes->setChecked(m_settings->get("OnlineFixes").toBool());
}
void InstanceSettingsPage::on_javaDownloadBtn_clicked()
{
auto jdialog = new Java::InstallDialog({}, m_instance, this);
jdialog->exec();
}
void InstanceSettingsPage::on_javaDetectBtn_clicked()
{
if (JavaUtils::getJavaCheckPath().isEmpty()) {
@@ -409,6 +464,15 @@ void InstanceSettingsPage::on_javaDetectBtn_clicked()
ui->labelPermGen->setVisible(visible);
ui->labelPermgenNote->setVisible(visible);
m_settings->set("PermGenVisible", visible);
if (!java->is_64bit && m_settings->get("MaxMemAlloc").toInt() > 2048) {
CustomMessageBox::selectable(this, tr("Confirm Selection"),
tr("You selected a 32-bit version of Java.\n"
"This installation does not support more than 2048MiB of RAM.\n"
"Please make sure that the maximum memory value is lower."),
QMessageBox::Warning, QMessageBox::Ok, QMessageBox::Ok)
->exec();
}
}
}
@@ -534,3 +598,13 @@ void InstanceSettingsPage::updateThresholds()
ui->labelMaxMemIcon->setPixmap(pix);
}
}
void InstanceSettingsPage::on_serverJoinAddressButton_toggled(bool checked)
{
ui->serverJoinAddress->setEnabled(checked);
}
void InstanceSettingsPage::on_worldJoinButton_toggled(bool checked)
{
ui->worldsCb->setEnabled(checked);
}

View File

@@ -69,7 +69,10 @@ class InstanceSettingsPage : public QWidget, public BasePage {
void on_javaDetectBtn_clicked();
void on_javaTestBtn_clicked();
void on_javaBrowseBtn_clicked();
void on_javaDownloadBtn_clicked();
void on_maxMemSpinBox_valueChanged(int i);
void on_serverJoinAddressButton_toggled(bool checked);
void on_worldJoinButton_toggled(bool checked);
void onUseNativeGLFWChanged(bool checked);
void onUseNativeOpenALChanged(bool checked);
@@ -90,4 +93,5 @@ class InstanceSettingsPage : public QWidget, public BasePage {
BaseInstance* m_instance;
SettingsObjectPtr m_settings;
unique_qobject_ptr<JavaCommon::TestCheck> checker;
bool m_world_quickplay_supported;
};

View File

@@ -84,6 +84,13 @@
</item>
<item row="2" column="0">
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QPushButton" name="javaDownloadBtn">
<property name="text">
<string>Download Java</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="javaDetectBtn">
<property name="text">
@@ -660,7 +667,7 @@
<item>
<widget class="QGroupBox" name="serverJoinGroupBox">
<property name="title">
<string>Set a server to join on launch</string>
<string>Set a target to join on launch</string>
</property>
<property name="checkable">
<bool>true</bool>
@@ -668,26 +675,26 @@
<property name="checked">
<bool>false</bool>
</property>
<layout class="QVBoxLayout" name="verticalLayout_11">
<item>
<layout class="QGridLayout" name="serverJoinLayout">
<item row="0" column="0">
<widget class="QLabel" name="serverJoinAddressLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>Server address:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLineEdit" name="serverJoinAddress"/>
</item>
</layout>
<layout class="QGridLayout" name="gridLayout_4">
<item row="0" column="0">
<widget class="QRadioButton" name="serverJoinAddressButton">
<property name="text">
<string>Server address:</string>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QLineEdit" name="serverJoinAddress"/>
</item>
<item row="1" column="0">
<widget class="QRadioButton" name="worldJoinButton">
<property name="text">
<string>Singleplayer world</string>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QComboBox" name="worldsCb"/>
</item>
</layout>
</widget>
@@ -764,6 +771,12 @@
<tabstop>openGlobalJavaSettingsButton</tabstop>
<tabstop>settingsTabs</tabstop>
<tabstop>javaSettingsGroupBox</tabstop>
<tabstop>javaPathTextBox</tabstop>
<tabstop>javaBrowseBtn</tabstop>
<tabstop>javaDownloadBtn</tabstop>
<tabstop>javaDetectBtn</tabstop>
<tabstop>javaTestBtn</tabstop>
<tabstop>skipCompatibilityCheckbox</tabstop>
<tabstop>memoryGroupBox</tabstop>
<tabstop>minMemSpinBox</tabstop>
<tabstop>maxMemSpinBox</tabstop>
@@ -783,6 +796,18 @@
<tabstop>useNativeOpenALCheck</tabstop>
<tabstop>showGameTime</tabstop>
<tabstop>recordGameTime</tabstop>
<tabstop>miscellaneousSettingsBox</tabstop>
<tabstop>closeAfterLaunchCheck</tabstop>
<tabstop>quitAfterGameStopCheck</tabstop>
<tabstop>perfomanceGroupBox</tabstop>
<tabstop>enableFeralGamemodeCheck</tabstop>
<tabstop>enableMangoHud</tabstop>
<tabstop>useDiscreteGpuCheck</tabstop>
<tabstop>gameTimeGroupBox</tabstop>
<tabstop>serverJoinGroupBox</tabstop>
<tabstop>serverJoinAddress</tabstop>
<tabstop>instanceAccountGroupBox</tabstop>
<tabstop>instanceAccountSelector</tabstop>
</tabstops>
<resources/>
<connections/>

View File

@@ -3,7 +3,7 @@
* 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>
* Copyright (C) 2024 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
@@ -47,8 +47,8 @@
#include "launch/LaunchTask.h"
#include "settings/Setting.h"
#include "ui/ColorCache.h"
#include "ui/GuiUtil.h"
#include "ui/themes/ThemeManager.h"
#include <BuildConfig.h>
@@ -57,26 +57,36 @@ class LogFormatProxyModel : public QIdentityProxyModel {
LogFormatProxyModel(QObject* parent = nullptr) : QIdentityProxyModel(parent) {}
QVariant data(const QModelIndex& index, int role) const override
{
const LogColors& colors = APPLICATION->themeManager()->getLogColors();
switch (role) {
case Qt::FontRole:
return m_font;
case Qt::ForegroundRole: {
MessageLevel::Enum level = (MessageLevel::Enum)QIdentityProxyModel::data(index, LogModel::LevelRole).toInt();
return m_colors->getFront(level);
auto level = static_cast<MessageLevel::Enum>(QIdentityProxyModel::data(index, LogModel::LevelRole).toInt());
QColor result = colors.foreground.value(level);
if (result.isValid())
return result;
break;
}
case Qt::BackgroundRole: {
MessageLevel::Enum level = (MessageLevel::Enum)QIdentityProxyModel::data(index, LogModel::LevelRole).toInt();
return m_colors->getBack(level);
auto level = static_cast<MessageLevel::Enum>(QIdentityProxyModel::data(index, LogModel::LevelRole).toInt());
QColor result = colors.background.value(level);
if (result.isValid())
return result;
break;
}
default:
return QIdentityProxyModel::data(index, role);
}
return QIdentityProxyModel::data(index, role);
}
void setFont(QFont font) { m_font = font; }
void setColors(LogColorCache* colors) { m_colors.reset(colors); }
QModelIndex find(const QModelIndex& start, const QString& value, bool reverse) const
{
QModelIndex parentIndex = parent(start);
@@ -125,7 +135,6 @@ class LogFormatProxyModel : public QIdentityProxyModel {
private:
QFont m_font;
std::unique_ptr<LogColorCache> m_colors;
};
LogPage::LogPage(InstancePtr instance, QWidget* parent) : QWidget(parent), ui(new Ui::LogPage), m_instance(instance)
@@ -134,12 +143,6 @@ LogPage::LogPage(InstancePtr instance, QWidget* parent) : QWidget(parent), ui(ne
ui->tabWidget->tabBar()->hide();
m_proxy = new LogFormatProxyModel(this);
// set up text colors in the log proxy and adapt them to the current theme foreground and background
{
auto origForeground = ui->text->palette().color(ui->text->foregroundRole());
auto origBackground = ui->text->palette().color(ui->text->backgroundRole());
m_proxy->setColors(new LogColorCache(origForeground, origBackground));
}
// set up fonts in the log proxy
{

View File

@@ -20,6 +20,7 @@
#include "InstanceTask.h"
#include "Json.h"
#include "Markdown.h"
#include "StringUtils.h"
#include "modplatform/modrinth/ModrinthPackManifest.h"
@@ -332,7 +333,7 @@ void ModrinthManagedPackPage::suggestVersion()
}
auto version = m_pack.versions.at(index);
ui->changelogTextBrowser->setHtml(markdownToHTML(version.changelog.toUtf8()));
ui->changelogTextBrowser->setHtml(StringUtils::htmlListPatch(markdownToHTML(version.changelog.toUtf8())));
ManagedPackPage::suggestVersion();
}
@@ -370,7 +371,7 @@ void ModrinthManagedPackPage::update()
void ModrinthManagedPackPage::updateFromFile()
{
auto output = QFileDialog::getOpenFileUrl(this, tr("Choose update file"), QDir::homePath(), "Modrinth pack (*.mrpack *.zip)");
auto output = QFileDialog::getOpenFileUrl(this, tr("Choose update file"), QDir::homePath(), tr("Modrinth pack") + " (*.mrpack *.zip)");
if (output.isEmpty())
return;
QMap<QString, QString> extra_info;
@@ -420,7 +421,7 @@ void FlameManagedPackPage::parseManagedPack()
"Don't worry though, it will ask you to update this instance instead, so you'll not lose this instance!"
"</h4>");
ui->changelogTextBrowser->setHtml(message);
ui->changelogTextBrowser->setHtml(StringUtils::htmlListPatch(message));
return;
}
@@ -502,7 +503,8 @@ void FlameManagedPackPage::suggestVersion()
}
auto version = m_pack.versions.at(index);
ui->changelogTextBrowser->setHtml(m_api.getModFileChangelog(m_inst->getManagedPackID().toInt(), version.fileId));
ui->changelogTextBrowser->setHtml(
StringUtils::htmlListPatch(m_api.getModFileChangelog(m_inst->getManagedPackID().toInt(), version.fileId)));
ManagedPackPage::suggestVersion();
}
@@ -536,7 +538,7 @@ void FlameManagedPackPage::update()
void FlameManagedPackPage::updateFromFile()
{
auto output = QFileDialog::getOpenFileUrl(this, tr("Choose update file"), QDir::homePath(), "CurseForge pack (*.zip)");
auto output = QFileDialog::getOpenFileUrl(this, tr("Choose update file"), QDir::homePath(), tr("CurseForge pack") + " (*.zip)");
if (output.isEmpty())
return;

View File

@@ -50,7 +50,7 @@ class ManagedPackPage : public QWidget, public BasePage {
/** Gets the necessary information about the managed pack, such as
* available versions*/
virtual void parseManagedPack(){};
virtual void parseManagedPack() {};
/** URL of the managed pack.
* Not the version-specific one.
@@ -64,8 +64,8 @@ class ManagedPackPage : public QWidget, public BasePage {
*/
virtual void suggestVersion();
virtual void update(){};
virtual void updateFromFile(){};
virtual void update() {};
virtual void updateFromFile() {};
protected slots:
/** Does the necessary UI changes for when something failed.
@@ -119,6 +119,7 @@ class ModrinthManagedPackPage final : public ManagedPackPage {
void parseManagedPack() override;
[[nodiscard]] QString url() const override;
[[nodiscard]] QString helpPage() const override { return "modrinth-managed-pack"; }
public slots:
void suggestVersion() override;
@@ -142,6 +143,7 @@ class FlameManagedPackPage final : public ManagedPackPage {
void parseManagedPack() override;
[[nodiscard]] QString url() const override;
[[nodiscard]] QString helpPage() const override { return "curseforge-managed-pack"; }
public slots:
void suggestVersion() override;

View File

@@ -37,9 +37,11 @@
*/
#include "ModFolderPage.h"
#include "ui/dialogs/ExportToModListDialog.h"
#include "ui_ExternalResourcesPage.h"
#include <QAbstractItemModel>
#include <QAction>
#include <QEvent>
#include <QKeyEvent>
#include <QMenu>
@@ -66,6 +68,7 @@
#include "Version.h"
#include "tasks/ConcurrentTask.h"
#include "tasks/Task.h"
#include "ui/dialogs/ProgressDialog.h"
ModFolderPage::ModFolderPage(BaseInstance* inst, std::shared_ptr<ModFolderModel> model, QWidget* parent)
@@ -99,6 +102,16 @@ ModFolderPage::ModFolderPage(BaseInstance* inst, std::shared_ptr<ModFolderModel>
connect(ui->actionResetItemMetadata, &QAction::triggered, this, &ModFolderPage::deleteModMetadata);
ui->actionUpdateItem->setMenu(updateMenu);
ui->actionChangeVersion->setToolTip(tr("Change a mod's version."));
connect(ui->actionChangeVersion, &QAction::triggered, this, &ModFolderPage::changeModVersion);
ui->actionsToolbar->insertActionAfter(ui->actionUpdateItem, ui->actionChangeVersion);
ui->actionsToolbar->addSeparator();
ui->actionExportMetadata->setToolTip(tr("Export mod's metadata to text."));
connect(ui->actionExportMetadata, &QAction::triggered, this, &ModFolderPage::exportModMetadata);
ui->actionsToolbar->addAction(ui->actionExportMetadata);
}
bool ModFolderPage::shouldDisplay() const
@@ -275,9 +288,92 @@ void ModFolderPage::deleteModMetadata()
m_model->deleteMetadata(selection);
}
void ModFolderPage::changeModVersion()
{
if (m_instance->typeName() != "Minecraft")
return; // this is a null instance or a legacy instance
auto profile = static_cast<MinecraftInstance*>(m_instance)->getPackProfile();
if (!profile->getModLoaders().has_value()) {
QMessageBox::critical(this, tr("Error"), tr("Please install a mod loader first!"));
return;
}
if (APPLICATION->settings()->get("ModMetadataDisabled").toBool()) {
QMessageBox::critical(this, tr("Error"), tr("Mod updates are unavailable when metadata is disabled!"));
return;
}
auto selection = m_filterModel->mapSelectionToSource(ui->treeView->selectionModel()->selection()).indexes();
auto mods_list = m_model->selectedMods(selection);
if (mods_list.length() != 1 || mods_list[0]->metadata() == nullptr)
return;
ResourceDownload::ModDownloadDialog mdownload(this, m_model, m_instance);
mdownload.setModMetadata((*mods_list.begin())->metadata());
if (mdownload.exec()) {
auto tasks = new ConcurrentTask(this, "Download Mods", APPLICATION->settings()->get("NumberOfConcurrentDownloads").toInt());
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();
}
}
void ModFolderPage::exportModMetadata()
{
auto selection = m_filterModel->mapSelectionToSource(ui->treeView->selectionModel()->selection()).indexes();
auto selectedMods = m_model->selectedMods(selection);
if (selectedMods.length() == 0)
selectedMods = m_model->allMods();
std::sort(selectedMods.begin(), selectedMods.end(), [](const Mod* a, const Mod* b) { return a->name() < b->name(); });
ExportToModListDialog dlg(m_instance->name(), selectedMods, this);
dlg.exec();
}
CoreModFolderPage::CoreModFolderPage(BaseInstance* inst, std::shared_ptr<ModFolderModel> mods, QWidget* parent)
: ModFolderPage(inst, mods, parent)
{}
{
auto mcInst = dynamic_cast<MinecraftInstance*>(m_instance);
if (mcInst) {
auto version = mcInst->getPackProfile();
if (version && version->getComponent("net.minecraftforge") && version->getComponent("net.minecraft")) {
auto minecraftCmp = version->getComponent("net.minecraft");
if (!minecraftCmp->m_loaded) {
version->reload(Net::Mode::Offline);
auto update = version->getCurrentTask();
if (update) {
connect(update.get(), &Task::finished, this, [this] {
if (m_container) {
m_container->refreshContainer();
}
});
update->start();
}
}
}
}
}
bool CoreModFolderPage::shouldDisplay() const
{
@@ -287,15 +383,10 @@ bool CoreModFolderPage::shouldDisplay() const
return true;
auto version = inst->getPackProfile();
if (!version)
return true;
if (!version->getComponent("net.minecraftforge"))
if (!version || !version->getComponent("net.minecraftforge") || !version->getComponent("net.minecraft"))
return false;
if (!version->getComponent("net.minecraft"))
return false;
if (version->getComponent("net.minecraft")->getReleaseDateTime() < g_VersionFilterData.legacyCutoffDate)
return true;
auto minecraftCmp = version->getComponent("net.minecraft");
return minecraftCmp->m_loaded && minecraftCmp->getReleaseDateTime() < g_VersionFilterData.legacyCutoffDate;
}
return false;
}

View File

@@ -65,6 +65,8 @@ class ModFolderPage : public ExternalResourcesPage {
void downloadMods();
void updateMods(bool includeDeps = false);
void deleteModMetadata();
void exportModMetadata();
void changeModVersion();
protected:
std::shared_ptr<ModFolderModel> m_model;

View File

@@ -57,7 +57,7 @@ class OtherLogsPage : public QWidget, public BasePage {
QString id() const override { return "logs"; }
QString displayName() const override { return tr("Other logs"); }
QIcon icon() const override { return APPLICATION->getThemedIcon("log"); }
QString helpPage() const override { return "Minecraft-Logs"; }
QString helpPage() const override { return "other-Logs"; }
void retranslate() override;
void openedImpl() override;

View File

@@ -242,6 +242,11 @@ ScreenshotsPage::ScreenshotsPage(QString path, QWidget* parent) : QMainWindow(pa
m_model->setReadOnly(false);
m_model->setNameFilters({ "*.png" });
m_model->setNameFilterDisables(false);
// Sorts by modified date instead of creation date because that column is not available and would require subclassing, this should work
// considering screenshots aren't modified after creation.
constexpr int file_modified_column_index = 3;
m_model->sort(file_modified_column_index, Qt::DescendingOrder);
m_folder = path;
m_valid = FS::ensureFolderPathExists(m_folder);

View File

@@ -168,7 +168,7 @@ class ServersModel : public QAbstractListModel {
m_saveTimer.setInterval(5000);
connect(&m_saveTimer, &QTimer::timeout, this, &ServersModel::save_internal);
}
virtual ~ServersModel(){};
virtual ~ServersModel() = default;
void observe()
{
@@ -731,7 +731,7 @@ void ServersPage::on_actionMove_Down_triggered()
void ServersPage::on_actionJoin_triggered()
{
const auto& address = m_model->at(currentServer)->m_address;
APPLICATION->launch(m_inst, true, false, std::make_shared<MinecraftServerTarget>(MinecraftServerTarget::parse(address)));
APPLICATION->launch(m_inst, true, false, std::make_shared<MinecraftTarget>(MinecraftTarget::parse(address, false)));
}
#include "ServersPage.moc"

View File

@@ -48,7 +48,7 @@ class ShaderPackPage : public ExternalResourcesPage {
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"; }
QString helpPage() const override { return "shader-packs"; }
bool shouldDisplay() const override { return true; }

View File

@@ -49,8 +49,12 @@
#include <QMessageBox>
#include <QString>
#include <QUrl>
#include <algorithm>
#include "QObjectPtr.h"
#include "VersionPage.h"
#include "meta/JsonFormat.h"
#include "tasks/SequentialTask.h"
#include "ui/dialogs/InstallLoaderDialog.h"
#include "ui_VersionPage.h"
@@ -63,11 +67,9 @@
#include "DesktopServices.h"
#include "Exception.h"
#include "Version.h"
#include "icons/IconList.h"
#include "minecraft/PackProfile.h"
#include "minecraft/auth/AccountList.h"
#include "minecraft/mod/Mod.h"
#include "meta/Index.h"
#include "meta/VersionList.h"
@@ -297,7 +299,7 @@ void VersionPage::on_actionRemove_triggered()
void VersionPage::on_actionAdd_to_Minecraft_jar_triggered()
{
auto list = GuiUtil::BrowseForFiles("jarmod", tr("Select jar mods"), tr("Minecraft.jar mods (*.zip *.jar)"),
auto list = GuiUtil::BrowseForFiles("jarmod", tr("Select jar mods"), tr("Minecraft.jar mods") + " (*.zip *.jar)",
APPLICATION->settings()->get("CentralModsDir").toString(), this->parentWidget());
if (!list.empty()) {
m_profile->installJarMods(list);
@@ -307,7 +309,7 @@ void VersionPage::on_actionAdd_to_Minecraft_jar_triggered()
void VersionPage::on_actionReplace_Minecraft_jar_triggered()
{
auto jarPath = GuiUtil::BrowseForFile("jar", tr("Select jar"), tr("Minecraft.jar replacement (*.jar)"),
auto jarPath = GuiUtil::BrowseForFile("jar", tr("Select jar"), tr("Minecraft.jar replacement") + " (*.jar)",
APPLICATION->settings()->get("CentralModsDir").toString(), this->parentWidget());
if (!jarPath.isEmpty()) {
m_profile->installCustomJar(jarPath);
@@ -317,7 +319,7 @@ void VersionPage::on_actionReplace_Minecraft_jar_triggered()
void VersionPage::on_actionImport_Components_triggered()
{
QStringList list = GuiUtil::BrowseForFiles("component", tr("Select components"), tr("Components (*.json)"),
QStringList list = GuiUtil::BrowseForFiles("component", tr("Select components"), tr("Components") + " (*.json)",
APPLICATION->settings()->get("CentralModsDir").toString(), this->parentWidget());
if (!list.isEmpty()) {
@@ -332,7 +334,7 @@ void VersionPage::on_actionImport_Components_triggered()
void VersionPage::on_actionAdd_Agents_triggered()
{
QStringList list = GuiUtil::BrowseForFiles("agent", tr("Select agents"), tr("Java agents (*.jar)"),
QStringList list = GuiUtil::BrowseForFiles("agent", tr("Select agents"), tr("Java agents") + " (*.jar)",
APPLICATION->settings()->get("CentralModsDir").toString(), this->parentWidget());
if (!list.isEmpty())
@@ -370,11 +372,25 @@ void VersionPage::on_actionChange_version_triggered()
auto patch = m_profile->getComponent(versionRow);
auto name = patch->getName();
auto list = patch->getVersionList();
list->clearExternalRecommends();
if (!list) {
return;
}
auto uid = list->uid();
// recommend the correct lwjgl version for the current minecraft version
if (uid == "org.lwjgl" || uid == "org.lwjgl3") {
auto minecraft = m_profile->getComponent("net.minecraft");
auto lwjglReq = std::find_if(minecraft->m_cachedRequires.cbegin(), minecraft->m_cachedRequires.cend(),
[uid](const Meta::Require& req) -> bool { return req.uid == uid; });
if (lwjglReq != minecraft->m_cachedRequires.cend()) {
auto lwjglVersion = !lwjglReq->equalsVersion.isEmpty() ? lwjglReq->equalsVersion : lwjglReq->suggests;
if (!lwjglVersion.isEmpty()) {
list->addExternalRecommends({ lwjglVersion });
}
}
}
VersionSelectDialog vselect(list.get(), tr("Change %1 version").arg(name), this);
if (uid == "net.fabricmc.intermediary" || uid == "org.quiltmc.hashed") {
vselect.setEmptyString(tr("No intermediary mappings versions are currently available."));
@@ -393,6 +409,11 @@ void VersionPage::on_actionChange_version_triggered()
bool important = false;
if (uid == "net.minecraft") {
important = true;
if (APPLICATION->settings()->get("AutomaticJavaSwitch").toBool() && m_inst->settings()->get("AutomaticJava").toBool() &&
m_inst->settings()->get("OverrideJavaLocation").toBool()) {
m_inst->settings()->set("OverrideJavaLocation", false);
m_inst->settings()->set("JavaPath", "");
}
}
m_profile->setComponentVersion(uid, vselect.selectedVersion()->descriptor(), important);
m_profile->resolve(Net::Mode::Online);
@@ -410,14 +431,18 @@ void VersionPage::on_actionDownload_All_triggered()
return;
}
auto updateTask = m_inst->createUpdateTask(Net::Mode::Online);
if (!updateTask) {
auto updateTasks = m_inst->createUpdateTask();
if (updateTasks.isEmpty()) {
return;
}
auto task = makeShared<SequentialTask>(this);
for (auto t : updateTasks) {
task->addTask(t);
}
ProgressDialog tDialog(this);
connect(updateTask.get(), &Task::failed, this, &VersionPage::onGameUpdateError);
connect(task.get(), &Task::failed, this, &VersionPage::onGameUpdateError);
// FIXME: unused return value
tDialog.execWithTask(updateTask.get());
tDialog.execWithTask(task.get());
updateButtons();
m_container->refreshContainer();
}

View File

@@ -41,6 +41,7 @@
#pragma once
#include <QMainWindow>
#include <QSortFilterProxyModel>
#include "minecraft/MinecraftInstance.h"
#include "minecraft/PackProfile.h"

View File

@@ -82,7 +82,7 @@ class WorldListProxyModel : public QSortFilterProxyModel {
}
};
WorldListPage::WorldListPage(BaseInstance* inst, std::shared_ptr<WorldList> worlds, QWidget* parent)
WorldListPage::WorldListPage(InstancePtr inst, std::shared_ptr<WorldList> worlds, QWidget* parent)
: QMainWindow(parent), m_inst(inst), ui(new Ui::WorldListPage), m_worlds(worlds)
{
ui->setupUi(this);
@@ -113,6 +113,11 @@ void WorldListPage::openedImpl()
{
m_worlds->startWatching();
auto mInst = std::dynamic_pointer_cast<MinecraftInstance>(m_inst);
if (!mInst || !mInst->traits().contains("feature:is_quick_play_singleplayer")) {
ui->toolBar->removeAction(ui->actionJoin);
}
auto const setting_name = QString("WideBarVisibility_%1").arg(id());
if (!APPLICATION->settings()->contains(setting_name))
m_wide_bar_setting = APPLICATION->settings()->registerSetting(setting_name);
@@ -339,11 +344,19 @@ void WorldListPage::worldChanged([[maybe_unused]] const QModelIndex& current, [[
ui->actionDatapacks->setEnabled(enable);
bool hasIcon = !index.data(WorldList::IconFileRole).isNull();
ui->actionReset_Icon->setEnabled(enable && hasIcon);
auto mInst = std::dynamic_pointer_cast<MinecraftInstance>(m_inst);
auto supportsJoin = mInst && mInst->traits().contains("feature:is_quick_play_singleplayer");
ui->actionJoin->setEnabled(enable && supportsJoin);
if (!supportsJoin) {
ui->toolBar->removeAction(ui->actionJoin);
}
}
void WorldListPage::on_actionAdd_triggered()
{
auto list = GuiUtil::BrowseForFiles(displayName(), tr("Select a Minecraft world zip"), tr("Minecraft World Zip File (*.zip)"),
auto list = GuiUtil::BrowseForFiles(displayName(), tr("Select a Minecraft world zip"), tr("Minecraft World Zip File") + " (*.zip)",
QString(), this->parentWidget());
if (!list.empty()) {
m_worlds->stopWatching();
@@ -418,4 +431,15 @@ void WorldListPage::on_actionRefresh_triggered()
m_worlds->update();
}
void WorldListPage::on_actionJoin_triggered()
{
QModelIndex index = getSelectedWorld();
if (!index.isValid()) {
return;
}
auto worldVariant = m_worlds->data(index, WorldList::ObjectRole);
auto world = (World*)worldVariant.value<void*>();
APPLICATION->launch(m_inst, true, false, std::make_shared<MinecraftTarget>(MinecraftTarget::parse(world->folderName(), true)));
}
#include "WorldListPage.moc"

View File

@@ -53,7 +53,7 @@ class WorldListPage : public QMainWindow, public BasePage {
Q_OBJECT
public:
explicit WorldListPage(BaseInstance* inst, std::shared_ptr<WorldList> worlds, QWidget* parent = 0);
explicit WorldListPage(InstancePtr inst, std::shared_ptr<WorldList> worlds, QWidget* parent = 0);
virtual ~WorldListPage();
virtual QString displayName() const override { return tr("Worlds"); }
@@ -72,7 +72,7 @@ class WorldListPage : public QMainWindow, public BasePage {
QMenu* createPopupMenu() override;
protected:
BaseInstance* m_inst;
InstancePtr m_inst;
private:
QModelIndex getSelectedWorld();
@@ -101,6 +101,7 @@ class WorldListPage : public QMainWindow, public BasePage {
void on_actionReset_Icon_triggered();
void worldChanged(const QModelIndex& current, const QModelIndex& previous);
void mceditState(LoggedProcess::State state);
void on_actionJoin_triggered();
void ShowContextMenu(const QPoint& pos);
};

View File

@@ -81,6 +81,7 @@
</attribute>
<addaction name="actionAdd"/>
<addaction name="separator"/>
<addaction name="actionJoin"/>
<addaction name="actionRename"/>
<addaction name="actionCopy"/>
<addaction name="actionRemove"/>
@@ -97,6 +98,11 @@
<string>Add</string>
</property>
</action>
<action name="actionJoin">
<property name="text">
<string>Join</string>
</property>
</action>
<action name="actionRename">
<property name="text">
<string>Rename</string>