Merge branch 'develop' of https://github.com/PrismLauncher/PrismLauncher into skin_selector

Signed-off-by: Trial97 <alexandru.tripon97@gmail.com>
This commit is contained in:
Trial97 2023-11-19 21:15:12 +02:00
commit 54c308e5b5
No known key found for this signature in database
GPG Key ID: 55EF5DA53DB36318
30 changed files with 232 additions and 157 deletions

View File

@ -24,7 +24,7 @@ jobs:
with: with:
ref: ${{ github.event.pull_request.head.sha }} ref: ${{ github.event.pull_request.head.sha }}
- name: Create backport PRs - name: Create backport PRs
uses: korthout/backport-action@v2.1.0 uses: korthout/backport-action@v2.1.1
with: with:
# Config README: https://github.com/korthout/backport-action#backport-action # Config README: https://github.com/korthout/backport-action#backport-action
pull_description: |- pull_description: |-

View File

@ -594,7 +594,7 @@ jobs:
flatpak: flatpak:
runs-on: ubuntu-latest runs-on: ubuntu-latest
container: container:
image: bilelmoussaoui/flatpak-github-actions:kde-5.15-22.08 image: bilelmoussaoui/flatpak-github-actions:kde-5.15-23.08
options: --privileged options: --privileged
steps: steps:
- name: Checkout - name: Checkout

18
flake.lock generated
View File

@ -76,11 +76,11 @@
"libnbtplusplus": { "libnbtplusplus": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1690036783, "lastModified": 1699286814,
"narHash": "sha256-A5kTgICnx+Qdq3Fir/bKTfdTt/T1NQP2SC+nhN1ENug=", "narHash": "sha256-yy0q+bky80LtK1GWzz7qpM+aAGrOqLuewbid8WT1ilk=",
"owner": "PrismLauncher", "owner": "PrismLauncher",
"repo": "libnbtplusplus", "repo": "libnbtplusplus",
"rev": "a5e8fd52b8bf4ab5d5bcc042b2a247867589985f", "rev": "23b955121b8217c1c348a9ed2483167a6f3ff4ad",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -106,11 +106,11 @@
}, },
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1699094435, "lastModified": 1700108881,
"narHash": "sha256-YLZ5/KKZ1PyLrm2MO8UxRe4H3M0/oaYqNhSlq6FDeeA=", "narHash": "sha256-+Lqybl8kj0+nD/IlAWPPG/RDTa47gff9nbei0u7BntE=",
"owner": "nixos", "owner": "nixos",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "9d5d25bbfe8c0297ebe85324addcb5020ed1a454", "rev": "7414e9ee0b3e9903c24d3379f577a417f0aae5f1",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -153,11 +153,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1698852633, "lastModified": 1700064067,
"narHash": "sha256-Hsc/cCHud8ZXLvmm8pxrXpuaPEeNaaUttaCvtdX/Wug=", "narHash": "sha256-1ZWNDzhu8UlVCK7+DUN9dVQfiHX1bv6OQP9VxstY/gs=",
"owner": "cachix", "owner": "cachix",
"repo": "pre-commit-hooks.nix", "repo": "pre-commit-hooks.nix",
"rev": "dec10399e5b56aa95fcd530e0338be72ad6462a0", "rev": "e558068cba67b23b4fbc5537173dbb43748a17e8",
"type": "github" "type": "github"
}, },
"original": { "original": {

View File

@ -1,6 +1,6 @@
id: org.prismlauncher.PrismLauncher id: org.prismlauncher.PrismLauncher
runtime: org.kde.Platform runtime: org.kde.Platform
runtime-version: "5.15-22.08" runtime-version: "5.15-23.08"
sdk: org.kde.Sdk sdk: org.kde.Sdk
sdk-extensions: sdk-extensions:
- org.freedesktop.Sdk.Extension.openjdk17 - org.freedesktop.Sdk.Extension.openjdk17
@ -113,6 +113,9 @@ modules:
version-query: .tag_name version-query: .tag_name
url-query: .tarball_url url-query: .tarball_url
timestamp-query: .published_at timestamp-query: .published_at
# from https://github.com/flathub/net.gaijin.WarThunder/blob/7ea6f7a9f84b9c77150c003a7059dc03f8dcbc7f/gamemode.patch
- type: patch
path: patches/gamemode.patch
cleanup: cleanup:
- /include - /include
- /lib/pkgconfig - /lib/pkgconfig

View File

@ -0,0 +1,12 @@
diff -ruN a/common/common-pidfds.c b/common/common-pidfds.c
--- a/common/common-pidfds.c 2021-02-18 20:00:12.000000000 +0100
+++ b/common/common-pidfds.c 2023-09-07 08:57:42.954362763 +0200
@@ -58,6 +58,8 @@
{
return (int)syscall(__NR_pidfd_open, pid, flags);
}
+#else
+#include <sys/pidfd.h>
#endif
/* pidfd functions */

View File

@ -108,12 +108,9 @@ bool openDirectory(const QString& path, [[maybe_unused]] bool ensureExists)
#if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) #if defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD)
if (!isSandbox()) { if (!isSandbox()) {
return IndirectOpen(f); return IndirectOpen(f);
} else {
return f();
} }
#else
return f();
#endif #endif
return f();
} }
bool openFile(const QString& path) bool openFile(const QString& path)

View File

