Merge branch 'develop' into refactor-instanceview
This commit is contained in:
@ -39,6 +39,7 @@
|
||||
|
||||
#include "Application.h"
|
||||
#include "BuildConfig.h"
|
||||
#include "FileSystem.h"
|
||||
|
||||
#include "MainWindow.h"
|
||||
|
||||
@ -49,7 +50,7 @@
|
||||
|
||||
#include <QKeyEvent>
|
||||
#include <QAction>
|
||||
|
||||
#include <QActionGroup>
|
||||
#include <QApplication>
|
||||
#include <QButtonGroup>
|
||||
#include <QHeaderView>
|
||||
@ -59,6 +60,7 @@
|
||||
#include <QMenu>
|
||||
#include <QMenuBar>
|
||||
#include <QMessageBox>
|
||||
#include <QFileDialog>
|
||||
#include <QInputDialog>
|
||||
#include <QLineEdit>
|
||||
#include <QLabel>
|
||||
@ -70,6 +72,7 @@
|
||||
|
||||
#include <BaseInstance.h>
|
||||
#include <InstanceList.h>
|
||||
#include <minecraft/MinecraftInstance.h>
|
||||
#include <MMCZip.h>
|
||||
#include <icons/IconList.h>
|
||||
#include <java/JavaUtils.h>
|
||||
@ -103,6 +106,13 @@
|
||||
#include "ui/dialogs/VersionSelectDialog.h"
|
||||
#include "ui/instanceview/InstancesView.h"
|
||||
#include "ui/widgets/LabeledToolButton.h"
|
||||
#include "ui/dialogs/ImportResourcePackDialog.h"
|
||||
#include "ui/themes/ITheme.h"
|
||||
|
||||
#include <minecraft/mod/ResourcePackFolderModel.h>
|
||||
#include <minecraft/mod/tasks/LocalResourcePackParseTask.h>
|
||||
#include <minecraft/mod/TexturePackFolderModel.h>
|
||||
#include <minecraft/mod/tasks/LocalTexturePackParseTask.h>
|
||||
|
||||
#include "UpdateController.h"
|
||||
|
||||
@ -236,6 +246,7 @@ public:
|
||||
TranslatedAction actionLaunchInstanceOffline;
|
||||
TranslatedAction actionLaunchInstanceDemo;
|
||||
TranslatedAction actionExportInstance;
|
||||
TranslatedAction actionCreateInstanceShortcut;
|
||||
QVector<TranslatedAction *> all_actions;
|
||||
|
||||
LabeledToolButton *renameButton = nullptr;
|
||||
@ -252,6 +263,9 @@ public:
|
||||
QMenu * helpMenu = nullptr;
|
||||
TranslatedToolButton helpMenuButton;
|
||||
TranslatedAction actionClearMetadata;
|
||||
#ifdef Q_OS_MAC
|
||||
TranslatedAction actionAddToPATH;
|
||||
#endif
|
||||
TranslatedAction actionReportBug;
|
||||
TranslatedAction actionDISCORD;
|
||||
TranslatedAction actionMATRIX;
|
||||
@ -261,6 +275,10 @@ public:
|
||||
TranslatedAction actionNoAccountsAdded;
|
||||
TranslatedAction actionNoDefaultAccount;
|
||||
|
||||
TranslatedAction actionLockToolbars;
|
||||
|
||||
TranslatedAction actionChangeTheme;
|
||||
|
||||
QVector<TranslatedToolButton *> all_toolbuttons;
|
||||
|
||||
QWidget *centralWidget = nullptr;
|
||||
@ -286,7 +304,6 @@ public:
|
||||
actionAddInstance = TranslatedAction(MainWindow);
|
||||
actionAddInstance->setObjectName(QStringLiteral("actionAddInstance"));
|
||||
actionAddInstance->setIcon(APPLICATION->getThemedIcon("new"));
|
||||
actionAddInstance->setIconVisibleInMenu(false);
|
||||
actionAddInstance.setTextId(QT_TRANSLATE_NOOP("MainWindow", "Add Instanc&e..."));
|
||||
actionAddInstance.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "Add a new instance."));
|
||||
actionAddInstance->setShortcut(QKeySequence::New);
|
||||
@ -333,11 +350,10 @@ public:
|
||||
all_actions.append(&actionSettings);
|
||||
|
||||
actionUndoTrashInstance = TranslatedAction(MainWindow);
|
||||
connect(actionUndoTrashInstance, SIGNAL(triggered(bool)), MainWindow, SLOT(undoTrashInstance()));
|
||||
actionUndoTrashInstance->setObjectName(QStringLiteral("actionUndoTrashInstance"));
|
||||
actionUndoTrashInstance.setTextId(QT_TRANSLATE_NOOP("MainWindow", "&Undo Last Instance Deletion"));
|
||||
actionUndoTrashInstance->setEnabled(APPLICATION->instances()->trashedSomething());
|
||||
actionUndoTrashInstance->setShortcut(QKeySequence("Ctrl+Z"));
|
||||
actionUndoTrashInstance->setShortcut(QKeySequence::Undo);
|
||||
all_actions.append(&actionUndoTrashInstance);
|
||||
|
||||
actionClearMetadata = TranslatedAction(MainWindow);
|
||||
@ -347,6 +363,14 @@ public:
|
||||
actionClearMetadata.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "Clear cached metadata"));
|
||||
all_actions.append(&actionClearMetadata);
|
||||
|
||||
#ifdef Q_OS_MAC
|
||||
actionAddToPATH = TranslatedAction(MainWindow);
|
||||
actionAddToPATH->setObjectName(QStringLiteral("actionAddToPATH"));
|
||||
actionAddToPATH.setTextId(QT_TRANSLATE_NOOP("MainWindow", "Install to &PATH"));
|
||||
actionAddToPATH.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "Install a prismlauncher symlink to /usr/local/bin"));
|
||||
all_actions.append(&actionAddToPATH);
|
||||
#endif
|
||||
|
||||
if (!BuildConfig.BUG_TRACKER_URL.isEmpty()) {
|
||||
actionReportBug = TranslatedAction(MainWindow);
|
||||
actionReportBug->setObjectName(QStringLiteral("actionReportBug"));
|
||||
@ -437,6 +461,17 @@ public:
|
||||
actionManageAccounts->setCheckable(false);
|
||||
actionManageAccounts->setIcon(APPLICATION->getThemedIcon("accounts"));
|
||||
all_actions.append(&actionManageAccounts);
|
||||
|
||||
actionLockToolbars = TranslatedAction(MainWindow);
|
||||
actionLockToolbars->setObjectName(QStringLiteral("actionLockToolbars"));
|
||||
actionLockToolbars.setTextId(QT_TRANSLATE_NOOP("MainWindow", "Lock Toolbars"));
|
||||
actionLockToolbars->setCheckable(true);
|
||||
all_actions.append(&actionLockToolbars);
|
||||
|
||||
actionChangeTheme = TranslatedAction(MainWindow);
|
||||
actionChangeTheme->setObjectName(QStringLiteral("actionChangeTheme"));
|
||||
actionChangeTheme.setTextId(QT_TRANSLATE_NOOP("MainWindow", "Themes"));
|
||||
all_actions.append(&actionChangeTheme);
|
||||
}
|
||||
|
||||
void createMainToolbar(QMainWindow *MainWindow)
|
||||
@ -444,7 +479,6 @@ public:
|
||||
mainToolBar = TranslatedToolbar(MainWindow);
|
||||
mainToolBar->setVisible(menuBar->isNativeMenuBar() || !APPLICATION->settings()->get("MenuBarInsteadOfToolBar").toBool());
|
||||
mainToolBar->setObjectName(QStringLiteral("mainToolBar"));
|
||||
mainToolBar->setMovable(true);
|
||||
mainToolBar->setAllowedAreas(Qt::TopToolBarArea | Qt::BottomToolBarArea);
|
||||
mainToolBar->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
|
||||
mainToolBar->setFloatable(false);
|
||||
@ -465,6 +499,10 @@ public:
|
||||
|
||||
helpMenu->addAction(actionClearMetadata);
|
||||
|
||||
#ifdef Q_OS_MAC
|
||||
helpMenu->addAction(actionAddToPATH);
|
||||
#endif
|
||||
|
||||
if (!BuildConfig.BUG_TRACKER_URL.isEmpty()) {
|
||||
helpMenu->addAction(actionReportBug);
|
||||
}
|
||||
@ -522,8 +560,6 @@ public:
|
||||
fileMenu->setSeparatorsCollapsible(false);
|
||||
fileMenu->addAction(actionAddInstance);
|
||||
fileMenu->addAction(actionLaunchInstance);
|
||||
fileMenu->addAction(actionLaunchInstanceOffline);
|
||||
fileMenu->addAction(actionLaunchInstanceDemo);
|
||||
fileMenu->addAction(actionKillInstance);
|
||||
fileMenu->addAction(actionCloseWindow);
|
||||
fileMenu->addSeparator();
|
||||
@ -541,20 +577,27 @@ public:
|
||||
|
||||
viewMenu = menuBar->addMenu(tr("&View"));
|
||||
viewMenu->setSeparatorsCollapsible(false);
|
||||
viewMenu->addAction(actionChangeTheme);
|
||||
viewMenu->addSeparator();
|
||||
viewMenu->addAction(actionCAT);
|
||||
viewMenu->addAction(actionTableMode);
|
||||
viewMenu->addAction(actionGridMode);
|
||||
viewMenu->addSeparator();
|
||||
|
||||
viewMenu->addAction(actionLockToolbars);
|
||||
|
||||
menuBar->addMenu(foldersMenu);
|
||||
|
||||
profileMenu = menuBar->addMenu(tr("&Profiles"));
|
||||
profileMenu = menuBar->addMenu(tr("&Accounts"));
|
||||
profileMenu->setSeparatorsCollapsible(false);
|
||||
profileMenu->addAction(actionManageAccounts);
|
||||
|
||||
helpMenu = menuBar->addMenu(tr("&Help"));
|
||||
helpMenu->setSeparatorsCollapsible(false);
|
||||
helpMenu->addAction(actionClearMetadata);
|
||||
#ifdef Q_OS_MAC
|
||||
helpMenu->addAction(actionAddToPATH);
|
||||
#endif
|
||||
helpMenu->addSeparator();
|
||||
helpMenu->addAction(actionAbout);
|
||||
helpMenu->addAction(actionOpenWiki);
|
||||
@ -568,10 +611,11 @@ public:
|
||||
helpMenu->addAction(actionDISCORD);
|
||||
if (!BuildConfig.SUBREDDIT_URL.isEmpty())
|
||||
helpMenu->addAction(actionREDDIT);
|
||||
helpMenu->addSeparator();
|
||||
if(BuildConfig.UPDATER_ENABLED)
|
||||
{
|
||||
helpMenu->addSeparator();
|
||||
helpMenu->addAction(actionCheckUpdate);
|
||||
|
||||
}
|
||||
MainWindow->setMenuBar(menuBar);
|
||||
}
|
||||
|
||||
@ -589,6 +633,7 @@ public:
|
||||
actionOpenWiki->setObjectName(QStringLiteral("actionOpenWiki"));
|
||||
actionOpenWiki.setTextId(QT_TRANSLATE_NOOP("MainWindow", "%1 &Help"));
|
||||
actionOpenWiki.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "Open the %1 wiki"));
|
||||
actionOpenWiki->setIcon(APPLICATION->getThemedIcon("help"));
|
||||
connect(actionOpenWiki, &QAction::triggered, MainWindow, &MainWindow::on_actionOpenWiki_triggered);
|
||||
all_actions.append(&actionOpenWiki);
|
||||
|
||||
@ -596,6 +641,7 @@ public:
|
||||
actionNewsMenuBar->setObjectName(QStringLiteral("actionNewsMenuBar"));
|
||||
actionNewsMenuBar.setTextId(QT_TRANSLATE_NOOP("MainWindow", "%1 &News"));
|
||||
actionNewsMenuBar.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "Open the %1 wiki"));
|
||||
actionNewsMenuBar->setIcon(APPLICATION->getThemedIcon("news"));
|
||||
connect(actionNewsMenuBar, &QAction::triggered, MainWindow, &MainWindow::on_actionMoreNews_triggered);
|
||||
all_actions.append(&actionNewsMenuBar);
|
||||
}
|
||||
@ -610,13 +656,13 @@ public:
|
||||
actionExportInstance->setEnabled(enabled);
|
||||
actionDeleteInstance->setEnabled(enabled);
|
||||
actionCopyInstance->setEnabled(enabled);
|
||||
actionCreateInstanceShortcut->setEnabled(enabled);
|
||||
}
|
||||
|
||||
void createNewsToolbar(QMainWindow *MainWindow)
|
||||
{
|
||||
newsToolBar = TranslatedToolbar(MainWindow);
|
||||
newsToolBar->setObjectName(QStringLiteral("newsToolBar"));
|
||||
newsToolBar->setMovable(true);
|
||||
newsToolBar->setAllowedAreas(Qt::TopToolBarArea | Qt::BottomToolBarArea);
|
||||
newsToolBar->setIconSize(QSize(16, 16));
|
||||
newsToolBar->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
|
||||
@ -670,6 +716,7 @@ public:
|
||||
actionLaunchInstance->setObjectName(QStringLiteral("actionLaunchInstance"));
|
||||
actionLaunchInstance.setTextId(QT_TRANSLATE_NOOP("MainWindow", "&Launch"));
|
||||
actionLaunchInstance.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "Launch the selected instance."));
|
||||
actionLaunchInstance->setIcon(APPLICATION->getThemedIcon("launch"));
|
||||
all_actions.append(&actionLaunchInstance);
|
||||
|
||||
actionLaunchInstanceOffline = TranslatedAction(MainWindow);
|
||||
@ -741,6 +788,15 @@ public:
|
||||
actionCopyInstance->setIcon(APPLICATION->getThemedIcon("copy"));
|
||||
all_actions.append(&actionCopyInstance);
|
||||
|
||||
actionCreateInstanceShortcut = TranslatedAction(MainWindow);
|
||||
actionCreateInstanceShortcut->setObjectName(QStringLiteral("actionCreateInstanceShortcut"));
|
||||
actionCreateInstanceShortcut.setTextId(QT_TRANSLATE_NOOP("MainWindow", "Create Shortcut"));
|
||||
actionCreateInstanceShortcut.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "Creates a shortcut on your desktop to launch the selected instance."));
|
||||
//actionCreateInstanceShortcut->setShortcut(QKeySequence(tr("Ctrl+D"))); // TODO
|
||||
// FIXME missing on Legacy, Flat and Flat (White)
|
||||
actionCreateInstanceShortcut->setIcon(APPLICATION->getThemedIcon("shortcut"));
|
||||
all_actions.append(&actionCreateInstanceShortcut);
|
||||
|
||||
setInstanceActionsEnabled(false);
|
||||
}
|
||||
|
||||
@ -750,12 +806,13 @@ public:
|
||||
instanceToolBar->setObjectName(QStringLiteral("instanceToolBar"));
|
||||
// disabled until we have an instance selected
|
||||
instanceToolBar->setEnabled(false);
|
||||
instanceToolBar->setMovable(true);
|
||||
// Qt doesn't like vertical moving toolbars, so we have to force them...
|
||||
// See https://github.com/PolyMC/PolyMC/issues/493
|
||||
connect(instanceToolBar, &QToolBar::orientationChanged, [=](Qt::Orientation){ instanceToolBar->setOrientation(Qt::Vertical); });
|
||||
instanceToolBar->setAllowedAreas(Qt::LeftToolBarArea | Qt::RightToolBarArea);
|
||||
instanceToolBar->setToolButtonStyle(Qt::ToolButtonTextOnly);
|
||||
instanceToolBar->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
|
||||
instanceToolBar->setIconSize(QSize(16, 16));
|
||||
|
||||
instanceToolBar->setFloatable(false);
|
||||
instanceToolBar->setWindowTitle(QT_TRANSLATE_NOOP("MainWindow", "Instance Toolbar"));
|
||||
|
||||
@ -775,8 +832,20 @@ public:
|
||||
instanceToolBar->addAction(actionViewSelectedInstFolder);
|
||||
|
||||
instanceToolBar->addAction(actionExportInstance);
|
||||
instanceToolBar->addAction(actionDeleteInstance);
|
||||
instanceToolBar->addAction(actionCopyInstance);
|
||||
instanceToolBar->addAction(actionDeleteInstance);
|
||||
|
||||
instanceToolBar->addAction(actionCreateInstanceShortcut); // TODO find better position for this
|
||||
|
||||
QLayout * lay = instanceToolBar->layout();
|
||||
for(int i = 0; i < lay->count(); i++)
|
||||
{
|
||||
QLayoutItem * item = lay->itemAt(i);
|
||||
if (item->widget()->metaObject()->className() == QString("QToolButton"))
|
||||
{
|
||||
item->setAlignment(Qt::AlignLeft);
|
||||
}
|
||||
}
|
||||
|
||||
all_toolbars.append(&instanceToolBar);
|
||||
MainWindow->addToolBar(Qt::RightToolBarArea, instanceToolBar);
|
||||
@ -816,6 +885,7 @@ public:
|
||||
createInstanceToolbar(MainWindow);
|
||||
|
||||
MainWindow->updateToolsMenu();
|
||||
MainWindow->updateThemeMenu();
|
||||
|
||||
retranslateUi(MainWindow);
|
||||
|
||||
@ -927,6 +997,14 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new MainWindow
|
||||
APPLICATION->settings()->set("InstanceDisplayMode", InstancesView::GridMode);
|
||||
});
|
||||
}
|
||||
|
||||
// Lock toolbars
|
||||
{
|
||||
bool toolbarsLocked = APPLICATION->settings()->get("ToolbarsLocked").toBool();
|
||||
ui->actionLockToolbars->setChecked(toolbarsLocked);
|
||||
connect(ui->actionLockToolbars, &QAction::toggled, this, &MainWindow::lockToolbars);
|
||||
lockToolbars(toolbarsLocked);
|
||||
}
|
||||
// start instance when double-clicked
|
||||
connect(view, &InstancesView::instanceActivated, this, &MainWindow::instanceActivated);
|
||||
|
||||
@ -1026,6 +1104,8 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new MainWindow
|
||||
}
|
||||
}
|
||||
|
||||
connect(ui->actionUndoTrashInstance.operator->(), &QAction::triggered, this, &MainWindow::undoTrashInstance);
|
||||
|
||||
setSelectedInstanceById(APPLICATION->settings()->get("SelectedInstance").toString());
|
||||
|
||||
// removing this looks stupid
|
||||
@ -1055,7 +1135,7 @@ void MainWindow::retranslateUi()
|
||||
accountMenuButton->setText(profileLabel);
|
||||
}
|
||||
else {
|
||||
accountMenuButton->setText(tr("Profiles"));
|
||||
accountMenuButton->setText(tr("Accounts"));
|
||||
}
|
||||
|
||||
ui->retranslateUi(this);
|
||||
@ -1069,8 +1149,19 @@ QMenu * MainWindow::createPopupMenu()
|
||||
{
|
||||
QMenu* filteredMenu = QMainWindow::createPopupMenu();
|
||||
filteredMenu->removeAction( ui->mainToolBar->toggleViewAction() );
|
||||
|
||||
filteredMenu->addAction(ui->actionLockToolbars);
|
||||
|
||||
return filteredMenu;
|
||||
}
|
||||
void MainWindow::lockToolbars(bool state)
|
||||
{
|
||||
ui->mainToolBar->setMovable(!state);
|
||||
ui->instanceToolBar->setMovable(!state);
|
||||
ui->newsToolBar->setMovable(!state);
|
||||
APPLICATION->settings()->set("ToolbarsLocked", state);
|
||||
}
|
||||
|
||||
|
||||
void MainWindow::showInstanceContextMenu(const QPoint &pos, InstancePtr inst)
|
||||
{
|
||||
@ -1202,6 +1293,38 @@ void MainWindow::updateToolsMenu()
|
||||
ui->actionLaunchInstance->setMenu(launchMenu);
|
||||
}
|
||||
|
||||
void MainWindow::updateThemeMenu()
|
||||
{
|
||||
QMenu *themeMenu = ui->actionChangeTheme->menu();
|
||||
|
||||
if (themeMenu) {
|
||||
themeMenu->clear();
|
||||
} else {
|
||||
themeMenu = new QMenu(this);
|
||||
}
|
||||
|
||||
auto themes = APPLICATION->getValidApplicationThemes();
|
||||
|
||||
QActionGroup* themesGroup = new QActionGroup( this );
|
||||
|
||||
for (auto* theme : themes) {
|
||||
QAction * themeAction = themeMenu->addAction(theme->name());
|
||||
|
||||
themeAction->setCheckable(true);
|
||||
if (APPLICATION->settings()->get("ApplicationTheme").toString() == theme->id()) {
|
||||
themeAction->setChecked(true);
|
||||
}
|
||||
themeAction->setActionGroup(themesGroup);
|
||||
|
||||
connect(themeAction, &QAction::triggered, [theme]() {
|
||||
APPLICATION->setApplicationTheme(theme->id(),false);
|
||||
APPLICATION->settings()->set("ApplicationTheme", theme->id());
|
||||
});
|
||||
}
|
||||
|
||||
ui->actionChangeTheme->setMenu(themeMenu);
|
||||
}
|
||||
|
||||
void MainWindow::repopulateAccountsMenu()
|
||||
{
|
||||
accountMenu->clear();
|
||||
@ -1348,7 +1471,7 @@ void MainWindow::defaultAccountChanged()
|
||||
|
||||
// Set the icon to the "no account" icon.
|
||||
accountMenuButton->setIcon(APPLICATION->getThemedIcon("noaccount"));
|
||||
accountMenuButton->setText(tr("Profiles"));
|
||||
accountMenuButton->setText(tr("Accounts"));
|
||||
}
|
||||
|
||||
bool MainWindow::eventFilter(QObject *obj, QEvent *ev)
|
||||
@ -1534,7 +1657,7 @@ void MainWindow::on_actionCopyInstance_triggered()
|
||||
if (!copyInstDlg.exec())
|
||||
return;
|
||||
|
||||
auto copyTask = new InstanceCopyTask(m_selectedInstance, copyInstDlg.shouldCopySaves(), copyInstDlg.shouldKeepPlaytime());
|
||||
auto copyTask = new InstanceCopyTask(m_selectedInstance, copyInstDlg.getChosenOptions());
|
||||
copyTask->setName(copyInstDlg.instName());
|
||||
copyTask->setGroup(copyInstDlg.instGroup());
|
||||
copyTask->setIcon(copyInstDlg.iconKey());
|
||||
@ -1614,17 +1737,41 @@ void MainWindow::on_actionAddInstance_triggered()
|
||||
|
||||
void MainWindow::droppedURLs(QList<QUrl> urls)
|
||||
{
|
||||
for(auto & url:urls)
|
||||
{
|
||||
if(url.isLocalFile())
|
||||
{
|
||||
addInstance(url.toLocalFile());
|
||||
}
|
||||
else
|
||||
{
|
||||
// NOTE: This loop only processes one dropped file!
|
||||
for (auto& url : urls) {
|
||||
// The isLocalFile() check below doesn't work as intended without an explicit scheme.
|
||||
if (url.scheme().isEmpty())
|
||||
url.setScheme("file");
|
||||
|
||||
if (!url.isLocalFile()) { // probably instance/modpack
|
||||
addInstance(url.toString());
|
||||
break;
|
||||
}
|
||||
// Only process one dropped file...
|
||||
|
||||
auto localFileName = url.toLocalFile();
|
||||
QFileInfo localFileInfo(localFileName);
|
||||
|
||||
bool isResourcePack = ResourcePackUtils::validate(localFileInfo);
|
||||
bool isTexturePack = TexturePackUtils::validate(localFileInfo);
|
||||
|
||||
if (!isResourcePack && !isTexturePack) { // probably instance/modpack
|
||||
addInstance(localFileName);
|
||||
break;
|
||||
}
|
||||
|
||||
ImportResourcePackDialog dlg(this);
|
||||
|
||||
if (dlg.exec() != QDialog::Accepted)
|
||||
break;
|
||||
|
||||
qDebug() << "Adding resource/texture pack" << localFileName << "to" << dlg.selectedInstanceKey;
|
||||
|
||||
auto inst = APPLICATION->instances()->getInstanceById(dlg.selectedInstanceKey);
|
||||
auto minecraftInst = std::dynamic_pointer_cast<MinecraftInstance>(inst);
|
||||
if (isResourcePack)
|
||||
minecraftInst->resourcePackList()->installResource(localFileName);
|
||||
else if (isTexturePack)
|
||||
minecraftInst->texturePackList()->installResource(localFileName);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -1730,6 +1877,7 @@ void MainWindow::deleteGroup()
|
||||
void MainWindow::undoTrashInstance()
|
||||
{
|
||||
APPLICATION->instances()->undoTrashInstance();
|
||||
ui->actionUndoTrashInstance->setEnabled(APPLICATION->instances()->trashedSomething());
|
||||
}
|
||||
|
||||
void MainWindow::on_actionViewInstanceFolder_triggered()
|
||||
@ -1774,6 +1922,7 @@ void MainWindow::globalSettingsClosed()
|
||||
//proxymodel->sort(0);
|
||||
updateMainToolBar();
|
||||
updateToolsMenu();
|
||||
updateThemeMenu();
|
||||
// This needs to be done to prevent UI elements disappearing in the event the config is changed
|
||||
// but Prism Launcher exits abnormally, causing the window state to never be saved:
|
||||
APPLICATION->settings()->set("MainWindowState", saveState().toBase64());
|
||||
@ -1798,8 +1947,32 @@ void MainWindow::on_actionReportBug_triggered()
|
||||
void MainWindow::on_actionClearMetadata_triggered()
|
||||
{
|
||||
APPLICATION->metacache()->evictAll();
|
||||
APPLICATION->metacache()->SaveNow();
|
||||
}
|
||||
|
||||
#ifdef Q_OS_MAC
|
||||
void MainWindow::on_actionAddToPATH_triggered()
|
||||
{
|
||||
auto binaryPath = APPLICATION->applicationFilePath();
|
||||
auto targetPath = QString("/usr/local/bin/%1").arg(BuildConfig.LAUNCHER_APP_BINARY_NAME);
|
||||
qDebug() << "Symlinking" << binaryPath << "to" << targetPath;
|
||||
|
||||
QStringList args;
|
||||
args << "-e";
|
||||
args << QString("do shell script \"mkdir -p /usr/local/bin && ln -sf '%1' '%2'\" with administrator privileges")
|
||||
.arg(binaryPath, targetPath);
|
||||
auto outcome = QProcess::execute("/usr/bin/osascript", args);
|
||||
if (!outcome) {
|
||||
QMessageBox::information(this, tr("Successfully added %1 to PATH").arg(BuildConfig.LAUNCHER_DISPLAYNAME),
|
||||
tr("%1 was successfully added to your PATH. You can now start it by running `%2`.")
|
||||
.arg(BuildConfig.LAUNCHER_DISPLAYNAME, BuildConfig.LAUNCHER_APP_BINARY_NAME));
|
||||
} else {
|
||||
QMessageBox::critical(this, tr("Failed to add %1 to PATH").arg(BuildConfig.LAUNCHER_DISPLAYNAME),
|
||||
tr("An error occurred while trying to add %1 to PATH").arg(BuildConfig.LAUNCHER_DISPLAYNAME));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void MainWindow::on_actionOpenWiki_triggered()
|
||||
{
|
||||
DesktopServices::openUrl(QUrl(BuildConfig.HELP_URL.arg("")));
|
||||
@ -1828,26 +2001,25 @@ void MainWindow::on_actionAbout_triggered()
|
||||
|
||||
void MainWindow::on_actionDeleteInstance_triggered()
|
||||
{
|
||||
if (!m_selectedInstance)
|
||||
{
|
||||
if (!m_selectedInstance) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto id = m_selectedInstance->id();
|
||||
if (APPLICATION->instances()->trashInstance(id)) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto response = CustomMessageBox::selectable(
|
||||
this,
|
||||
tr("CAREFUL!"),
|
||||
tr("About to delete: %1\nThis is permanent and will completely delete the instance.\n\nAre you sure?").arg(m_selectedInstance->name()),
|
||||
QMessageBox::Warning,
|
||||
QMessageBox::Yes | QMessageBox::No,
|
||||
QMessageBox::No
|
||||
)->exec();
|
||||
if (response == QMessageBox::Yes)
|
||||
{
|
||||
|
||||
auto response =
|
||||
CustomMessageBox::selectable(this, tr("CAREFUL!"),
|
||||
tr("About to delete: %1\nThis may be permanent and will completely delete the instance.\n\nAre you sure?")
|
||||
.arg(m_selectedInstance->name()),
|
||||
QMessageBox::Warning, QMessageBox::Yes | QMessageBox::No, QMessageBox::No)
|
||||
->exec();
|
||||
|
||||
if (response == QMessageBox::Yes) {
|
||||
if (APPLICATION->instances()->trashInstance(id)) {
|
||||
ui->actionUndoTrashInstance->setEnabled(APPLICATION->instances()->trashedSomething());
|
||||
return;
|
||||
}
|
||||
|
||||
APPLICATION->instances()->deleteInstance(id);
|
||||
}
|
||||
}
|
||||
@ -1940,6 +2112,130 @@ void MainWindow::on_actionKillInstance_triggered()
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::on_actionCreateInstanceShortcut_triggered()
|
||||
{
|
||||
if (m_selectedInstance)
|
||||
{
|
||||
auto desktopPath = FS::getDesktopDir();
|
||||
if (desktopPath.isEmpty()) {
|
||||
// TODO come up with an alternative solution (open "save file" dialog)
|
||||
QMessageBox::critical(this, tr("Create instance shortcut"), tr("Couldn't find desktop?!"));
|
||||
return;
|
||||
}
|
||||
|
||||
#if defined(Q_OS_MACOS)
|
||||
QString appPath = QApplication::applicationFilePath();
|
||||
if (appPath.startsWith("/private/var/")) {
|
||||
QMessageBox::critical(this, tr("Create instance shortcut"), tr("The launcher is in the folder it was extracted from, therefore it cannot create shortcuts."));
|
||||
return;
|
||||
}
|
||||
|
||||
if (FS::createShortcut(FS::PathCombine(desktopPath, m_selectedInstance->name()),
|
||||
appPath, { "--launch", m_selectedInstance->id() },
|
||||
m_selectedInstance->name(), "")) {
|
||||
QMessageBox::information(this, tr("Create instance shortcut"), tr("Created a shortcut to this instance on your desktop!"));
|
||||
}
|
||||
else
|
||||
{
|
||||
QMessageBox::critical(this, tr("Create instance shortcut"), tr("Failed to create instance shortcut!"));
|
||||
}
|
||||
#elif defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) || defined(Q_OS_OPENBSD)
|
||||
QString appPath = QApplication::applicationFilePath();
|
||||
if (appPath.startsWith("/tmp/.mount_")) {
|
||||
// AppImage!
|
||||
appPath = QProcessEnvironment::systemEnvironment().value(QStringLiteral("APPIMAGE"));
|
||||
if (appPath.isEmpty())
|
||||
{
|
||||
QMessageBox::critical(this, tr("Create instance shortcut"), tr("Launcher is running as misconfigured AppImage? ($APPIMAGE environment variable is missing)"));
|
||||
}
|
||||
else if (appPath.endsWith("/"))
|
||||
{
|
||||
appPath.chop(1);
|
||||
}
|
||||
}
|
||||
|
||||
auto icon = APPLICATION->icons()->icon(m_selectedInstance->iconKey());
|
||||
if (icon == nullptr)
|
||||
{
|
||||
icon = APPLICATION->icons()->icon("grass");
|
||||
}
|
||||
|
||||
QString iconPath = FS::PathCombine(m_selectedInstance->instanceRoot(), "icon.png");
|
||||
|
||||
QFile iconFile(iconPath);
|
||||
if (!iconFile.open(QFile::WriteOnly))
|
||||
{
|
||||
QMessageBox::critical(this, tr("Create instance shortcut"), tr("Failed to create icon for shortcut."));
|
||||
return;
|
||||
}
|
||||
bool success = icon->icon().pixmap(64, 64).save(&iconFile, "PNG");
|
||||
iconFile.close();
|
||||
|
||||
if (!success)
|
||||
{
|
||||
iconFile.remove();
|
||||
QMessageBox::critical(this, tr("Create instance shortcut"), tr("Failed to create icon for shortcut."));
|
||||
return;
|
||||
}
|
||||
|
||||
if (FS::createShortcut(FS::PathCombine(desktopPath, m_selectedInstance->name()),
|
||||
appPath, { "--launch", m_selectedInstance->id() },
|
||||
m_selectedInstance->name(), iconPath)) {
|
||||
QMessageBox::information(this, tr("Create instance shortcut"), tr("Created a shortcut to this instance on your desktop!"));
|
||||
}
|
||||
else
|
||||
{
|
||||
iconFile.remove();
|
||||
QMessageBox::critical(this, tr("Create instance shortcut"), tr("Failed to create instance shortcut!"));
|
||||
}
|
||||
#elif defined(Q_OS_WIN)
|
||||
auto icon = APPLICATION->icons()->icon(m_selectedInstance->iconKey());
|
||||
if (icon == nullptr)
|
||||
{
|
||||
icon = APPLICATION->icons()->icon("grass");
|
||||
}
|
||||
|
||||
QString iconPath = FS::PathCombine(m_selectedInstance->instanceRoot(), "icon.ico");
|
||||
|
||||
// part of fix for weird bug involving the window icon being replaced
|
||||
// dunno why it happens, but this 2-line fix seems to be enough, so w/e
|
||||
auto appIcon = APPLICATION->getThemedIcon("logo");
|
||||
|
||||
QFile iconFile(iconPath);
|
||||
if (!iconFile.open(QFile::WriteOnly))
|
||||
{
|
||||
QMessageBox::critical(this, tr("Create instance shortcut"), tr("Failed to create icon for shortcut."));
|
||||
return;
|
||||
}
|
||||
bool success = icon->icon().pixmap(64, 64).save(&iconFile, "ICO");
|
||||
iconFile.close();
|
||||
|
||||
// restore original window icon
|
||||
QGuiApplication::setWindowIcon(appIcon);
|
||||
|
||||
if (!success)
|
||||
{
|
||||
iconFile.remove();
|
||||
QMessageBox::critical(this, tr("Create instance shortcut"), tr("Failed to create icon for shortcut."));
|
||||
return;
|
||||
}
|
||||
|
||||
if (FS::createShortcut(FS::PathCombine(desktopPath, m_selectedInstance->name()),
|
||||
QApplication::applicationFilePath(), { "--launch", m_selectedInstance->id() },
|
||||
m_selectedInstance->name(), iconPath)) {
|
||||
QMessageBox::information(this, tr("Create instance shortcut"), tr("Created a shortcut to this instance on your desktop!"));
|
||||
}
|
||||
else
|
||||
{
|
||||
iconFile.remove();
|
||||
QMessageBox::critical(this, tr("Create instance shortcut"), tr("Failed to create instance shortcut!"));
|
||||
}
|
||||
#else
|
||||
QMessageBox::critical(this, tr("Create instance shortcut"), tr("Not supported on your platform!"));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::taskEnd()
|
||||
{
|
||||
QObject *sender = QObject::sender();
|
||||
|
@ -127,6 +127,10 @@ private slots:
|
||||
|
||||
void on_actionClearMetadata_triggered();
|
||||
|
||||
#ifdef Q_OS_MAC
|
||||
void on_actionAddToPATH_triggered();
|
||||
#endif
|
||||
|
||||
void on_actionOpenWiki_triggered();
|
||||
|
||||
void on_actionMoreNews_triggered();
|
||||
@ -156,6 +160,8 @@ private slots:
|
||||
|
||||
void on_actionEditInstance_triggered();
|
||||
|
||||
void on_actionCreateInstanceShortcut_triggered();
|
||||
|
||||
void taskEnd();
|
||||
|
||||
/**
|
||||
@ -169,6 +175,8 @@ private slots:
|
||||
|
||||
void updateToolsMenu();
|
||||
|
||||
void updateThemeMenu();
|
||||
|
||||
void instanceActivated(InstancePtr inst);
|
||||
|
||||
void instanceChanged(InstancePtr current, InstancePtr previous);
|
||||
@ -198,6 +206,8 @@ private slots:
|
||||
|
||||
void globalSettingsClosed();
|
||||
|
||||
void lockToolbars(bool);
|
||||
|
||||
#ifndef Q_OS_MAC
|
||||
void keyReleaseEvent(QKeyEvent *event) override;
|
||||
#endif
|
||||
|
@ -73,17 +73,12 @@ QString getCreditsHtml()
|
||||
stream << "<h3>" << QObject::tr("%1 Developers", "About Credits").arg(BuildConfig.LAUNCHER_DISPLAYNAME) << "</h3>\n";
|
||||
stream << QString("<p>Sefa Eyeoglu (Scrumplex) %1</p>\n") .arg(getWebsite("https://scrumplex.net"));
|
||||
stream << QString("<p>dada513 %1</p>\n") .arg(getGitHub("dada513"));
|
||||
stream << QString("<p>txtsd %1</p>\n") .arg(getGitHub("txtsd"));
|
||||
stream << QString("<p>txtsd %1</p>\n") .arg(getWebsite("https://ihavea.quest"));
|
||||
stream << QString("<p>timoreo %1</p>\n") .arg(getGitHub("timoreo22"));
|
||||
stream << QString("<p>Ezekiel Smith (ZekeSmith) %1</p>\n") .arg(getGitHub("ZekeSmith"));
|
||||
stream << QString("<p>cozyGalvinism %1</p>\n") .arg(getGitHub("cozyGalvinism"));
|
||||
stream << "<br />\n";
|
||||
|
||||
//: %1 is the name of the launcher, determined at build time, e.g. "Prism Launcher Contributors"
|
||||
stream << "<h3>" << QObject::tr("%1 Contributors", "About Credits").arg(BuildConfig.LAUNCHER_DISPLAYNAME) << "</h3>\n";
|
||||
stream << QString("<p>DioEgizio %1</p>\n") .arg(getGitHub("DioEgizio"));
|
||||
stream << QString("<p>flowln %1</p>\n") .arg(getGitHub("flowln"));
|
||||
stream << QString("<p>swirl %1</p>\n") .arg(getWebsite("https://swurl.xyz/"));
|
||||
stream << "<br />\n";
|
||||
|
||||
// TODO: possibly retrieve from git history at build time?
|
||||
@ -97,7 +92,7 @@ QString getCreditsHtml()
|
||||
stream << "<br />\n";
|
||||
|
||||
stream << "<h3>" << QObject::tr("With thanks to", "About Credits") << "</h3>\n";
|
||||
stream << QString("<p>Boba %1</p>\n") .arg(getWebsite("https://cmdplusv.neocities.org/"));
|
||||
stream << QString("<p>Boba %1</p>\n") .arg(getWebsite("https://bobaonline.neocities.org/"));
|
||||
stream << QString("<p>Davi Rafael %1</p>\n") .arg(getWebsite("https://auti.one/"));
|
||||
stream << QString("<p>Fulmine %1</p>\n") .arg(getWebsite("https://www.fulmine.xyz/"));
|
||||
stream << QString("<p>ely %1</p>\n") .arg(getGitHub("elyrodso"));
|
||||
|
@ -1,28 +1,327 @@
|
||||
#include "BlockedModsDialog.h"
|
||||
#include "ui_BlockedModsDialog.h"
|
||||
#include <QPushButton>
|
||||
#include <QDialogButtonBox>
|
||||
#include <QDesktopServices>
|
||||
#include <QDialogButtonBox>
|
||||
#include <QPushButton>
|
||||
#include "Application.h"
|
||||
#include "ui_BlockedModsDialog.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QDragEnterEvent>
|
||||
#include <QFileDialog>
|
||||
#include <QFileInfo>
|
||||
#include <QStandardPaths>
|
||||
|
||||
BlockedModsDialog::BlockedModsDialog(QWidget* parent, const QString& title, const QString& text, QList<BlockedMod>& mods)
|
||||
: QDialog(parent), ui(new Ui::BlockedModsDialog), m_mods(mods)
|
||||
{
|
||||
m_hashing_task = shared_qobject_ptr<ConcurrentTask>(new ConcurrentTask(this, "MakeHashesTask", 10));
|
||||
connect(m_hashing_task.get(), &Task::finished, this, &BlockedModsDialog::hashTaskFinished);
|
||||
|
||||
BlockedModsDialog::BlockedModsDialog(QWidget *parent, const QString &title, const QString &text, const QString &body, const QList<QUrl> &urls) :
|
||||
QDialog(parent), ui(new Ui::BlockedModsDialog), urls(urls) {
|
||||
ui->setupUi(this);
|
||||
|
||||
auto openAllButton = ui->buttonBox->addButton(tr("Open All"), QDialogButtonBox::ActionRole);
|
||||
connect(openAllButton, &QPushButton::clicked, this, &BlockedModsDialog::openAll);
|
||||
|
||||
auto downloadFolderButton = ui->buttonBox->addButton(tr("Add Download Folder"), QDialogButtonBox::ActionRole);
|
||||
connect(downloadFolderButton, &QPushButton::clicked, this, &BlockedModsDialog::addDownloadFolder);
|
||||
|
||||
connect(&m_watcher, &QFileSystemWatcher::directoryChanged, this, &BlockedModsDialog::directoryChanged);
|
||||
|
||||
qDebug() << "[Blocked Mods Dialog] Mods List: " << mods;
|
||||
|
||||
setupWatch();
|
||||
scanPaths();
|
||||
|
||||
this->setWindowTitle(title);
|
||||
ui->label->setText(text);
|
||||
ui->textBrowser->setText(body);
|
||||
ui->labelDescription->setText(text);
|
||||
ui->labelExplain->setText(
|
||||
QString(tr("Your configured global mods folder and default downloads folder "
|
||||
"are automatically checked for the downloaded mods and they will be copied to the instance if found.<br/>"
|
||||
"Optionally, you may drag and drop the downloaded mods onto this dialog or add a folder to watch "
|
||||
"if you did not download the mods to a default location."))
|
||||
.arg(APPLICATION->settings()->get("CentralModsDir").toString(),
|
||||
QStandardPaths::writableLocation(QStandardPaths::DownloadLocation)));
|
||||
|
||||
// force all URL handeling as external
|
||||
connect(ui->textBrowserWatched, &QTextBrowser::anchorClicked, this, [](const QUrl url) { QDesktopServices::openUrl(url); });
|
||||
|
||||
setAcceptDrops(true);
|
||||
|
||||
update();
|
||||
}
|
||||
|
||||
BlockedModsDialog::~BlockedModsDialog() {
|
||||
BlockedModsDialog::~BlockedModsDialog()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void BlockedModsDialog::openAll() {
|
||||
for(auto &url : urls) {
|
||||
QDesktopServices::openUrl(url);
|
||||
void BlockedModsDialog::dragEnterEvent(QDragEnterEvent* e)
|
||||
{
|
||||
if (e->mimeData()->hasUrls()) {
|
||||
e->acceptProposedAction();
|
||||
}
|
||||
}
|
||||
|
||||
void BlockedModsDialog::dropEvent(QDropEvent* e)
|
||||
{
|
||||
for (const QUrl& url : e->mimeData()->urls()) {
|
||||
QString filePath = url.toLocalFile();
|
||||
qDebug() << "[Blocked Mods Dialog] Dropped file:" << filePath;
|
||||
addHashTask(filePath);
|
||||
|
||||
// watch for changes
|
||||
QFileInfo file = QFileInfo(filePath);
|
||||
QString path = file.dir().absolutePath();
|
||||
qDebug() << "[Blocked Mods Dialog] Adding watch path:" << path;
|
||||
m_watcher.addPath(path);
|
||||
}
|
||||
scanPaths();
|
||||
update();
|
||||
}
|
||||
|
||||
void BlockedModsDialog::done(int r)
|
||||
{
|
||||
QDialog::done(r);
|
||||
disconnect(&m_watcher, &QFileSystemWatcher::directoryChanged, this, &BlockedModsDialog::directoryChanged);
|
||||
}
|
||||
|
||||
void BlockedModsDialog::openAll()
|
||||
{
|
||||
for (auto& mod : m_mods) {
|
||||
QDesktopServices::openUrl(mod.websiteUrl);
|
||||
}
|
||||
}
|
||||
|
||||
void BlockedModsDialog::addDownloadFolder()
|
||||
{
|
||||
QString dir =
|
||||
QFileDialog::getExistingDirectory(this, tr("Select directory where you downloaded the mods"),
|
||||
QStandardPaths::writableLocation(QStandardPaths::DownloadLocation), QFileDialog::ShowDirsOnly);
|
||||
qDebug() << "[Blocked Mods Dialog] Adding watch path:" << dir;
|
||||
m_watcher.addPath(dir);
|
||||
scanPath(dir, true);
|
||||
update();
|
||||
}
|
||||
|
||||
/// @brief update UI with current status of the blocked mod detection
|
||||
void BlockedModsDialog::update()
|
||||
{
|
||||
QString text;
|
||||
QString span;
|
||||
|
||||
for (auto& mod : m_mods) {
|
||||
if (mod.matched) {
|
||||
// ✔ -> html for HEAVY CHECK MARK : ✔
|
||||
span = QString(tr("<span style=\"color:green\"> ✔ Found at %1 </span>")).arg(mod.localPath);
|
||||
} else {
|
||||
// ✘ -> html for HEAVY BALLOT X : ✘
|
||||
span = QString(tr("<span style=\"color:red\"> ✘ Not Found </span>"));
|
||||
}
|
||||
text += QString(tr("%1: <a href='%2'>%2</a> <p>Hash: %3 %4</p> <br/>")).arg(mod.name, mod.websiteUrl, mod.hash, span);
|
||||
}
|
||||
|
||||
ui->textBrowserModsListing->setText(text);
|
||||
|
||||
QString watching;
|
||||
for (auto& dir : m_watcher.directories()) {
|
||||
watching += QString("<a href=\"%1\">%1</a><br/>").arg(dir);
|
||||
}
|
||||
|
||||
ui->textBrowserWatched->setText(watching);
|
||||
|
||||
if (allModsMatched()) {
|
||||
ui->labelModsFound->setText("<span style=\"color:green\">✔</span>" + tr("All mods found"));
|
||||
} else {
|
||||
ui->labelModsFound->setText(tr("Please download the missing mods."));
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief Signal fired when a watched direcotry has changed
|
||||
/// @param path the path to the changed directory
|
||||
void BlockedModsDialog::directoryChanged(QString path)
|
||||
{
|
||||
qDebug() << "[Blocked Mods Dialog] Directory changed: " << path;
|
||||
validateMatchedMods();
|
||||
scanPath(path, true);
|
||||
}
|
||||
|
||||
/// @brief add the user downloads folder and the global mods folder to the filesystem watcher
|
||||
void BlockedModsDialog::setupWatch()
|
||||
{
|
||||
const QString downloadsFolder = QStandardPaths::writableLocation(QStandardPaths::DownloadLocation);
|
||||
const QString modsFolder = APPLICATION->settings()->get("CentralModsDir").toString();
|
||||
m_watcher.addPath(downloadsFolder);
|
||||
m_watcher.addPath(modsFolder);
|
||||
}
|
||||
|
||||
/// @brief scan all watched folder
|
||||
void BlockedModsDialog::scanPaths()
|
||||
{
|
||||
for (auto& dir : m_watcher.directories()) {
|
||||
scanPath(dir, false);
|
||||
}
|
||||
runHashTask();
|
||||
}
|
||||
|
||||
/// @brief Scan the directory at path, skip paths that do not contain a file name
|
||||
/// of a blocked mod we are looking for
|
||||
/// @param path the directory to scan
|
||||
void BlockedModsDialog::scanPath(QString path, bool start_task)
|
||||
{
|
||||
QDir scan_dir(path);
|
||||
QDirIterator scan_it(path, QDir::Filter::Files | QDir::Filter::Hidden, QDirIterator::NoIteratorFlags);
|
||||
while (scan_it.hasNext()) {
|
||||
QString file = scan_it.next();
|
||||
|
||||
if (!checkValidPath(file)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
addHashTask(file);
|
||||
}
|
||||
|
||||
if (start_task) {
|
||||
runHashTask();
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief add a hashing task for the file located at path, add the path to the pending set if the hasing task is already running
|
||||
/// @param path the path to the local file being hashed
|
||||
void BlockedModsDialog::addHashTask(QString path)
|
||||
{
|
||||
qDebug() << "[Blocked Mods Dialog] adding a Hash task for" << path << "to the pending set.";
|
||||
m_pending_hash_paths.insert(path);
|
||||
}
|
||||
|
||||
/// @brief add a hashing task for the file located at path and connect it to check that hash against
|
||||
/// our blocked mods list
|
||||
/// @param path the path to the local file being hashed
|
||||
void BlockedModsDialog::buildHashTask(QString path)
|
||||
{
|
||||
auto hash_task = Hashing::createBlockedModHasher(path, ModPlatform::Provider::FLAME, "sha1");
|
||||
|
||||
qDebug() << "[Blocked Mods Dialog] Creating Hash task for path: " << path;
|
||||
|
||||
connect(hash_task.get(), &Task::succeeded, this, [this, hash_task, path] { checkMatchHash(hash_task->getResult(), path); });
|
||||
connect(hash_task.get(), &Task::failed, this, [path] { qDebug() << "Failed to hash path: " << path; });
|
||||
|
||||
m_hashing_task->addTask(hash_task);
|
||||
}
|
||||
|
||||
/// @brief check if the computed hash for the provided path matches a blocked
|
||||
/// mod we are looking for
|
||||
/// @param hash the computed hash for the provided path
|
||||
/// @param path the path to the local file being compared
|
||||
void BlockedModsDialog::checkMatchHash(QString hash, QString path)
|
||||
{
|
||||
bool match = false;
|
||||
|
||||
qDebug() << "[Blocked Mods Dialog] Checking for match on hash: " << hash << "| From path:" << path;
|
||||
|
||||
for (auto& mod : m_mods) {
|
||||
if (mod.matched) {
|
||||
continue;
|
||||
}
|
||||
if (mod.hash.compare(hash, Qt::CaseInsensitive) == 0) {
|
||||
mod.matched = true;
|
||||
mod.localPath = path;
|
||||
match = true;
|
||||
|
||||
qDebug() << "[Blocked Mods Dialog] Hash match found:" << mod.name << hash << "| From path:" << path;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (match) {
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief Check if the name of the file at path matches the name of a blocked mod we are searching for
|
||||
/// @param path the path to check
|
||||
/// @return boolean: did the path match the name of a blocked mod?
|
||||
bool BlockedModsDialog::checkValidPath(QString path)
|
||||
{
|
||||
QFileInfo file = QFileInfo(path);
|
||||
QString filename = file.fileName();
|
||||
|
||||
for (auto& mod : m_mods) {
|
||||
if (mod.name.compare(filename, Qt::CaseInsensitive) == 0) {
|
||||
qDebug() << "[Blocked Mods Dialog] Name match found:" << mod.name << "| From path:" << path;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool BlockedModsDialog::allModsMatched()
|
||||
{
|
||||
return std::all_of(m_mods.begin(), m_mods.end(), [](auto const& mod) { return mod.matched; });
|
||||
}
|
||||
|
||||
/// @brief ensure matched file paths still exist
|
||||
void BlockedModsDialog::validateMatchedMods()
|
||||
{
|
||||
bool changed = false;
|
||||
for (auto& mod : m_mods) {
|
||||
if (mod.matched) {
|
||||
QFileInfo file = QFileInfo(mod.localPath);
|
||||
if (!file.exists() || !file.isFile()) {
|
||||
qDebug() << "[Blocked Mods Dialog] File" << mod.localPath << "for mod" << mod.name
|
||||
<< "has vanshed! marking as not matched.";
|
||||
mod.localPath = "";
|
||||
mod.matched = false;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (changed) {
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief run hash task or mark a pending run if it is already runing
|
||||
void BlockedModsDialog::runHashTask()
|
||||
{
|
||||
if (!m_hashing_task->isRunning()) {
|
||||
m_rehash_pending = false;
|
||||
|
||||
if (!m_pending_hash_paths.isEmpty()) {
|
||||
qDebug() << "[Blocked Mods Dialog] there are pending hash tasks, building and running tasks";
|
||||
|
||||
auto path = m_pending_hash_paths.begin();
|
||||
while (path != m_pending_hash_paths.end()) {
|
||||
buildHashTask(*path);
|
||||
path = m_pending_hash_paths.erase(path);
|
||||
}
|
||||
|
||||
m_hashing_task->start();
|
||||
}
|
||||
} else {
|
||||
qDebug() << "[Blocked Mods Dialog] queueing another run of the hashing task";
|
||||
qDebug() << "[Blocked Mods Dialog] pending hash tasks:" << m_pending_hash_paths;
|
||||
m_rehash_pending = true;
|
||||
}
|
||||
}
|
||||
|
||||
void BlockedModsDialog::hashTaskFinished()
|
||||
{
|
||||
qDebug() << "[Blocked Mods Dialog] All hash tasks finished";
|
||||
if (m_rehash_pending) {
|
||||
qDebug() << "[Blocked Mods Dialog] task finished with a rehash pending, rerunning";
|
||||
runHashTask();
|
||||
}
|
||||
}
|
||||
|
||||
/// qDebug print support for the BlockedMod struct
|
||||
QDebug operator<<(QDebug debug, const BlockedMod& m)
|
||||
{
|
||||
QDebugStateSaver saver(debug);
|
||||
|
||||
debug.nospace() << "{ name: " << m.name << ", websiteUrl: " << m.websiteUrl << ", hash: " << m.hash << ", matched: " << m.matched
|
||||
<< ", localPath: " << m.localPath << "}";
|
||||
|
||||
return debug;
|
||||
}
|
||||
|
@ -1,22 +1,68 @@
|
||||
#pragma once
|
||||
|
||||
#include <QDialog>
|
||||
#include <QList>
|
||||
#include <QString>
|
||||
|
||||
#include <QFileSystemWatcher>
|
||||
|
||||
#include "modplatform/helpers/HashUtils.h"
|
||||
|
||||
#include "tasks/ConcurrentTask.h"
|
||||
|
||||
struct BlockedMod {
|
||||
QString name;
|
||||
QString websiteUrl;
|
||||
QString hash;
|
||||
bool matched;
|
||||
QString localPath;
|
||||
};
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
namespace Ui { class BlockedModsDialog; }
|
||||
namespace Ui {
|
||||
class BlockedModsDialog;
|
||||
}
|
||||
QT_END_NAMESPACE
|
||||
|
||||
class BlockedModsDialog : public QDialog {
|
||||
Q_OBJECT
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
BlockedModsDialog(QWidget *parent, const QString &title, const QString &text, const QString &body, const QList<QUrl> &urls);
|
||||
public:
|
||||
BlockedModsDialog(QWidget* parent, const QString& title, const QString& text, QList<BlockedMod>& mods);
|
||||
|
||||
~BlockedModsDialog() override;
|
||||
|
||||
private:
|
||||
Ui::BlockedModsDialog *ui;
|
||||
const QList<QUrl> &urls;
|
||||
protected:
|
||||
void dragEnterEvent(QDragEnterEvent* event) override;
|
||||
void dropEvent(QDropEvent* event) override;
|
||||
|
||||
protected slots:
|
||||
void done(int r) override;
|
||||
|
||||
private:
|
||||
Ui::BlockedModsDialog* ui;
|
||||
QList<BlockedMod>& m_mods;
|
||||
QFileSystemWatcher m_watcher;
|
||||
shared_qobject_ptr<ConcurrentTask> m_hashing_task;
|
||||
QSet<QString> m_pending_hash_paths;
|
||||
bool m_rehash_pending;
|
||||
|
||||
void openAll();
|
||||
void addDownloadFolder();
|
||||
void update();
|
||||
void directoryChanged(QString path);
|
||||
void setupWatch();
|
||||
void scanPaths();
|
||||
void scanPath(QString path, bool start_task);
|
||||
void addHashTask(QString path);
|
||||
void buildHashTask(QString path);
|
||||
void checkMatchHash(QString hash, QString path);
|
||||
void validateMatchedMods();
|
||||
void runHashTask();
|
||||
void hashTaskFinished();
|
||||
|
||||
bool checkValidPath(QString path);
|
||||
bool allModsMatched();
|
||||
};
|
||||
|
||||
QDebug operator<<(QDebug debug, const BlockedMod& m);
|
||||
|
@ -13,29 +13,41 @@
|
||||
<property name="windowTitle">
|
||||
<string notr="true">BlockedModsDialog</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="labelDescription">
|
||||
<property name="text">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<property name="textFormat">
|
||||
<enum>Qt::RichText</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QTextBrowser" name="textBrowser">
|
||||
<item>
|
||||
<widget class="QLabel" name="labelExplain">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="openExternalLinks">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QTextBrowser" name="textBrowserModsListing">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>165</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="acceptRichText">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
@ -44,6 +56,68 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="labelWatched">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>1</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Watched Folders:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QTextBrowser" name="textBrowserWatched">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Minimum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>16</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="baseSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>12</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="openExternalLinks">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="openLinks">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="bottomBoxH">
|
||||
<item>
|
||||
<widget class="QLabel" name="labelModsFound">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
|
@ -44,7 +44,6 @@
|
||||
|
||||
#include "BaseVersion.h"
|
||||
#include "icons/IconList.h"
|
||||
#include "tasks/Task.h"
|
||||
#include "BaseInstance.h"
|
||||
#include "InstanceList.h"
|
||||
|
||||
@ -78,8 +77,14 @@ CopyInstanceDialog::CopyInstanceDialog(InstancePtr original, QWidget *parent)
|
||||
}
|
||||
ui->groupBox->setCurrentIndex(index);
|
||||
ui->groupBox->lineEdit()->setPlaceholderText(tr("No category"));
|
||||
ui->copySavesCheckbox->setChecked(m_copySaves);
|
||||
ui->keepPlaytimeCheckbox->setChecked(m_keepPlaytime);
|
||||
ui->copySavesCheckbox->setChecked(m_selectedOptions.isCopySavesEnabled());
|
||||
ui->keepPlaytimeCheckbox->setChecked(m_selectedOptions.isKeepPlaytimeEnabled());
|
||||
ui->copyGameOptionsCheckbox->setChecked(m_selectedOptions.isCopyGameOptionsEnabled());
|
||||
ui->copyResPacksCheckbox->setChecked(m_selectedOptions.isCopyResourcePacksEnabled());
|
||||
ui->copyShaderPacksCheckbox->setChecked(m_selectedOptions.isCopyShaderPacksEnabled());
|
||||
ui->copyServersCheckbox->setChecked(m_selectedOptions.isCopyServersEnabled());
|
||||
ui->copyModsCheckbox->setChecked(m_selectedOptions.isCopyModsEnabled());
|
||||
ui->copyScreenshotsCheckbox->setChecked(m_selectedOptions.isCopyScreenshotsEnabled());
|
||||
}
|
||||
|
||||
CopyInstanceDialog::~CopyInstanceDialog()
|
||||
@ -117,6 +122,31 @@ QString CopyInstanceDialog::instGroup() const
|
||||
return ui->groupBox->currentText();
|
||||
}
|
||||
|
||||
const InstanceCopyPrefs& CopyInstanceDialog::getChosenOptions() const
|
||||
{
|
||||
return m_selectedOptions;
|
||||
}
|
||||
|
||||
void CopyInstanceDialog::checkAllCheckboxes(const bool& b)
|
||||
{
|
||||
ui->keepPlaytimeCheckbox->setChecked(b);
|
||||
ui->copySavesCheckbox->setChecked(b);
|
||||
ui->copyGameOptionsCheckbox->setChecked(b);
|
||||
ui->copyResPacksCheckbox->setChecked(b);
|
||||
ui->copyShaderPacksCheckbox->setChecked(b);
|
||||
ui->copyServersCheckbox->setChecked(b);
|
||||
ui->copyModsCheckbox->setChecked(b);
|
||||
ui->copyScreenshotsCheckbox->setChecked(b);
|
||||
}
|
||||
|
||||
// Check the "Select all" checkbox if all options are already selected:
|
||||
void CopyInstanceDialog::updateSelectAllCheckbox()
|
||||
{
|
||||
ui->selectAllCheckbox->blockSignals(true);
|
||||
ui->selectAllCheckbox->setChecked(m_selectedOptions.allTrue());
|
||||
ui->selectAllCheckbox->blockSignals(false);
|
||||
}
|
||||
|
||||
void CopyInstanceDialog::on_iconButton_clicked()
|
||||
{
|
||||
IconPickerDialog dlg(this);
|
||||
@ -129,42 +159,64 @@ void CopyInstanceDialog::on_iconButton_clicked()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void CopyInstanceDialog::on_instNameTextBox_textChanged(const QString &arg1)
|
||||
{
|
||||
updateDialogState();
|
||||
}
|
||||
|
||||
bool CopyInstanceDialog::shouldCopySaves() const
|
||||
void CopyInstanceDialog::on_selectAllCheckbox_stateChanged(int state)
|
||||
{
|
||||
return m_copySaves;
|
||||
bool checked;
|
||||
checked = (state == Qt::Checked);
|
||||
checkAllCheckboxes(checked);
|
||||
}
|
||||
|
||||
void CopyInstanceDialog::on_copySavesCheckbox_stateChanged(int state)
|
||||
{
|
||||
if(state == Qt::Unchecked)
|
||||
{
|
||||
m_copySaves = false;
|
||||
}
|
||||
else if(state == Qt::Checked)
|
||||
{
|
||||
m_copySaves = true;
|
||||
}
|
||||
}
|
||||
|
||||
bool CopyInstanceDialog::shouldKeepPlaytime() const
|
||||
{
|
||||
return m_keepPlaytime;
|
||||
m_selectedOptions.enableCopySaves(state == Qt::Checked);
|
||||
updateSelectAllCheckbox();
|
||||
}
|
||||
|
||||
|
||||
void CopyInstanceDialog::on_keepPlaytimeCheckbox_stateChanged(int state)
|
||||
{
|
||||
if(state == Qt::Unchecked)
|
||||
{
|
||||
m_keepPlaytime = false;
|
||||
}
|
||||
else if(state == Qt::Checked)
|
||||
{
|
||||
m_keepPlaytime = true;
|
||||
}
|
||||
m_selectedOptions.enableKeepPlaytime(state == Qt::Checked);
|
||||
updateSelectAllCheckbox();
|
||||
}
|
||||
|
||||
void CopyInstanceDialog::on_copyGameOptionsCheckbox_stateChanged(int state)
|
||||
{
|
||||
m_selectedOptions.enableCopyGameOptions(state == Qt::Checked);
|
||||
updateSelectAllCheckbox();
|
||||
}
|
||||
|
||||
void CopyInstanceDialog::on_copyResPacksCheckbox_stateChanged(int state)
|
||||
{
|
||||
m_selectedOptions.enableCopyResourcePacks(state == Qt::Checked);
|
||||
updateSelectAllCheckbox();
|
||||
}
|
||||
|
||||
void CopyInstanceDialog::on_copyShaderPacksCheckbox_stateChanged(int state)
|
||||
{
|
||||
m_selectedOptions.enableCopyShaderPacks(state == Qt::Checked);
|
||||
updateSelectAllCheckbox();
|
||||
}
|
||||
|
||||
void CopyInstanceDialog::on_copyServersCheckbox_stateChanged(int state)
|
||||
{
|
||||
m_selectedOptions.enableCopyServers(state == Qt::Checked);
|
||||
updateSelectAllCheckbox();
|
||||
}
|
||||
|
||||
void CopyInstanceDialog::on_copyModsCheckbox_stateChanged(int state)
|
||||
{
|
||||
m_selectedOptions.enableCopyMods(state == Qt::Checked);
|
||||
updateSelectAllCheckbox();
|
||||
}
|
||||
|
||||
void CopyInstanceDialog::on_copyScreenshotsCheckbox_stateChanged(int state)
|
||||
{
|
||||
m_selectedOptions.enableCopyScreenshots(state == Qt::Checked);
|
||||
updateSelectAllCheckbox();
|
||||
}
|
||||
|
@ -17,7 +17,7 @@
|
||||
|
||||
#include <QDialog>
|
||||
#include "BaseVersion.h"
|
||||
#include <BaseInstance.h>
|
||||
#include "InstanceCopyPrefs.h"
|
||||
|
||||
class BaseInstance;
|
||||
|
||||
@ -39,20 +39,29 @@ public:
|
||||
QString instName() const;
|
||||
QString instGroup() const;
|
||||
QString iconKey() const;
|
||||
bool shouldCopySaves() const;
|
||||
bool shouldKeepPlaytime() const;
|
||||
const InstanceCopyPrefs& getChosenOptions() const;
|
||||
|
||||
private
|
||||
slots:
|
||||
void on_iconButton_clicked();
|
||||
void on_instNameTextBox_textChanged(const QString &arg1);
|
||||
// Checkboxes
|
||||
void on_selectAllCheckbox_stateChanged(int state);
|
||||
void on_copySavesCheckbox_stateChanged(int state);
|
||||
void on_keepPlaytimeCheckbox_stateChanged(int state);
|
||||
void on_copyGameOptionsCheckbox_stateChanged(int state);
|
||||
void on_copyResPacksCheckbox_stateChanged(int state);
|
||||
void on_copyShaderPacksCheckbox_stateChanged(int state);
|
||||
void on_copyServersCheckbox_stateChanged(int state);
|
||||
void on_copyModsCheckbox_stateChanged(int state);
|
||||
void on_copyScreenshotsCheckbox_stateChanged(int state);
|
||||
|
||||
private:
|
||||
void checkAllCheckboxes(const bool& b);
|
||||
void updateSelectAllCheckbox();
|
||||
/* data */
|
||||
Ui::CopyInstanceDialog *ui;
|
||||
QString InstIconKey;
|
||||
InstancePtr m_original;
|
||||
bool m_copySaves = true;
|
||||
bool m_keepPlaytime = true;
|
||||
InstanceCopyPrefs m_selectedOptions;
|
||||
};
|
||||
|
@ -9,8 +9,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>345</width>
|
||||
<height>323</height>
|
||||
<width>341</width>
|
||||
<height>399</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
@ -33,7 +33,7 @@
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<width>60</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
@ -60,7 +60,7 @@
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<width>60</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
@ -83,7 +83,10 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<layout class="QGridLayout" name="groupDropdownLayout">
|
||||
<property name="verticalSpacing">
|
||||
<number>6</number>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="labelVersion_3">
|
||||
<property name="text">
|
||||
@ -110,18 +113,96 @@
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="copySavesCheckbox">
|
||||
<property name="text">
|
||||
<string>Copy saves</string>
|
||||
</property>
|
||||
</widget>
|
||||
<layout class="QHBoxLayout" name="selectAllButtonLayout">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="selectAllCheckbox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="layoutDirection">
|
||||
<enum>Qt::LeftToRight</enum>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Select all</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="keepPlaytimeCheckbox">
|
||||
<property name="text">
|
||||
<string>Keep play time</string>
|
||||
</property>
|
||||
</widget>
|
||||
<layout class="QGridLayout" name="copyOptionsLayout">
|
||||
<item row="6" column="1">
|
||||
<widget class="QCheckBox" name="copyModsCheckbox">
|
||||
<property name="toolTip">
|
||||
<string>Disabling this will still keep the mod loader (ex: Fabric, Quilt, etc.) but erase the mods folder and their configs.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Copy mods</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<widget class="QCheckBox" name="copyGameOptionsCheckbox">
|
||||
<property name="toolTip">
|
||||
<string>Copy the in-game options like FOV, max framerate, etc.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Copy game options</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QCheckBox" name="copySavesCheckbox">
|
||||
<property name="text">
|
||||
<string>Copy saves</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QCheckBox" name="copyShaderPacksCheckbox">
|
||||
<property name="text">
|
||||
<string>Copy shader packs</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<widget class="QCheckBox" name="copyServersCheckbox">
|
||||
<property name="text">
|
||||
<string>Copy servers</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="0">
|
||||
<widget class="QCheckBox" name="copyResPacksCheckbox">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Copy resource packs</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QCheckBox" name="keepPlaytimeCheckbox">
|
||||
<property name="text">
|
||||
<string>Keep play time</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QCheckBox" name="copyScreenshotsCheckbox">
|
||||
<property name="text">
|
||||
<string>Copy screenshots</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
@ -139,8 +220,6 @@
|
||||
<tabstop>iconButton</tabstop>
|
||||
<tabstop>instNameTextBox</tabstop>
|
||||
<tabstop>groupBox</tabstop>
|
||||
<tabstop>copySavesCheckbox</tabstop>
|
||||
<tabstop>keepPlaytimeCheckbox</tabstop>
|
||||
</tabstops>
|
||||
<resources>
|
||||
<include location="../../graphics.qrc"/>
|
||||
@ -153,8 +232,8 @@
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>248</x>
|
||||
<y>254</y>
|
||||
<x>254</x>
|
||||
<y>316</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
@ -169,8 +248,8 @@
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>316</x>
|
||||
<y>260</y>
|
||||
<x>322</x>
|
||||
<y>316</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
|
@ -39,13 +39,12 @@
|
||||
#include <MMCZip.h>
|
||||
#include <QFileDialog>
|
||||
#include <QMessageBox>
|
||||
#include <qfilesystemmodel.h>
|
||||
#include <QFileSystemModel>
|
||||
|
||||
#include <QSortFilterProxyModel>
|
||||
#include <QDebug>
|
||||
#include <qstack.h>
|
||||
#include <QSaveFile>
|
||||
#include "MMCStrings.h"
|
||||
#include "StringUtils.h"
|
||||
#include "SeparatorPrefixTree.h"
|
||||
#include "Application.h"
|
||||
#include <icons/IconList.h>
|
||||
@ -85,7 +84,7 @@ public:
|
||||
// sort and proxy model breaks the original model...
|
||||
if (sortColumn() == 0)
|
||||
{
|
||||
return Strings::naturalCompare(leftFileInfo.fileName(), rightFileInfo.fileName(),
|
||||
return StringUtils::naturalCompare(leftFileInfo.fileName(), rightFileInfo.fileName(),
|
||||
Qt::CaseInsensitive) < 0;
|
||||
}
|
||||
if (sortColumn() == 1)
|
||||
@ -94,7 +93,7 @@ public:
|
||||
auto rightSize = rightFileInfo.size();
|
||||
if ((leftSize == rightSize) || (leftFileInfo.isDir() && rightFileInfo.isDir()))
|
||||
{
|
||||
return Strings::naturalCompare(leftFileInfo.fileName(),
|
||||
return StringUtils::naturalCompare(leftFileInfo.fileName(),
|
||||
rightFileInfo.fileName(),
|
||||
Qt::CaseInsensitive) < 0
|
||||
? asc
|
||||
|
66
launcher/ui/dialogs/ImportResourcePackDialog.cpp
Normal file
66
launcher/ui/dialogs/ImportResourcePackDialog.cpp
Normal file
@ -0,0 +1,66 @@
|
||||
#include "ImportResourcePackDialog.h"
|
||||
#include "ui_ImportResourcePackDialog.h"
|
||||
|
||||
#include <QFileDialog>
|
||||
#include <QPushButton>
|
||||
|
||||
#include "Application.h"
|
||||
#include "InstanceList.h"
|
||||
|
||||
#include <InstanceList.h>
|
||||
#include "ui/instanceview/InstanceGridProxyModel.h"
|
||||
#include "ui/instanceview/InstanceDelegate.h"
|
||||
|
||||
ImportResourcePackDialog::ImportResourcePackDialog(QWidget* parent) : QDialog(parent), ui(new Ui::ImportResourcePackDialog)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
setWindowModality(Qt::WindowModal);
|
||||
|
||||
auto contentsWidget = ui->instanceView;
|
||||
contentsWidget->setViewMode(QListView::ListMode);
|
||||
contentsWidget->setFlow(QListView::LeftToRight);
|
||||
contentsWidget->setIconSize(QSize(48, 48));
|
||||
contentsWidget->setMovement(QListView::Static);
|
||||
contentsWidget->setResizeMode(QListView::Adjust);
|
||||
contentsWidget->setSelectionMode(QAbstractItemView::SingleSelection);
|
||||
contentsWidget->setSpacing(5);
|
||||
contentsWidget->setWordWrap(true);
|
||||
contentsWidget->setWrapping(true);
|
||||
// NOTE: We can't have uniform sizes because the text may wrap if it's too long. If we set this, it will cut off the wrapped text.
|
||||
contentsWidget->setUniformItemSizes(false);
|
||||
contentsWidget->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel);
|
||||
contentsWidget->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
|
||||
contentsWidget->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||
contentsWidget->setItemDelegate(new InstanceDelegate());
|
||||
|
||||
proxyModel = new InstanceGridProxyModel(this);
|
||||
proxyModel->setSourceModel(APPLICATION->instances().get());
|
||||
proxyModel->sort(0);
|
||||
contentsWidget->setModel(proxyModel);
|
||||
|
||||
connect(contentsWidget, SIGNAL(doubleClicked(QModelIndex)), SLOT(activated(QModelIndex)));
|
||||
connect(contentsWidget->selectionModel(), SIGNAL(selectionChanged(QItemSelection, QItemSelection)),
|
||||
SLOT(selectionChanged(QItemSelection, QItemSelection)));
|
||||
}
|
||||
|
||||
void ImportResourcePackDialog::activated(QModelIndex index)
|
||||
{
|
||||
selectedInstanceKey = index.data(InstanceList::InstanceIDRole).toString();
|
||||
accept();
|
||||
}
|
||||
|
||||
void ImportResourcePackDialog::selectionChanged(QItemSelection selected, QItemSelection deselected)
|
||||
{
|
||||
if (selected.empty())
|
||||
return;
|
||||
|
||||
QString key = selected.first().indexes().first().data(InstanceList::InstanceIDRole).toString();
|
||||
if (!key.isEmpty()) {
|
||||
selectedInstanceKey = key;
|
||||
}
|
||||
}
|
||||
|
||||
ImportResourcePackDialog::~ImportResourcePackDialog()
|
||||
{
|
||||
delete ui;
|
||||
}
|
27
launcher/ui/dialogs/ImportResourcePackDialog.h
Normal file
27
launcher/ui/dialogs/ImportResourcePackDialog.h
Normal file
@ -0,0 +1,27 @@
|
||||
#pragma once
|
||||
|
||||
#include <QDialog>
|
||||
#include <QItemSelection>
|
||||
|
||||
#include "ui/instanceview/InstanceGridProxyModel.h"
|
||||
|
||||
namespace Ui {
|
||||
class ImportResourcePackDialog;
|
||||
}
|
||||
|
||||
class ImportResourcePackDialog : public QDialog {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ImportResourcePackDialog(QWidget* parent = 0);
|
||||
~ImportResourcePackDialog();
|
||||
InstanceGridProxyModel* proxyModel;
|
||||
QString selectedInstanceKey;
|
||||
|
||||
private:
|
||||
Ui::ImportResourcePackDialog* ui;
|
||||
|
||||
private slots:
|
||||
void selectionChanged(QItemSelection, QItemSelection);
|
||||
void activated(QModelIndex);
|
||||
};
|
74
launcher/ui/dialogs/ImportResourcePackDialog.ui
Normal file
74
launcher/ui/dialogs/ImportResourcePackDialog.ui
Normal file
@ -0,0 +1,74 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>ImportResourcePackDialog</class>
|
||||
<widget class="QDialog" name="ImportResourcePackDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>676</width>
|
||||
<height>555</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Choose instance to import</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Choose the instance you would like to import this resource pack to.</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QListView" name="instanceView"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>ImportResourcePackDialog</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>248</x>
|
||||
<y>254</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>157</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>ImportResourcePackDialog</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>316</x>
|
||||
<y>260</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>286</x>
|
||||
<y>274</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
@ -1,7 +1,8 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Prism Launcher - Minecraft Launcher
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||
* Copyright (C) 2022 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
|
||||
@ -131,6 +132,8 @@ QList<BasePage*> ModDownloadDialog::getPages()
|
||||
if (APPLICATION->capabilities() & Application::SupportsFlame)
|
||||
pages.append(FlameModPage::create(this, m_instance));
|
||||
|
||||
m_selectedPage = dynamic_cast<ModPage*>(pages[0]);
|
||||
|
||||
return pages;
|
||||
}
|
||||
|
||||
@ -178,12 +181,22 @@ void ModDownloadDialog::selectedPageChanged(BasePage* previous, BasePage* select
|
||||
return;
|
||||
}
|
||||
|
||||
auto* selected_page = dynamic_cast<ModPage*>(selected);
|
||||
if (!selected_page) {
|
||||
m_selectedPage = dynamic_cast<ModPage*>(selected);
|
||||
if (!m_selectedPage) {
|
||||
qCritical() << "Page '" << selected->displayName() << "' in ModDownloadDialog is not a ModPage!";
|
||||
return;
|
||||
}
|
||||
|
||||
// Same effect as having a global search bar
|
||||
selected_page->setSearchTerm(prev_page->getSearchTerm());
|
||||
m_selectedPage->setSearchTerm(prev_page->getSearchTerm());
|
||||
}
|
||||
|
||||
bool ModDownloadDialog::selectPage(QString pageId)
|
||||
{
|
||||
return m_container->selectPage(pageId);
|
||||
}
|
||||
|
||||
ModPage* ModDownloadDialog::getSelectedPage()
|
||||
{
|
||||
return m_selectedPage;
|
||||
}
|
||||
|
@ -1,7 +1,8 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Prism Launcher - Minecraft Launcher
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||
* Copyright (C) 2022 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
|
||||
@ -32,13 +33,14 @@ class ModDownloadDialog;
|
||||
|
||||
class PageContainer;
|
||||
class QDialogButtonBox;
|
||||
class ModPage;
|
||||
class ModrinthModPage;
|
||||
|
||||
class ModDownloadDialog final : public QDialog, public BasePageProvider
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
public:
|
||||
explicit ModDownloadDialog(const std::shared_ptr<ModFolderModel>& mods, QWidget* parent, BaseInstance* instance);
|
||||
~ModDownloadDialog() override = default;
|
||||
|
||||
@ -51,22 +53,26 @@ public:
|
||||
bool isModSelected(QString name) const;
|
||||
|
||||
const QList<ModDownloadTask*> getTasks();
|
||||
const std::shared_ptr<ModFolderModel> &mods;
|
||||
const std::shared_ptr<ModFolderModel>& mods;
|
||||
|
||||
public slots:
|
||||
bool selectPage(QString pageId);
|
||||
ModPage* getSelectedPage();
|
||||
|
||||
public slots:
|
||||
void confirm();
|
||||
void accept() override;
|
||||
void reject() override;
|
||||
|
||||
private slots:
|
||||
private slots:
|
||||
void selectedPageChanged(BasePage* previous, BasePage* selected);
|
||||
|
||||
private:
|
||||
Ui::ModDownloadDialog *ui = nullptr;
|
||||
PageContainer * m_container = nullptr;
|
||||
QDialogButtonBox * m_buttons = nullptr;
|
||||
QVBoxLayout *m_verticalLayout = nullptr;
|
||||
private:
|
||||
Ui::ModDownloadDialog* ui = nullptr;
|
||||
PageContainer* m_container = nullptr;
|
||||
QDialogButtonBox* m_buttons = nullptr;
|
||||
QVBoxLayout* m_verticalLayout = nullptr;
|
||||
ModPage* m_selectedPage = nullptr;
|
||||
|
||||
QHash<QString, ModDownloadTask*> modTask;
|
||||
BaseInstance *m_instance;
|
||||
BaseInstance* m_instance;
|
||||
};
|
||||
|
@ -366,33 +366,28 @@ void ModUpdateDialog::appendMod(CheckUpdateTask::UpdatableMod const& info)
|
||||
auto changelog = new QTreeWidgetItem(changelog_item);
|
||||
auto changelog_area = new QTextBrowser();
|
||||
|
||||
QString text = info.changelog;
|
||||
switch (info.provider) {
|
||||
case ModPlatform::Provider::MODRINTH: {
|
||||
HoeDown h;
|
||||
// HoeDown bug?: \n aren't converted to <br>
|
||||
auto text = h.process(info.changelog.toUtf8());
|
||||
text = h.process(info.changelog.toUtf8());
|
||||
|
||||
// Don't convert if there's an HTML tag right after (Qt rendering weirdness)
|
||||
text.remove(QRegularExpression("(\n+)(?=<)"));
|
||||
text.replace('\n', "<br>");
|
||||
|
||||
changelog_area->setHtml(text);
|
||||
break;
|
||||
}
|
||||
case ModPlatform::Provider::FLAME: {
|
||||
changelog_area->setHtml(info.changelog);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
changelog_area->setHtml(text);
|
||||
changelog_area->setOpenExternalLinks(true);
|
||||
changelog_area->setLineWrapMode(QTextBrowser::LineWrapMode::NoWrap);
|
||||
changelog_area->setLineWrapMode(QTextBrowser::LineWrapMode::WidgetWidth);
|
||||
changelog_area->setVerticalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAsNeeded);
|
||||
|
||||
// HACK: Is there a better way of achieving this?
|
||||
auto font_height = QFontMetrics(changelog_area->font()).height();
|
||||
changelog_area->setMaximumHeight((changelog_area->toPlainText().count(QRegularExpression("\n|<br>")) + 2) * font_height);
|
||||
|
||||
ui->modTreeWidget->setItemWidget(changelog, 0, changelog_area);
|
||||
|
||||
ui->modTreeWidget->addTopLevelItem(item_top);
|
||||
|
@ -44,7 +44,8 @@ void ProgressDialog::setSkipButton(bool present, QString label)
|
||||
void ProgressDialog::on_skipButton_clicked(bool checked)
|
||||
{
|
||||
Q_UNUSED(checked);
|
||||
task->abort();
|
||||
if (ui->skipButton->isEnabled()) // prevent other triggers from aborting
|
||||
task->abort();
|
||||
}
|
||||
|
||||
ProgressDialog::~ProgressDialog()
|
||||
|
@ -120,7 +120,7 @@ void VersionSelectDialog::selectRecommended()
|
||||
m_versionWidget->selectRecommended();
|
||||
}
|
||||
|
||||
BaseVersionPtr VersionSelectDialog::selectedVersion() const
|
||||
BaseVersion::Ptr VersionSelectDialog::selectedVersion() const
|
||||
{
|
||||
return m_versionWidget->selectedVersion();
|
||||
}
|
||||
|
@ -44,7 +44,7 @@ public:
|
||||
|
||||
int exec() override;
|
||||
|
||||
BaseVersionPtr selectedVersion() const;
|
||||
BaseVersion::Ptr selectedVersion() const;
|
||||
|
||||
void setCurrentVersion(const QString & version);
|
||||
void setFuzzyFilter(BaseVersionList::ModelRoles role, QString filter);
|
||||
|
@ -261,15 +261,16 @@ void InstancesView::setCatDisplayed(bool enabled)
|
||||
{
|
||||
if (enabled) {
|
||||
QDateTime now = QDateTime::currentDateTime();
|
||||
QDateTime birthday(QDate(now.date().year(), 12, 28), QTime(0, 0));
|
||||
QDateTime xmas(QDate(now.date().year(), 12, 25), QTime(0, 0));
|
||||
QString cat;
|
||||
QDateTime halloween(QDate(now.date().year(), 10, 31), QTime(0, 0));
|
||||
QDateTime birthday(QDate(now.date().year(), 10, 17), QTime(00, 0));
|
||||
QString cat = APPLICATION->settings()->get("BackgroundCat").toString();
|
||||
if (std::abs(now.daysTo(xmas)) <= 4) {
|
||||
cat = "catmas";
|
||||
cat += "-xmas";
|
||||
} else if (std::abs(now.daysTo(halloween)) <= 12) {
|
||||
cat += "-spooky";
|
||||
} else if (std::abs(now.daysTo(birthday)) <= 12) {
|
||||
cat = "cattiversary";
|
||||
} else {
|
||||
cat = "kitteh";
|
||||
cat += "-bday";
|
||||
}
|
||||
setStyleSheet(QString(R"(
|
||||
* {
|
||||
|
@ -179,7 +179,7 @@
|
||||
<item>
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>Enter a custom client ID for Microsoft Authentication here. </string>
|
||||
<string>Enter a custom client ID for Microsoft Authentication here.</string>
|
||||
</property>
|
||||
<property name="textFormat">
|
||||
<enum>Qt::RichText</enum>
|
||||
|
@ -58,9 +58,8 @@ JavaPage::JavaPage(QWidget *parent) : QWidget(parent), ui(new Ui::JavaPage)
|
||||
ui->setupUi(this);
|
||||
ui->tabWidget->tabBar()->hide();
|
||||
|
||||
auto sysMiB = Sys::getSystemRam() / Sys::mebibyte;
|
||||
ui->maxMemSpinBox->setMaximum(sysMiB);
|
||||
loadSettings();
|
||||
updateThresholds();
|
||||
}
|
||||
|
||||
JavaPage::~JavaPage()
|
||||
@ -177,6 +176,11 @@ void JavaPage::on_javaTestBtn_clicked()
|
||||
checker->run();
|
||||
}
|
||||
|
||||
void JavaPage::on_maxMemSpinBox_valueChanged(int i)
|
||||
{
|
||||
updateThresholds();
|
||||
}
|
||||
|
||||
void JavaPage::checkerFinished()
|
||||
{
|
||||
checker.reset();
|
||||
@ -186,3 +190,29 @@ void JavaPage::retranslate()
|
||||
{
|
||||
ui->retranslateUi(this);
|
||||
}
|
||||
|
||||
void JavaPage::updateThresholds()
|
||||
{
|
||||
auto sysMiB = Sys::getSystemRam() / Sys::mebibyte;
|
||||
unsigned int maxMem = ui->maxMemSpinBox->value();
|
||||
|
||||
QString iconName;
|
||||
|
||||
if (maxMem >= sysMiB) {
|
||||
iconName = "status-bad";
|
||||
ui->labelMaxMemIcon->setToolTip(tr("Your maximum memory allocation exceeds your system memory capacity."));
|
||||
} else if (maxMem > (sysMiB * 0.9)) {
|
||||
iconName = "status-yellow";
|
||||
ui->labelMaxMemIcon->setToolTip(tr("Your maximum memory allocation approaches your system memory capacity."));
|
||||
} else {
|
||||
iconName = "status-good";
|
||||
ui->labelMaxMemIcon->setToolTip("");
|
||||
}
|
||||
|
||||
{
|
||||
auto height = ui->labelMaxMemIcon->fontInfo().pixelSize();
|
||||
QIcon icon = APPLICATION->getThemedIcon(iconName);
|
||||
QPixmap pix = icon.pixmap(height, height);
|
||||
ui->labelMaxMemIcon->setPixmap(pix);
|
||||
}
|
||||
}
|
||||
|
@ -76,6 +76,8 @@ public:
|
||||
bool apply() override;
|
||||
void retranslate() override;
|
||||
|
||||
void updateThresholds();
|
||||
|
||||
private:
|
||||
void applySettings();
|
||||
void loadSettings();
|
||||
@ -85,6 +87,7 @@ slots:
|
||||
void on_javaDetectBtn_clicked();
|
||||
void on_javaTestBtn_clicked();
|
||||
void on_javaBrowseBtn_clicked();
|
||||
void on_maxMemSpinBox_valueChanged(int i);
|
||||
void checkerFinished();
|
||||
|
||||
private:
|
||||
|
@ -44,39 +44,7 @@
|
||||
<property name="title">
|
||||
<string>Memory</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<item row="1" column="1">
|
||||
<widget class="QSpinBox" name="maxMemSpinBox">
|
||||
<property name="toolTip">
|
||||
<string>The maximum amount of memory Minecraft is allowed to use.</string>
|
||||
</property>
|
||||
<property name="suffix">
|
||||
<string notr="true"> MiB</string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>128</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>65536</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<number>128</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>1024</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="labelMinMem">
|
||||
<property name="text">
|
||||
<string>&Minimum memory allocation:</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>minMemSpinBox</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<layout class="QGridLayout" name="gridLayout_2" columnstretch="1,0,0,0">
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="labelMaxMem">
|
||||
<property name="text">
|
||||
@ -87,28 +55,6 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QSpinBox" name="minMemSpinBox">
|
||||
<property name="toolTip">
|
||||
<string>The amount of memory Minecraft is started with.</string>
|
||||
</property>
|
||||
<property name="suffix">
|
||||
<string notr="true"> MiB</string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>128</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>65536</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<number>128</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>256</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="labelPermGen">
|
||||
<property name="text">
|
||||
@ -119,7 +65,61 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="labelMinMem">
|
||||
<property name="text">
|
||||
<string>&Minimum memory allocation:</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>minMemSpinBox</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QSpinBox" name="minMemSpinBox">
|
||||
<property name="toolTip">
|
||||
<string>The amount of memory Minecraft is started with.</string>
|
||||
</property>
|
||||
<property name="suffix">
|
||||
<string notr="true"> MiB</string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>128</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>1048576</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<number>128</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>256</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QSpinBox" name="maxMemSpinBox">
|
||||
<property name="toolTip">
|
||||
<string>The maximum amount of memory Minecraft is allowed to use.</string>
|
||||
</property>
|
||||
<property name="suffix">
|
||||
<string notr="true"> MiB</string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>128</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>1048576</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<number>128</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>1024</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="2">
|
||||
<widget class="QSpinBox" name="permGenSpinBox">
|
||||
<property name="toolTip">
|
||||
<string>The amount of memory available to store loaded Java classes.</string>
|
||||
@ -141,6 +141,16 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="3">
|
||||
<widget class="QLabel" name="labelMaxMemIcon">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>maxMemSpinBox</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
|
@ -1,8 +1,9 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Prism Launcher - Minecraft Launcher
|
||||
* Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
|
||||
* Copyright (c) 2022 dada513 <dada513@protonmail.com>
|
||||
* Copyright (C) 2022 Tayou <tayou@gmx.net>
|
||||
*
|
||||
* 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
|
||||
@ -49,6 +50,7 @@
|
||||
#include <FileSystem.h>
|
||||
#include "Application.h"
|
||||
#include "BuildConfig.h"
|
||||
#include "DesktopServices.h"
|
||||
#include "ui/themes/ITheme.h"
|
||||
|
||||
#include <QApplication>
|
||||
@ -143,7 +145,7 @@ void LauncherPage::on_instDirBrowseBtn_clicked()
|
||||
ui->instDirTextBox->setText(cooked_dir);
|
||||
}
|
||||
}
|
||||
else if(APPLICATION->isFlatpak() && raw_dir.startsWith("/run/user"))
|
||||
else if(DesktopServices::isFlatpak() && raw_dir.startsWith("/run/user"))
|
||||
{
|
||||
QMessageBox warning;
|
||||
warning.setText(tr("You're trying to specify an instance folder "
|
||||
@ -301,18 +303,27 @@ void LauncherPage::applySettings()
|
||||
s->set("IconTheme", "pe_blue");
|
||||
break;
|
||||
case 4:
|
||||
s->set("IconTheme", "OSX");
|
||||
s->set("IconTheme", "breeze_light");
|
||||
break;
|
||||
case 5:
|
||||
s->set("IconTheme", "iOS");
|
||||
s->set("IconTheme", "breeze_dark");
|
||||
break;
|
||||
case 6:
|
||||
s->set("IconTheme", "flat");
|
||||
s->set("IconTheme", "OSX");
|
||||
break;
|
||||
case 7:
|
||||
s->set("IconTheme", "multimc");
|
||||
s->set("IconTheme", "iOS");
|
||||
break;
|
||||
case 8:
|
||||
s->set("IconTheme", "flat");
|
||||
break;
|
||||
case 9:
|
||||
s->set("IconTheme", "flat_white");
|
||||
break;
|
||||
case 10:
|
||||
s->set("IconTheme", "multimc");
|
||||
break;
|
||||
case 11:
|
||||
s->set("IconTheme", "custom");
|
||||
break;
|
||||
}
|
||||
@ -330,6 +341,18 @@ void LauncherPage::applySettings()
|
||||
APPLICATION->setApplicationTheme(newAppTheme, false);
|
||||
}
|
||||
|
||||
switch (ui->themeBackgroundCat->currentIndex()) {
|
||||
case 0: // original cat
|
||||
s->set("BackgroundCat", "kitteh");
|
||||
break;
|
||||
case 1: // rory the cat
|
||||
s->set("BackgroundCat", "rory");
|
||||
break;
|
||||
case 2: // rory the cat flat edition
|
||||
s->set("BackgroundCat", "rory-flat");
|
||||
break;
|
||||
}
|
||||
|
||||
s->set("MenuBarInsteadOfToolBar", ui->preferMenuBarCheckBox->isChecked());
|
||||
|
||||
// Console settings
|
||||
@ -380,41 +403,27 @@ void LauncherPage::loadSettings()
|
||||
m_currentUpdateChannel = s->get("UpdateChannel").toString();
|
||||
//FIXME: make generic
|
||||
auto theme = s->get("IconTheme").toString();
|
||||
if (theme == "pe_colored")
|
||||
{
|
||||
ui->themeComboBox->setCurrentIndex(0);
|
||||
}
|
||||
else if (theme == "pe_light")
|
||||
{
|
||||
ui->themeComboBox->setCurrentIndex(1);
|
||||
}
|
||||
else if (theme == "pe_dark")
|
||||
{
|
||||
ui->themeComboBox->setCurrentIndex(2);
|
||||
}
|
||||
else if (theme == "pe_blue")
|
||||
{
|
||||
ui->themeComboBox->setCurrentIndex(3);
|
||||
}
|
||||
else if (theme == "OSX")
|
||||
{
|
||||
ui->themeComboBox->setCurrentIndex(4);
|
||||
}
|
||||
else if (theme == "iOS")
|
||||
{
|
||||
ui->themeComboBox->setCurrentIndex(5);
|
||||
}
|
||||
else if (theme == "flat")
|
||||
{
|
||||
ui->themeComboBox->setCurrentIndex(6);
|
||||
}
|
||||
else if (theme == "multimc")
|
||||
{
|
||||
ui->themeComboBox->setCurrentIndex(7);
|
||||
}
|
||||
else if (theme == "custom")
|
||||
{
|
||||
ui->themeComboBox->setCurrentIndex(8);
|
||||
QStringList iconThemeOptions{"pe_colored",
|
||||
"pe_light",
|
||||
"pe_dark",
|
||||
"pe_blue",
|
||||
"breeze_light",
|
||||
"breeze_dark",
|
||||
"OSX",
|
||||
"iOS",
|
||||
"flat",
|
||||
"flat_white",
|
||||
"multimc",
|
||||
"custom"};
|
||||
ui->themeComboBox->setCurrentIndex(iconThemeOptions.indexOf(theme));
|
||||
|
||||
auto cat = s->get("BackgroundCat").toString();
|
||||
if (cat == "kitteh") {
|
||||
ui->themeBackgroundCat->setCurrentIndex(0);
|
||||
} else if (cat == "rory") {
|
||||
ui->themeBackgroundCat->setCurrentIndex(1);
|
||||
} else if (cat == "rory-flat") {
|
||||
ui->themeBackgroundCat->setCurrentIndex(2);
|
||||
}
|
||||
|
||||
{
|
||||
|
@ -285,6 +285,16 @@
|
||||
<string>Simple (Blue Icons)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Breeze Light</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Breeze Dark</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string notr="true">OSX</string>
|
||||
@ -300,6 +310,11 @@
|
||||
<string>Flat</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Flat (White)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Legacy</string>
|
||||
@ -335,6 +350,44 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>C&at</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>themeBackgroundCat</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QComboBox" name="themeBackgroundCat">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="focusPolicy">
|
||||
<enum>Qt::StrongFocus</enum>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Background Cat (from MultiMC)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Rory ID 11 (drawn by Ashtaka)</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Rory ID 11 (flat edition, drawn by Ashtaka)</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
|
@ -14,8 +14,6 @@ ExternalResourcesPage::ExternalResourcesPage(BaseInstance* instance, std::shared
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
ExternalResourcesPage::runningStateChanged(m_instance && m_instance->isRunning());
|
||||
|
||||
ui->actionsToolbar->insertSpacer(ui->actionViewConfigs);
|
||||
|
||||
m_filterModel = model->createFilterProxyModel(this);
|
||||
@ -45,7 +43,6 @@ ExternalResourcesPage::ExternalResourcesPage(BaseInstance* instance, std::shared
|
||||
auto selection_model = ui->treeView->selectionModel();
|
||||
connect(selection_model, &QItemSelectionModel::currentChanged, this, &ExternalResourcesPage::current);
|
||||
connect(ui->filterEdit, &QLineEdit::textChanged, this, &ExternalResourcesPage::filterTextChanged);
|
||||
connect(m_instance, &BaseInstance::runningStatusChanged, this, &ExternalResourcesPage::runningStateChanged);
|
||||
}
|
||||
|
||||
ExternalResourcesPage::~ExternalResourcesPage()
|
||||
@ -97,14 +94,6 @@ void ExternalResourcesPage::filterTextChanged(const QString& newContents)
|
||||
m_filterModel->setFilterRegularExpression(m_viewFilter);
|
||||
}
|
||||
|
||||
void ExternalResourcesPage::runningStateChanged(bool running)
|
||||
{
|
||||
if (m_controlsEnabled == !running)
|
||||
return;
|
||||
|
||||
m_controlsEnabled = !running;
|
||||
}
|
||||
|
||||
bool ExternalResourcesPage::shouldDisplay() const
|
||||
{
|
||||
return true;
|
||||
|
@ -47,7 +47,6 @@ class ExternalResourcesPage : public QMainWindow, public BasePage {
|
||||
protected slots:
|
||||
void itemActivated(const QModelIndex& index);
|
||||
void filterTextChanged(const QString& newContents);
|
||||
virtual void runningStateChanged(bool running);
|
||||
|
||||
virtual void addItem();
|
||||
virtual void removeItem();
|
||||
|
@ -27,11 +27,7 @@
|
||||
<item row="4" column="1" colspan="3">
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="filterEdit">
|
||||
<property name="clearButtonEnabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLineEdit" name="filterEdit"/>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="filterLabel">
|
||||
|
@ -59,12 +59,12 @@ InstanceSettingsPage::InstanceSettingsPage(BaseInstance *inst, QWidget *parent)
|
||||
{
|
||||
m_settings = inst->settings();
|
||||
ui->setupUi(this);
|
||||
auto sysMB = Sys::getSystemRam() / Sys::mebibyte;
|
||||
ui->maxMemSpinBox->setMaximum(sysMB);
|
||||
|
||||
connect(ui->openGlobalJavaSettingsButton, &QCommandLinkButton::clicked, this, &InstanceSettingsPage::globalSettingsButtonClicked);
|
||||
connect(APPLICATION, &Application::globalSettingsAboutToOpen, this, &InstanceSettingsPage::applySettings);
|
||||
connect(APPLICATION, &Application::globalSettingsClosed, this, &InstanceSettingsPage::loadSettings);
|
||||
loadSettings();
|
||||
updateThresholds();
|
||||
}
|
||||
|
||||
bool InstanceSettingsPage::shouldDisplay() const
|
||||
@ -437,6 +437,11 @@ void InstanceSettingsPage::on_javaTestBtn_clicked()
|
||||
checker->run();
|
||||
}
|
||||
|
||||
void InstanceSettingsPage::on_maxMemSpinBox_valueChanged(int i)
|
||||
{
|
||||
updateThresholds();
|
||||
}
|
||||
|
||||
void InstanceSettingsPage::checkerFinished()
|
||||
{
|
||||
checker.reset();
|
||||
@ -447,3 +452,29 @@ void InstanceSettingsPage::retranslate()
|
||||
ui->retranslateUi(this);
|
||||
ui->customCommands->retranslate(); // TODO: why is this seperate from the others?
|
||||
}
|
||||
|
||||
void InstanceSettingsPage::updateThresholds()
|
||||
{
|
||||
auto sysMiB = Sys::getSystemRam() / Sys::mebibyte;
|
||||
unsigned int maxMem = ui->maxMemSpinBox->value();
|
||||
|
||||
QString iconName;
|
||||
|
||||
if (maxMem >= sysMiB) {
|
||||
iconName = "status-bad";
|
||||
ui->labelMaxMemIcon->setToolTip(tr("Your maximum memory allocation exceeds your system memory capacity."));
|
||||
} else if (maxMem > (sysMiB * 0.9)) {
|
||||
iconName = "status-yellow";
|
||||
ui->labelMaxMemIcon->setToolTip(tr("Your maximum memory allocation approaches your system memory capacity."));
|
||||
} else {
|
||||
iconName = "status-good";
|
||||
ui->labelMaxMemIcon->setToolTip("");
|
||||
}
|
||||
|
||||
{
|
||||
auto height = ui->labelMaxMemIcon->fontInfo().pixelSize();
|
||||
QIcon icon = APPLICATION->getThemedIcon(iconName);
|
||||
QPixmap pix = icon.pixmap(height, height);
|
||||
ui->labelMaxMemIcon->setPixmap(pix);
|
||||
}
|
||||
}
|
||||
|
@ -77,10 +77,13 @@ public:
|
||||
virtual bool shouldDisplay() const override;
|
||||
void retranslate() override;
|
||||
|
||||
void updateThresholds();
|
||||
|
||||
private slots:
|
||||
void on_javaDetectBtn_clicked();
|
||||
void on_javaTestBtn_clicked();
|
||||
void on_javaBrowseBtn_clicked();
|
||||
void on_maxMemSpinBox_valueChanged(int i);
|
||||
|
||||
void applySettings();
|
||||
void loadSettings();
|
||||
|
@ -112,7 +112,14 @@
|
||||
<property name="checked">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<layout class="QGridLayout" name="gridLayout_2" columnstretch="1,0,0,0">
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="labelPermGen">
|
||||
<property name="text">
|
||||
<string notr="true">PermGen:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="labelMinMem">
|
||||
<property name="text">
|
||||
@ -120,29 +127,21 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QSpinBox" name="maxMemSpinBox">
|
||||
<property name="toolTip">
|
||||
<string>The maximum amount of memory Minecraft is allowed to use.</string>
|
||||
</property>
|
||||
<property name="suffix">
|
||||
<string notr="true"> MiB</string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>128</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>65536</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<number>128</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>1024</number>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="labelMaxMem">
|
||||
<property name="text">
|
||||
<string>Maximum memory allocation:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<item row="3" column="0" colspan="3">
|
||||
<widget class="QLabel" name="labelPermgenNote">
|
||||
<property name="text">
|
||||
<string>Note: Permgen is set automatically by Java 8 and later</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QSpinBox" name="minMemSpinBox">
|
||||
<property name="toolTip">
|
||||
<string>The amount of memory Minecraft is started with.</string>
|
||||
@ -154,7 +153,7 @@
|
||||
<number>128</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>65536</number>
|
||||
<number>1048576</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<number>128</number>
|
||||
@ -164,7 +163,29 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<item row="1" column="2">
|
||||
<widget class="QSpinBox" name="maxMemSpinBox">
|
||||
<property name="toolTip">
|
||||
<string>The maximum amount of memory Minecraft is allowed to use.</string>
|
||||
</property>
|
||||
<property name="suffix">
|
||||
<string notr="true"> MiB</string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>128</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>1048576</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<number>128</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>1024</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="2">
|
||||
<widget class="QSpinBox" name="permGenSpinBox">
|
||||
<property name="toolTip">
|
||||
<string>The amount of memory available to store loaded Java classes.</string>
|
||||
@ -186,24 +207,16 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="labelPermGen">
|
||||
<item row="1" column="3">
|
||||
<widget class="QLabel" name="labelMaxMemIcon">
|
||||
<property name="text">
|
||||
<string notr="true">PermGen:</string>
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="labelMaxMem">
|
||||
<property name="text">
|
||||
<string>Maximum memory allocation:</string>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0" colspan="2">
|
||||
<widget class="QLabel" name="labelPermgenNote">
|
||||
<property name="text">
|
||||
<string>Note: Permgen is set automatically by Java 8 and later</string>
|
||||
<property name="buddy">
|
||||
<cstring>maxMemSpinBox</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
@ -108,13 +108,13 @@ ModFolderPage::ModFolderPage(BaseInstance* inst, std::shared_ptr<ModFolderModel>
|
||||
disconnect(mods.get(), &ModFolderModel::updateFinished, this, 0);
|
||||
});
|
||||
|
||||
connect(m_instance, &BaseInstance::runningStatusChanged, this, &ModFolderPage::runningStateChanged);
|
||||
ModFolderPage::runningStateChanged(m_instance && m_instance->isRunning());
|
||||
}
|
||||
}
|
||||
|
||||
void ModFolderPage::runningStateChanged(bool running)
|
||||
{
|
||||
ExternalResourcesPage::runningStateChanged(running);
|
||||
ui->actionDownloadItem->setEnabled(!running);
|
||||
ui->actionUpdateItem->setEnabled(!running);
|
||||
ui->actionAddItem->setEnabled(!running);
|
||||
|
@ -53,12 +53,12 @@ class ModFolderPage : public ExternalResourcesPage {
|
||||
virtual QString helpPage() const override { return "Loader-mods"; }
|
||||
|
||||
virtual bool shouldDisplay() const override;
|
||||
void runningStateChanged(bool running) override;
|
||||
|
||||
public slots:
|
||||
bool onSelectionChanged(const QModelIndex& current, const QModelIndex& previous) override;
|
||||
|
||||
private slots:
|
||||
void runningStateChanged(bool running);
|
||||
void removeItem() override;
|
||||
|
||||
void installMods();
|
||||
|
@ -400,11 +400,11 @@ public:
|
||||
|
||||
virtual int rowCount(const QModelIndex &parent = QModelIndex()) const override
|
||||
{
|
||||
return m_servers.size();
|
||||
return parent.isValid() ? 0 : m_servers.size();
|
||||
}
|
||||
int columnCount(const QModelIndex & parent) const override
|
||||
{
|
||||
return COLUMN_COUNT;
|
||||
return parent.isValid() ? 0 : COLUMN_COUNT;
|
||||
}
|
||||
|
||||
Server * at(int index)
|
||||
|
@ -68,7 +68,7 @@ public:
|
||||
}
|
||||
virtual QIcon icon() const override
|
||||
{
|
||||
return APPLICATION->getThemedIcon("unknown_server");
|
||||
return APPLICATION->getThemedIcon("server");
|
||||
}
|
||||
virtual QString id() const override
|
||||
{
|
||||
|
@ -1,8 +1,9 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Prism Launcher - Minecraft Launcher
|
||||
* Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||
* Copyright (C) 2022 TheKodeToad <TheKodeToad@proton.me>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@ -270,6 +271,7 @@ void VersionPage::updateButtons(int row)
|
||||
ui->actionInstall_mods->setEnabled(controlsEnabled);
|
||||
ui->actionReplace_Minecraft_jar->setEnabled(controlsEnabled);
|
||||
ui->actionAdd_to_Minecraft_jar->setEnabled(controlsEnabled);
|
||||
ui->actionAdd_Agents->setEnabled(controlsEnabled);
|
||||
}
|
||||
|
||||
bool VersionPage::reloadPackProfile()
|
||||
@ -342,6 +344,18 @@ void VersionPage::on_actionReplace_Minecraft_jar_triggered()
|
||||
updateButtons();
|
||||
}
|
||||
|
||||
|
||||
void VersionPage::on_actionAdd_Agents_triggered()
|
||||
{
|
||||
QStringList list = GuiUtil::BrowseForFiles("agent", tr("Select agents"), tr("Java agents (*.jar)"),
|
||||
APPLICATION->settings()->get("CentralModsDir").toString(), this->parentWidget());
|
||||
|
||||
if (!list.isEmpty())
|
||||
m_profile->installAgents(list);
|
||||
|
||||
updateButtons();
|
||||
}
|
||||
|
||||
void VersionPage::on_actionMove_up_triggered()
|
||||
{
|
||||
try
|
||||
|
@ -1,7 +1,8 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Prism Launcher - Minecraft Launcher
|
||||
* Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
|
||||
* Copyright (C) 2022 TheKodeToad <TheKodeToad@proton.me>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@ -82,6 +83,7 @@ private slots:
|
||||
void on_actionMove_down_triggered();
|
||||
void on_actionAdd_to_Minecraft_jar_triggered();
|
||||
void on_actionReplace_Minecraft_jar_triggered();
|
||||
void on_actionAdd_Agents_triggered();
|
||||
void on_actionRevert_triggered();
|
||||
void on_actionEdit_triggered();
|
||||
void on_actionInstall_mods_triggered();
|
||||
|
@ -48,11 +48,7 @@
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="filterEdit">
|
||||
<property name="clearButtonEnabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLineEdit" name="filterEdit"/>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="filterLabel">
|
||||
@ -113,6 +109,7 @@
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionAdd_to_Minecraft_jar"/>
|
||||
<addaction name="actionReplace_Minecraft_jar"/>
|
||||
<addaction name="actionAdd_Agents"/>
|
||||
<addaction name="actionAdd_Empty"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionMinecraftFolder"/>
|
||||
@ -230,6 +227,14 @@
|
||||
<string>Replace Minecraft.jar</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionAdd_Agents">
|
||||
<property name="text">
|
||||
<string>Add Agents</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Add Java agents.</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionAdd_Empty">
|
||||
<property name="text">
|
||||
<string>Add Empty</string>
|
||||
|
@ -267,18 +267,25 @@ void ListModel::searchRequestFailed(QString reason)
|
||||
.arg(m_parent->displayName())
|
||||
.arg(tr("API version too old!\nPlease update %1!").arg(BuildConfig.LAUNCHER_DISPLAYNAME)));
|
||||
}
|
||||
|
||||
jobPtr.reset();
|
||||
searchState = Finished;
|
||||
}
|
||||
|
||||
void ListModel::searchRequestAborted()
|
||||
{
|
||||
if (searchState != ResetRequested)
|
||||
qCritical() << "Search task in ModModel aborted by an unknown reason!";
|
||||
|
||||
// Retry fetching
|
||||
jobPtr.reset();
|
||||
|
||||
if (searchState == ResetRequested) {
|
||||
beginResetModel();
|
||||
modpacks.clear();
|
||||
endResetModel();
|
||||
beginResetModel();
|
||||
modpacks.clear();
|
||||
endResetModel();
|
||||
|
||||
nextSearchOffset = 0;
|
||||
performPaginatedSearch();
|
||||
} else {
|
||||
searchState = Finished;
|
||||
}
|
||||
nextSearchOffset = 0;
|
||||
performPaginatedSearch();
|
||||
}
|
||||
|
||||
void ListModel::infoRequestFinished(QJsonDocument& doc, ModPlatform::IndexedPack& pack, const QModelIndex& index)
|
||||
|
@ -20,8 +20,8 @@ class ListModel : public QAbstractListModel {
|
||||
ListModel(ModPage* parent);
|
||||
~ListModel() override;
|
||||
|
||||
inline auto rowCount(const QModelIndex& parent) const -> int override { return modpacks.size(); };
|
||||
inline auto columnCount(const QModelIndex& parent) const -> int override { return 1; };
|
||||
inline auto rowCount(const QModelIndex& parent) const -> int override { return parent.isValid() ? 0 : modpacks.size(); };
|
||||
inline auto columnCount(const QModelIndex& parent) const -> int override { return parent.isValid() ? 0 : 1; };
|
||||
inline auto flags(const QModelIndex& index) const -> Qt::ItemFlags override { return QAbstractListModel::flags(index); };
|
||||
|
||||
auto debugName() const -> QString;
|
||||
@ -41,16 +41,17 @@ class ListModel : public QAbstractListModel {
|
||||
void requestModVersions(const ModPlatform::IndexedPack& current, QModelIndex index);
|
||||
|
||||
virtual void loadIndexedPack(ModPlatform::IndexedPack& m, QJsonObject& obj) = 0;
|
||||
virtual void loadExtraPackInfo(ModPlatform::IndexedPack& m, QJsonObject& obj) {};
|
||||
virtual void loadExtraPackInfo(ModPlatform::IndexedPack& m, QJsonObject& obj) = 0;
|
||||
virtual void loadIndexedPackVersions(ModPlatform::IndexedPack& m, QJsonArray& arr) = 0;
|
||||
|
||||
void getLogo(const QString& logo, const QString& logoUrl, LogoCallback callback);
|
||||
|
||||
inline auto canFetchMore(const QModelIndex& parent) const -> bool override { return searchState == CanPossiblyFetchMore; };
|
||||
inline auto canFetchMore(const QModelIndex& parent) const -> bool override { return parent.isValid() ? false : searchState == CanPossiblyFetchMore; };
|
||||
|
||||
public slots:
|
||||
void searchRequestFinished(QJsonDocument& doc);
|
||||
void searchRequestFailed(QString reason);
|
||||
void searchRequestAborted();
|
||||
|
||||
void infoRequestFinished(QJsonDocument& doc, ModPlatform::IndexedPack& pack, const QModelIndex& index);
|
||||
|
||||
|
@ -1,7 +1,8 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Prism Launcher - Minecraft Launcher
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||
* Copyright (C) 2022 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
|
||||
@ -37,7 +38,9 @@
|
||||
#include "Application.h"
|
||||
#include "ui_ModPage.h"
|
||||
|
||||
#include <QDesktopServices>
|
||||
#include <QKeyEvent>
|
||||
#include <QRegularExpression>
|
||||
#include <memory>
|
||||
|
||||
#include <HoeDown.h>
|
||||
@ -80,6 +83,8 @@ ModPage::ModPage(ModDownloadDialog* dialog, BaseInstance* instance, ModAPI* api)
|
||||
|
||||
ui->packView->setItemDelegate(new ProjectItemDelegate(this));
|
||||
ui->packView->installEventFilter(this);
|
||||
|
||||
connect(ui->packDescription, &QTextBrowser::anchorClicked, this, &ModPage::openUrl);
|
||||
}
|
||||
|
||||
ModPage::~ModPage()
|
||||
@ -158,8 +163,8 @@ void ModPage::triggerSearch()
|
||||
{
|
||||
auto changed = m_filter_widget->changed();
|
||||
m_filter = m_filter_widget->getFilter();
|
||||
|
||||
if(changed){
|
||||
|
||||
if (changed) {
|
||||
ui->packView->clearSelection();
|
||||
ui->packDescription->clear();
|
||||
ui->versionSelectionBox->clear();
|
||||
@ -241,6 +246,79 @@ void ModPage::onModSelected()
|
||||
ui->packView->adjustSize();
|
||||
}
|
||||
|
||||
static const QRegularExpression modrinth(QRegularExpression::anchoredPattern("(?:www\\.)?modrinth\\.com\\/mod\\/([^\\/]+)\\/?"));
|
||||
static const QRegularExpression curseForge(QRegularExpression::anchoredPattern("(?:www\\.)?curseforge\\.com\\/minecraft\\/mc-mods\\/([^\\/]+)\\/?"));
|
||||
static const QRegularExpression curseForgeOld(QRegularExpression::anchoredPattern("minecraft\\.curseforge\\.com\\/projects\\/([^\\/]+)\\/?"));
|
||||
|
||||
void ModPage::openUrl(const QUrl& url)
|
||||
{
|
||||
// do not allow other url schemes for security reasons
|
||||
if (!(url.scheme() == "http" || url.scheme() == "https")) {
|
||||
qWarning() << "Unsupported scheme" << url.scheme();
|
||||
return;
|
||||
}
|
||||
|
||||
// detect mod URLs and search instead
|
||||
|
||||
const QString address = url.host() + url.path();
|
||||
QRegularExpressionMatch match;
|
||||
QString page;
|
||||
|
||||
match = modrinth.match(address);
|
||||
if (match.hasMatch())
|
||||
page = "modrinth";
|
||||
else if (APPLICATION->capabilities() & Application::SupportsFlame) {
|
||||
match = curseForge.match(address);
|
||||
if (!match.hasMatch())
|
||||
match = curseForgeOld.match(address);
|
||||
|
||||
if (match.hasMatch())
|
||||
page = "curseforge";
|
||||
}
|
||||
|
||||
if (!page.isNull()) {
|
||||
const QString slug = match.captured(1);
|
||||
|
||||
// ensure the user isn't opening the same mod
|
||||
if (slug != current.slug) {
|
||||
dialog->selectPage(page);
|
||||
|
||||
ModPage* newPage = dialog->getSelectedPage();
|
||||
|
||||
QLineEdit* searchEdit = newPage->ui->searchEdit;
|
||||
ModPlatform::ListModel* model = newPage->listModel;
|
||||
QListView* view = newPage->ui->packView;
|
||||
|
||||
auto jump = [url, slug, model, view] {
|
||||
for (int row = 0; row < model->rowCount({}); row++) {
|
||||
const QModelIndex index = model->index(row);
|
||||
const auto pack = model->data(index, Qt::UserRole).value<ModPlatform::IndexedPack>();
|
||||
|
||||
if (pack.slug == slug) {
|
||||
view->setCurrentIndex(index);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// The final fallback.
|
||||
QDesktopServices::openUrl(url);
|
||||
};
|
||||
|
||||
searchEdit->setText(slug);
|
||||
newPage->triggerSearch();
|
||||
|
||||
if (model->activeJob())
|
||||
connect(model->activeJob(), &Task::finished, jump);
|
||||
else
|
||||
jump();
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// open in the user's web browser
|
||||
QDesktopServices::openUrl(url);
|
||||
}
|
||||
|
||||
/******** Make changes to the UI ********/
|
||||
|
||||
@ -270,8 +348,8 @@ void ModPage::updateModVersions(int prev_count)
|
||||
if ((valid || m_filter->versions.empty()) && !optedOut(version))
|
||||
ui->versionSelectionBox->addItem(version.version, QVariant(i));
|
||||
}
|
||||
if (ui->versionSelectionBox->count() == 0 && prev_count != 0) {
|
||||
ui->versionSelectionBox->addItem(tr("No valid version found!"), QVariant(-1));
|
||||
if (ui->versionSelectionBox->count() == 0 && prev_count != 0) {
|
||||
ui->versionSelectionBox->addItem(tr("No valid version found!"), QVariant(-1));
|
||||
ui->modSelectionButton->setText(tr("Cannot select invalid version :("));
|
||||
}
|
||||
|
||||
@ -317,8 +395,7 @@ void ModPage::updateUi()
|
||||
text += "<br>" + tr(" by ") + authorStrs.join(", ");
|
||||
}
|
||||
|
||||
|
||||
if(current.extraDataLoaded) {
|
||||
if (current.extraDataLoaded) {
|
||||
if (!current.extraData.donate.isEmpty()) {
|
||||
text += "<br><br>" + tr("Donate information: ");
|
||||
auto donateToStr = [](ModPlatform::DonationData& donate) -> QString {
|
||||
|
@ -82,6 +82,7 @@ class ModPage : public QWidget, public BasePage {
|
||||
void onSelectionChanged(QModelIndex first, QModelIndex second);
|
||||
void onVersionSelectionChanged(QString data);
|
||||
void onModSelected();
|
||||
virtual void openUrl(const QUrl& url);
|
||||
|
||||
protected:
|
||||
Ui::ModPage* ui = nullptr;
|
||||
|
@ -16,10 +16,10 @@
|
||||
<item row="1" column="2">
|
||||
<widget class="ProjectDescriptionPage" name="packDescription">
|
||||
<property name="openExternalLinks">
|
||||
<bool>true</bool>
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="openLinks">
|
||||
<bool>true</bool>
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
@ -187,12 +187,12 @@ void VanillaPage::retranslate()
|
||||
ui->retranslateUi(this);
|
||||
}
|
||||
|
||||
BaseVersionPtr VanillaPage::selectedVersion() const
|
||||
BaseVersion::Ptr VanillaPage::selectedVersion() const
|
||||
{
|
||||
return m_selectedVersion;
|
||||
}
|
||||
|
||||
BaseVersionPtr VanillaPage::selectedLoaderVersion() const
|
||||
BaseVersion::Ptr VanillaPage::selectedLoaderVersion() const
|
||||
{
|
||||
return m_selectedLoaderVersion;
|
||||
}
|
||||
@ -227,14 +227,14 @@ void VanillaPage::suggestCurrent()
|
||||
dialog->setSuggestedIcon("default");
|
||||
}
|
||||
|
||||
void VanillaPage::setSelectedVersion(BaseVersionPtr version)
|
||||
void VanillaPage::setSelectedVersion(BaseVersion::Ptr version)
|
||||
{
|
||||
m_selectedVersion = version;
|
||||
suggestCurrent();
|
||||
loaderFilterChanged();
|
||||
}
|
||||
|
||||
void VanillaPage::setSelectedLoaderVersion(BaseVersionPtr version)
|
||||
void VanillaPage::setSelectedLoaderVersion(BaseVersion::Ptr version)
|
||||
{
|
||||
m_selectedLoaderVersion = version;
|
||||
suggestCurrent();
|
||||
|
@ -76,13 +76,13 @@ public:
|
||||
|
||||
void openedImpl() override;
|
||||
|
||||
BaseVersionPtr selectedVersion() const;
|
||||
BaseVersionPtr selectedLoaderVersion() const;
|
||||
BaseVersion::Ptr selectedVersion() const;
|
||||
BaseVersion::Ptr selectedLoaderVersion() const;
|
||||
QString selectedLoader() const;
|
||||
|
||||
public slots:
|
||||
void setSelectedVersion(BaseVersionPtr version);
|
||||
void setSelectedLoaderVersion(BaseVersionPtr version);
|
||||
void setSelectedVersion(BaseVersion::Ptr version);
|
||||
void setSelectedLoaderVersion(BaseVersion::Ptr version);
|
||||
|
||||
private slots:
|
||||
void filterChanged();
|
||||
@ -98,7 +98,7 @@ private:
|
||||
NewInstanceDialog *dialog = nullptr;
|
||||
Ui::VanillaPage *ui = nullptr;
|
||||
bool m_versionSetByUser = false;
|
||||
BaseVersionPtr m_selectedVersion;
|
||||
BaseVersionPtr m_selectedLoaderVersion;
|
||||
BaseVersion::Ptr m_selectedVersion;
|
||||
BaseVersion::Ptr m_selectedLoaderVersion;
|
||||
QString m_selectedLoader;
|
||||
};
|
||||
|
@ -20,7 +20,8 @@
|
||||
|
||||
#include <modplatform/atlauncher/ATLPackIndex.h>
|
||||
#include <Version.h>
|
||||
#include <MMCStrings.h>
|
||||
|
||||
#include "StringUtils.h"
|
||||
|
||||
namespace Atl {
|
||||
|
||||
@ -86,7 +87,7 @@ bool FilterModel::lessThan(const QModelIndex &left, const QModelIndex &right) co
|
||||
return lv < rv;
|
||||
}
|
||||
else if (currentSorting == ByName) {
|
||||
return Strings::naturalCompare(leftPack.name, rightPack.name, Qt::CaseSensitive) >= 0;
|
||||
return StringUtils::naturalCompare(leftPack.name, rightPack.name, Qt::CaseSensitive) >= 0;
|
||||
}
|
||||
|
||||
// Invalid sorting set, somehow...
|
||||
|
@ -32,12 +32,12 @@ ListModel::~ListModel()
|
||||
|
||||
int ListModel::rowCount(const QModelIndex &parent) const
|
||||
{
|
||||
return modpacks.size();
|
||||
return parent.isValid() ? 0 : modpacks.size();
|
||||
}
|
||||
|
||||
int ListModel::columnCount(const QModelIndex &parent) const
|
||||
{
|
||||
return 1;
|
||||
return parent.isValid() ? 0 : 1;
|
||||
}
|
||||
|
||||
QVariant ListModel::data(const QModelIndex &index, int role) const
|
||||
|
@ -75,12 +75,12 @@ QVector<QString> AtlOptionalModListModel::getResult() {
|
||||
}
|
||||
|
||||
int AtlOptionalModListModel::rowCount(const QModelIndex &parent) const {
|
||||
return m_mods.size();
|
||||
return parent.isValid() ? 0 : m_mods.size();
|
||||
}
|
||||
|
||||
int AtlOptionalModListModel::columnCount(const QModelIndex &parent) const {
|
||||
// Enabled, Name, Description
|
||||
return 3;
|
||||
return parent.isValid() ? 0 : 3;
|
||||
}
|
||||
|
||||
QVariant AtlOptionalModListModel::data(const QModelIndex &index, int role) const {
|
||||
|
@ -53,7 +53,7 @@ std::optional<QVector<QString>> AtlUserInteractionSupportImpl::chooseOptionalMod
|
||||
return optionalModDialog.getResult();
|
||||
}
|
||||
|
||||
QString AtlUserInteractionSupportImpl::chooseVersion(Meta::VersionListPtr vlist, QString minecraftVersion)
|
||||
QString AtlUserInteractionSupportImpl::chooseVersion(Meta::VersionList::Ptr vlist, QString minecraftVersion)
|
||||
{
|
||||
VersionSelectDialog vselect(vlist.get(), "Choose Version", m_parent, false);
|
||||
if (minecraftVersion != nullptr) {
|
||||
|
@ -46,7 +46,7 @@ public:
|
||||
AtlUserInteractionSupportImpl(QWidget* parent);
|
||||
|
||||
private:
|
||||
QString chooseVersion(Meta::VersionListPtr vlist, QString minecraftVersion) override;
|
||||
QString chooseVersion(Meta::VersionList::Ptr vlist, QString minecraftVersion) override;
|
||||
std::optional<QVector<QString>> chooseOptionalMods(ATLauncher::PackVersion version, QVector<ATLauncher::VersionMod> mods) override;
|
||||
void displayMessage(QString message) override;
|
||||
|
||||
|
@ -1,7 +1,8 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Prism Launcher - Minecraft Launcher
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||
* Copyright (C) 2022 TheKodeToad <TheKodeToad@proton.me>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@ -39,7 +40,7 @@
|
||||
#include "FlameModModel.h"
|
||||
#include "ui/dialogs/ModDownloadDialog.h"
|
||||
|
||||
FlameModPage::FlameModPage(ModDownloadDialog* dialog, BaseInstance* instance)
|
||||
FlameModPage::FlameModPage(ModDownloadDialog* dialog, BaseInstance* instance)
|
||||
: ModPage(dialog, instance, new FlameAPI())
|
||||
{
|
||||
listModel = new FlameMod::ListModel(this);
|
||||
@ -53,7 +54,7 @@ FlameModPage::FlameModPage(ModDownloadDialog* dialog, BaseInstance* instance)
|
||||
ui->sortByBox->addItem(tr("Sort by Author"));
|
||||
ui->sortByBox->addItem(tr("Sort by Downloads"));
|
||||
|
||||
// sometimes Qt just ignores virtual slots and doesn't work as intended it seems,
|
||||
// sometimes Qt just ignores virtual slots and doesn't work as intended it seems,
|
||||
// so it's best not to connect them in the parent's contructor...
|
||||
connect(ui->sortByBox, SIGNAL(currentIndexChanged(int)), this, SLOT(triggerSearch()));
|
||||
connect(ui->packView->selectionModel(), &QItemSelectionModel::currentChanged, this, &FlameModPage::onSelectionChanged);
|
||||
@ -78,3 +79,19 @@ bool FlameModPage::optedOut(ModPlatform::IndexedVersion& ver) const
|
||||
// other mod providers start loading before being selected, at least with
|
||||
// my Qt, so we need to implement this in every derived class...
|
||||
auto FlameModPage::shouldDisplay() const -> bool { return true; }
|
||||
|
||||
void FlameModPage::openUrl(const QUrl& url)
|
||||
{
|
||||
if (url.scheme().isEmpty()) {
|
||||
QString query = url.query(QUrl::FullyDecoded);
|
||||
|
||||
if (query.startsWith("remoteUrl=")) {
|
||||
// attempt to resolve url from warning page
|
||||
query.remove(0, 10);
|
||||
ModPage::openUrl({QUrl::fromPercentEncoding(query.toUtf8())}); // double decoding is necessary
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
ModPage::openUrl(url);
|
||||
}
|
||||
|
@ -1,7 +1,8 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Prism Launcher - Minecraft Launcher
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||
* Copyright (C) 2022 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
|
||||
@ -64,4 +65,6 @@ class FlameModPage : public ModPage {
|
||||
bool optedOut(ModPlatform::IndexedVersion& ver) const override;
|
||||
|
||||
auto shouldDisplay() const -> bool override;
|
||||
|
||||
void openUrl(const QUrl& url) override;
|
||||
};
|
||||
|
@ -3,7 +3,6 @@
|
||||
#include "Application.h"
|
||||
#include "ui/widgets/ProjectItem.h"
|
||||
|
||||
#include <MMCStrings.h>
|
||||
#include <Version.h>
|
||||
|
||||
#include <QtMath>
|
||||
@ -16,12 +15,12 @@ ListModel::~ListModel() {}
|
||||
|
||||
int ListModel::rowCount(const QModelIndex& parent) const
|
||||
{
|
||||
return modpacks.size();
|
||||
return parent.isValid() ? 0 : modpacks.size();
|
||||
}
|
||||
|
||||
int ListModel::columnCount(const QModelIndex& parent) const
|
||||
{
|
||||
return 1;
|
||||
return parent.isValid() ? 0 : 1;
|
||||
}
|
||||
|
||||
QVariant ListModel::data(const QModelIndex& index, int role) const
|
||||
|
@ -19,7 +19,8 @@
|
||||
#include <QDebug>
|
||||
|
||||
#include "modplatform/modpacksch/FTBPackManifest.h"
|
||||
#include <MMCStrings.h>
|
||||
|
||||
#include "StringUtils.h"
|
||||
|
||||
namespace Ftb {
|
||||
|
||||
@ -81,7 +82,7 @@ bool FilterModel::lessThan(const QModelIndex &left, const QModelIndex &right) co
|
||||
return leftPack.installs < rightPack.installs;
|
||||
}
|
||||
else if (currentSorting == ByName) {
|
||||
return Strings::naturalCompare(leftPack.name, rightPack.name, Qt::CaseSensitive) >= 0;
|
||||
return StringUtils::naturalCompare(leftPack.name, rightPack.name, Qt::CaseSensitive) >= 0;
|
||||
}
|
||||
|
||||
// Invalid sorting set, somehow...
|
||||
|
@ -34,12 +34,12 @@ ListModel::~ListModel()
|
||||
|
||||
int ListModel::rowCount(const QModelIndex &parent) const
|
||||
{
|
||||
return modpacks.size();
|
||||
return parent.isValid() ? 0 : modpacks.size();
|
||||
}
|
||||
|
||||
int ListModel::columnCount(const QModelIndex &parent) const
|
||||
{
|
||||
return 1;
|
||||
return parent.isValid() ? 0 : 1;
|
||||
}
|
||||
|
||||
QVariant ListModel::data(const QModelIndex &index, int role) const
|
||||
|
@ -36,7 +36,7 @@
|
||||
#include "ListModel.h"
|
||||
#include "Application.h"
|
||||
|
||||
#include <MMCStrings.h>
|
||||
#include "StringUtils.h"
|
||||
#include <Version.h>
|
||||
|
||||
#include <QtMath>
|
||||
@ -66,7 +66,7 @@ bool FilterModel::lessThan(const QModelIndex &left, const QModelIndex &right) co
|
||||
return lv < rv;
|
||||
|
||||
} else if(currentSorting == Sorting::ByName) {
|
||||
return Strings::naturalCompare(leftPack.name, rightPack.name, Qt::CaseSensitive) >= 0;
|
||||
return StringUtils::naturalCompare(leftPack.name, rightPack.name, Qt::CaseSensitive) >= 0;
|
||||
}
|
||||
|
||||
//UHM, some inavlid value set?!
|
||||
@ -125,12 +125,12 @@ QString ListModel::translatePackType(PackType type) const
|
||||
|
||||
int ListModel::rowCount(const QModelIndex &parent) const
|
||||
{
|
||||
return modpacks.size();
|
||||
return parent.isValid() ? 0 : modpacks.size();
|
||||
}
|
||||
|
||||
int ListModel::columnCount(const QModelIndex &parent) const
|
||||
{
|
||||
return 1;
|
||||
return parent.isValid() ? 0 : 1;
|
||||
}
|
||||
|
||||
QVariant ListModel::data(const QModelIndex &index, int role) const
|
||||
|
@ -53,7 +53,7 @@ ModrinthModPage::ModrinthModPage(ModDownloadDialog* dialog, BaseInstance* instan
|
||||
ui->sortByBox->addItem(tr("Sort by Last Updated"));
|
||||
ui->sortByBox->addItem(tr("Sort by Newest"));
|
||||
|
||||
// sometimes Qt just ignores virtual slots and doesn't work as intended it seems,
|
||||
// sometimes Qt just ignores virtual slots and doesn't work as intended it seems,
|
||||
// so it's best not to connect them in the parent's constructor...
|
||||
connect(ui->sortByBox, SIGNAL(currentIndexChanged(int)), this, SLOT(triggerSearch()));
|
||||
connect(ui->packView->selectionModel(), &QItemSelectionModel::currentChanged, this, &ModrinthModPage::onSelectionChanged);
|
||||
|
@ -55,8 +55,8 @@ class ModpackListModel : public QAbstractListModel {
|
||||
ModpackListModel(ModrinthPage* parent);
|
||||
~ModpackListModel() override = default;
|
||||
|
||||
inline auto rowCount(const QModelIndex& parent) const -> int override { return modpacks.size(); };
|
||||
inline auto columnCount(const QModelIndex& parent) const -> int override { return 1; };
|
||||
inline auto rowCount(const QModelIndex& parent) const -> int override { return parent.isValid() ? 0 : modpacks.size(); };
|
||||
inline auto columnCount(const QModelIndex& parent) const -> int override { return parent.isValid() ? 0 : 1; };
|
||||
inline auto flags(const QModelIndex& index) const -> Qt::ItemFlags override { return QAbstractListModel::flags(index); };
|
||||
|
||||
auto debugName() const -> QString;
|
||||
@ -74,7 +74,7 @@ class ModpackListModel : public QAbstractListModel {
|
||||
|
||||
void getLogo(const QString& logo, const QString& logoUrl, LogoCallback callback);
|
||||
|
||||
inline auto canFetchMore(const QModelIndex& parent) const -> bool override { return searchState == CanPossiblyFetchMore; };
|
||||
inline auto canFetchMore(const QModelIndex& parent) const -> bool override { return parent.isValid() ? false : searchState == CanPossiblyFetchMore; };
|
||||
|
||||
public slots:
|
||||
void searchRequestFinished(QJsonDocument& doc_all);
|
||||
|
@ -80,14 +80,14 @@ QVariant Technic::ListModel::data(const QModelIndex& index, int role) const
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
int Technic::ListModel::columnCount(const QModelIndex&) const
|
||||
int Technic::ListModel::columnCount(const QModelIndex& parent) const
|
||||
{
|
||||
return 1;
|
||||
return parent.isValid() ? 0 : 1;
|
||||
}
|
||||
|
||||
int Technic::ListModel::rowCount(const QModelIndex&) const
|
||||
int Technic::ListModel::rowCount(const QModelIndex& parent) const
|
||||
{
|
||||
return modpacks.size();
|
||||
return parent.isValid() ? 0 : modpacks.size();
|
||||
}
|
||||
|
||||
void Technic::ListModel::searchWithTerm(const QString& term)
|
||||
|
@ -1,48 +1,81 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* Prism Launcher - Minecraft Launcher
|
||||
* Copyright (C) 2022 Tayou <tayou@gmx.net>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* This file incorporates work covered by the following copyright and
|
||||
* permission notice:
|
||||
*
|
||||
* Copyright 2013-2021 MultiMC Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#include "CustomTheme.h"
|
||||
#include <QDir>
|
||||
#include <Json.h>
|
||||
#include <FileSystem.h>
|
||||
#include <Json.h>
|
||||
#include "ThemeManager.h"
|
||||
|
||||
const char * themeFile = "theme.json";
|
||||
const char * styleFile = "themeStyle.css";
|
||||
const char* themeFile = "theme.json";
|
||||
|
||||
static bool readThemeJson(const QString &path, QPalette &palette, double &fadeAmount, QColor &fadeColor, QString &name, QString &widgets)
|
||||
static bool readThemeJson(const QString& path,
|
||||
QPalette& palette,
|
||||
double& fadeAmount,
|
||||
QColor& fadeColor,
|
||||
QString& name,
|
||||
QString& widgets,
|
||||
QString& qssFilePath,
|
||||
bool& dataIncomplete)
|
||||
{
|
||||
QFileInfo pathInfo(path);
|
||||
if(pathInfo.exists() && pathInfo.isFile())
|
||||
{
|
||||
try
|
||||
{
|
||||
if (pathInfo.exists() && pathInfo.isFile()) {
|
||||
try {
|
||||
auto doc = Json::requireDocument(path, "Theme JSON file");
|
||||
const QJsonObject root = doc.object();
|
||||
dataIncomplete = !root.contains("qssFilePath");
|
||||
name = Json::requireString(root, "name", "Theme name");
|
||||
widgets = Json::requireString(root, "widgets", "Qt widget theme");
|
||||
qssFilePath = Json::ensureString(root, "qssFilePath", "themeStyle.css");
|
||||
auto colorsRoot = Json::requireObject(root, "colors", "colors object");
|
||||
auto readColor = [&](QString colorName) -> QColor
|
||||
{
|
||||
auto readColor = [&](QString colorName) -> QColor {
|
||||
auto colorValue = Json::ensureString(colorsRoot, colorName, QString());
|
||||
if(!colorValue.isEmpty())
|
||||
{
|
||||
if (!colorValue.isEmpty()) {
|
||||
QColor color(colorValue);
|
||||
if(!color.isValid())
|
||||
{
|
||||
qWarning() << "Color value" << colorValue << "for" << colorName << "was not recognized.";
|
||||
if (!color.isValid()) {
|
||||
themeWarningLog() << "Color value" << colorValue << "for" << colorName << "was not recognized.";
|
||||
return QColor();
|
||||
}
|
||||
return color;
|
||||
}
|
||||
return QColor();
|
||||
};
|
||||
auto readAndSetColor = [&](QPalette::ColorRole role, QString colorName)
|
||||
{
|
||||
auto readAndSetColor = [&](QPalette::ColorRole role, QString colorName) {
|
||||
auto color = readColor(colorName);
|
||||
if(color.isValid())
|
||||
{
|
||||
if (color.isValid()) {
|
||||
palette.setColor(role, color);
|
||||
}
|
||||
else
|
||||
{
|
||||
qDebug() << "Color value for" << colorName << "was not present.";
|
||||
} else {
|
||||
themeDebugLog() << "Color value for" << colorName << "was not present.";
|
||||
}
|
||||
};
|
||||
|
||||
@ -61,36 +94,36 @@ static bool readThemeJson(const QString &path, QPalette &palette, double &fadeAm
|
||||
readAndSetColor(QPalette::Highlight, "Highlight");
|
||||
readAndSetColor(QPalette::HighlightedText, "HighlightedText");
|
||||
|
||||
//fade
|
||||
// fade
|
||||
fadeColor = readColor("fadeColor");
|
||||
fadeAmount = Json::ensureDouble(colorsRoot, "fadeAmount", 0.5, "fade amount");
|
||||
|
||||
}
|
||||
catch (const Exception &e)
|
||||
{
|
||||
qWarning() << "Couldn't load theme json: " << e.cause();
|
||||
} catch (const Exception& e) {
|
||||
themeWarningLog() << "Couldn't load theme json: " << e.cause();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
qDebug() << "No theme json present.";
|
||||
} else {
|
||||
themeDebugLog() << "No theme json present.";
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool writeThemeJson(const QString &path, const QPalette &palette, double fadeAmount, QColor fadeColor, QString name, QString widgets)
|
||||
static bool writeThemeJson(const QString& path,
|
||||
const QPalette& palette,
|
||||
double fadeAmount,
|
||||
QColor fadeColor,
|
||||
QString name,
|
||||
QString widgets,
|
||||
QString qssFilePath)
|
||||
{
|
||||
QJsonObject rootObj;
|
||||
rootObj.insert("name", name);
|
||||
rootObj.insert("widgets", widgets);
|
||||
rootObj.insert("qssFilePath", qssFilePath);
|
||||
|
||||
QJsonObject colorsObj;
|
||||
auto insertColor = [&](QPalette::ColorRole role, QString colorName)
|
||||
{
|
||||
colorsObj.insert(colorName, palette.color(role).name());
|
||||
};
|
||||
auto insertColor = [&](QPalette::ColorRole role, QString colorName) { colorsObj.insert(colorName, palette.color(role).name()); };
|
||||
|
||||
// palette
|
||||
insertColor(QPalette::Window, "Window");
|
||||
@ -112,82 +145,95 @@ static bool writeThemeJson(const QString &path, const QPalette &palette, double
|
||||
colorsObj.insert("fadeAmount", fadeAmount);
|
||||
|
||||
rootObj.insert("colors", colorsObj);
|
||||
try
|
||||
{
|
||||
try {
|
||||
Json::write(rootObj, path);
|
||||
return true;
|
||||
}
|
||||
catch (const Exception &e)
|
||||
{
|
||||
qWarning() << "Failed to write theme json to" << path;
|
||||
} catch (const Exception& e) {
|
||||
themeWarningLog() << "Failed to write theme json to" << path;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
CustomTheme::CustomTheme(ITheme* baseTheme, QString folder)
|
||||
/// @param baseTheme Base Theme
|
||||
/// @param fileInfo FileInfo object for file to load
|
||||
/// @param isManifest whether to load a theme manifest or a qss file
|
||||
CustomTheme::CustomTheme(ITheme* baseTheme, QFileInfo& fileInfo, bool isManifest)
|
||||
{
|
||||
m_id = folder;
|
||||
QString path = FS::PathCombine("themes", m_id);
|
||||
QString pathResources = FS::PathCombine("themes", m_id, "resources");
|
||||
if (isManifest) {
|
||||
m_id = fileInfo.dir().dirName();
|
||||
|
||||
qDebug() << "Loading theme" << m_id;
|
||||
QString path = FS::PathCombine("themes", m_id);
|
||||
QString pathResources = FS::PathCombine("themes", m_id, "resources");
|
||||
|
||||
if(!FS::ensureFolderPathExists(path) || !FS::ensureFolderPathExists(pathResources))
|
||||
{
|
||||
qWarning() << "couldn't create folder for theme!";
|
||||
m_palette = baseTheme->colorScheme();
|
||||
m_styleSheet = baseTheme->appStyleSheet();
|
||||
return;
|
||||
}
|
||||
|
||||
auto themeFilePath = FS::PathCombine(path, themeFile);
|
||||
|
||||
m_palette = baseTheme->colorScheme();
|
||||
if (!readThemeJson(themeFilePath, m_palette, m_fadeAmount, m_fadeColor, m_name, m_widgets))
|
||||
{
|
||||
m_name = "Custom";
|
||||
m_palette = baseTheme->colorScheme();
|
||||
m_fadeColor = baseTheme->fadeColor();
|
||||
m_fadeAmount = baseTheme->fadeAmount();
|
||||
m_widgets = baseTheme->qtTheme();
|
||||
|
||||
QFileInfo info(themeFilePath);
|
||||
if(!info.exists())
|
||||
{
|
||||
writeThemeJson(themeFilePath, m_palette, m_fadeAmount, m_fadeColor, "Custom", m_widgets);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_palette = fadeInactive(m_palette, m_fadeAmount, m_fadeColor);
|
||||
}
|
||||
|
||||
auto cssFilePath = FS::PathCombine(path, styleFile);
|
||||
QFileInfo info (cssFilePath);
|
||||
if(info.isFile())
|
||||
{
|
||||
try
|
||||
{
|
||||
// TODO: validate css?
|
||||
m_styleSheet = QString::fromUtf8(FS::read(cssFilePath));
|
||||
}
|
||||
catch (const Exception &e)
|
||||
{
|
||||
qWarning() << "Couldn't load css:" << e.cause() << "from" << cssFilePath;
|
||||
if (!FS::ensureFolderPathExists(path) || !FS::ensureFolderPathExists(pathResources)) {
|
||||
themeWarningLog() << "couldn't create folder for theme!";
|
||||
m_palette = baseTheme->colorScheme();
|
||||
m_styleSheet = baseTheme->appStyleSheet();
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
qDebug() << "No theme css present.";
|
||||
m_styleSheet = baseTheme->appStyleSheet();
|
||||
try
|
||||
{
|
||||
FS::write(cssFilePath, m_styleSheet.toUtf8());
|
||||
|
||||
auto themeFilePath = FS::PathCombine(path, themeFile);
|
||||
|
||||
bool jsonDataIncomplete = false;
|
||||
|
||||
m_palette = baseTheme->colorScheme();
|
||||
if (!readThemeJson(themeFilePath, m_palette, m_fadeAmount, m_fadeColor, m_name, m_widgets, m_qssFilePath, jsonDataIncomplete)) {
|
||||
themeDebugLog() << "Did not read theme json file correctly, writing new one to: " << themeFilePath;
|
||||
m_name = "Custom";
|
||||
m_palette = baseTheme->colorScheme();
|
||||
m_fadeColor = baseTheme->fadeColor();
|
||||
m_fadeAmount = baseTheme->fadeAmount();
|
||||
m_widgets = baseTheme->qtTheme();
|
||||
m_qssFilePath = "themeStyle.css";
|
||||
} else {
|
||||
m_palette = fadeInactive(m_palette, m_fadeAmount, m_fadeColor);
|
||||
}
|
||||
catch (const Exception &e)
|
||||
{
|
||||
qWarning() << "Couldn't write css:" << e.cause() << "to" << cssFilePath;
|
||||
|
||||
if (jsonDataIncomplete) {
|
||||
writeThemeJson(fileInfo.absoluteFilePath(), m_palette, m_fadeAmount, m_fadeColor, m_name, m_widgets, m_qssFilePath);
|
||||
}
|
||||
|
||||
auto qssFilePath = FS::PathCombine(path, m_qssFilePath);
|
||||
QFileInfo info(qssFilePath);
|
||||
if (info.isFile()) {
|
||||
try {
|
||||
// TODO: validate css?
|
||||
m_styleSheet = QString::fromUtf8(FS::read(qssFilePath));
|
||||
} catch (const Exception& e) {
|
||||
themeWarningLog() << "Couldn't load css:" << e.cause() << "from" << qssFilePath;
|
||||
m_styleSheet = baseTheme->appStyleSheet();
|
||||
}
|
||||
} else {
|
||||
themeDebugLog() << "No theme css present.";
|
||||
m_styleSheet = baseTheme->appStyleSheet();
|
||||
try {
|
||||
FS::write(qssFilePath, m_styleSheet.toUtf8());
|
||||
} catch (const Exception& e) {
|
||||
themeWarningLog() << "Couldn't write css:" << e.cause() << "to" << qssFilePath;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
m_id = fileInfo.fileName();
|
||||
m_name = fileInfo.baseName();
|
||||
QString path = fileInfo.filePath();
|
||||
// themeDebugLog << "Theme ID: " << m_id;
|
||||
// themeDebugLog << "Theme Name: " << m_name;
|
||||
// themeDebugLog << "Theme Path: " << path;
|
||||
|
||||
if (!FS::ensureFilePathExists(path)) {
|
||||
themeWarningLog() << m_name << " Theme file path doesn't exist!";
|
||||
m_palette = baseTheme->colorScheme();
|
||||
m_styleSheet = baseTheme->appStyleSheet();
|
||||
return;
|
||||
}
|
||||
|
||||
m_palette = baseTheme->colorScheme();
|
||||
try {
|
||||
// TODO: validate qss?
|
||||
m_styleSheet = QString::fromUtf8(FS::read(path));
|
||||
} catch (const Exception& e) {
|
||||
themeWarningLog() << "Couldn't load qss:" << e.cause() << "from" << path;
|
||||
m_styleSheet = baseTheme->appStyleSheet();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -197,7 +243,6 @@ QStringList CustomTheme::searchPaths()
|
||||
return { FS::PathCombine("themes", m_id, "resources") };
|
||||
}
|
||||
|
||||
|
||||
QString CustomTheme::id()
|
||||
{
|
||||
return m_id;
|
||||
|
@ -1,11 +1,45 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* Prism Launcher - Minecraft Launcher
|
||||
* Copyright (C) 2022 Tayou <tayou@gmx.net>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* This file incorporates work covered by the following copyright and
|
||||
* permission notice:
|
||||
*
|
||||
* Copyright 2013-2021 MultiMC Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <QFileInfo>
|
||||
#include "ITheme.h"
|
||||
|
||||
class CustomTheme: public ITheme
|
||||
{
|
||||
public:
|
||||
CustomTheme(ITheme * baseTheme, QString folder);
|
||||
class CustomTheme : public ITheme {
|
||||
public:
|
||||
CustomTheme(ITheme* baseTheme, QFileInfo& file, bool isManifest);
|
||||
virtual ~CustomTheme() {}
|
||||
|
||||
QString id() override;
|
||||
@ -19,7 +53,7 @@ public:
|
||||
QString qtTheme() override;
|
||||
QStringList searchPaths() override;
|
||||
|
||||
private: /* data */
|
||||
private: /* data */
|
||||
QPalette m_palette;
|
||||
QColor m_fadeColor;
|
||||
double m_fadeAmount;
|
||||
@ -27,5 +61,5 @@ private: /* data */
|
||||
QString m_name;
|
||||
QString m_id;
|
||||
QString m_widgets;
|
||||
QString m_qssFilePath;
|
||||
};
|
||||
|
||||
|
@ -1,30 +1,65 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* Prism Launcher - Minecraft Launcher
|
||||
* Copyright (C) 2022 Tayou <tayou@gmx.net>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* This file incorporates work covered by the following copyright and
|
||||
* permission notice:
|
||||
*
|
||||
* Copyright 2013-2021 MultiMC Contributors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
#include "SystemTheme.h"
|
||||
#include <QApplication>
|
||||
#include <QStyle>
|
||||
#include <QStyleFactory>
|
||||
#include <QDebug>
|
||||
#include "ThemeManager.h"
|
||||
|
||||
SystemTheme::SystemTheme()
|
||||
{
|
||||
qDebug() << "Determining System Theme...";
|
||||
themeDebugLog() << "Determining System Theme...";
|
||||
const auto & style = QApplication::style();
|
||||
systemPalette = style->standardPalette();
|
||||
QString lowerThemeName = style->objectName();
|
||||
qDebug() << "System theme seems to be:" << lowerThemeName;
|
||||
themeDebugLog() << "System theme seems to be:" << lowerThemeName;
|
||||
QStringList styles = QStyleFactory::keys();
|
||||
for(auto &st: styles)
|
||||
{
|
||||
qDebug() << "Considering theme from theme factory:" << st.toLower();
|
||||
themeDebugLog() << "Considering theme from theme factory:" << st.toLower();
|
||||
if(st.toLower() == lowerThemeName)
|
||||
{
|
||||
systemTheme = st;
|
||||
qDebug() << "System theme has been determined to be:" << systemTheme;
|
||||
themeDebugLog() << "System theme has been determined to be:" << systemTheme;
|
||||
return;
|
||||
}
|
||||
}
|
||||
// fall back to fusion if we can't find the current theme.
|
||||
systemTheme = "Fusion";
|
||||
qDebug() << "System theme not found, defaulted to Fusion";
|
||||
themeDebugLog() << "System theme not found, defaulted to Fusion";
|
||||
}
|
||||
|
||||
void SystemTheme::apply(bool initial)
|
||||
|
155
launcher/ui/themes/ThemeManager.cpp
Normal file
155
launcher/ui/themes/ThemeManager.cpp
Normal file
@ -0,0 +1,155 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* Prism Launcher - Minecraft Launcher
|
||||
* Copyright (C) 2022 Tayou <tayou@gmx.net>
|
||||
*
|
||||
* 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 "ThemeManager.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QDir>
|
||||
#include <QDirIterator>
|
||||
#include <QIcon>
|
||||
#include "ui/themes/BrightTheme.h"
|
||||
#include "ui/themes/CustomTheme.h"
|
||||
#include "ui/themes/DarkTheme.h"
|
||||
#include "ui/themes/SystemTheme.h"
|
||||
|
||||
#include "Application.h"
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
#include <windows.h>
|
||||
// this is needed for versionhelpers.h, it is also included in WinDarkmode, but we can't rely on that.
|
||||
// Ultimately this should be included in versionhelpers, but that is outside of the project.
|
||||
#include "ui/WinDarkmode.h"
|
||||
#include <versionhelpers.h>
|
||||
#endif
|
||||
|
||||
ThemeManager::ThemeManager(MainWindow* mainWindow)
|
||||
{
|
||||
m_mainWindow = mainWindow;
|
||||
InitializeThemes();
|
||||
}
|
||||
|
||||
/// @brief Adds the Theme to the list of themes
|
||||
/// @param theme The Theme to add
|
||||
/// @return Theme ID
|
||||
QString ThemeManager::AddTheme(std::unique_ptr<ITheme> theme)
|
||||
{
|
||||
QString id = theme->id();
|
||||
m_themes.emplace(id, std::move(theme));
|
||||
return id;
|
||||
}
|
||||
|
||||
/// @brief Gets the Theme from the List via ID
|
||||
/// @param themeId Theme ID of theme to fetch
|
||||
/// @return Theme at themeId
|
||||
ITheme* ThemeManager::GetTheme(QString themeId)
|
||||
{
|
||||
return m_themes[themeId].get();
|
||||
}
|
||||
|
||||
void ThemeManager::InitializeThemes()
|
||||
{
|
||||
// Icon themes
|
||||
{
|
||||
// TODO: icon themes and instance icons do not mesh well together. Rearrange and fix discrepancies!
|
||||
// set icon theme search path!
|
||||
auto searchPaths = QIcon::themeSearchPaths();
|
||||
searchPaths.append("iconthemes");
|
||||
QIcon::setThemeSearchPaths(searchPaths);
|
||||
themeDebugLog() << "<> Icon themes initialized.";
|
||||
}
|
||||
|
||||
// Initialize widget themes
|
||||
{
|
||||
themeDebugLog() << "<> Initializing Widget Themes";
|
||||
themeDebugLog() << "Loading Built-in Theme:" << AddTheme(std::make_unique<SystemTheme>());
|
||||
auto darkThemeId = AddTheme(std::make_unique<DarkTheme>());
|
||||
themeDebugLog() << "Loading Built-in Theme:" << darkThemeId;
|
||||
themeDebugLog() << "Loading Built-in Theme:" << AddTheme(std::make_unique<BrightTheme>());
|
||||
|
||||
// TODO: need some way to differentiate same name themes in different subdirectories (maybe smaller grey text next to theme name in
|
||||
// dropdown?)
|
||||
QString themeFolder = QDir("./themes/").absoluteFilePath("");
|
||||
themeDebugLog() << "Theme Folder Path: " << themeFolder;
|
||||
|
||||
QDirIterator directoryIterator(themeFolder, QDir::Dirs | QDir::NoDotAndDotDot, QDirIterator::Subdirectories);
|
||||
while (directoryIterator.hasNext()) {
|
||||
QDir dir(directoryIterator.next());
|
||||
QFileInfo themeJson(dir.absoluteFilePath("theme.json"));
|
||||
if (themeJson.exists()) {
|
||||
// Load "theme.json" based themes
|
||||
themeDebugLog() << "Loading JSON Theme from:" << themeJson.absoluteFilePath();
|
||||
AddTheme(std::make_unique<CustomTheme>(GetTheme(darkThemeId), themeJson, true));
|
||||
} else {
|
||||
// Load pure QSS Themes
|
||||
QDirIterator stylesheetFileIterator(dir.absoluteFilePath(""), { "*.qss", "*.css" }, QDir::Files);
|
||||
while (stylesheetFileIterator.hasNext()) {
|
||||
QFile customThemeFile(stylesheetFileIterator.next());
|
||||
QFileInfo customThemeFileInfo(customThemeFile);
|
||||
themeDebugLog() << "Loading QSS Theme from:" << customThemeFileInfo.absoluteFilePath();
|
||||
AddTheme(std::make_unique<CustomTheme>(GetTheme(darkThemeId), customThemeFileInfo, false));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
themeDebugLog() << "<> Widget themes initialized.";
|
||||
}
|
||||
}
|
||||
|
||||
QList<ITheme*> ThemeManager::getValidApplicationThemes()
|
||||
{
|
||||
QList<ITheme*> ret;
|
||||
ret.reserve(m_themes.size());
|
||||
for (auto&& [id, theme] : m_themes) {
|
||||
ret.append(theme.get());
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ThemeManager::setIconTheme(const QString& name)
|
||||
{
|
||||
QIcon::setThemeName(name);
|
||||
}
|
||||
|
||||
void ThemeManager::applyCurrentlySelectedTheme()
|
||||
{
|
||||
setIconTheme(APPLICATION->settings()->get("IconTheme").toString());
|
||||
themeDebugLog() << "<> Icon theme set.";
|
||||
setApplicationTheme(APPLICATION->settings()->get("ApplicationTheme").toString(), true);
|
||||
themeDebugLog() << "<> Application theme set.";
|
||||
}
|
||||
|
||||
void ThemeManager::setApplicationTheme(const QString& name, bool initial)
|
||||
{
|
||||
auto systemPalette = qApp->palette();
|
||||
auto themeIter = m_themes.find(name);
|
||||
if (themeIter != m_themes.end()) {
|
||||
auto& theme = themeIter->second;
|
||||
themeDebugLog() << "applying theme" << theme->name();
|
||||
theme->apply(initial);
|
||||
#ifdef Q_OS_WIN
|
||||
if (m_mainWindow && IsWindows10OrGreater()) {
|
||||
if (QString::compare(theme->id(), "dark") == 0) {
|
||||
WinDarkmode::setDarkWinTitlebar(m_mainWindow->winId(), true);
|
||||
} else {
|
||||
WinDarkmode::setDarkWinTitlebar(m_mainWindow->winId(), false);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
themeWarningLog() << "Tried to set invalid theme:" << name;
|
||||
}
|
||||
}
|
52
launcher/ui/themes/ThemeManager.h
Normal file
52
launcher/ui/themes/ThemeManager.h
Normal file
@ -0,0 +1,52 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* Prism Launcher - Minecraft Launcher
|
||||
* Copyright (C) 2022 Tayou <tayou@gmx.net>
|
||||
*
|
||||
* 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 <QString>
|
||||
|
||||
#include "ui/MainWindow.h"
|
||||
#include "ui/themes/ITheme.h"
|
||||
|
||||
inline auto themeDebugLog()
|
||||
{
|
||||
return qDebug() << "[Theme]";
|
||||
}
|
||||
inline auto themeWarningLog()
|
||||
{
|
||||
return qWarning() << "[Theme]";
|
||||
}
|
||||
|
||||
class ThemeManager {
|
||||
public:
|
||||
ThemeManager(MainWindow* mainWindow);
|
||||
|
||||
// maybe make private? Or put in ctor?
|
||||
void InitializeThemes();
|
||||
|
||||
QList<ITheme*> getValidApplicationThemes();
|
||||
void setIconTheme(const QString& name);
|
||||
void applyCurrentlySelectedTheme();
|
||||
void setApplicationTheme(const QString& name, bool initial);
|
||||
|
||||
private:
|
||||
std::map<QString, std::unique_ptr<ITheme>> m_themes;
|
||||
MainWindow* m_mainWindow;
|
||||
|
||||
QString AddTheme(std::unique_ptr<ITheme> theme);
|
||||
ITheme* GetTheme(QString themeId);
|
||||
};
|
@ -71,6 +71,7 @@ void JavaSettingsWidget::setupUi()
|
||||
m_memoryGroupBox->setObjectName(QStringLiteral("memoryGroupBox"));
|
||||
m_gridLayout_2 = new QGridLayout(m_memoryGroupBox);
|
||||
m_gridLayout_2->setObjectName(QStringLiteral("gridLayout_2"));
|
||||
m_gridLayout_2->setColumnStretch(0, 1);
|
||||
|
||||
m_labelMinMem = new QLabel(m_memoryGroupBox);
|
||||
m_labelMinMem->setObjectName(QStringLiteral("labelMinMem"));
|
||||
@ -80,7 +81,7 @@ void JavaSettingsWidget::setupUi()
|
||||
m_minMemSpinBox->setObjectName(QStringLiteral("minMemSpinBox"));
|
||||
m_minMemSpinBox->setSuffix(QStringLiteral(" MiB"));
|
||||
m_minMemSpinBox->setMinimum(128);
|
||||
m_minMemSpinBox->setMaximum(m_availableMemory);
|
||||
m_minMemSpinBox->setMaximum(1048576);
|
||||
m_minMemSpinBox->setSingleStep(128);
|
||||
m_labelMinMem->setBuddy(m_minMemSpinBox);
|
||||
m_gridLayout_2->addWidget(m_minMemSpinBox, 0, 1, 1, 1);
|
||||
@ -93,11 +94,15 @@ void JavaSettingsWidget::setupUi()
|
||||
m_maxMemSpinBox->setObjectName(QStringLiteral("maxMemSpinBox"));
|
||||
m_maxMemSpinBox->setSuffix(QStringLiteral(" MiB"));
|
||||
m_maxMemSpinBox->setMinimum(128);
|
||||
m_maxMemSpinBox->setMaximum(m_availableMemory);
|
||||
m_maxMemSpinBox->setMaximum(1048576);
|
||||
m_maxMemSpinBox->setSingleStep(128);
|
||||
m_labelMaxMem->setBuddy(m_maxMemSpinBox);
|
||||
m_gridLayout_2->addWidget(m_maxMemSpinBox, 1, 1, 1, 1);
|
||||
|
||||
m_labelMaxMemIcon = new QLabel(m_memoryGroupBox);
|
||||
m_labelMaxMemIcon->setObjectName(QStringLiteral("labelMaxMemIcon"));
|
||||
m_gridLayout_2->addWidget(m_labelMaxMemIcon, 1, 2, 1, 1);
|
||||
|
||||
m_labelPermGen = new QLabel(m_memoryGroupBox);
|
||||
m_labelPermGen->setObjectName(QStringLiteral("labelPermGen"));
|
||||
m_labelPermGen->setText(QStringLiteral("PermGen:"));
|
||||
@ -108,7 +113,7 @@ void JavaSettingsWidget::setupUi()
|
||||
m_permGenSpinBox->setObjectName(QStringLiteral("permGenSpinBox"));
|
||||
m_permGenSpinBox->setSuffix(QStringLiteral(" MiB"));
|
||||
m_permGenSpinBox->setMinimum(64);
|
||||
m_permGenSpinBox->setMaximum(m_availableMemory);
|
||||
m_permGenSpinBox->setMaximum(1048576);
|
||||
m_permGenSpinBox->setSingleStep(8);
|
||||
m_gridLayout_2->addWidget(m_permGenSpinBox, 2, 1, 1, 1);
|
||||
m_permGenSpinBox->setVisible(false);
|
||||
@ -130,6 +135,7 @@ void JavaSettingsWidget::initialize()
|
||||
m_minMemSpinBox->setValue(observedMinMemory);
|
||||
m_maxMemSpinBox->setValue(observedMaxMemory);
|
||||
m_permGenSpinBox->setValue(observedPermGenMemory);
|
||||
updateThresholds();
|
||||
}
|
||||
|
||||
void JavaSettingsWidget::refresh()
|
||||
@ -210,9 +216,9 @@ int JavaSettingsWidget::permGenSize() const
|
||||
void JavaSettingsWidget::memoryValueChanged(int)
|
||||
{
|
||||
bool actuallyChanged = false;
|
||||
int min = m_minMemSpinBox->value();
|
||||
int max = m_maxMemSpinBox->value();
|
||||
int permgen = m_permGenSpinBox->value();
|
||||
unsigned int min = m_minMemSpinBox->value();
|
||||
unsigned int max = m_maxMemSpinBox->value();
|
||||
unsigned int permgen = m_permGenSpinBox->value();
|
||||
QObject *obj = sender();
|
||||
if (obj == m_minMemSpinBox && min != observedMinMemory)
|
||||
{
|
||||
@ -242,10 +248,11 @@ void JavaSettingsWidget::memoryValueChanged(int)
|
||||
if(actuallyChanged)
|
||||
{
|
||||
checkJavaPathOnEdit(m_javaPathTextBox->text());
|
||||
updateThresholds();
|
||||
}
|
||||
}
|
||||
|
||||
void JavaSettingsWidget::javaVersionSelected(BaseVersionPtr version)
|
||||
void JavaSettingsWidget::javaVersionSelected(BaseVersion::Ptr version)
|
||||
{
|
||||
auto java = std::dynamic_pointer_cast<JavaInstall>(version);
|
||||
if(!java)
|
||||
@ -435,3 +442,26 @@ void JavaSettingsWidget::retranslate()
|
||||
m_permGenSpinBox->setToolTip(tr("The amount of memory available to store loaded Java classes."));
|
||||
m_javaBrowseBtn->setText(tr("Browse"));
|
||||
}
|
||||
|
||||
void JavaSettingsWidget::updateThresholds()
|
||||
{
|
||||
QString iconName;
|
||||
|
||||
if (observedMaxMemory >= m_availableMemory) {
|
||||
iconName = "status-bad";
|
||||
m_labelMaxMemIcon->setToolTip(tr("Your maximum memory allocation exceeds your system memory capacity."));
|
||||
} else if (observedMaxMemory > (m_availableMemory * 0.9)) {
|
||||
iconName = "status-yellow";
|
||||
m_labelMaxMemIcon->setToolTip(tr("Your maximum memory allocation approaches your system memory capacity."));
|
||||
} else {
|
||||
iconName = "status-good";
|
||||
m_labelMaxMemIcon->setToolTip("");
|
||||
}
|
||||
|
||||
{
|
||||
auto height = m_labelMaxMemIcon->fontInfo().pixelSize();
|
||||
QIcon icon = APPLICATION->getThemedIcon(iconName);
|
||||
QPixmap pix = icon.pixmap(height, height);
|
||||
m_labelMaxMemIcon->setPixmap(pix);
|
||||
}
|
||||
}
|
||||
|
@ -56,11 +56,13 @@ public:
|
||||
int maxHeapSize() const;
|
||||
QString javaPath() const;
|
||||
|
||||
void updateThresholds();
|
||||
|
||||
|
||||
protected slots:
|
||||
void memoryValueChanged(int);
|
||||
void javaPathEdited(const QString &path);
|
||||
void javaVersionSelected(BaseVersionPtr version);
|
||||
void javaVersionSelected(BaseVersion::Ptr version);
|
||||
void on_javaBrowseBtn_clicked();
|
||||
void on_javaStatusBtn_clicked();
|
||||
void checkFinished(JavaCheckResult result);
|
||||
@ -85,6 +87,7 @@ private: /* data */
|
||||
QSpinBox *m_maxMemSpinBox = nullptr;
|
||||
QLabel *m_labelMinMem = nullptr;
|
||||
QLabel *m_labelMaxMem = nullptr;
|
||||
QLabel *m_labelMaxMemIcon = nullptr;
|
||||
QSpinBox *m_minMemSpinBox = nullptr;
|
||||
QLabel *m_labelPermGen = nullptr;
|
||||
QSpinBox *m_permGenSpinBox = nullptr;
|
||||
@ -92,9 +95,9 @@ private: /* data */
|
||||
QIcon yellowIcon;
|
||||
QIcon badIcon;
|
||||
|
||||
int observedMinMemory = 0;
|
||||
int observedMaxMemory = 0;
|
||||
int observedPermGenMemory = 0;
|
||||
unsigned int observedMinMemory = 0;
|
||||
unsigned int observedMaxMemory = 0;
|
||||
unsigned int observedPermGenMemory = 0;
|
||||
QString queuedCheck;
|
||||
uint64_t m_availableMemory = 0ull;
|
||||
shared_qobject_ptr<JavaChecker> m_checker;
|
||||
|
@ -49,7 +49,7 @@ public:
|
||||
auto getFilter() -> std::shared_ptr<Filter>;
|
||||
auto changed() const -> bool { return m_last_version_id != m_version_id; }
|
||||
|
||||
Meta::VersionListPtr versionList() { return m_version_list; }
|
||||
Meta::VersionList::Ptr versionList() { return m_version_list; }
|
||||
|
||||
private:
|
||||
ModFilterWidget(Version def, QWidget* parent = nullptr);
|
||||
@ -73,7 +73,7 @@ private:
|
||||
/* Version stuff */
|
||||
QButtonGroup m_mcVersion_buttons;
|
||||
|
||||
Meta::VersionListPtr m_version_list;
|
||||
Meta::VersionList::Ptr m_version_list;
|
||||
|
||||
/* Used to tell if the filter was changed since the last getFilter() call */
|
||||
VersionButtonID m_last_version_id = VersionButtonID::Strict;
|
||||
|
@ -142,7 +142,7 @@ void VersionSelectWidget::changeProgress(qint64 current, qint64 total)
|
||||
void VersionSelectWidget::currentRowChanged(const QModelIndex& current, const QModelIndex&)
|
||||
{
|
||||
auto variant = m_proxyModel->data(current, BaseVersionList::VersionPointerRole);
|
||||
emit selectedVersionChanged(variant.value<BaseVersionPtr>());
|
||||
emit selectedVersionChanged(variant.value<BaseVersion::Ptr>());
|
||||
}
|
||||
|
||||
void VersionSelectWidget::preselect()
|
||||
@ -186,11 +186,11 @@ bool VersionSelectWidget::hasVersions() const
|
||||
return m_proxyModel->rowCount(QModelIndex()) != 0;
|
||||
}
|
||||
|
||||
BaseVersionPtr VersionSelectWidget::selectedVersion() const
|
||||
BaseVersion::Ptr VersionSelectWidget::selectedVersion() const
|
||||
{
|
||||
auto currentIndex = listView->selectionModel()->currentIndex();
|
||||
auto variant = m_proxyModel->data(currentIndex, BaseVersionList::VersionPointerRole);
|
||||
return variant.value<BaseVersionPtr>();
|
||||
return variant.value<BaseVersion::Ptr>();
|
||||
}
|
||||
|
||||
void VersionSelectWidget::setExactFilter(BaseVersionList::ModelRoles role, QString filter)
|
||||
|
@ -40,7 +40,7 @@ public:
|
||||
void loadList();
|
||||
|
||||
bool hasVersions() const;
|
||||
BaseVersionPtr selectedVersion() const;
|
||||
BaseVersion::Ptr selectedVersion() const;
|
||||
void selectRecommended();
|
||||
void selectCurrent();
|
||||
|
||||
@ -54,7 +54,7 @@ public:
|
||||
void setResizeOn(int column);
|
||||
|
||||
signals:
|
||||
void selectedVersionChanged(BaseVersionPtr version);
|
||||
void selectedVersionChanged(BaseVersion::Ptr version);
|
||||
|
||||
protected:
|
||||
virtual void closeEvent ( QCloseEvent* );
|
||||
|
Reference in New Issue
Block a user