@ -943,6 +943,8 @@ bool createShortcut(QString destination, QString target, QStringList args, QStri
<< "\n"; << "\n";
stream << "Type=Application" stream << "Type=Application"
<< "\n"; << "\n";
stream << "Categories=Game;ActionGame;AdventureGame;Simulation"
<< "\n";
stream << "Exec=\"" << target.toLocal8Bit() << "\"" << argstring.toLocal8Bit() << "\n"; stream << "Exec=\"" << target.toLocal8Bit() << "\"" << argstring.toLocal8Bit() << "\n";
stream << "Name=" << name.toLocal8Bit() << "\n"; stream << "Name=" << name.toLocal8Bit() << "\n";
if (!icon.isEmpty()) { if (!icon.isEmpty()) {

View File

@ -34,6 +34,7 @@
*/ */
#include <QDir> #include <QDir>
#include <QFileInfo>
#include <QString> #include <QString>
#include <QStringList> #include <QStringList>
@ -440,18 +441,26 @@ QStringList getMinecraftJavaBundle()
{ {
QString partialPath; QString partialPath;
QString executable = "java"; QString executable = "java";
QStringList processpaths;
#if defined(Q_OS_OSX) #if defined(Q_OS_OSX)
partialPath = FS::PathCombine(QDir::homePath(), "Library/Application Support"); partialPath = FS::PathCombine(QDir::homePath(), "Library/Application Support");
#elif defined(Q_OS_WIN32) #elif defined(Q_OS_WIN32)
partialPath = QProcessEnvironment::systemEnvironment().value("LOCALAPPDATA", ""); partialPath = QProcessEnvironment::systemEnvironment().value("LOCALAPPDATA", "");
executable += "w.exe"; executable += "w.exe";
// add the microsoft store version of the launcher to the search. the current path is:
// C:\Users\USERNAME\AppData\Local\Packages\Microsoft.4297127D64EC6_8wekyb3d8bbwe\LocalCache\Local\runtime
auto minecraftMSStorePath =
FS::PathCombine(QFileInfo(partialPath).absolutePath(), "Local", "Packages", "Microsoft.4297127D64EC6_8wekyb3d8bbwe");
minecraftMSStorePath = FS::PathCombine(minecraftMSStorePath, "LocalCache", "Local", "runtime");
processpaths << minecraftMSStorePath;
#else #else
partialPath = QDir::homePath(); partialPath = QDir::homePath();
#endif #endif
auto minecraftPath = FS::PathCombine(partialPath, ".minecraft", "runtime"); auto minecraftDataPath = FS::PathCombine(partialPath, ".minecraft", "runtime");
QStringList javas; processpaths << minecraftDataPath;
QStringList processpaths{ minecraftPath };
QStringList javas;
while (!processpaths.isEmpty()) { while (!processpaths.isEmpty()) {
auto dirPath = processpaths.takeFirst(); auto dirPath = processpaths.takeFirst();
QDir dir(dirPath); QDir dir(dirPath);

View File

@ -565,6 +565,22 @@ QProcessEnvironment MinecraftInstance::createEnvironment()
for (auto it = variables.begin(); it != variables.end(); ++it) { for (auto it = variables.begin(); it != variables.end(); ++it) {
env.insert(it.key(), it.value()); env.insert(it.key(), it.value());
} }
// custom env
auto insertEnv = [&env](QMap<QString, QVariant> envMap) {
if (envMap.isEmpty())
return;
for (auto iter = envMap.begin(); iter != envMap.end(); iter++)
env.insert(iter.key(), iter.value().toString());
};
bool overrideEnv = settings()->get("OverrideEnv").toBool();
if (!overrideEnv)
insertEnv(APPLICATION->settings()->get("Env").toMap());
else
insertEnv(settings()->get("Env").toMap());
return env; return env;
} }
@ -606,24 +622,6 @@ QProcessEnvironment MinecraftInstance::createLaunchEnvironment()
env.insert("__GLX_VENDOR_LIBRARY_NAME", "nvidia"); env.insert("__GLX_VENDOR_LIBRARY_NAME", "nvidia");
} }
#endif #endif
// custom env
auto insertEnv = [&env](QMap<QString, QVariant> envMap) {
if (envMap.isEmpty())
return;
for (auto iter = envMap.begin(); iter != envMap.end(); iter++)
env.insert(iter.key(), iter.value().toString());
};
bool overrideEnv = settings()->get("OverrideEnv").toBool();
if (!overrideEnv)
insertEnv(APPLICATION->settings()->get("Env").toMap());
else
insertEnv(settings()->get("Env").toMap());
return env; return env;
} }

View File

@ -37,9 +37,9 @@
#include "ModFolderModel.h" #include "ModFolderModel.h"
#include <FileSystem.h> #include <FileSystem.h>
#include <qheaderview.h>
#include <QDebug> #include <QDebug>
#include <QFileSystemWatcher> #include <QFileSystemWatcher>
#include <QHeaderView>
#include <QIcon> #include <QIcon>
#include <QMimeData> #include <QMimeData>
#include <QString> #include <QString>
@ -65,8 +65,8 @@ ModFolderModel::ModFolderModel(const QString& dir, BaseInstance* instance, bool
m_column_names = QStringList({ "Enable", "Image", "Name", "Version", "Last Modified", "Provider" }); m_column_names = QStringList({ "Enable", "Image", "Name", "Version", "Last Modified", "Provider" });
m_column_names_translated = QStringList({ tr("Enable"), tr("Image"), tr("Name"), tr("Version"), tr("Last Modified"), tr("Provider") }); m_column_names_translated = QStringList({ tr("Enable"), tr("Image"), tr("Name"), tr("Version"), tr("Last Modified"), tr("Provider") });
m_column_sort_keys = { SortType::ENABLED, SortType::NAME, SortType::NAME, SortType::VERSION, SortType::DATE, SortType::PROVIDER }; m_column_sort_keys = { SortType::ENABLED, SortType::NAME, SortType::NAME, SortType::VERSION, SortType::DATE, SortType::PROVIDER };
m_column_resize_modes = { QHeaderView::ResizeToContents, QHeaderView::Interactive, QHeaderView::Stretch, m_column_resize_modes = { QHeaderView::Interactive, QHeaderView::Interactive, QHeaderView::Stretch,
QHeaderView::ResizeToContents, QHeaderView::ResizeToContents, QHeaderView::ResizeToContents }; QHeaderView::Interactive, QHeaderView::Interactive, QHeaderView::Interactive };
m_columnsHideable = { false, true, false, true, true, true }; m_columnsHideable = { false, true, false, true, true, true };
} }

View File

@ -4,6 +4,7 @@
#include <QCoreApplication> #include <QCoreApplication>
#include <QDebug> #include <QDebug>
#include <QFileInfo> #include <QFileInfo>
#include <QHeaderView>
#include <QIcon> #include <QIcon>
#include <QMenu> #include <QMenu>
#include <QMimeData> #include <QMimeData>
@ -516,36 +517,22 @@ void ResourceFolderModel::setupHeaderAction(QAction* act, int column)
act->setText(columnNames().at(column)); act->setText(columnNames().at(column));
} }
void ResourceFolderModel::saveHiddenColumn(int column, bool hidden) void ResourceFolderModel::saveColumns(QTreeView* tree)
{ {
auto const setting_name = QString("UI/%1_Page/HiddenColumns").arg(id()); auto const setting_name = QString("UI/%1_Page/Columns").arg(id());
auto setting = (m_instance->settings()->contains(setting_name)) ? m_instance->settings()->getSetting(setting_name) auto setting = (m_instance->settings()->contains(setting_name)) ? m_instance->settings()->getSetting(setting_name)
: m_instance->settings()->registerSetting(setting_name); : m_instance->settings()->registerSetting(setting_name);
auto hiddenColumns = setting->get().toStringList(); setting->set(tree->header()->saveState());
auto name = columnNames(false).at(column);
auto index = hiddenColumns.indexOf(name);
if (index >= 0 && !hidden) {
hiddenColumns.removeAt(index);
} else if (index < 0 && hidden) {
hiddenColumns.append(name);
}
setting->set(hiddenColumns);
} }
void ResourceFolderModel::loadHiddenColumns(QTreeView* tree) void ResourceFolderModel::loadColumns(QTreeView* tree)
{ {
auto const setting_name = QString("UI/%1_Page/HiddenColumns").arg(id()); auto const setting_name = QString("UI/%1_Page/Columns").arg(id());
auto setting = (m_instance->settings()->contains(setting_name)) ? m_instance->settings()->getSetting(setting_name) auto setting = (m_instance->settings()->contains(setting_name)) ? m_instance->settings()->getSetting(setting_name)
: m_instance->settings()->registerSetting(setting_name); : m_instance->settings()->registerSetting(setting_name);
auto hiddenColumns = setting->get().toStringList(); tree->header()->restoreState(setting->get().toByteArray());
auto col_names = columnNames(false);
for (auto col_name : hiddenColumns) {
auto index = col_names.indexOf(col_name);
if (index >= 0)
tree->setColumnHidden(index, true);
}
} }
QMenu* ResourceFolderModel::createHeaderContextMenu(QTreeView* tree) QMenu* ResourceFolderModel::createHeaderContextMenu(QTreeView* tree)
@ -570,7 +557,7 @@ QMenu* ResourceFolderModel::createHeaderContextMenu(QTreeView* tree)
if (m_column_resize_modes.at(c) == QHeaderView::ResizeToContents) if (m_column_resize_modes.at(c) == QHeaderView::ResizeToContents)
tree->resizeColumnToContents(c); tree->resizeColumnToContents(c);
} }
saveHiddenColumn(col, !toggled); saveColumns(tree);
}); });
menu->addAction(act); menu->addAction(act);

View File

@ -117,8 +117,8 @@ class ResourceFolderModel : public QAbstractListModel {
[[nodiscard]] QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; [[nodiscard]] QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
void setupHeaderAction(QAction* act, int column); void setupHeaderAction(QAction* act, int column);
void saveHiddenColumn(int column, bool hidden); void saveColumns(QTreeView* tree);
void loadHiddenColumns(QTreeView* tree); void loadColumns(QTreeView* tree);
QMenu* createHeaderContextMenu(QTreeView* tree); QMenu* createHeaderContextMenu(QTreeView* tree);
/** This creates a proxy model to filter / sort the model for a UI. /** This creates a proxy model to filter / sort the model for a UI.
@ -201,8 +201,7 @@ class ResourceFolderModel : public QAbstractListModel {
QList<SortType> m_column_sort_keys = { SortType::ENABLED, SortType::NAME, SortType::DATE }; QList<SortType> m_column_sort_keys = { SortType::ENABLED, SortType::NAME, SortType::DATE };
QStringList m_column_names = { "Enable", "Name", "Last Modified" }; QStringList m_column_names = { "Enable", "Name", "Last Modified" };
QStringList m_column_names_translated = { tr("Enable"), tr("Name"), tr("Last Modified") }; QStringList m_column_names_translated = { tr("Enable"), tr("Name"), tr("Last Modified") };
QList<QHeaderView::ResizeMode> m_column_resize_modes = { QHeaderView::ResizeToContents, QHeaderView::Stretch, QList<QHeaderView::ResizeMode> m_column_resize_modes = { QHeaderView::Interactive, QHeaderView::Stretch, QHeaderView::Interactive };
QHeaderView::ResizeToContents };
QList<bool> m_columnsHideable = { false, false, true }; QList<bool> m_columnsHideable = { false, false, true };
QDir m_dir; QDir m_dir;

View File

@ -52,8 +52,8 @@ ResourcePackFolderModel::ResourcePackFolderModel(const QString& dir, BaseInstanc
m_column_names = QStringList({ "Enable", "Image", "Name", "Pack Format", "Last Modified" }); m_column_names = QStringList({ "Enable", "Image", "Name", "Pack Format", "Last Modified" });
m_column_names_translated = QStringList({ tr("Enable"), tr("Image"), tr("Name"), tr("Pack Format"), tr("Last Modified") }); m_column_names_translated = QStringList({ tr("Enable"), tr("Image"), tr("Name"), tr("Pack Format"), tr("Last Modified") });
m_column_sort_keys = { SortType::ENABLED, SortType::NAME, SortType::NAME, SortType::PACK_FORMAT, SortType::DATE }; m_column_sort_keys = { SortType::ENABLED, SortType::NAME, SortType::NAME, SortType::PACK_FORMAT, SortType::DATE };
m_column_resize_modes = { QHeaderView::ResizeToContents, QHeaderView::Interactive, QHeaderView::Stretch, QHeaderView::ResizeToContents, m_column_resize_modes = { QHeaderView::Interactive, QHeaderView::Interactive, QHeaderView::Stretch, QHeaderView::Interactive,
QHeaderView::ResizeToContents }; QHeaderView::Interactive };
m_columnsHideable = { false, true, false, true, true }; m_columnsHideable = { false, true, false, true, true };
} }

View File

@ -47,8 +47,7 @@ TexturePackFolderModel::TexturePackFolderModel(const QString& dir, BaseInstance*
m_column_names = QStringList({ "Enable", "Image", "Name", "Last Modified" }); m_column_names = QStringList({ "Enable", "Image", "Name", "Last Modified" });
m_column_names_translated = QStringList({ tr("Enable"), tr("Image"), tr("Name"), tr("Last Modified") }); m_column_names_translated = QStringList({ tr("Enable"), tr("Image"), tr("Name"), tr("Last Modified") });
m_column_sort_keys = { SortType::ENABLED, SortType::NAME, SortType::NAME, SortType::DATE }; m_column_sort_keys = { SortType::ENABLED, SortType::NAME, SortType::NAME, SortType::DATE };
m_column_resize_modes = { QHeaderView::ResizeToContents, QHeaderView::Interactive, QHeaderView::Stretch, m_column_resize_modes = { QHeaderView::Interactive, QHeaderView::Interactive, QHeaderView::Stretch, QHeaderView::Interactive };
QHeaderView::ResizeToContents };
m_columnsHideable = { false, true, false, true }; m_columnsHideable = { false, true, false, true };
} }

View File

@ -117,6 +117,6 @@ QList<ResourceAPI::SortingMethod> ModrinthAPI::getSortingMethods() const
return { { 1, "relevance", QObject::tr("Sort by Relevance") }, return { { 1, "relevance", QObject::tr("Sort by Relevance") },
{ 2, "downloads", QObject::tr("Sort by Downloads") }, { 2, "downloads", QObject::tr("Sort by Downloads") },
{ 3, "follows", QObject::tr("Sort by Follows") }, { 3, "follows", QObject::tr("Sort by Follows") },
{ 4, "newest", QObject::tr("Sort by Last Updated") }, { 4, "newest", QObject::tr("Sort by Newest") },
{ 5, "updated", QObject::tr("Sort by Newest") } }; { 5, "updated", QObject::tr("Sort by Last Updated") } };
} }

View File

@ -1202,17 +1202,27 @@ void MainWindow::on_actionViewSkinsFolder_triggered()
void MainWindow::on_actionViewIconThemeFolder_triggered() void MainWindow::on_actionViewIconThemeFolder_triggered()
{ {
DesktopServices::openDirectory(APPLICATION->themeManager()->getIconThemesFolder().path()); DesktopServices::openDirectory(APPLICATION->themeManager()->getIconThemesFolder().path(), true);
} }
void MainWindow::on_actionViewWidgetThemeFolder_triggered() void MainWindow::on_actionViewWidgetThemeFolder_triggered()
{ {
DesktopServices::openDirectory(APPLICATION->themeManager()->getApplicationThemesFolder().path()); DesktopServices::openDirectory(APPLICATION->themeManager()->getApplicationThemesFolder().path(), true);
} }
void MainWindow::on_actionViewCatPackFolder_triggered() void MainWindow::on_actionViewCatPackFolder_triggered()
{ {
DesktopServices::openDirectory(APPLICATION->themeManager()->getCatPacksFolder().path()); DesktopServices::openDirectory(APPLICATION->themeManager()->getCatPacksFolder().path(), true);
}
void MainWindow::on_actionViewIconsFolder_triggered()
{
DesktopServices::openDirectory(APPLICATION->icons()->getDirectory(), true);
}
void MainWindow::on_actionViewLogsFolder_triggered()
{
DesktopServices::openDirectory("logs", true);
} }
void MainWindow::refreshInstances() void MainWindow::refreshInstances()

View File

@ -117,6 +117,8 @@ class MainWindow : public QMainWindow {
void on_actionViewIconThemeFolder_triggered(); void on_actionViewIconThemeFolder_triggered();
void on_actionViewWidgetThemeFolder_triggered(); void on_actionViewWidgetThemeFolder_triggered();
void on_actionViewCatPackFolder_triggered(); void on_actionViewCatPackFolder_triggered();
void on_actionViewIconsFolder_triggered();
void on_actionViewLogsFolder_triggered();
void on_actionViewSkinsFolder_triggered(); void on_actionViewSkinsFolder_triggered();

View File

@ -131,7 +131,7 @@
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>800</width> <width>800</width>
<height>20</height> <height>22</height>
</rect> </rect>
</property> </property>
<widget class="QMenu" name="fileMenu"> <widget class="QMenu" name="fileMenu">
@ -195,6 +195,9 @@
<addaction name="actionViewIconThemeFolder"/> <addaction name="actionViewIconThemeFolder"/>
<addaction name="actionViewWidgetThemeFolder"/> <addaction name="actionViewWidgetThemeFolder"/>
<addaction name="actionViewCatPackFolder"/> <addaction name="actionViewCatPackFolder"/>
<addaction name="actionViewIconsFolder"/>
<addaction name="separator"/>
<addaction name="actionViewLogsFolder"/>
</widget> </widget>
<widget class="QMenu" name="accountsMenu"> <widget class="QMenu" name="accountsMenu">
<property name="title"> <property name="title">
@ -546,10 +549,10 @@
<normaloff>.</normaloff>.</iconset> <normaloff>.</normaloff>.</iconset>
</property> </property>
<property name="text"> <property name="text">
<string>View &amp;Instance Folder</string> <string>&amp;Instances</string>
</property> </property>
<property name="toolTip"> <property name="toolTip">
<string>Open the instance folder in a file browser.</string> <string>Open the instances folder in a file browser.</string>
</property> </property>
</action> </action>
<action name="actionViewLauncherRootFolder"> <action name="actionViewLauncherRootFolder">
@ -558,7 +561,7 @@
<normaloff>.</normaloff>.</iconset> <normaloff>.</normaloff>.</iconset>
</property> </property>
<property name="text"> <property name="text">
<string>View Launcher &amp;Root Folder</string> <string>Launcher &amp;Root</string>
</property> </property>
<property name="toolTip"> <property name="toolTip">
<string>Open the launcher's root folder in a file browser.</string> <string>Open the launcher's root folder in a file browser.</string>
@ -570,7 +573,7 @@
<normaloff>.</normaloff>.</iconset> <normaloff>.</normaloff>.</iconset>
</property> </property>
<property name="text"> <property name="text">
<string>View &amp;Central Mods Folder</string> <string>&amp;Central Mods</string>
</property> </property>
<property name="toolTip"> <property name="toolTip">
<string>Open the central mods folder in a file browser.</string> <string>Open the central mods folder in a file browser.</string>
@ -582,12 +585,36 @@
<normaloff>.</normaloff>.</iconset> <normaloff>.</normaloff>.</iconset>
</property> </property>
<property name="text"> <property name="text">
<string>View &amp;Skins Folder</string> <string>&amp;Skins</string>
</property> </property>
<property name="toolTip"> <property name="toolTip">
<string>Open the skins folder in a file browser.</string> <string>Open the skins folder in a file browser.</string>
</property> </property>
</action> </action>
<action name="actionViewIconsFolder">
<property name="icon">
<iconset theme="viewfolder">
<normaloff>.</normaloff>.</iconset>
</property>
<property name="text">
<string>Instance Icons</string>
</property>
<property name="toolTip">
<string>Open the instance icons folder in a file browser.</string>
</property>
</action>
<action name="actionViewLogsFolder">
<property name="icon">
<iconset theme="viewfolder">
<normaloff>.</normaloff>.</iconset>
</property>
<property name="text">
<string>Logs</string>
</property>
<property name="toolTip">
<string>Open the logs folder in a file browser.</string>
</property>
</action>
<action name="actionChangeTheme"> <action name="actionChangeTheme">
<property name="text"> <property name="text">
<string>Themes</string> <string>Themes</string>
@ -731,10 +758,10 @@
<normaloff>.</normaloff>.</iconset> <normaloff>.</normaloff>.</iconset>
</property> </property>
<property name="text"> <property name="text">
<string>View &amp;Widget Themes Folder</string> <string>&amp;Widget Themes</string>
</property> </property>
<property name="toolTip"> <property name="toolTip">
<string>View Widget Theme Folder</string> <string>Open the widget themes folder in a file browser.</string>
</property> </property>
</action> </action>
<action name="actionViewIconThemeFolder"> <action name="actionViewIconThemeFolder">
@ -743,18 +770,22 @@
<normaloff>.</normaloff>.</iconset> <normaloff>.</normaloff>.</iconset>
</property> </property>
<property name="text"> <property name="text">
<string>View I&amp;con Theme Folder</string> <string>I&amp;con Theme</string>
</property> </property>
<property name="toolTip"> <property name="toolTip">
<string>View Icon Theme Folder</string> <string>Open the icon theme folder in a file browser.</string>
</property> </property>
</action> </action>
<action name="actionViewCatPackFolder"> <action name="actionViewCatPackFolder">
<property name="icon"> <property name="icon">
<iconset theme="viewfolder"/> <iconset theme="viewfolder">
<normaloff>.</normaloff>.</iconset>
</property> </property>
<property name="text"> <property name="text">
<string>View Cat Packs Folder</string> <string>Cat Packs</string>
</property>
<property name="toolTip">
<string>Open the cat packs folder in a file browser.</string>
</property> </property>
</action> </action>
</widget> </widget>

View File

@ -13,7 +13,6 @@ enum class ResourceProvider;
class Mod; class Mod;
class NetJob; class NetJob;
class ModUpdateDialog;
class ChooseProviderDialog : public QDialog { class ChooseProviderDialog : public QDialog {
Q_OBJECT Q_OBJECT

View File

@ -105,8 +105,16 @@ void MSALoginDialog::showVerificationUriAndCode(const QUrl& uri, const QString&
QString urlString = uri.toString(); QString urlString = uri.toString();
QString linkString = QString("<a href=\"%1\">%2</a>").arg(urlString, urlString); QString linkString = QString("<a href=\"%1\">%2</a>").arg(urlString, urlString);
if (urlString == "https://www.microsoft.com/link" && !code.isEmpty()) {
urlString += QString("?otc=%1").arg(code);
DesktopServices::openUrl(urlString);
ui->label->setText(tr("<p>Please login in the opened browser. If no browser was opened, please open up %1 in "
"a browser and put in the code <b>%2</b> to proceed with login.</p>")
.arg(linkString, code));
} else {
ui->label->setText( ui->label->setText(
tr("<p>Please open up %1 in a browser and put in the code <b>%2</b> to proceed with login.</p>").arg(linkString, code)); tr("<p>Please open up %1 in a browser and put in the code <b>%2</b> to proceed with login.</p>").arg(linkString, code));
}
ui->actionButton->setVisible(true); ui->actionButton->setVisible(true);
connect(ui->actionButton, &QPushButton::clicked, [=]() { connect(ui->actionButton, &QPushButton::clicked, [=]() {
DesktopServices::openUrl(uri); DesktopServices::openUrl(uri);

View File

@ -39,7 +39,8 @@ static std::optional<ModPlatform::ModLoaderTypes> mcLoaders(BaseInstance* inst)
ModUpdateDialog::ModUpdateDialog(QWidget* parent, ModUpdateDialog::ModUpdateDialog(QWidget* parent,
BaseInstance* instance, BaseInstance* instance,
const std::shared_ptr<ModFolderModel> mods, const std::shared_ptr<ModFolderModel> mods,
QList<Mod*>& search_for) QList<Mod*>& search_for,
bool includeDeps)
: ReviewMessageBox(parent, tr("Confirm mods to update"), "") : ReviewMessageBox(parent, tr("Confirm mods to update"), "")
, m_parent(parent) , m_parent(parent)
, m_mod_model(mods) , m_mod_model(mods)
@ -47,6 +48,7 @@ ModUpdateDialog::ModUpdateDialog(QWidget* parent,
, m_second_try_metadata( , m_second_try_metadata(
new ConcurrentTask(nullptr, "Second Metadata Search", APPLICATION->settings()->get("NumberOfConcurrentTasks").toInt())) new ConcurrentTask(nullptr, "Second Metadata Search", APPLICATION->settings()->get("NumberOfConcurrentTasks").toInt()))
, m_instance(instance) , m_instance(instance)
, m_include_deps(includeDeps)
{ {
ReviewMessageBox::setGeometry(0, 0, 800, 600); ReviewMessageBox::setGeometry(0, 0, 800, 600);
@ -186,7 +188,7 @@ void ModUpdateDialog::checkCandidates()
} }
} }
if (!APPLICATION->settings()->get("ModDependenciesDisabled").toBool()) { // dependencies if (m_include_deps && !APPLICATION->settings()->get("ModDependenciesDisabled").toBool()) { // dependencies
auto depTask = makeShared<GetModDependenciesTask>(this, m_instance, m_mod_model.get(), selectedVers); auto depTask = makeShared<GetModDependenciesTask>(this, m_instance, m_mod_model.get(), selectedVers);
connect(depTask.get(), &Task::failed, this, connect(depTask.get(), &Task::failed, this,

View File

@ -19,7 +19,8 @@ class ModUpdateDialog final : public ReviewMessageBox {
explicit ModUpdateDialog(QWidget* parent, explicit ModUpdateDialog(QWidget* parent,
BaseInstance* instance, BaseInstance* instance,
const std::shared_ptr<ModFolderModel> mod_model, const std::shared_ptr<ModFolderModel> mod_model,
QList<Mod*>& search_for); QList<Mod*>& search_for,
bool includeDeps);
void checkCandidates(); void checkCandidates();
@ -61,4 +62,5 @@ class ModUpdateDialog final : public ReviewMessageBox {
bool m_no_updates = false; bool m_no_updates = false;
bool m_aborted = false; bool m_aborted = false;
bool m_include_deps = false;
}; };

View File

@ -278,6 +278,7 @@ void InstanceView::mousePressEvent(QMouseEvent* event)
m_pressedAlreadySelected = selectionModel()->isSelected(m_pressedIndex); m_pressedAlreadySelected = selectionModel()->isSelected(m_pressedIndex);
m_pressedPosition = geometryPos; m_pressedPosition = geometryPos;
if (event->button() == Qt::LeftButton) {
VisualGroup::HitResults hitResult; VisualGroup::HitResults hitResult;
m_pressedCategory = categoryAt(geometryPos, hitResult); m_pressedCategory = categoryAt(geometryPos, hitResult);
if (m_pressedCategory && hitResult & VisualGroup::CheckboxHit) { if (m_pressedCategory && hitResult & VisualGroup::CheckboxHit) {
@ -285,6 +286,7 @@ void InstanceView::mousePressEvent(QMouseEvent* event)
event->accept(); event->accept();
return; return;
} }
}
if (index.isValid() && (index.flags() & Qt::ItemIsEnabled)) { if (index.isValid() && (index.flags() & Qt::ItemIsEnabled)) {
if (index != currentIndex()) { if (index != currentIndex()) {
@ -366,10 +368,7 @@ void InstanceView::mouseReleaseEvent(QMouseEvent* event)
VisualGroup::HitResults hitResult; VisualGroup::HitResults hitResult;
bool click = if (event->button() == Qt::LeftButton && m_pressedCategory != nullptr && m_pressedCategory == categoryAt(geometryPos, hitResult)) {
(index == m_pressedIndex && index.isValid()) || (m_pressedCategory && m_pressedCategory == categoryAt(geometryPos, hitResult));
if (click && m_pressedCategory) {
if (state() == ExpandingState) { if (state() == ExpandingState) {
m_pressedCategory->collapsed = false; m_pressedCategory->collapsed = false;
emit groupStateChanged(m_pressedCategory->text, false); emit groupStateChanged(m_pressedCategory->text, false);
@ -397,7 +396,7 @@ void InstanceView::mouseReleaseEvent(QMouseEvent* event)
setState(NoState); setState(NoState);
if (click) { if (index == m_pressedIndex && index.isValid()) {
if (event->button() == Qt::LeftButton) { if (event->button() == Qt::LeftButton) {
emit clicked(index); emit clicked(index);
} }

View File

@ -226,6 +226,7 @@ void AccountListPage::updateButtonStates()
ui->actionNoDefault->setEnabled(true); ui->actionNoDefault->setEnabled(true);
ui->actionNoDefault->setChecked(false); ui->actionNoDefault->setChecked(false);
} }
ui->listView->resizeColumnToContents(3);
} }
void AccountListPage::on_actionManageSkins_triggered() void AccountListPage::on_actionManageSkins_triggered()

View File

@ -209,10 +209,10 @@
<item> <item>
<widget class="QCheckBox" name="dependenciesDisableBtn"> <widget class="QCheckBox" name="dependenciesDisableBtn">
<property name="toolTip"> <property name="toolTip">
<string>Disable automatically checking and installation of mod dependencies.</string> <string>Disable the automatic detection, installation, and updating of mod dependencies.</string>
</property> </property>
<property name="text"> <property name="text">
<string>Do not install mod dependencies</string> <string>Disable automatic mod dependency management</string>
</property> </property>
</widget> </widget>
</item> </item>

View File

@ -42,6 +42,7 @@
#include "minecraft/mod/ResourceFolderModel.h" #include "minecraft/mod/ResourceFolderModel.h"
#include "ui/GuiUtil.h" #include "ui/GuiUtil.h"
#include <QHeaderView>
#include <QKeyEvent> #include <QKeyEvent>
#include <QMenu> #include <QMenu>
#include <algorithm> #include <algorithm>
@ -95,7 +96,8 @@ ExternalResourcesPage::ExternalResourcesPage(BaseInstance* instance, std::shared
connect(viewHeader, &QHeaderView::customContextMenuRequested, this, &ExternalResourcesPage::ShowHeaderContextMenu); connect(viewHeader, &QHeaderView::customContextMenuRequested, this, &ExternalResourcesPage::ShowHeaderContextMenu);
m_model->loadHiddenColumns(ui->treeView); m_model->loadColumns(ui->treeView);
connect(ui->treeView->header(), &QHeaderView::sectionResized, this, [this] { m_model->saveColumns(ui->treeView); });
} }
ExternalResourcesPage::~ExternalResourcesPage() ExternalResourcesPage::~ExternalResourcesPage()

View File

@ -70,6 +70,9 @@
</layout> </layout>
</widget> </widget>
<widget class="WideBar" name="actionsToolbar"> <widget class="WideBar" name="actionsToolbar">
<property name="useDefaultAction" stdset="0">
<bool>true</bool>
</property>
<property name="windowTitle"> <property name="windowTitle">
<string>Actions</string> <string>Actions</string>
</property> </property>
@ -146,17 +149,6 @@
<string>Download a new resource</string> <string>Download a new resource</string>
</property> </property>
</action> </action>
<action name="actionUpdateItem">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Check for &amp;Updates</string>
</property>
<property name="toolTip">
<string>Try to check or update all selected resources (all resources if none are selected)</string>
</property>
</action>
<action name="actionVisitItemPage"> <action name="actionVisitItemPage">
<property name="enabled"> <property name="enabled">
<bool>false</bool> <bool>false</bool>
@ -168,15 +160,15 @@
<string>Go to mods home page</string> <string>Go to mods home page</string>
</property> </property>
</action> </action>
<action name="actionRemoveItemMetadata"> <action name="actionUpdateItem">
<property name="enabled"> <property name="enabled">
<bool>false</bool> <bool>true</bool>
</property> </property>
<property name="text"> <property name="text">
<string>Remove metadata</string> <string>Check for &amp;Updates</string>
</property> </property>
<property name="toolTip"> <property name="toolTip">
<string>Remove mod's metadata</string> <string>Try to check or update all selected resources (all resources if none are selected)</string>
</property> </property>
</action> </action>
</widget> </widget>

View File

@ -84,21 +84,47 @@ ModFolderPage::ModFolderPage(BaseInstance* inst, std::shared_ptr<ModFolderModel>
connect(ui->actionDownloadItem, &QAction::triggered, this, &ModFolderPage::installMods); connect(ui->actionDownloadItem, &QAction::triggered, this, &ModFolderPage::installMods);
// update menu
auto updateMenu = ui->actionUpdateItem->menu();
if (updateMenu) {
updateMenu->clear();
} else {
updateMenu = new QMenu(this);
}
auto update = updateMenu->addAction(tr("Check for Updates"));
update->setToolTip(tr("Try to check or update all selected mods (all mods if none are selected)"));
connect(update, &QAction::triggered, this, &ModFolderPage::updateMods);
auto updateWithDeps = updateMenu->addAction(tr("Verify Dependencies"));
updateWithDeps->setToolTip(
tr("Try to update and check for missing dependencies all selected mods (all mods if none are selected)"));
connect(updateWithDeps, &QAction::triggered, this, [this] { updateMods(true); });
auto depsDisabled = APPLICATION->settings()->getSetting("ModDependenciesDisabled");
updateWithDeps->setVisible(!depsDisabled->get().toBool());
connect(depsDisabled.get(), &Setting::SettingChanged, this,
[updateWithDeps](const Setting& setting, QVariant value) { updateWithDeps->setVisible(!value.toBool()); });
auto actionRemoveItemMetadata = updateMenu->addAction(tr("Reset update metadata"));
actionRemoveItemMetadata->setToolTip(tr("Remove mod's metadata"));
connect(actionRemoveItemMetadata, &QAction::triggered, this, &ModFolderPage::deleteModMetadata);
actionRemoveItemMetadata->setEnabled(false);
ui->actionUpdateItem->setMenu(updateMenu);
ui->actionUpdateItem->setToolTip(tr("Try to check or update all selected mods (all mods if none are selected)")); ui->actionUpdateItem->setToolTip(tr("Try to check or update all selected mods (all mods if none are selected)"));
ui->actionsToolbar->insertActionAfter(ui->actionAddItem, ui->actionUpdateItem);
connect(ui->actionUpdateItem, &QAction::triggered, this, &ModFolderPage::updateMods); connect(ui->actionUpdateItem, &QAction::triggered, this, &ModFolderPage::updateMods);
ui->actionsToolbar->insertActionBefore(ui->actionAddItem, ui->actionUpdateItem);
ui->actionVisitItemPage->setToolTip(tr("Go to mod's home page")); ui->actionVisitItemPage->setToolTip(tr("Go to mod's home page"));
ui->actionsToolbar->addAction(ui->actionVisitItemPage); ui->actionsToolbar->addAction(ui->actionVisitItemPage);
connect(ui->actionVisitItemPage, &QAction::triggered, this, &ModFolderPage::visitModPages); connect(ui->actionVisitItemPage, &QAction::triggered, this, &ModFolderPage::visitModPages);
ui->actionRemoveItemMetadata->setToolTip(tr("Remove mod's metadata"));
ui->actionsToolbar->insertActionAfter(ui->actionRemoveItem, ui->actionRemoveItemMetadata);
connect(ui->actionRemoveItemMetadata, &QAction::triggered, this, &ModFolderPage::deleteModMetadata);
auto check_allow_update = [this] { return ui->treeView->selectionModel()->hasSelection() || !m_model->empty(); }; auto check_allow_update = [this] { return ui->treeView->selectionModel()->hasSelection() || !m_model->empty(); };
connect(ui->treeView->selectionModel(), &QItemSelectionModel::selectionChanged, this, [this, check_allow_update] { connect(ui->treeView->selectionModel(), &QItemSelectionModel::selectionChanged, this,
[this, check_allow_update, actionRemoveItemMetadata] {
ui->actionUpdateItem->setEnabled(check_allow_update()); ui->actionUpdateItem->setEnabled(check_allow_update());
auto selection = m_filterModel->mapSelectionToSource(ui->treeView->selectionModel()->selection()).indexes(); auto selection = m_filterModel->mapSelectionToSource(ui->treeView->selectionModel()->selection()).indexes();
@ -109,25 +135,20 @@ ModFolderPage::ModFolderPage(BaseInstance* inst, std::shared_ptr<ModFolderModel>
ui->actionVisitItemPage->setText(tr("Visit mod's page")); ui->actionVisitItemPage->setText(tr("Visit mod's page"));
ui->actionVisitItemPage->setToolTip(tr("Go to mod's home page")); ui->actionVisitItemPage->setToolTip(tr("Go to mod's home page"));
ui->actionRemoveItemMetadata->setToolTip(tr("Remove mod's metadata"));
} else { } else {
ui->actionVisitItemPage->setText(tr("Visit mods' pages")); ui->actionVisitItemPage->setText(tr("Visit mods' pages"));
ui->actionVisitItemPage->setToolTip(tr("Go to the pages of the selected mods")); ui->actionVisitItemPage->setToolTip(tr("Go to the pages of the selected mods"));
ui->actionRemoveItemMetadata->setToolTip(tr("Remove mods' metadata"));
} }
ui->actionVisitItemPage->setEnabled(selected != 0); ui->actionVisitItemPage->setEnabled(selected != 0);
ui->actionRemoveItemMetadata->setEnabled(selected != 0); actionRemoveItemMetadata->setEnabled(selected != 0);
}); });
connect(mods.get(), &ModFolderModel::rowsInserted, this, auto updateButtons = [this, check_allow_update] { ui->actionUpdateItem->setEnabled(check_allow_update()); };
[this, check_allow_update] { ui->actionUpdateItem->setEnabled(check_allow_update()); }); connect(mods.get(), &ModFolderModel::rowsInserted, this, updateButtons);
connect(mods.get(), &ModFolderModel::rowsRemoved, this, connect(mods.get(), &ModFolderModel::rowsRemoved, this, updateButtons);
[this, check_allow_update] { ui->actionUpdateItem->setEnabled(check_allow_update()); });
connect(mods.get(), &ModFolderModel::updateFinished, this, connect(mods.get(), &ModFolderModel::updateFinished, this, updateButtons);
[this, check_allow_update] { ui->actionUpdateItem->setEnabled(check_allow_update()); });
} }
} }
@ -204,7 +225,7 @@ void ModFolderPage::installMods()
} }
} }
void ModFolderPage::updateMods() void ModFolderPage::updateMods(bool includeDeps)
{ {
if (m_instance->typeName() != "Minecraft") if (m_instance->typeName() != "Minecraft")
return; // this is a null instance or a legacy instance return; // this is a null instance or a legacy instance
@ -225,7 +246,7 @@ void ModFolderPage::updateMods()
if (use_all) if (use_all)
mods_list = m_model->allMods(); mods_list = m_model->allMods();
ModUpdateDialog update_dialog(this, m_instance, m_model, mods_list); ModUpdateDialog update_dialog(this, m_instance, m_model, mods_list, includeDeps);
update_dialog.checkCandidates(); update_dialog.checkCandidates();
if (update_dialog.aborted()) { if (update_dialog.aborted()) {

View File

@ -64,7 +64,7 @@ class ModFolderPage : public ExternalResourcesPage {
void deleteModMetadata(); void deleteModMetadata();
void installMods(); void installMods();
void updateMods(); void updateMods(bool includeDeps = false);
void visitModPages(); void visitModPages();
protected: protected:

View File

@ -48,14 +48,14 @@ void ModListView::setModel(QAbstractItemModel* model)
return; return;
} }
if (!string.size()) { if (!string.size()) {
head->setSectionResizeMode(0, QHeaderView::ResizeToContents); head->setSectionResizeMode(0, QHeaderView::Interactive);
head->setSectionResizeMode(1, QHeaderView::Stretch); head->setSectionResizeMode(1, QHeaderView::Stretch);
for (int i = 2; i < head->count(); i++) for (int i = 2; i < head->count(); i++)
head->setSectionResizeMode(i, QHeaderView::ResizeToContents); head->setSectionResizeMode(i, QHeaderView::Interactive);
} else { } else {
head->setSectionResizeMode(0, QHeaderView::Stretch); head->setSectionResizeMode(0, QHeaderView::Stretch);
for (int i = 1; i < head->count(); i++) for (int i = 1; i < head->count(); i++)
head->setSectionResizeMode(i, QHeaderView::ResizeToContents); head->setSectionResizeMode(i, QHeaderView::Interactive);
} }
} }