Merge branch 'develop' into feature/sparkle-mac
# Conflicts: # .github/workflows/build.yml
This commit is contained in:
@@ -1,3 +1,39 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Copyright (C) 2022 Lenny McLennington <lenny@sneed.church>
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.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 "GuiUtil.h"
|
||||
|
||||
#include <QClipboard>
|
||||
@@ -16,8 +52,9 @@
|
||||
QString GuiUtil::uploadPaste(const QString &text, QWidget *parentWidget)
|
||||
{
|
||||
ProgressDialog dialog(parentWidget);
|
||||
auto pasteUrlSetting = APPLICATION->settings()->get("PastebinURL").toString();
|
||||
std::unique_ptr<PasteUpload> paste(new PasteUpload(parentWidget, text, pasteUrlSetting));
|
||||
auto pasteTypeSetting = static_cast<PasteUpload::PasteType>(APPLICATION->settings()->get("PastebinType").toInt());
|
||||
auto pasteCustomAPIBaseSetting = APPLICATION->settings()->get("PastebinCustomAPIBase").toString();
|
||||
std::unique_ptr<PasteUpload> paste(new PasteUpload(parentWidget, text, pasteCustomAPIBaseSetting, pasteTypeSetting));
|
||||
|
||||
dialog.execWithTask(paste.get());
|
||||
if (!paste->wasSuccessful())
|
||||
|
@@ -1,16 +1,36 @@
|
||||
/* Copyright 2013-2021 MultiMC Contributors
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||
*
|
||||
* 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
|
||||
* 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.
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
* 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 "InstanceWindow.h"
|
||||
@@ -97,9 +117,9 @@ InstanceWindow::InstanceWindow(InstancePtr instance, QWidget *parent)
|
||||
// set up instance and launch process recognition
|
||||
{
|
||||
auto launchTask = m_instance->getLaunchTask();
|
||||
on_InstanceLaunchTask_changed(launchTask);
|
||||
connect(m_instance.get(), &BaseInstance::launchTaskChanged, this, &InstanceWindow::on_InstanceLaunchTask_changed);
|
||||
connect(m_instance.get(), &BaseInstance::runningStatusChanged, this, &InstanceWindow::on_RunningState_changed);
|
||||
instanceLaunchTaskChanged(launchTask);
|
||||
connect(m_instance.get(), &BaseInstance::launchTaskChanged, this, &InstanceWindow::instanceLaunchTaskChanged);
|
||||
connect(m_instance.get(), &BaseInstance::runningStatusChanged, this, &InstanceWindow::runningStateChanged);
|
||||
}
|
||||
|
||||
// set up instance destruction detection
|
||||
@@ -152,12 +172,12 @@ void InstanceWindow::on_btnLaunchMinecraftOffline_clicked()
|
||||
APPLICATION->launch(m_instance, false, nullptr);
|
||||
}
|
||||
|
||||
void InstanceWindow::on_InstanceLaunchTask_changed(shared_qobject_ptr<LaunchTask> proc)
|
||||
void InstanceWindow::instanceLaunchTaskChanged(shared_qobject_ptr<LaunchTask> proc)
|
||||
{
|
||||
m_proc = proc;
|
||||
}
|
||||
|
||||
void InstanceWindow::on_RunningState_changed(bool running)
|
||||
void InstanceWindow::runningStateChanged(bool running)
|
||||
{
|
||||
updateLaunchButtons();
|
||||
m_container->refreshContainer();
|
||||
|
@@ -1,16 +1,36 @@
|
||||
/* Copyright 2013-2021 MultiMC Contributors
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||
*
|
||||
* 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
|
||||
* 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.
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
* 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
|
||||
@@ -55,8 +75,8 @@ slots:
|
||||
void on_btnKillMinecraft_clicked();
|
||||
void on_btnLaunchMinecraftOffline_clicked();
|
||||
|
||||
void on_InstanceLaunchTask_changed(shared_qobject_ptr<LaunchTask> proc);
|
||||
void on_RunningState_changed(bool running);
|
||||
void instanceLaunchTaskChanged(shared_qobject_ptr<LaunchTask> proc);
|
||||
void runningStateChanged(bool running);
|
||||
void on_instanceStatusChanged(BaseInstance::Status, BaseInstance::Status newStatus);
|
||||
|
||||
protected:
|
||||
|
@@ -1,51 +1,72 @@
|
||||
/* Copyright 2013-2021 MultiMC Contributors
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||
*
|
||||
* Authors: Andrew Okin
|
||||
* Peterix
|
||||
* Orochimarufan <orochimarufan.x3@gmail.com>
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* 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
|
||||
* 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.
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* 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.
|
||||
* This file incorporates work covered by the following copyright and
|
||||
* permission notice:
|
||||
*
|
||||
* Copyright 2013-2021 MultiMC Contributors
|
||||
*
|
||||
* Authors: Andrew Okin
|
||||
* Peterix
|
||||
* Orochimarufan <orochimarufan.x3@gmail.com>
|
||||
*
|
||||
* 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 "Application.h"
|
||||
#include "BuildConfig.h"
|
||||
|
||||
#include "MainWindow.h"
|
||||
|
||||
#include <QtCore/QVariant>
|
||||
#include <QtCore/QUrl>
|
||||
#include <QtCore/QDir>
|
||||
#include <QtCore/QFileInfo>
|
||||
#include <QVariant>
|
||||
#include <QUrl>
|
||||
#include <QDir>
|
||||
#include <QFileInfo>
|
||||
|
||||
#include <QtGui/QKeyEvent>
|
||||
#include <QKeyEvent>
|
||||
#include <QAction>
|
||||
|
||||
#include <QtWidgets/QAction>
|
||||
#include <QtWidgets/QApplication>
|
||||
#include <QtWidgets/QButtonGroup>
|
||||
#include <QtWidgets/QHBoxLayout>
|
||||
#include <QtWidgets/QHeaderView>
|
||||
#include <QtWidgets/QMainWindow>
|
||||
#include <QtWidgets/QStatusBar>
|
||||
#include <QtWidgets/QToolBar>
|
||||
#include <QtWidgets/QWidget>
|
||||
#include <QtWidgets/QMenu>
|
||||
#include <QtWidgets/QMenuBar>
|
||||
#include <QtWidgets/QMessageBox>
|
||||
#include <QtWidgets/QInputDialog>
|
||||
#include <QtWidgets/QLabel>
|
||||
#include <QtWidgets/QToolButton>
|
||||
#include <QtWidgets/QWidgetAction>
|
||||
#include <QtWidgets/QProgressDialog>
|
||||
#include <QtWidgets/QShortcut>
|
||||
#include <QApplication>
|
||||
#include <QButtonGroup>
|
||||
#include <QHBoxLayout>
|
||||
#include <QHeaderView>
|
||||
#include <QMainWindow>
|
||||
#include <QStatusBar>
|
||||
#include <QToolBar>
|
||||
#include <QWidget>
|
||||
#include <QMenu>
|
||||
#include <QMenuBar>
|
||||
#include <QMessageBox>
|
||||
#include <QInputDialog>
|
||||
#include <QLabel>
|
||||
#include <QToolButton>
|
||||
#include <QWidgetAction>
|
||||
#include <QProgressDialog>
|
||||
#include <QShortcut>
|
||||
|
||||
#include <BaseInstance.h>
|
||||
#include <InstanceList.h>
|
||||
@@ -74,6 +95,7 @@
|
||||
#include "ui/instanceview/InstanceDelegate.h"
|
||||
#include "ui/widgets/LabeledToolButton.h"
|
||||
#include "ui/dialogs/NewInstanceDialog.h"
|
||||
#include "ui/dialogs/NewsDialog.h"
|
||||
#include "ui/dialogs/ProgressDialog.h"
|
||||
#include "ui/dialogs/AboutDialog.h"
|
||||
#include "ui/dialogs/VersionSelectDialog.h"
|
||||
@@ -203,6 +225,7 @@ public:
|
||||
TranslatedAction actionMoreNews;
|
||||
TranslatedAction actionManageAccounts;
|
||||
TranslatedAction actionLaunchInstance;
|
||||
TranslatedAction actionKillInstance;
|
||||
TranslatedAction actionRenameInstance;
|
||||
TranslatedAction actionChangeInstGroup;
|
||||
TranslatedAction actionChangeInstIcon;
|
||||
@@ -212,7 +235,6 @@ public:
|
||||
TranslatedAction actionMods;
|
||||
TranslatedAction actionViewSelectedInstFolder;
|
||||
TranslatedAction actionViewSelectedMCFolder;
|
||||
TranslatedAction actionViewSelectedModsFolder;
|
||||
TranslatedAction actionDeleteInstance;
|
||||
TranslatedAction actionConfig_Folder;
|
||||
TranslatedAction actionCAT;
|
||||
@@ -261,27 +283,6 @@ public:
|
||||
TranslatedToolbar instanceToolBar;
|
||||
TranslatedToolbar newsToolBar;
|
||||
QVector<TranslatedToolbar *> all_toolbars;
|
||||
bool m_kill = false;
|
||||
|
||||
void updateLaunchAction()
|
||||
{
|
||||
if(m_kill)
|
||||
{
|
||||
actionLaunchInstance.setTextId(QT_TRANSLATE_NOOP("MainWindow", "&Kill"));
|
||||
actionLaunchInstance.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "Kill the running instance"));
|
||||
}
|
||||
else
|
||||
{
|
||||
actionLaunchInstance.setTextId(QT_TRANSLATE_NOOP("MainWindow", "&Launch"));
|
||||
actionLaunchInstance.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "Launch the selected instance."));
|
||||
}
|
||||
actionLaunchInstance.retranslate();
|
||||
}
|
||||
void setLaunchAction(bool kill)
|
||||
{
|
||||
m_kill = kill;
|
||||
updateLaunchAction();
|
||||
}
|
||||
|
||||
void createMainToolbarActions(MainWindow *MainWindow)
|
||||
{
|
||||
@@ -482,9 +483,12 @@ public:
|
||||
menuBar->setVisible(APPLICATION->settings()->get("MenuBarInsteadOfToolBar").toBool());
|
||||
|
||||
fileMenu = menuBar->addMenu(tr("&File"));
|
||||
// Workaround for QTBUG-94802 (https://bugreports.qt.io/browse/QTBUG-94802); also present for other menus
|
||||
fileMenu->setSeparatorsCollapsible(false);
|
||||
fileMenu->addAction(actionAddInstance);
|
||||
fileMenu->addAction(actionLaunchInstance);
|
||||
fileMenu->addAction(actionLaunchInstanceOffline);
|
||||
fileMenu->addAction(actionKillInstance);
|
||||
fileMenu->addAction(actionCloseWindow);
|
||||
fileMenu->addSeparator();
|
||||
fileMenu->addAction(actionEditInstance);
|
||||
@@ -505,15 +509,18 @@ public:
|
||||
fileMenu->addAction(actionSettings);
|
||||
|
||||
viewMenu = menuBar->addMenu(tr("&View"));
|
||||
viewMenu->setSeparatorsCollapsible(false);
|
||||
viewMenu->addAction(actionCAT);
|
||||
viewMenu->addSeparator();
|
||||
|
||||
menuBar->addMenu(foldersMenu);
|
||||
|
||||
profileMenu = menuBar->addMenu(tr("&Profiles"));
|
||||
profileMenu->setSeparatorsCollapsible(false);
|
||||
profileMenu->addAction(actionManageAccounts);
|
||||
|
||||
helpMenu = menuBar->addMenu(tr("&Help"));
|
||||
helpMenu->setSeparatorsCollapsible(false);
|
||||
helpMenu->addAction(actionAbout);
|
||||
helpMenu->addAction(actionOpenWiki);
|
||||
helpMenu->addAction(actionNewsMenuBar);
|
||||
@@ -559,10 +566,9 @@ public:
|
||||
}
|
||||
|
||||
// "Instance actions" are actions that require an instance to be selected (i.e. "new instance" is not here)
|
||||
// Actions that also require other conditions (e.g. a running instance) won't be changed.
|
||||
void setInstanceActionsEnabled(bool enabled)
|
||||
{
|
||||
actionLaunchInstance->setEnabled(enabled);
|
||||
actionLaunchInstanceOffline->setEnabled(enabled);
|
||||
actionEditInstance->setEnabled(enabled);
|
||||
actionEditInstNotes->setEnabled(enabled);
|
||||
actionMods->setEnabled(enabled);
|
||||
@@ -649,6 +655,14 @@ public:
|
||||
actionLaunchInstanceOffline.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "Launch the selected instance in offline mode."));
|
||||
all_actions.append(&actionLaunchInstanceOffline);
|
||||
|
||||
actionKillInstance = TranslatedAction(MainWindow);
|
||||
actionKillInstance->setObjectName(QStringLiteral("actionKillInstance"));
|
||||
actionKillInstance->setDisabled(true);
|
||||
actionKillInstance.setTextId(QT_TRANSLATE_NOOP("MainWindow", "&Kill"));
|
||||
actionKillInstance.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "Kill the running instance"));
|
||||
actionKillInstance->setShortcut(QKeySequence(tr("Ctrl+K")));
|
||||
all_actions.append(&actionKillInstance);
|
||||
|
||||
actionEditInstance = TranslatedAction(MainWindow);
|
||||
actionEditInstance->setObjectName(QStringLiteral("actionEditInstance"));
|
||||
actionEditInstance.setTextId(QT_TRANSLATE_NOOP("MainWindow", "Edit Inst&ance..."));
|
||||
@@ -694,14 +708,6 @@ public:
|
||||
actionViewSelectedMCFolder->setShortcut(QKeySequence(tr("Ctrl+M")));
|
||||
all_actions.append(&actionViewSelectedMCFolder);
|
||||
|
||||
/*
|
||||
actionViewSelectedModsFolder = TranslatedAction(MainWindow);
|
||||
actionViewSelectedModsFolder->setObjectName(QStringLiteral("actionViewSelectedModsFolder"));
|
||||
actionViewSelectedModsFolder.setTextId(QT_TRANSLATE_NOOP("MainWindow", "Mods Folder"));
|
||||
actionViewSelectedModsFolder.setTooltipId(QT_TRANSLATE_NOOP("MainWindow", "Open the selected instance's mods folder in a file browser."));
|
||||
all_actions.append(&actionViewSelectedModsFolder);
|
||||
*/
|
||||
|
||||
actionConfig_Folder = TranslatedAction(MainWindow);
|
||||
actionConfig_Folder->setObjectName(QStringLiteral("actionConfig_Folder"));
|
||||
actionConfig_Folder.setTextId(QT_TRANSLATE_NOOP("MainWindow", "Confi&g Folder"));
|
||||
@@ -764,6 +770,7 @@ public:
|
||||
|
||||
instanceToolBar->addAction(actionLaunchInstance);
|
||||
instanceToolBar->addAction(actionLaunchInstanceOffline);
|
||||
instanceToolBar->addAction(actionKillInstance);
|
||||
|
||||
instanceToolBar->addSeparator();
|
||||
|
||||
@@ -777,9 +784,6 @@ public:
|
||||
instanceToolBar->addSeparator();
|
||||
|
||||
instanceToolBar->addAction(actionViewSelectedMCFolder);
|
||||
/*
|
||||
instanceToolBar->addAction(actionViewSelectedModsFolder);
|
||||
*/
|
||||
instanceToolBar->addAction(actionConfig_Folder);
|
||||
instanceToolBar->addAction(actionViewSelectedInstFolder);
|
||||
|
||||
@@ -801,7 +805,7 @@ public:
|
||||
}
|
||||
MainWindow->resize(800, 600);
|
||||
MainWindow->setWindowIcon(APPLICATION->getThemedIcon("logo"));
|
||||
MainWindow->setWindowTitle(BuildConfig.LAUNCHER_DISPLAYNAME);
|
||||
MainWindow->setWindowTitle(APPLICATION->applicationDisplayName());
|
||||
#ifndef QT_NO_ACCESSIBILITY
|
||||
MainWindow->setAccessibleName(BuildConfig.LAUNCHER_NAME);
|
||||
#endif
|
||||
@@ -836,8 +840,6 @@ public:
|
||||
|
||||
void retranslateUi(MainWindow *MainWindow)
|
||||
{
|
||||
QString winTitle = tr("%1 - Version %2", "Launcher - Version X").arg(BuildConfig.LAUNCHER_DISPLAYNAME, BuildConfig.printableVersionString());
|
||||
MainWindow->setWindowTitle(winTitle);
|
||||
// all the actions
|
||||
for(auto * item: all_actions)
|
||||
{
|
||||
@@ -1169,14 +1171,10 @@ void MainWindow::updateToolsMenu()
|
||||
QToolButton *launchButton = dynamic_cast<QToolButton*>(ui->instanceToolBar->widgetForAction(ui->actionLaunchInstance));
|
||||
QToolButton *launchOfflineButton = dynamic_cast<QToolButton*>(ui->instanceToolBar->widgetForAction(ui->actionLaunchInstanceOffline));
|
||||
|
||||
if(m_selectedInstance && m_selectedInstance->isRunning())
|
||||
{
|
||||
ui->actionLaunchInstance->setMenu(nullptr);
|
||||
ui->actionLaunchInstanceOffline->setMenu(nullptr);
|
||||
launchButton->setPopupMode(QToolButton::InstantPopup);
|
||||
launchOfflineButton->setPopupMode(QToolButton::InstantPopup);
|
||||
return;
|
||||
}
|
||||
bool currentInstanceRunning = m_selectedInstance && m_selectedInstance->isRunning();
|
||||
|
||||
ui->actionLaunchInstance->setDisabled(!m_selectedInstance || currentInstanceRunning);
|
||||
ui->actionLaunchInstanceOffline->setDisabled(!m_selectedInstance || currentInstanceRunning);
|
||||
|
||||
QMenu *launchMenu = ui->actionLaunchInstance->menu();
|
||||
QMenu *launchOfflineMenu = ui->actionLaunchInstanceOffline->menu();
|
||||
@@ -1204,6 +1202,9 @@ void MainWindow::updateToolsMenu()
|
||||
normalLaunchOffline->setShortcut(QKeySequence(tr("Ctrl+Shift+O")));
|
||||
if (m_selectedInstance)
|
||||
{
|
||||
normalLaunch->setEnabled(m_selectedInstance->canLaunch());
|
||||
normalLaunchOffline->setEnabled(m_selectedInstance->canLaunch());
|
||||
|
||||
connect(normalLaunch, &QAction::triggered, [this]() {
|
||||
APPLICATION->launch(m_selectedInstance, true);
|
||||
});
|
||||
@@ -1234,6 +1235,9 @@ void MainWindow::updateToolsMenu()
|
||||
}
|
||||
else if (m_selectedInstance)
|
||||
{
|
||||
profilerAction->setEnabled(m_selectedInstance->canLaunch());
|
||||
profilerOfflineAction->setEnabled(m_selectedInstance->canLaunch());
|
||||
|
||||
connect(profilerAction, &QAction::triggered, [this, profiler]()
|
||||
{
|
||||
APPLICATION->launch(m_selectedInstance, true, profiler.get());
|
||||
@@ -1486,7 +1490,11 @@ void MainWindow::updateNotAvailable()
|
||||
|
||||
QList<int> stringToIntList(const QString &string)
|
||||
{
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
|
||||
QStringList split = string.split(',', Qt::SkipEmptyParts);
|
||||
#else
|
||||
QStringList split = string.split(',', QString::SkipEmptyParts);
|
||||
#endif
|
||||
QList<int> out;
|
||||
for (int i = 0; i < split.size(); ++i)
|
||||
{
|
||||
@@ -1876,14 +1884,12 @@ void MainWindow::globalSettingsClosed()
|
||||
updateMainToolBar();
|
||||
updateToolsMenu();
|
||||
updateStatusCenter();
|
||||
// This needs to be done to prevent UI elements disappearing in the event the config is changed
|
||||
// but PolyMC exits abnormally, causing the window state to never be saved:
|
||||
APPLICATION->settings()->set("MainWindowState", saveState().toBase64());
|
||||
update();
|
||||
}
|
||||
|
||||
void MainWindow::on_actionInstanceSettings_triggered()
|
||||
{
|
||||
APPLICATION->showInstanceWindow(m_selectedInstance, "settings");
|
||||
}
|
||||
|
||||
void MainWindow::on_actionEditInstNotes_triggered()
|
||||
{
|
||||
APPLICATION->showInstanceWindow(m_selectedInstance, "notes");
|
||||
@@ -1926,20 +1932,17 @@ void MainWindow::on_actionOpenWiki_triggered()
|
||||
|
||||
void MainWindow::on_actionMoreNews_triggered()
|
||||
{
|
||||
DesktopServices::openUrl(QUrl(BuildConfig.NEWS_OPEN_URL));
|
||||
auto entries = m_newsChecker->getNewsEntries();
|
||||
NewsDialog news_dialog(entries, this);
|
||||
news_dialog.exec();
|
||||
}
|
||||
|
||||
void MainWindow::newsButtonClicked()
|
||||
{
|
||||
QList<NewsEntryPtr> entries = m_newsChecker->getNewsEntries();
|
||||
if (entries.count() > 0)
|
||||
{
|
||||
DesktopServices::openUrl(QUrl(entries[0]->link));
|
||||
}
|
||||
else
|
||||
{
|
||||
DesktopServices::openUrl(QUrl(BuildConfig.NEWS_OPEN_URL));
|
||||
}
|
||||
auto entries = m_newsChecker->getNewsEntries();
|
||||
NewsDialog news_dialog(entries, this);
|
||||
news_dialog.toggleArticleList();
|
||||
news_dialog.exec();
|
||||
}
|
||||
|
||||
void MainWindow::on_actionAbout_triggered()
|
||||
@@ -2009,20 +2012,6 @@ void MainWindow::on_actionViewSelectedMCFolder_triggered()
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::on_actionViewSelectedModsFolder_triggered()
|
||||
{
|
||||
if (m_selectedInstance)
|
||||
{
|
||||
QString str = m_selectedInstance->modsRoot();
|
||||
if (!FS::ensureFilePathExists(str))
|
||||
{
|
||||
// TODO: report error
|
||||
return;
|
||||
}
|
||||
DesktopServices::openDirectory(QDir(str).absolutePath());
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::closeEvent(QCloseEvent *event)
|
||||
{
|
||||
// Save the window state and geometry.
|
||||
@@ -2055,15 +2044,7 @@ void MainWindow::instanceActivated(QModelIndex index)
|
||||
|
||||
void MainWindow::on_actionLaunchInstance_triggered()
|
||||
{
|
||||
if (!m_selectedInstance)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if(m_selectedInstance->isRunning())
|
||||
{
|
||||
APPLICATION->kill(m_selectedInstance);
|
||||
}
|
||||
else
|
||||
if(m_selectedInstance && !m_selectedInstance->isRunning())
|
||||
{
|
||||
APPLICATION->launch(m_selectedInstance);
|
||||
}
|
||||
@@ -2082,6 +2063,14 @@ void MainWindow::on_actionLaunchInstanceOffline_triggered()
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::on_actionKillInstance_triggered()
|
||||
{
|
||||
if(m_selectedInstance && m_selectedInstance->isRunning())
|
||||
{
|
||||
APPLICATION->kill(m_selectedInstance);
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::taskEnd()
|
||||
{
|
||||
QObject *sender = QObject::sender();
|
||||
@@ -2106,23 +2095,18 @@ void MainWindow::instanceChanged(const QModelIndex ¤t, const QModelIndex &
|
||||
selectionBad();
|
||||
return;
|
||||
}
|
||||
if (m_selectedInstance) {
|
||||
disconnect(m_selectedInstance.get(), &BaseInstance::runningStatusChanged, this, &MainWindow::refreshCurrentInstance);
|
||||
}
|
||||
QString id = current.data(InstanceList::InstanceIDRole).toString();
|
||||
m_selectedInstance = APPLICATION->instances()->getInstanceById(id);
|
||||
if (m_selectedInstance)
|
||||
{
|
||||
ui->instanceToolBar->setEnabled(true);
|
||||
ui->setInstanceActionsEnabled(true);
|
||||
if(m_selectedInstance->isRunning())
|
||||
{
|
||||
ui->actionLaunchInstance->setEnabled(true);
|
||||
ui->setLaunchAction(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
ui->actionLaunchInstance->setEnabled(m_selectedInstance->canLaunch());
|
||||
ui->setLaunchAction(false);
|
||||
}
|
||||
ui->actionLaunchInstance->setEnabled(m_selectedInstance->canLaunch());
|
||||
ui->actionLaunchInstanceOffline->setEnabled(m_selectedInstance->canLaunch());
|
||||
ui->actionKillInstance->setEnabled(m_selectedInstance->isRunning());
|
||||
ui->actionExportInstance->setEnabled(m_selectedInstance->canExport());
|
||||
ui->renameButton->setText(m_selectedInstance->name());
|
||||
m_statusLeft->setText(m_selectedInstance->getStatusbarDescription());
|
||||
@@ -2132,11 +2116,16 @@ void MainWindow::instanceChanged(const QModelIndex ¤t, const QModelIndex &
|
||||
updateToolsMenu();
|
||||
|
||||
APPLICATION->settings()->set("SelectedInstance", m_selectedInstance->id());
|
||||
|
||||
connect(m_selectedInstance.get(), &BaseInstance::runningStatusChanged, this, &MainWindow::refreshCurrentInstance);
|
||||
}
|
||||
else
|
||||
{
|
||||
ui->instanceToolBar->setEnabled(false);
|
||||
ui->setInstanceActionsEnabled(false);
|
||||
ui->actionLaunchInstance->setEnabled(false);
|
||||
ui->actionLaunchInstanceOffline->setEnabled(false);
|
||||
ui->actionKillInstance->setEnabled(false);
|
||||
APPLICATION->settings()->set("SelectedInstance", QString());
|
||||
selectionBad();
|
||||
return;
|
||||
@@ -2166,6 +2155,7 @@ void MainWindow::selectionBad()
|
||||
statusBar()->clearMessage();
|
||||
ui->instanceToolBar->setEnabled(false);
|
||||
ui->setInstanceActionsEnabled(false);
|
||||
updateToolsMenu();
|
||||
ui->renameButton->setText(tr("Rename Instance"));
|
||||
updateInstanceToolIcon("grass");
|
||||
|
||||
@@ -2221,3 +2211,9 @@ void MainWindow::updateStatusCenter()
|
||||
m_statusCenter->setText(tr("Total playtime: %1").arg(Time::prettifyDuration(timePlayed)));
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::refreshCurrentInstance(bool running)
|
||||
{
|
||||
auto current = view->selectionModel()->currentIndex();
|
||||
instanceChanged(current, current);
|
||||
}
|
||||
|
@@ -1,16 +1,40 @@
|
||||
/* Copyright 2013-2021 MultiMC Contributors
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||
*
|
||||
* 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
|
||||
* 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.
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
* 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
|
||||
*
|
||||
* Authors: Andrew Okin
|
||||
* Peterix
|
||||
* Orochimarufan <orochimarufan.x3@gmail.com>
|
||||
*
|
||||
* 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
|
||||
@@ -94,8 +118,6 @@ private slots:
|
||||
|
||||
void on_actionViewSelectedMCFolder_triggered();
|
||||
|
||||
void on_actionViewSelectedModsFolder_triggered();
|
||||
|
||||
void refreshInstances();
|
||||
|
||||
void on_actionViewCentralModsFolder_triggered();
|
||||
@@ -104,8 +126,6 @@ private slots:
|
||||
|
||||
void on_actionSettings_triggered();
|
||||
|
||||
void on_actionInstanceSettings_triggered();
|
||||
|
||||
void on_actionManageAccounts_triggered();
|
||||
|
||||
void on_actionReportBug_triggered();
|
||||
@@ -120,6 +140,8 @@ private slots:
|
||||
|
||||
void on_actionLaunchInstanceOffline_triggered();
|
||||
|
||||
void on_actionKillInstance_triggered();
|
||||
|
||||
void on_actionDeleteInstance_triggered();
|
||||
|
||||
void deleteGroup();
|
||||
@@ -192,6 +214,8 @@ private slots:
|
||||
void keyReleaseEvent(QKeyEvent *event) override;
|
||||
#endif
|
||||
|
||||
void refreshCurrentInstance(bool running);
|
||||
|
||||
private:
|
||||
void retranslateUi();
|
||||
|
||||
|
@@ -64,7 +64,9 @@ QString getCreditsHtml()
|
||||
{
|
||||
QString output;
|
||||
QTextStream stream(&output);
|
||||
#if QT_VERSION <= QT_VERSION_CHECK(6, 0, 0)
|
||||
stream.setCodec(QTextCodec::codecForName("UTF-8"));
|
||||
#endif
|
||||
stream << "<center>\n";
|
||||
|
||||
//: %1 is the name of the launcher, determined at build time, e.g. "PolyMC Developers"
|
||||
|
@@ -89,9 +89,15 @@
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="versionLabel">
|
||||
<property name="cursor">
|
||||
<cursorShape>IBeamCursor</cursorShape>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
<property name="textInteractionFlags">
|
||||
<set>Qt::TextSelectableByMouse</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
@@ -133,6 +139,9 @@
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
<property name="textInteractionFlags">
|
||||
<set>Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
@@ -160,32 +169,50 @@
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="platformLabel">
|
||||
<property name="cursor">
|
||||
<cursorShape>IBeamCursor</cursorShape>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Platform:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
<property name="textInteractionFlags">
|
||||
<set>Qt::TextSelectableByMouse</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="buildNumLabel">
|
||||
<property name="cursor">
|
||||
<cursorShape>IBeamCursor</cursorShape>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Build Number:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
<property name="textInteractionFlags">
|
||||
<set>Qt::TextSelectableByMouse</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="channelLabel">
|
||||
<property name="cursor">
|
||||
<cursorShape>IBeamCursor</cursorShape>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Channel:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
<property name="textInteractionFlags">
|
||||
<set>Qt::TextSelectableByMouse</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
|
@@ -1,16 +1,36 @@
|
||||
/* Copyright 2013-2021 MultiMC Contributors
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||
*
|
||||
* 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
|
||||
* 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.
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
* 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 <QLayout>
|
||||
@@ -39,8 +59,14 @@ CopyInstanceDialog::CopyInstanceDialog(InstancePtr original, QWidget *parent)
|
||||
ui->iconButton->setIcon(APPLICATION->icons()->getIcon(InstIconKey));
|
||||
ui->instNameTextBox->setText(original->name());
|
||||
ui->instNameTextBox->setFocus();
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
|
||||
auto groupList = APPLICATION->instances()->getGroups();
|
||||
QSet<QString> groups(groupList.begin(), groupList.end());
|
||||
groupList = QStringList(groups.values());
|
||||
#else
|
||||
auto groups = APPLICATION->instances()->getGroups().toSet();
|
||||
auto groupList = QStringList(groups.toList());
|
||||
#endif
|
||||
groupList.sort(Qt::CaseInsensitive);
|
||||
groupList.removeOne("");
|
||||
groupList.push_front("");
|
||||
|
@@ -488,7 +488,11 @@ void ExportInstanceDialog::loadPackIgnore()
|
||||
}
|
||||
auto data = ignoreFile.readAll();
|
||||
auto string = QString::fromUtf8(data);
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
|
||||
proxyModel->setBlockedPaths(string.split('\n', Qt::SkipEmptyParts));
|
||||
#else
|
||||
proxyModel->setBlockedPaths(string.split('\n', QString::SkipEmptyParts));
|
||||
#endif
|
||||
}
|
||||
|
||||
void ExportInstanceDialog::savePackIgnore()
|
||||
|
@@ -77,18 +77,20 @@ void ModDownloadDialog::confirm()
|
||||
auto keys = modTask.keys();
|
||||
keys.sort(Qt::CaseInsensitive);
|
||||
|
||||
auto confirm_dialog = ReviewMessageBox::create(
|
||||
this,
|
||||
tr("Confirm mods to download")
|
||||
);
|
||||
auto confirm_dialog = ReviewMessageBox::create(this, tr("Confirm mods to download"));
|
||||
|
||||
for(auto& task : keys){
|
||||
confirm_dialog->appendMod(task, modTask.find(task).value()->getFilename());
|
||||
for (auto& task : keys) {
|
||||
confirm_dialog->appendMod({ task, modTask.find(task).value()->getFilename() });
|
||||
}
|
||||
|
||||
connect(confirm_dialog, &QDialog::accepted, this, &ModDownloadDialog::accept);
|
||||
if (confirm_dialog->exec()) {
|
||||
auto deselected = confirm_dialog->deselectedMods();
|
||||
for (auto name : deselected) {
|
||||
modTask.remove(name);
|
||||
}
|
||||
|
||||
confirm_dialog->open();
|
||||
this->accept();
|
||||
}
|
||||
}
|
||||
|
||||
void ModDownloadDialog::accept()
|
||||
@@ -132,6 +134,12 @@ bool ModDownloadDialog::isModSelected(const QString &name, const QString& filena
|
||||
return iter != modTask.end() && (iter.value()->getFilename() == filename);
|
||||
}
|
||||
|
||||
bool ModDownloadDialog::isModSelected(const QString &name) const
|
||||
{
|
||||
auto iter = modTask.find(name);
|
||||
return iter != modTask.end();
|
||||
}
|
||||
|
||||
ModDownloadDialog::~ModDownloadDialog()
|
||||
{
|
||||
}
|
||||
|
@@ -32,6 +32,7 @@ public:
|
||||
void addSelectedMod(const QString & name = QString(), ModDownloadTask * task = nullptr);
|
||||
void removeSelectedMod(const QString & name = QString());
|
||||
bool isModSelected(const QString & name, const QString & filename) const;
|
||||
bool isModSelected(const QString & name) const;
|
||||
|
||||
const QList<ModDownloadTask*> getTasks();
|
||||
const std::shared_ptr<ModFolderModel> &mods;
|
||||
@@ -41,8 +42,6 @@ public slots:
|
||||
void accept() override;
|
||||
void reject() override;
|
||||
|
||||
//private slots:
|
||||
|
||||
private:
|
||||
Ui::ModDownloadDialog *ui = nullptr;
|
||||
PageContainer * m_container = nullptr;
|
||||
|
@@ -1,16 +1,36 @@
|
||||
/* Copyright 2013-2021 MultiMC Contributors
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||
*
|
||||
* 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
|
||||
* 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.
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
* 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 "Application.h"
|
||||
@@ -46,7 +66,6 @@ NewComponentDialog::NewComponentDialog(const QString & initialName, const QStrin
|
||||
connect(ui->nameTextBox, &QLineEdit::textChanged, this, &NewComponentDialog::updateDialogState);
|
||||
connect(ui->uidTextBox, &QLineEdit::textChanged, this, &NewComponentDialog::updateDialogState);
|
||||
|
||||
auto groups = APPLICATION->instances()->getGroups().toSet();
|
||||
ui->nameTextBox->setFocus();
|
||||
|
||||
originalPlaceholderText = ui->uidTextBox->placeholderText();
|
||||
|
@@ -1,16 +1,36 @@
|
||||
/* Copyright 2013-2021 MultiMC Contributors
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||
*
|
||||
* 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
|
||||
* 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.
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
* 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 "Application.h"
|
||||
@@ -54,8 +74,14 @@ NewInstanceDialog::NewInstanceDialog(const QString & initialGroup, const QString
|
||||
InstIconKey = "default";
|
||||
ui->iconButton->setIcon(APPLICATION->icons()->getIcon(InstIconKey));
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
|
||||
auto groupList = APPLICATION->instances()->getGroups();
|
||||
auto groups = QSet<QString>(groupList.begin(), groupList.end());
|
||||
groupList = groups.values();
|
||||
#else
|
||||
auto groups = APPLICATION->instances()->getGroups().toSet();
|
||||
auto groupList = QStringList(groups.toList());
|
||||
#endif
|
||||
groupList.sort(Qt::CaseInsensitive);
|
||||
groupList.removeOne("");
|
||||
groupList.push_front(initialGroup);
|
||||
|
49
launcher/ui/dialogs/NewsDialog.cpp
Normal file
49
launcher/ui/dialogs/NewsDialog.cpp
Normal file
@@ -0,0 +1,49 @@
|
||||
#include "NewsDialog.h"
|
||||
#include "ui_NewsDialog.h"
|
||||
|
||||
NewsDialog::NewsDialog(QList<NewsEntryPtr> entries, QWidget* parent) : QDialog(parent), ui(new Ui::NewsDialog())
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
for (auto entry : entries) {
|
||||
ui->articleListWidget->addItem(entry->title);
|
||||
m_entries.insert(entry->title, entry);
|
||||
}
|
||||
|
||||
connect(ui->articleListWidget, &QListWidget::currentTextChanged, this, &NewsDialog::selectedArticleChanged);
|
||||
connect(ui->toggleListButton, &QPushButton::clicked, this, &NewsDialog::toggleArticleList);
|
||||
|
||||
m_article_list_hidden = ui->articleListWidget->isHidden();
|
||||
|
||||
auto first_item = ui->articleListWidget->item(0);
|
||||
first_item->setSelected(true);
|
||||
|
||||
auto article_entry = m_entries.constFind(first_item->text()).value();
|
||||
ui->articleTitleLabel->setText(QString("<a href='%1'>%2</a>").arg(article_entry->link, first_item->text()));
|
||||
ui->currentArticleContentBrowser->setText(article_entry->content);
|
||||
}
|
||||
|
||||
NewsDialog::~NewsDialog()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void NewsDialog::selectedArticleChanged(const QString& new_title)
|
||||
{
|
||||
auto const& article_entry = m_entries.constFind(new_title).value();
|
||||
|
||||
ui->articleTitleLabel->setText(QString("<a href='%1'>%2</a>").arg(article_entry->link, new_title));
|
||||
ui->currentArticleContentBrowser->setText(article_entry->content);
|
||||
}
|
||||
|
||||
void NewsDialog::toggleArticleList()
|
||||
{
|
||||
m_article_list_hidden = !m_article_list_hidden;
|
||||
|
||||
ui->articleListWidget->setHidden(m_article_list_hidden);
|
||||
|
||||
if (m_article_list_hidden)
|
||||
ui->toggleListButton->setText(tr("Show article list"));
|
||||
else
|
||||
ui->toggleListButton->setText(tr("Hide article list"));
|
||||
}
|
30
launcher/ui/dialogs/NewsDialog.h
Normal file
30
launcher/ui/dialogs/NewsDialog.h
Normal file
@@ -0,0 +1,30 @@
|
||||
#pragma once
|
||||
|
||||
#include <QDialog>
|
||||
#include <QHash>
|
||||
|
||||
#include "news/NewsEntry.h"
|
||||
|
||||
namespace Ui {
|
||||
class NewsDialog;
|
||||
}
|
||||
|
||||
class NewsDialog : public QDialog {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
NewsDialog(QList<NewsEntryPtr> entries, QWidget* parent = nullptr);
|
||||
~NewsDialog();
|
||||
|
||||
public slots:
|
||||
void toggleArticleList();
|
||||
|
||||
private slots:
|
||||
void selectedArticleChanged(const QString& new_title);
|
||||
|
||||
private:
|
||||
Ui::NewsDialog* ui;
|
||||
|
||||
QHash<QString, NewsEntryPtr> m_entries;
|
||||
bool m_article_list_hidden = false;
|
||||
};
|
113
launcher/ui/dialogs/NewsDialog.ui
Normal file
113
launcher/ui/dialogs/NewsDialog.ui
Normal file
@@ -0,0 +1,113 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>NewsDialog</class>
|
||||
<widget class="QDialog" name="NewsDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>800</width>
|
||||
<height>500</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>News</string>
|
||||
</property>
|
||||
<property name="sizeGripEnabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="leftVerticalLayout">
|
||||
<item>
|
||||
<widget class="QListWidget" name="articleListWidget">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Minimum" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="rightVerticalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="articleTitleLabel">
|
||||
<property name="text">
|
||||
<string notr="true">Placeholder</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
<property name="openExternalLinks">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QTextBrowser" name="currentArticleContentBrowser">
|
||||
<property name="textInteractionFlags">
|
||||
<set>Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse|Qt::TextBrowserInteraction|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse</set>
|
||||
</property>
|
||||
<property name="openExternalLinks">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="openLinks">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="1">
|
||||
<widget class="QPushButton" name="closeButton">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>10</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Close</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QPushButton" name="toggleListButton">
|
||||
<property name="text">
|
||||
<string>Hide article list</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>closeButton</sender>
|
||||
<signal>clicked()</signal>
|
||||
<receiver>NewsDialog</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>199</x>
|
||||
<y>277</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>199</x>
|
||||
<y>149</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
@@ -1,16 +1,36 @@
|
||||
/* Copyright 2013-2021 MultiMC Contributors
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||
*
|
||||
* 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
|
||||
* 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.
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
* 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 "ProfileSetupDialog.h"
|
||||
@@ -18,7 +38,7 @@
|
||||
|
||||
#include <QPushButton>
|
||||
#include <QAction>
|
||||
#include <QRegExpValidator>
|
||||
#include <QRegularExpressionValidator>
|
||||
#include <QJsonDocument>
|
||||
#include <QDebug>
|
||||
|
||||
@@ -39,9 +59,9 @@ ProfileSetupDialog::ProfileSetupDialog(MinecraftAccountPtr accountToSetup, QWidg
|
||||
yellowIcon = APPLICATION->getThemedIcon("status-yellow");
|
||||
badIcon = APPLICATION->getThemedIcon("status-bad");
|
||||
|
||||
QRegExp permittedNames("[a-zA-Z0-9_]{3,16}");
|
||||
QRegularExpression permittedNames("[a-zA-Z0-9_]{3,16}");
|
||||
auto nameEdit = ui->nameEdit;
|
||||
nameEdit->setValidator(new QRegExpValidator(permittedNames));
|
||||
nameEdit->setValidator(new QRegularExpressionValidator(permittedNames));
|
||||
nameEdit->setClearButtonEnabled(true);
|
||||
validityAction = nameEdit->addAction(yellowIcon, QLineEdit::LeadingPosition);
|
||||
connect(nameEdit, &QLineEdit::textEdited, this, &ProfileSetupDialog::nameEdited);
|
||||
|
@@ -16,12 +16,12 @@
|
||||
#include "ProgressDialog.h"
|
||||
#include "ui_ProgressDialog.h"
|
||||
|
||||
#include <QKeyEvent>
|
||||
#include <QDebug>
|
||||
#include <QKeyEvent>
|
||||
|
||||
#include "tasks/Task.h"
|
||||
|
||||
ProgressDialog::ProgressDialog(QWidget *parent) : QDialog(parent), ui(new Ui::ProgressDialog)
|
||||
ProgressDialog::ProgressDialog(QWidget* parent) : QDialog(parent), ui(new Ui::ProgressDialog)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
this->setWindowFlags(this->windowFlags() & ~Qt::WindowContextHelpButtonHint);
|
||||
@@ -44,6 +44,7 @@ void ProgressDialog::on_skipButton_clicked(bool checked)
|
||||
{
|
||||
Q_UNUSED(checked);
|
||||
task->abort();
|
||||
QDialog::reject();
|
||||
}
|
||||
|
||||
ProgressDialog::~ProgressDialog()
|
||||
@@ -53,24 +54,22 @@ ProgressDialog::~ProgressDialog()
|
||||
|
||||
void ProgressDialog::updateSize()
|
||||
{
|
||||
QSize qSize = QSize(480, minimumSizeHint().height());
|
||||
QSize qSize = QSize(480, minimumSizeHint().height());
|
||||
resize(qSize);
|
||||
setFixedSize(qSize);
|
||||
setFixedSize(qSize);
|
||||
}
|
||||
|
||||
int ProgressDialog::execWithTask(Task *task)
|
||||
int ProgressDialog::execWithTask(Task* task)
|
||||
{
|
||||
this->task = task;
|
||||
QDialog::DialogCode result;
|
||||
|
||||
if(!task)
|
||||
{
|
||||
if (!task) {
|
||||
qDebug() << "Programmer error: progress dialog created with null task.";
|
||||
return Accepted;
|
||||
}
|
||||
|
||||
if(handleImmediateResult(result))
|
||||
{
|
||||
if (handleImmediateResult(result)) {
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -78,58 +77,51 @@ int ProgressDialog::execWithTask(Task *task)
|
||||
connect(task, SIGNAL(started()), SLOT(onTaskStarted()));
|
||||
connect(task, SIGNAL(failed(QString)), SLOT(onTaskFailed(QString)));
|
||||
connect(task, SIGNAL(succeeded()), SLOT(onTaskSucceeded()));
|
||||
connect(task, SIGNAL(status(QString)), SLOT(changeStatus(const QString &)));
|
||||
connect(task, SIGNAL(status(QString)), SLOT(changeStatus(const QString&)));
|
||||
connect(task, SIGNAL(stepStatus(QString)), SLOT(changeStatus(const QString&)));
|
||||
connect(task, SIGNAL(progress(qint64, qint64)), SLOT(changeProgress(qint64, qint64)));
|
||||
|
||||
connect(task, &Task::aborted, [this] { onTaskFailed(tr("Aborted by user")); });
|
||||
|
||||
m_is_multi_step = task->isMultiStep();
|
||||
if(!m_is_multi_step){
|
||||
if (!m_is_multi_step) {
|
||||
ui->globalStatusLabel->setHidden(true);
|
||||
ui->globalProgressBar->setHidden(true);
|
||||
}
|
||||
|
||||
// if this didn't connect to an already running task, invoke start
|
||||
if(!task->isRunning())
|
||||
{
|
||||
if (!task->isRunning()) {
|
||||
task->start();
|
||||
}
|
||||
if(task->isRunning())
|
||||
{
|
||||
if (task->isRunning()) {
|
||||
changeProgress(task->getProgress(), task->getTotalProgress());
|
||||
changeStatus(task->getStatus());
|
||||
return QDialog::exec();
|
||||
}
|
||||
else if(handleImmediateResult(result))
|
||||
{
|
||||
} else if (handleImmediateResult(result)) {
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
return QDialog::Rejected;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: only provide the unique_ptr overloads
|
||||
int ProgressDialog::execWithTask(std::unique_ptr<Task> &&task)
|
||||
int ProgressDialog::execWithTask(std::unique_ptr<Task>&& task)
|
||||
{
|
||||
connect(this, &ProgressDialog::destroyed, task.get(), &Task::deleteLater);
|
||||
return execWithTask(task.release());
|
||||
}
|
||||
int ProgressDialog::execWithTask(std::unique_ptr<Task> &task)
|
||||
int ProgressDialog::execWithTask(std::unique_ptr<Task>& task)
|
||||
{
|
||||
connect(this, &ProgressDialog::destroyed, task.get(), &Task::deleteLater);
|
||||
return execWithTask(task.release());
|
||||
}
|
||||
|
||||
bool ProgressDialog::handleImmediateResult(QDialog::DialogCode &result)
|
||||
bool ProgressDialog::handleImmediateResult(QDialog::DialogCode& result)
|
||||
{
|
||||
if(task->isFinished())
|
||||
{
|
||||
if(task->wasSuccessful())
|
||||
{
|
||||
if (task->isFinished()) {
|
||||
if (task->wasSuccessful()) {
|
||||
result = QDialog::Accepted;
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
result = QDialog::Rejected;
|
||||
}
|
||||
return true;
|
||||
@@ -137,14 +129,12 @@ bool ProgressDialog::handleImmediateResult(QDialog::DialogCode &result)
|
||||
return false;
|
||||
}
|
||||
|
||||
Task *ProgressDialog::getTask()
|
||||
Task* ProgressDialog::getTask()
|
||||
{
|
||||
return task;
|
||||
}
|
||||
|
||||
void ProgressDialog::onTaskStarted()
|
||||
{
|
||||
}
|
||||
void ProgressDialog::onTaskStarted() {}
|
||||
|
||||
void ProgressDialog::onTaskFailed(QString failure)
|
||||
{
|
||||
@@ -156,10 +146,11 @@ void ProgressDialog::onTaskSucceeded()
|
||||
accept();
|
||||
}
|
||||
|
||||
void ProgressDialog::changeStatus(const QString &status)
|
||||
void ProgressDialog::changeStatus(const QString& status)
|
||||
{
|
||||
ui->globalStatusLabel->setText(task->getStatus());
|
||||
ui->statusLabel->setText(task->getStepStatus());
|
||||
ui->globalStatusLabel->setText(status);
|
||||
|
||||
updateSize();
|
||||
}
|
||||
|
||||
@@ -168,27 +159,22 @@ void ProgressDialog::changeProgress(qint64 current, qint64 total)
|
||||
ui->globalProgressBar->setMaximum(total);
|
||||
ui->globalProgressBar->setValue(current);
|
||||
|
||||
if(!m_is_multi_step){
|
||||
if (!m_is_multi_step) {
|
||||
ui->taskProgressBar->setMaximum(total);
|
||||
ui->taskProgressBar->setValue(current);
|
||||
}
|
||||
else{
|
||||
} else {
|
||||
ui->taskProgressBar->setMaximum(task->getStepProgress());
|
||||
ui->taskProgressBar->setValue(task->getStepTotalProgress());
|
||||
}
|
||||
}
|
||||
|
||||
void ProgressDialog::keyPressEvent(QKeyEvent *e)
|
||||
void ProgressDialog::keyPressEvent(QKeyEvent* e)
|
||||
{
|
||||
if(ui->skipButton->isVisible())
|
||||
{
|
||||
if (e->key() == Qt::Key_Escape)
|
||||
{
|
||||
if (ui->skipButton->isVisible()) {
|
||||
if (e->key() == Qt::Key_Escape) {
|
||||
on_skipButton_clicked(true);
|
||||
return;
|
||||
}
|
||||
else if(e->key() == Qt::Key_Tab)
|
||||
{
|
||||
} else if (e->key() == Qt::Key_Tab) {
|
||||
ui->skipButton->setFocusPolicy(Qt::StrongFocus);
|
||||
ui->skipButton->setFocus();
|
||||
ui->skipButton->setAutoDefault(true);
|
||||
@@ -199,14 +185,11 @@ void ProgressDialog::keyPressEvent(QKeyEvent *e)
|
||||
QDialog::keyPressEvent(e);
|
||||
}
|
||||
|
||||
void ProgressDialog::closeEvent(QCloseEvent *e)
|
||||
void ProgressDialog::closeEvent(QCloseEvent* e)
|
||||
{
|
||||
if (task && task->isRunning())
|
||||
{
|
||||
if (task && task->isRunning()) {
|
||||
e->ignore();
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
QDialog::closeEvent(e);
|
||||
}
|
||||
}
|
||||
|
@@ -40,6 +40,12 @@
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="statusLabel">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="MinimumExpanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Task Status...</string>
|
||||
</property>
|
||||
|
@@ -5,6 +5,9 @@ ReviewMessageBox::ReviewMessageBox(QWidget* parent, QString const& title, QStrin
|
||||
: QDialog(parent), ui(new Ui::ReviewMessageBox)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
connect(ui->buttonBox, &QDialogButtonBox::accepted, this, &ReviewMessageBox::accept);
|
||||
connect(ui->buttonBox, &QDialogButtonBox::rejected, this, &ReviewMessageBox::reject);
|
||||
}
|
||||
|
||||
ReviewMessageBox::~ReviewMessageBox()
|
||||
@@ -17,15 +20,33 @@ auto ReviewMessageBox::create(QWidget* parent, QString&& title, QString&& icon)
|
||||
return new ReviewMessageBox(parent, title, icon);
|
||||
}
|
||||
|
||||
void ReviewMessageBox::appendMod(const QString& name, const QString& filename)
|
||||
void ReviewMessageBox::appendMod(ModInformation&& info)
|
||||
{
|
||||
auto itemTop = new QTreeWidgetItem(ui->modTreeWidget);
|
||||
itemTop->setText(0, name);
|
||||
itemTop->setCheckState(0, Qt::CheckState::Checked);
|
||||
itemTop->setText(0, info.name);
|
||||
|
||||
auto filenameItem = new QTreeWidgetItem(itemTop);
|
||||
filenameItem->setText(0, tr("Filename: %1").arg(filename));
|
||||
filenameItem->setText(0, tr("Filename: %1").arg(info.filename));
|
||||
|
||||
itemTop->insertChildren(0, { filenameItem });
|
||||
|
||||
ui->modTreeWidget->addTopLevelItem(itemTop);
|
||||
}
|
||||
|
||||
auto ReviewMessageBox::deselectedMods() -> QStringList
|
||||
{
|
||||
QStringList list;
|
||||
|
||||
auto* item = ui->modTreeWidget->topLevelItem(0);
|
||||
|
||||
for (int i = 0; item != nullptr; ++i) {
|
||||
if (item->checkState(0) == Qt::CheckState::Unchecked) {
|
||||
list.append(item->text(0));
|
||||
}
|
||||
|
||||
item = ui->modTreeWidget->topLevelItem(i);
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
@@ -6,17 +6,23 @@ namespace Ui {
|
||||
class ReviewMessageBox;
|
||||
}
|
||||
|
||||
class ReviewMessageBox final : public QDialog {
|
||||
class ReviewMessageBox : public QDialog {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
static auto create(QWidget* parent, QString&& title, QString&& icon = "") -> ReviewMessageBox*;
|
||||
|
||||
void appendMod(const QString& name, const QString& filename);
|
||||
using ModInformation = struct {
|
||||
QString name;
|
||||
QString filename;
|
||||
};
|
||||
|
||||
void appendMod(ModInformation&& info);
|
||||
auto deselectedMods() -> QStringList;
|
||||
|
||||
~ReviewMessageBox();
|
||||
|
||||
private:
|
||||
protected:
|
||||
ReviewMessageBox(QWidget* parent, const QString& title, const QString& icon);
|
||||
|
||||
Ui::ReviewMessageBox* ui;
|
||||
|
@@ -6,8 +6,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>400</width>
|
||||
<height>300</height>
|
||||
<width>500</width>
|
||||
<height>350</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
@@ -20,24 +20,7 @@
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>You're about to download the following mods:</string>
|
||||
</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>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QTreeWidget" name="modTreeWidget">
|
||||
<property name="alternatingRowColors">
|
||||
<bool>true</bool>
|
||||
@@ -58,41 +41,33 @@
|
||||
</column>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="explainLabel">
|
||||
<property name="text">
|
||||
<string>You're about to download the following mods:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0" rowspan="2">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="onlyCheckedLabel">
|
||||
<property name="text">
|
||||
<string>Only mods with a check will be downloaded!</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttonBox">
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>ReviewMessageBox</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>200</x>
|
||||
<y>265</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>199</x>
|
||||
<y>149</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>ReviewMessageBox</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>200</x>
|
||||
<y>265</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>199</x>
|
||||
<y>149</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
<connections/>
|
||||
</ui>
|
||||
|
15
launcher/ui/dialogs/ScrollMessageBox.cpp
Normal file
15
launcher/ui/dialogs/ScrollMessageBox.cpp
Normal file
@@ -0,0 +1,15 @@
|
||||
#include "ScrollMessageBox.h"
|
||||
#include "ui_ScrollMessageBox.h"
|
||||
|
||||
|
||||
ScrollMessageBox::ScrollMessageBox(QWidget *parent, const QString &title, const QString &text, const QString &body) :
|
||||
QDialog(parent), ui(new Ui::ScrollMessageBox) {
|
||||
ui->setupUi(this);
|
||||
this->setWindowTitle(title);
|
||||
ui->label->setText(text);
|
||||
ui->textBrowser->setText(body);
|
||||
}
|
||||
|
||||
ScrollMessageBox::~ScrollMessageBox() {
|
||||
delete ui;
|
||||
}
|
20
launcher/ui/dialogs/ScrollMessageBox.h
Normal file
20
launcher/ui/dialogs/ScrollMessageBox.h
Normal file
@@ -0,0 +1,20 @@
|
||||
#pragma once
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
namespace Ui { class ScrollMessageBox; }
|
||||
QT_END_NAMESPACE
|
||||
|
||||
class ScrollMessageBox : public QDialog {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ScrollMessageBox(QWidget *parent, const QString &title, const QString &text, const QString &body);
|
||||
|
||||
~ScrollMessageBox() override;
|
||||
|
||||
private:
|
||||
Ui::ScrollMessageBox *ui;
|
||||
};
|
84
launcher/ui/dialogs/ScrollMessageBox.ui
Normal file
84
launcher/ui/dialogs/ScrollMessageBox.ui
Normal file
@@ -0,0 +1,84 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>ScrollMessageBox</class>
|
||||
<widget class="QDialog" name="ScrollMessageBox">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>400</width>
|
||||
<height>455</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string notr="true">ScrollMessageBox</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<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>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QTextBrowser" name="textBrowser">
|
||||
<property name="acceptRichText">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="openExternalLinks">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>ScrollMessageBox</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>199</x>
|
||||
<y>425</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>199</x>
|
||||
<y>227</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttonBox</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>ScrollMessageBox</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>199</x>
|
||||
<y>425</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>199</x>
|
||||
<y>227</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
@@ -1,3 +1,38 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.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 <QFileInfo>
|
||||
#include <QFileDialog>
|
||||
#include <QPainter>
|
||||
@@ -22,10 +57,10 @@ void SkinUploadDialog::on_buttonBox_accepted()
|
||||
{
|
||||
QString fileName;
|
||||
QString input = ui->skinPathTextBox->text();
|
||||
QRegExp urlPrefixMatcher("^([a-z]+)://.+$");
|
||||
QRegularExpression urlPrefixMatcher(QRegularExpression::anchoredPattern("^([a-z]+)://.+$"));
|
||||
bool isLocalFile = false;
|
||||
// it has an URL prefix -> it is an URL
|
||||
if(urlPrefixMatcher.exactMatch(input))
|
||||
if(urlPrefixMatcher.match(input).hasMatch())
|
||||
{
|
||||
QUrl fileURL = input;
|
||||
if(fileURL.isValid())
|
||||
|
@@ -1,3 +1,38 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.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 "UpdateDialog.h"
|
||||
#include "ui_UpdateDialog.h"
|
||||
#include <QDebug>
|
||||
@@ -58,7 +93,7 @@ QString reprocessMarkdown(QByteArray markdown)
|
||||
QString output = hoedown.process(markdown);
|
||||
|
||||
// HACK: easier than customizing hoedown
|
||||
output.replace(QRegExp("GH-([0-9]+)"), "<a href=\"https://github.com/PolyMC/PolyMC/issues/\\1\">GH-\\1</a>");
|
||||
output.replace(QRegularExpression("GH-([0-9]+)"), "<a href=\"https://github.com/PolyMC/PolyMC/issues/\\1\">GH-\\1</a>");
|
||||
qDebug() << output;
|
||||
return output;
|
||||
}
|
||||
|
@@ -1,16 +1,36 @@
|
||||
/* Copyright 2013-2021 MultiMC Contributors
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||
*
|
||||
* 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
|
||||
* 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.
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
* 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 "InstanceDelegate.h"
|
||||
@@ -24,7 +44,7 @@
|
||||
#include "InstanceView.h"
|
||||
#include "BaseInstance.h"
|
||||
#include "InstanceList.h"
|
||||
#include <xdgicon.h>
|
||||
#include <QIcon>
|
||||
#include <QTextEdit>
|
||||
|
||||
// Origin: Qt
|
||||
@@ -61,7 +81,7 @@ void drawSelectionRect(QPainter *painter, const QStyleOptionViewItem &option,
|
||||
painter->fillRect(rect, option.palette.brush(QPalette::Highlight));
|
||||
else
|
||||
{
|
||||
QColor backgroundColor = option.palette.color(QPalette::Background);
|
||||
QColor backgroundColor = option.palette.color(QPalette::Window);
|
||||
backgroundColor.setAlpha(160);
|
||||
painter->fillRect(rect, QBrush(backgroundColor));
|
||||
}
|
||||
@@ -142,7 +162,7 @@ void drawBadges(QPainter *painter, const QStyleOptionViewItem &option, BaseInsta
|
||||
return;
|
||||
}
|
||||
// FIXME: inject this.
|
||||
auto icon = XdgIcon::fromTheme(it.next());
|
||||
auto icon = QIcon::fromTheme(it.next());
|
||||
// opt.icon.paint(painter, iconbox, Qt::AlignCenter, mode, state);
|
||||
const QPixmap pixmap;
|
||||
// itemSide
|
||||
|
@@ -1,16 +1,36 @@
|
||||
/* Copyright 2013-2021 MultiMC Contributors
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||
*
|
||||
* 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
|
||||
* 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.
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
* 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 "InstanceView.h"
|
||||
@@ -425,7 +445,12 @@ void InstanceView::mouseReleaseEvent(QMouseEvent *event)
|
||||
{
|
||||
emit clicked(index);
|
||||
}
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||
QStyleOptionViewItem option;
|
||||
initViewItemOption(&option);
|
||||
#else
|
||||
QStyleOptionViewItem option = viewOptions();
|
||||
#endif
|
||||
if (m_pressedAlreadySelected)
|
||||
{
|
||||
option.state |= QStyle::State_Selected;
|
||||
@@ -461,7 +486,12 @@ void InstanceView::mouseDoubleClickEvent(QMouseEvent *event)
|
||||
QPersistentModelIndex persistent = index;
|
||||
emit doubleClicked(persistent);
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||
QStyleOptionViewItem option;
|
||||
initViewItemOption(&option);
|
||||
#else
|
||||
QStyleOptionViewItem option = viewOptions();
|
||||
#endif
|
||||
if ((model()->flags(index) & Qt::ItemIsEnabled) && !style()->styleHint(QStyle::SH_ItemView_ActivateItemOnSingleClick, &option, this))
|
||||
{
|
||||
emit activated(index);
|
||||
@@ -474,7 +504,12 @@ void InstanceView::paintEvent(QPaintEvent *event)
|
||||
|
||||
QPainter painter(this->viewport());
|
||||
|
||||
QStyleOptionViewItem option(viewOptions());
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||
QStyleOptionViewItem option;
|
||||
initViewItemOption(&option);
|
||||
#else
|
||||
QStyleOptionViewItem option = viewOptions();
|
||||
#endif
|
||||
option.widget = this;
|
||||
|
||||
int wpWidth = viewport()->width();
|
||||
@@ -528,9 +563,9 @@ void InstanceView::paintEvent(QPaintEvent *event)
|
||||
#if 0
|
||||
if (!m_lastDragPosition.isNull())
|
||||
{
|
||||
QPair<Group *, int> pair = rowDropPos(m_lastDragPosition);
|
||||
Group *category = pair.first;
|
||||
int row = pair.second;
|
||||
std::pair<VisualGroup *, VisualGroup::HitResults> pair = rowDropPos(m_lastDragPosition);
|
||||
VisualGroup *category = pair.first;
|
||||
VisualGroup::HitResults row = pair.second;
|
||||
if (category)
|
||||
{
|
||||
int internalRow = row - category->firstItemIndex;
|
||||
@@ -618,7 +653,7 @@ void InstanceView::dropEvent(QDropEvent *event)
|
||||
{
|
||||
if(event->possibleActions() & Qt::MoveAction)
|
||||
{
|
||||
QPair<VisualGroup *, VisualGroup::HitResults> dropPos = rowDropPos(event->pos());
|
||||
std::pair<VisualGroup *, VisualGroup::HitResults> dropPos = rowDropPos(event->pos());
|
||||
const VisualGroup *group = dropPos.first;
|
||||
auto hitresult = dropPos.second;
|
||||
|
||||
@@ -709,10 +744,18 @@ QRect InstanceView::geometryRect(const QModelIndex &index) const
|
||||
int x = pos.first;
|
||||
// int y = pos.second;
|
||||
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||
QStyleOptionViewItem option;
|
||||
initViewItemOption(&option);
|
||||
#else
|
||||
QStyleOptionViewItem option = viewOptions();
|
||||
#endif
|
||||
|
||||
QRect out;
|
||||
out.setTop(cat->verticalPosition() + cat->headerHeight() + 5 + cat->rowTopOf(index));
|
||||
out.setLeft(m_spacing + x * (itemWidth() + m_spacing));
|
||||
out.setSize(itemDelegate()->sizeHint(viewOptions(), index));
|
||||
out.setSize(itemDelegate()->sizeHint(option, index));
|
||||
geometryCache.insert(row, new QRect(out));
|
||||
return out;
|
||||
}
|
||||
@@ -759,7 +802,12 @@ QPixmap InstanceView::renderToPixmap(const QModelIndexList &indices, QRect *r) c
|
||||
QPixmap pixmap(r->size());
|
||||
pixmap.fill(Qt::transparent);
|
||||
QPainter painter(&pixmap);
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||
QStyleOptionViewItem option;
|
||||
initViewItemOption(&option);
|
||||
#else
|
||||
QStyleOptionViewItem option = viewOptions();
|
||||
#endif
|
||||
option.state |= QStyle::State_Selected;
|
||||
for (int j = 0; j < paintPairs.count(); ++j)
|
||||
{
|
||||
@@ -770,16 +818,16 @@ QPixmap InstanceView::renderToPixmap(const QModelIndexList &indices, QRect *r) c
|
||||
return pixmap;
|
||||
}
|
||||
|
||||
QList<QPair<QRect, QModelIndex>> InstanceView::draggablePaintPairs(const QModelIndexList &indices, QRect *r) const
|
||||
QList<std::pair<QRect, QModelIndex>> InstanceView::draggablePaintPairs(const QModelIndexList &indices, QRect *r) const
|
||||
{
|
||||
Q_ASSERT(r);
|
||||
QRect &rect = *r;
|
||||
QList<QPair<QRect, QModelIndex>> ret;
|
||||
QList<std::pair<QRect, QModelIndex>> ret;
|
||||
for (int i = 0; i < indices.count(); ++i)
|
||||
{
|
||||
const QModelIndex &index = indices.at(i);
|
||||
const QRect current = geometryRect(index);
|
||||
ret += qMakePair(current, index);
|
||||
ret += std::make_pair(current, index);
|
||||
rect |= current;
|
||||
}
|
||||
return ret;
|
||||
@@ -790,11 +838,11 @@ bool InstanceView::isDragEventAccepted(QDropEvent *event)
|
||||
return true;
|
||||
}
|
||||
|
||||
QPair<VisualGroup *, VisualGroup::HitResults> InstanceView::rowDropPos(const QPoint &pos)
|
||||
std::pair<VisualGroup *, VisualGroup::HitResults> InstanceView::rowDropPos(const QPoint &pos)
|
||||
{
|
||||
VisualGroup::HitResults hitresult;
|
||||
auto group = categoryAt(pos + offset(), hitresult);
|
||||
return qMakePair<VisualGroup*, int>(group, hitresult);
|
||||
return std::make_pair(group, hitresult);
|
||||
}
|
||||
|
||||
QPoint InstanceView::offset() const
|
||||
|
@@ -1,16 +1,36 @@
|
||||
/* Copyright 2013-2021 MultiMC Contributors
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||
*
|
||||
* 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
|
||||
* 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.
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
* 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
|
||||
@@ -143,11 +163,11 @@ private: /* methods */
|
||||
int calculateItemsPerRow() const;
|
||||
int verticalScrollToValue(const QModelIndex &index, const QRect &rect, QListView::ScrollHint hint) const;
|
||||
QPixmap renderToPixmap(const QModelIndexList &indices, QRect *r) const;
|
||||
QList<QPair<QRect, QModelIndex>> draggablePaintPairs(const QModelIndexList &indices, QRect *r) const;
|
||||
QList<std::pair<QRect, QModelIndex>> draggablePaintPairs(const QModelIndexList &indices, QRect *r) const;
|
||||
|
||||
bool isDragEventAccepted(QDropEvent *event);
|
||||
|
||||
QPair<VisualGroup *, VisualGroup::HitResults> rowDropPos(const QPoint &pos);
|
||||
std::pair<VisualGroup *, VisualGroup::HitResults> rowDropPos(const QPoint &pos);
|
||||
|
||||
QPoint offset() const;
|
||||
};
|
||||
|
@@ -1,16 +1,36 @@
|
||||
/* Copyright 2013-2021 MultiMC Contributors
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||
*
|
||||
* 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
|
||||
* 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.
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
* 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 "VisualGroup.h"
|
||||
@@ -55,7 +75,14 @@ void VisualGroup::update()
|
||||
positionInRow = 0;
|
||||
maxRowHeight = 0;
|
||||
}
|
||||
auto itemHeight = view->itemDelegate()->sizeHint(view->viewOptions(), item).height();
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
|
||||
QStyleOptionViewItem viewItemOption;
|
||||
view->initViewItemOption(&viewItemOption);
|
||||
#else
|
||||
QStyleOptionViewItem viewItemOption = view->viewOptions();
|
||||
#endif
|
||||
|
||||
auto itemHeight = view->itemDelegate()->sizeHint(viewItemOption, item).height();
|
||||
if(itemHeight > maxRowHeight)
|
||||
{
|
||||
maxRowHeight = itemHeight;
|
||||
|
@@ -3,6 +3,7 @@
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||
* Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
|
||||
* Copyright (c) 2022 Lenny McLennington <lenny@sneed.church>
|
||||
*
|
||||
* 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
|
||||
@@ -46,16 +47,43 @@
|
||||
#include "settings/SettingsObject.h"
|
||||
#include "tools/BaseProfiler.h"
|
||||
#include "Application.h"
|
||||
#include "net/PasteUpload.h"
|
||||
#include "BuildConfig.h"
|
||||
|
||||
APIPage::APIPage(QWidget *parent) :
|
||||
QWidget(parent),
|
||||
ui(new Ui::APIPage)
|
||||
{
|
||||
// This is here so you can reorder the entries in the combobox without messing stuff up
|
||||
int comboBoxEntries[] = {
|
||||
PasteUpload::PasteType::Mclogs,
|
||||
PasteUpload::PasteType::NullPointer,
|
||||
PasteUpload::PasteType::PasteGG,
|
||||
PasteUpload::PasteType::Hastebin
|
||||
};
|
||||
|
||||
static QRegularExpression validUrlRegExp("https?://.+");
|
||||
|
||||
ui->setupUi(this);
|
||||
ui->urlChoices->setValidator(new QRegularExpressionValidator(validUrlRegExp, ui->urlChoices));
|
||||
ui->tabWidget->tabBar()->hide();\
|
||||
|
||||
for (auto pasteType : comboBoxEntries) {
|
||||
ui->pasteTypeComboBox->addItem(PasteUpload::PasteTypes.at(pasteType).name, pasteType);
|
||||
}
|
||||
|
||||
void (QComboBox::*currentIndexChangedSignal)(int) (&QComboBox::currentIndexChanged);
|
||||
connect(ui->pasteTypeComboBox, currentIndexChangedSignal, this, &APIPage::updateBaseURLPlaceholder);
|
||||
// This function needs to be called even when the ComboBox's index is still in its default state.
|
||||
updateBaseURLPlaceholder(ui->pasteTypeComboBox->currentIndex());
|
||||
ui->baseURLEntry->setValidator(new QRegularExpressionValidator(validUrlRegExp, ui->baseURLEntry));
|
||||
|
||||
ui->metaURL->setPlaceholderText(BuildConfig.META_URL);
|
||||
ui->userAgentLineEdit->setPlaceholderText(BuildConfig.USER_AGENT);
|
||||
|
||||
loadSettings();
|
||||
|
||||
resetBaseURLNote();
|
||||
connect(ui->pasteTypeComboBox, currentIndexChangedSignal, this, &APIPage::updateBaseURLNote);
|
||||
connect(ui->baseURLEntry, &QLineEdit::textEdited, this, &APIPage::resetBaseURLNote);
|
||||
}
|
||||
|
||||
APIPage::~APIPage()
|
||||
@@ -63,22 +91,85 @@ APIPage::~APIPage()
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void APIPage::resetBaseURLNote()
|
||||
{
|
||||
ui->baseURLNote->hide();
|
||||
baseURLPasteType = ui->pasteTypeComboBox->currentIndex();
|
||||
}
|
||||
|
||||
void APIPage::updateBaseURLNote(int index)
|
||||
{
|
||||
if (baseURLPasteType == index)
|
||||
{
|
||||
ui->baseURLNote->hide();
|
||||
}
|
||||
else if (!ui->baseURLEntry->text().isEmpty())
|
||||
{
|
||||
ui->baseURLNote->show();
|
||||
}
|
||||
}
|
||||
|
||||
void APIPage::updateBaseURLPlaceholder(int index)
|
||||
{
|
||||
int pasteType = ui->pasteTypeComboBox->itemData(index).toInt();
|
||||
QString pasteDefaultURL = PasteUpload::PasteTypes.at(pasteType).defaultBase;
|
||||
ui->baseURLEntry->setPlaceholderText(pasteDefaultURL);
|
||||
}
|
||||
|
||||
void APIPage::loadSettings()
|
||||
{
|
||||
auto s = APPLICATION->settings();
|
||||
QString pastebinURL = s->get("PastebinURL").toString();
|
||||
ui->urlChoices->setCurrentText(pastebinURL);
|
||||
|
||||
int pasteType = s->get("PastebinType").toInt();
|
||||
QString pastebinURL = s->get("PastebinCustomAPIBase").toString();
|
||||
|
||||
ui->baseURLEntry->setText(pastebinURL);
|
||||
int pasteTypeIndex = ui->pasteTypeComboBox->findData(pasteType);
|
||||
if (pasteTypeIndex == -1)
|
||||
{
|
||||
pasteTypeIndex = ui->pasteTypeComboBox->findData(PasteUpload::PasteType::Mclogs);
|
||||
ui->baseURLEntry->clear();
|
||||
}
|
||||
|
||||
ui->pasteTypeComboBox->setCurrentIndex(pasteTypeIndex);
|
||||
|
||||
QString msaClientID = s->get("MSAClientIDOverride").toString();
|
||||
ui->msaClientID->setText(msaClientID);
|
||||
QString metaURL = s->get("MetaURLOverride").toString();
|
||||
ui->metaURL->setText(metaURL);
|
||||
QString curseKey = s->get("CFKeyOverride").toString();
|
||||
ui->curseKey->setText(curseKey);
|
||||
QString customUserAgent = s->get("UserAgentOverride").toString();
|
||||
ui->userAgentLineEdit->setText(customUserAgent);
|
||||
}
|
||||
|
||||
void APIPage::applySettings()
|
||||
{
|
||||
auto s = APPLICATION->settings();
|
||||
QString pastebinURL = ui->urlChoices->currentText();
|
||||
s->set("PastebinURL", pastebinURL);
|
||||
|
||||
s->set("PastebinType", ui->pasteTypeComboBox->currentData().toInt());
|
||||
s->set("PastebinCustomAPIBase", ui->baseURLEntry->text());
|
||||
|
||||
QString msaClientID = ui->msaClientID->text();
|
||||
s->set("MSAClientIDOverride", msaClientID);
|
||||
QUrl metaURL = ui->metaURL->text();
|
||||
// Add required trailing slash
|
||||
if (!metaURL.isEmpty() && !metaURL.path().endsWith('/'))
|
||||
{
|
||||
QString path = metaURL.path();
|
||||
path.append('/');
|
||||
metaURL.setPath(path);
|
||||
}
|
||||
// Don't allow HTTP, since meta is basically RCE with all the jar files.
|
||||
if(!metaURL.isEmpty() && metaURL.scheme() == "http")
|
||||
{
|
||||
metaURL.setScheme("https");
|
||||
}
|
||||
|
||||
s->set("MetaURLOverride", metaURL);
|
||||
QString curseKey = ui->curseKey->text();
|
||||
s->set("CFKeyOverride", curseKey);
|
||||
s->set("UserAgentOverride", ui->userAgentLineEdit->text());
|
||||
}
|
||||
|
||||
bool APIPage::apply()
|
||||
|
@@ -3,6 +3,7 @@
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||
* Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
|
||||
* Copyright (c) 2022 Lenny McLennington <lenny@sneed.church>
|
||||
*
|
||||
* 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
|
||||
@@ -73,6 +74,10 @@ public:
|
||||
void retranslate() override;
|
||||
|
||||
private:
|
||||
int baseURLPasteType;
|
||||
void resetBaseURLNote();
|
||||
void updateBaseURLNote(int index);
|
||||
void updateBaseURLPlaceholder(int index);
|
||||
void loadSettings();
|
||||
void applySettings();
|
||||
|
||||
|
@@ -6,8 +6,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>491</width>
|
||||
<height>474</height>
|
||||
<width>800</width>
|
||||
<height>600</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
@@ -30,56 +30,91 @@
|
||||
</property>
|
||||
<widget class="QWidget" name="tab">
|
||||
<attribute name="title">
|
||||
<string notr="true">Tab 1</string>
|
||||
<string notr="true">Services</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_paste">
|
||||
<property name="title">
|
||||
<string>&Pastebin URL</string>
|
||||
<string>&Pastebin Service</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item>
|
||||
<widget class="Line" name="line">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>10</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<widget class="QLabel" name="pasteServiceTypeLabel">
|
||||
<property name="text">
|
||||
<string><html><head/><body><p>Note: only input that starts with <span style=" font-weight:600;">http://</span> or <span style=" font-weight:600;">https://</span> will be accepted.</p></body></html></string>
|
||||
<string>Paste Service &Type</string>
|
||||
</property>
|
||||
<property name="scaledContents">
|
||||
<bool>false</bool>
|
||||
<property name="buddy">
|
||||
<cstring>pasteTypeComboBox</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="urlChoices">
|
||||
<property name="editable">
|
||||
<widget class="QComboBox" name="pasteTypeComboBox"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="baseURLLabel">
|
||||
<property name="text">
|
||||
<string>Base &URL</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>baseURLEntry</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="baseURLEntry">
|
||||
<property name="placeholderText">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="clearButtonEnabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="insertPolicy">
|
||||
<enum>QComboBox::NoInsert</enum>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string notr="true">https://0x0.st</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<widget class="QLabel" name="baseURLNote">
|
||||
<property name="text">
|
||||
<string><html><head/><body><p>Here you can choose from a predefined list of paste services, or input the URL of a different paste service of your choice, provided it supports the same protocol as 0x0.st, that is POST a file parameter to the URL and return a link in the response body.</p></body></html></string>
|
||||
<string>Note: you probably want to change or clear the Base URL after changing the paste service type.</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_meta">
|
||||
<property name="title">
|
||||
<string>Meta&data Server</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_5">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>You can set this to a third-party metadata server to use patched libraries or other hacks.</string>
|
||||
</property>
|
||||
<property name="textFormat">
|
||||
<enum>Qt::RichText</enum>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="metaURL">
|
||||
<property name="placeholderText">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="text">
|
||||
<string>Enter a custom URL for meta here.</string>
|
||||
</property>
|
||||
<property name="textFormat">
|
||||
<enum>Qt::RichText</enum>
|
||||
@@ -95,19 +130,32 @@
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tab_2">
|
||||
<attribute name="title">
|
||||
<string>API Keys</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_8">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_msa">
|
||||
<property name="title">
|
||||
<string>&Microsoft Authentication</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||
<item>
|
||||
<widget class="Line" name="line_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
@@ -147,6 +195,51 @@
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_curse">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>&CurseForge Core API</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_8">
|
||||
<property name="text">
|
||||
<string>Note: you probably don't need to set this if CurseForge already works.</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_7">
|
||||
<property name="text">
|
||||
<string>Enter a custom API Key for CurseForge here. </string>
|
||||
</property>
|
||||
<property name="textFormat">
|
||||
<enum>Qt::RichText</enum>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="openExternalLinks">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLineEdit" name="curseKey">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="placeholderText">
|
||||
<string>(Default)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
@@ -162,13 +255,55 @@
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tab_3">
|
||||
<attribute name="title">
|
||||
<string>Miscellaneous</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_6">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_ua">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>User Agent</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_7">
|
||||
<item>
|
||||
<widget class="QLineEdit" name="userAgentLineEdit"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="userAgentLabel">
|
||||
<property name="text">
|
||||
<string>Enter a custom User Agent here. The special string $LAUNCHER_VER will be replaced with the version of the launcher.</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<tabstops>
|
||||
<tabstop>tabWidget</tabstop>
|
||||
</tabstops>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
|
@@ -73,9 +73,11 @@ AccountListPage::AccountListPage(QWidget *parent)
|
||||
m_accounts = APPLICATION->accounts();
|
||||
|
||||
ui->listView->setModel(m_accounts.get());
|
||||
ui->listView->header()->setSectionResizeMode(0, QHeaderView::Stretch);
|
||||
ui->listView->header()->setSectionResizeMode(1, QHeaderView::Stretch);
|
||||
ui->listView->header()->setSectionResizeMode(2, QHeaderView::ResizeToContents);
|
||||
ui->listView->header()->setSectionResizeMode(AccountList::VListColumns::ProfileNameColumn, QHeaderView::Stretch);
|
||||
ui->listView->header()->setSectionResizeMode(AccountList::VListColumns::NameColumn, QHeaderView::Stretch);
|
||||
ui->listView->header()->setSectionResizeMode(AccountList::VListColumns::MigrationColumn, QHeaderView::ResizeToContents);
|
||||
ui->listView->header()->setSectionResizeMode(AccountList::VListColumns::TypeColumn, QHeaderView::ResizeToContents);
|
||||
ui->listView->header()->setSectionResizeMode(AccountList::VListColumns::StatusColumn, QHeaderView::ResizeToContents);
|
||||
ui->listView->setSelectionMode(QAbstractItemView::SingleSelection);
|
||||
|
||||
// Expand the account column
|
||||
@@ -253,19 +255,21 @@ void AccountListPage::updateButtonStates()
|
||||
{
|
||||
// If there is no selection, disable buttons that require something selected.
|
||||
QModelIndexList selection = ui->listView->selectionModel()->selectedIndexes();
|
||||
bool hasSelection = selection.size() > 0;
|
||||
bool hasSelection = !selection.empty();
|
||||
bool accountIsReady = false;
|
||||
bool accountIsOnline = false;
|
||||
if (hasSelection)
|
||||
{
|
||||
QModelIndex selected = selection.first();
|
||||
MinecraftAccountPtr account = selected.data(AccountList::PointerRole).value<MinecraftAccountPtr>();
|
||||
accountIsReady = !account->isActive();
|
||||
accountIsOnline = !account->isOffline();
|
||||
}
|
||||
ui->actionRemove->setEnabled(accountIsReady);
|
||||
ui->actionSetDefault->setEnabled(accountIsReady);
|
||||
ui->actionUploadSkin->setEnabled(accountIsReady);
|
||||
ui->actionDeleteSkin->setEnabled(accountIsReady);
|
||||
ui->actionRefresh->setEnabled(accountIsReady);
|
||||
ui->actionUploadSkin->setEnabled(accountIsReady && accountIsOnline);
|
||||
ui->actionDeleteSkin->setEnabled(accountIsReady && accountIsOnline);
|
||||
ui->actionRefresh->setEnabled(accountIsReady && accountIsOnline);
|
||||
|
||||
if(m_accounts->defaultAccount().get() == nullptr) {
|
||||
ui->actionNoDefault->setEnabled(false);
|
||||
|
@@ -2,7 +2,7 @@
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
|
||||
* Copyright (c) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.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
|
||||
|
@@ -95,7 +95,7 @@ void JavaPage::applySettings()
|
||||
|
||||
// Java Settings
|
||||
s->set("JavaPath", ui->javaPathTextBox->text());
|
||||
s->set("JvmArgs", ui->jvmArgsTextBox->text());
|
||||
s->set("JvmArgs", ui->jvmArgsTextBox->toPlainText().replace("\n", " "));
|
||||
s->set("IgnoreJavaCompatibility", ui->skipCompatibilityCheckbox->isChecked());
|
||||
s->set("IgnoreJavaWizard", ui->skipJavaWizardCheckbox->isChecked());
|
||||
JavaCommon::checkJVMArgs(s->get("JvmArgs").toString(), this->parentWidget());
|
||||
@@ -120,13 +120,18 @@ void JavaPage::loadSettings()
|
||||
|
||||
// Java Settings
|
||||
ui->javaPathTextBox->setText(s->get("JavaPath").toString());
|
||||
ui->jvmArgsTextBox->setText(s->get("JvmArgs").toString());
|
||||
ui->jvmArgsTextBox->setPlainText(s->get("JvmArgs").toString());
|
||||
ui->skipCompatibilityCheckbox->setChecked(s->get("IgnoreJavaCompatibility").toBool());
|
||||
ui->skipJavaWizardCheckbox->setChecked(s->get("IgnoreJavaWizard").toBool());
|
||||
}
|
||||
|
||||
void JavaPage::on_javaDetectBtn_clicked()
|
||||
{
|
||||
if (JavaUtils::getJavaCheckPath().isEmpty()) {
|
||||
JavaCommon::javaCheckNotFound(this);
|
||||
return;
|
||||
}
|
||||
|
||||
JavaInstallPtr java;
|
||||
|
||||
VersionSelectDialog vselect(APPLICATION->javalist().get(), tr("Select a Java version"), this, true);
|
||||
@@ -166,7 +171,7 @@ void JavaPage::on_javaTestBtn_clicked()
|
||||
return;
|
||||
}
|
||||
checker.reset(new JavaCommon::TestCheck(
|
||||
this, ui->javaPathTextBox->text(), ui->jvmArgsTextBox->text(),
|
||||
this, ui->javaPathTextBox->text(), ui->jvmArgsTextBox->toPlainText().replace("\n", " "),
|
||||
ui->minMemSpinBox->value(), ui->maxMemSpinBox->value(), ui->permGenSpinBox->value()));
|
||||
connect(checker.get(), SIGNAL(finished()), SLOT(checkerFinished()));
|
||||
checker->run();
|
||||
|
@@ -150,6 +150,35 @@
|
||||
<string>Java Runtime</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_3">
|
||||
<item row="3" column="1">
|
||||
<widget class="QPushButton" name="javaDetectBtn">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Auto-detect...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="labelJVMArgs">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>JVM arguments:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="labelJavaPath">
|
||||
<property name="sizePolicy">
|
||||
@@ -166,40 +195,8 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="labelJVMArgs">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>J&VM arguments:</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>jvmArgsTextBox</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QCheckBox" name="skipCompatibilityCheckbox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>If enabled, the launcher will not check if an instance is compatible with the selected Java version.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Skip Java compatibility checks</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QPushButton" name="javaDetectBtn">
|
||||
<item row="3" column="2">
|
||||
<widget class="QPushButton" name="javaTestBtn">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
@@ -207,7 +204,7 @@
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Auto-detect...</string>
|
||||
<string>&Test</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@@ -237,22 +234,22 @@
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="3" column="2">
|
||||
<widget class="QPushButton" name="javaTestBtn">
|
||||
<item row="4" column="1">
|
||||
<widget class="QCheckBox" name="skipCompatibilityCheckbox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>If enabled, the launcher will not check if an instance is compatible with the selected Java version.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Test</string>
|
||||
<string>&Skip Java compatibility checks</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1" colspan="2">
|
||||
<widget class="QLineEdit" name="jvmArgsTextBox"/>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<widget class="QCheckBox" name="skipJavaWizardCheckbox">
|
||||
<property name="toolTip">
|
||||
@@ -263,6 +260,25 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1" colspan="2">
|
||||
<widget class="QPlainTextEdit" name="jvmArgsTextBox">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16777215</width>
|
||||
<height>100</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
@@ -291,7 +307,6 @@
|
||||
<tabstop>permGenSpinBox</tabstop>
|
||||
<tabstop>javaBrowseBtn</tabstop>
|
||||
<tabstop>javaPathTextBox</tabstop>
|
||||
<tabstop>jvmArgsTextBox</tabstop>
|
||||
<tabstop>javaDetectBtn</tabstop>
|
||||
<tabstop>javaTestBtn</tabstop>
|
||||
<tabstop>tabWidget</tabstop>
|
||||
|
@@ -2,6 +2,7 @@
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.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
|
||||
|
@@ -2,6 +2,7 @@
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.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
|
||||
|
@@ -191,6 +191,11 @@ void LauncherPage::on_modsDirBrowseBtn_clicked()
|
||||
}
|
||||
}
|
||||
|
||||
void LauncherPage::on_metadataDisableBtn_clicked()
|
||||
{
|
||||
ui->metadataWarningLabel->setHidden(!ui->metadataDisableBtn->isChecked());
|
||||
}
|
||||
|
||||
void LauncherPage::refreshUpdateChannelList()
|
||||
{
|
||||
// Stop listening for selection changes. It's going to change a lot while we update it and
|
||||
@@ -354,6 +359,9 @@ void LauncherPage::applySettings()
|
||||
s->set("InstSortMode", "Name");
|
||||
break;
|
||||
}
|
||||
|
||||
// Mods
|
||||
s->set("ModMetadataDisabled", ui->metadataDisableBtn->isChecked());
|
||||
}
|
||||
void LauncherPage::loadSettings()
|
||||
{
|
||||
@@ -465,6 +473,10 @@ void LauncherPage::loadSettings()
|
||||
{
|
||||
ui->sortByNameBtn->setChecked(true);
|
||||
}
|
||||
|
||||
// Mods
|
||||
ui->metadataDisableBtn->setChecked(s->get("ModMetadataDisabled").toBool());
|
||||
ui->metadataWarningLabel->setHidden(!ui->metadataDisableBtn->isChecked());
|
||||
}
|
||||
|
||||
void LauncherPage::refreshFontPreview()
|
||||
|
@@ -88,6 +88,7 @@ slots:
|
||||
void on_instDirBrowseBtn_clicked();
|
||||
void on_modsDirBrowseBtn_clicked();
|
||||
void on_iconsDirBrowseBtn_clicked();
|
||||
void on_metadataDisableBtn_clicked();
|
||||
|
||||
/*!
|
||||
* Updates the list of update channels in the combo box.
|
||||
|
@@ -94,19 +94,13 @@
|
||||
<string>Folders</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="foldersBoxLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="labelInstDir">
|
||||
<item row="1" column="2">
|
||||
<widget class="QToolButton" name="modsDirBrowseBtn">
|
||||
<property name="text">
|
||||
<string>I&nstances:</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>instDirTextBox</cstring>
|
||||
<string notr="true">...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="instDirTextBox"/>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QToolButton" name="instDirBrowseBtn">
|
||||
<property name="text">
|
||||
@@ -114,28 +108,15 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="labelModsDir">
|
||||
<property name="text">
|
||||
<string>&Mods:</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>modsDirTextBox</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLineEdit" name="modsDirTextBox"/>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QToolButton" name="modsDirBrowseBtn">
|
||||
<item row="2" column="2">
|
||||
<widget class="QToolButton" name="iconsDirBrowseBtn">
|
||||
<property name="text">
|
||||
<string notr="true">...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QLineEdit" name="iconsDirTextBox"/>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="instDirTextBox"/>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="labelIconsDir">
|
||||
@@ -147,10 +128,58 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="2">
|
||||
<widget class="QToolButton" name="iconsDirBrowseBtn">
|
||||
<item row="1" column="1">
|
||||
<widget class="QLineEdit" name="modsDirTextBox"/>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="labelInstDir">
|
||||
<property name="text">
|
||||
<string notr="true">...</string>
|
||||
<string>I&nstances:</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>instDirTextBox</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QLineEdit" name="iconsDirTextBox"/>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="labelModsDir">
|
||||
<property name="text">
|
||||
<string>&Mods:</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>modsDirTextBox</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="modsBox">
|
||||
<property name="title">
|
||||
<string>Mods</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="metadataDisableBtn">
|
||||
<property name="toolTip">
|
||||
<string>Disable using metadata provided by mod providers (like Modrinth or Curseforge) for mods.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Disable using metadata for mods?</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="metadataWarningLabel">
|
||||
<property name="text">
|
||||
<string><html><head/><body><p><span style=" font-weight:600; color:#f5c211;">Warning</span><span style=" color:#f5c211;">: Disabling mod metadata may also disable some upcoming QoL features, such as mod updating!</span></p></body></html></string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
@@ -87,6 +87,11 @@ void MinecraftPage::applySettings()
|
||||
s->set("UseNativeOpenAL", ui->useNativeOpenALCheck->isChecked());
|
||||
s->set("UseNativeGLFW", ui->useNativeGLFWCheck->isChecked());
|
||||
|
||||
// Peformance related options
|
||||
s->set("EnableFeralGamemode", ui->enableFeralGamemodeCheck->isChecked());
|
||||
s->set("EnableMangoHud", ui->enableMangoHud->isChecked());
|
||||
s->set("UseDiscreteGpu", ui->useDiscreteGpuCheck->isChecked());
|
||||
|
||||
// Game time
|
||||
s->set("ShowGameTime", ui->showGameTime->isChecked());
|
||||
s->set("ShowGlobalGameTime", ui->showGlobalGameTime->isChecked());
|
||||
@@ -109,6 +114,14 @@ void MinecraftPage::loadSettings()
|
||||
ui->useNativeOpenALCheck->setChecked(s->get("UseNativeOpenAL").toBool());
|
||||
ui->useNativeGLFWCheck->setChecked(s->get("UseNativeGLFW").toBool());
|
||||
|
||||
ui->enableFeralGamemodeCheck->setChecked(s->get("EnableFeralGamemode").toBool());
|
||||
ui->enableMangoHud->setChecked(s->get("EnableMangoHud").toBool());
|
||||
ui->useDiscreteGpuCheck->setChecked(s->get("UseDiscreteGpu").toBool());
|
||||
|
||||
#if !defined(Q_OS_LINUX)
|
||||
ui->perfomanceGroupBox->setVisible(false);
|
||||
#endif
|
||||
|
||||
ui->showGameTime->setChecked(s->get("ShowGameTime").toBool());
|
||||
ui->showGlobalGameTime->setChecked(s->get("ShowGlobalGameTime").toBool());
|
||||
ui->recordGameTime->setChecked(s->get("RecordGameTime").toBool());
|
||||
|
@@ -134,6 +134,45 @@
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="perfomanceGroupBox">
|
||||
<property name="title">
|
||||
<string>Performance</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="enableFeralGamemodeCheck">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Enable Feral Interactive's GameMode, to potentially improve gaming performance.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Enable Feral GameMode</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="enableMangoHud">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Enable MangoHud's advanced performance overlay.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Enable MangoHud</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="useDiscreteGpuCheck">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Use the discrete GPU instead of the primary GPU.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Use discrete GPU</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="gameTimeGroupBox">
|
||||
<property name="title">
|
||||
@@ -181,15 +220,15 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="quitAfterGameStopCheck">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>The launcher will automatically quit after the game exits or crashes.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Quit the launcher after game window closes</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<widget class="QCheckBox" name="quitAfterGameStopCheck">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>The launcher will automatically quit after the game exits or crashes.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Quit the launcher after game window closes</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
@@ -218,6 +257,9 @@
|
||||
<tabstop>windowHeightSpinBox</tabstop>
|
||||
<tabstop>useNativeGLFWCheck</tabstop>
|
||||
<tabstop>useNativeOpenALCheck</tabstop>
|
||||
<tabstop>enableFeralGamemodeCheck</tabstop>
|
||||
<tabstop>enableMangoHud</tabstop>
|
||||
<tabstop>useDiscreteGpuCheck</tabstop>
|
||||
</tabstops>
|
||||
<resources/>
|
||||
<connections/>
|
||||
|
@@ -2,6 +2,7 @@
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.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
|
||||
@@ -36,11 +37,11 @@
|
||||
#include "ProxyPage.h"
|
||||
#include "ui_ProxyPage.h"
|
||||
|
||||
#include <QButtonGroup>
|
||||
#include <QTabBar>
|
||||
|
||||
#include "settings/SettingsObject.h"
|
||||
#include "Application.h"
|
||||
#include "Application.h"
|
||||
|
||||
ProxyPage::ProxyPage(QWidget *parent) : QWidget(parent), ui(new Ui::ProxyPage)
|
||||
{
|
||||
@@ -49,7 +50,8 @@ ProxyPage::ProxyPage(QWidget *parent) : QWidget(parent), ui(new Ui::ProxyPage)
|
||||
loadSettings();
|
||||
updateCheckboxStuff();
|
||||
|
||||
connect(ui->proxyGroup, SIGNAL(buttonClicked(int)), SLOT(proxyChanged(int)));
|
||||
connect(ui->proxyGroup, QOverload<QAbstractButton *>::of(&QButtonGroup::buttonClicked),
|
||||
this, &ProxyPage::proxyGroupChanged);
|
||||
}
|
||||
|
||||
ProxyPage::~ProxyPage()
|
||||
@@ -65,13 +67,13 @@ bool ProxyPage::apply()
|
||||
|
||||
void ProxyPage::updateCheckboxStuff()
|
||||
{
|
||||
ui->proxyAddrBox->setEnabled(!ui->proxyNoneBtn->isChecked() &&
|
||||
!ui->proxyDefaultBtn->isChecked());
|
||||
ui->proxyAuthBox->setEnabled(!ui->proxyNoneBtn->isChecked() &&
|
||||
!ui->proxyDefaultBtn->isChecked());
|
||||
bool enableEditing = ui->proxyHTTPBtn->isChecked()
|
||||
|| ui->proxySOCKS5Btn->isChecked();
|
||||
ui->proxyAddrBox->setEnabled(enableEditing);
|
||||
ui->proxyAuthBox->setEnabled(enableEditing);
|
||||
}
|
||||
|
||||
void ProxyPage::proxyChanged(int)
|
||||
void ProxyPage::proxyGroupChanged(QAbstractButton *button)
|
||||
{
|
||||
updateCheckboxStuff();
|
||||
}
|
||||
|
@@ -2,6 +2,7 @@
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.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
|
||||
@@ -36,6 +37,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <QAbstractButton>
|
||||
#include <QDialog>
|
||||
|
||||
#include "ui/pages/BasePage.h"
|
||||
@@ -73,15 +75,14 @@ public:
|
||||
bool apply() override;
|
||||
void retranslate() override;
|
||||
|
||||
private slots:
|
||||
void proxyGroupChanged(QAbstractButton *button);
|
||||
|
||||
private:
|
||||
void updateCheckboxStuff();
|
||||
void applySettings();
|
||||
void loadSettings();
|
||||
|
||||
private
|
||||
slots:
|
||||
void proxyChanged(int);
|
||||
|
||||
private:
|
||||
Ui::ProxyPage *ui;
|
||||
};
|
||||
|
297
launcher/ui/pages/instance/ExternalResourcesPage.cpp
Normal file
297
launcher/ui/pages/instance/ExternalResourcesPage.cpp
Normal file
@@ -0,0 +1,297 @@
|
||||
#include "ExternalResourcesPage.h"
|
||||
#include "ui_ExternalResourcesPage.h"
|
||||
|
||||
#include "DesktopServices.h"
|
||||
#include "Version.h"
|
||||
#include "minecraft/mod/ModFolderModel.h"
|
||||
#include "ui/GuiUtil.h"
|
||||
|
||||
#include <QKeyEvent>
|
||||
#include <QMenu>
|
||||
|
||||
namespace {
|
||||
// FIXME: wasteful
|
||||
void RemoveThePrefix(QString& string)
|
||||
{
|
||||
QRegularExpression regex(QStringLiteral("^(?:the|teh) +"), QRegularExpression::CaseInsensitiveOption);
|
||||
string.remove(regex);
|
||||
string = string.trimmed();
|
||||
}
|
||||
} // namespace
|
||||
|
||||
class SortProxy : public QSortFilterProxyModel {
|
||||
public:
|
||||
explicit SortProxy(QObject* parent = nullptr) : QSortFilterProxyModel(parent) {}
|
||||
|
||||
protected:
|
||||
bool filterAcceptsRow(int source_row, const QModelIndex& source_parent) const override
|
||||
{
|
||||
ModFolderModel* model = qobject_cast<ModFolderModel*>(sourceModel());
|
||||
if (!model)
|
||||
return false;
|
||||
|
||||
const auto& mod = model->at(source_row);
|
||||
|
||||
if (mod.name().contains(filterRegularExpression()))
|
||||
return true;
|
||||
if (mod.description().contains(filterRegularExpression()))
|
||||
return true;
|
||||
|
||||
for (auto& author : mod.authors()) {
|
||||
if (author.contains(filterRegularExpression())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool lessThan(const QModelIndex& source_left, const QModelIndex& source_right) const override
|
||||
{
|
||||
ModFolderModel* model = qobject_cast<ModFolderModel*>(sourceModel());
|
||||
if (!model || !source_left.isValid() || !source_right.isValid() || source_left.column() != source_right.column()) {
|
||||
return QSortFilterProxyModel::lessThan(source_left, source_right);
|
||||
}
|
||||
|
||||
// we are now guaranteed to have two valid indexes in the same column... we love the provided invariants unconditionally and
|
||||
// proceed.
|
||||
|
||||
auto column = (ModFolderModel::Columns) source_left.column();
|
||||
bool invert = false;
|
||||
switch (column) {
|
||||
// GH-2550 - sort by enabled/disabled
|
||||
case ModFolderModel::ActiveColumn: {
|
||||
auto dataL = source_left.data(Qt::CheckStateRole).toBool();
|
||||
auto dataR = source_right.data(Qt::CheckStateRole).toBool();
|
||||
if (dataL != dataR)
|
||||
return dataL > dataR;
|
||||
|
||||
// fallthrough
|
||||
invert = sortOrder() == Qt::DescendingOrder;
|
||||
}
|
||||
// GH-2722 - sort mod names in a way that discards "The" prefixes
|
||||
case ModFolderModel::NameColumn: {
|
||||
auto dataL = model->data(model->index(source_left.row(), ModFolderModel::NameColumn)).toString();
|
||||
RemoveThePrefix(dataL);
|
||||
auto dataR = model->data(model->index(source_right.row(), ModFolderModel::NameColumn)).toString();
|
||||
RemoveThePrefix(dataR);
|
||||
|
||||
auto less = dataL.compare(dataR, sortCaseSensitivity());
|
||||
if (less != 0)
|
||||
return invert ? (less > 0) : (less < 0);
|
||||
|
||||
// fallthrough
|
||||
invert = sortOrder() == Qt::DescendingOrder;
|
||||
}
|
||||
// GH-2762 - sort versions by parsing them as versions
|
||||
case ModFolderModel::VersionColumn: {
|
||||
auto dataL = Version(model->data(model->index(source_left.row(), ModFolderModel::VersionColumn)).toString());
|
||||
auto dataR = Version(model->data(model->index(source_right.row(), ModFolderModel::VersionColumn)).toString());
|
||||
return invert ? (dataL > dataR) : (dataL < dataR);
|
||||
}
|
||||
default: {
|
||||
return QSortFilterProxyModel::lessThan(source_left, source_right);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
ExternalResourcesPage::ExternalResourcesPage(BaseInstance* instance, std::shared_ptr<ModFolderModel> model, QWidget* parent)
|
||||
: QMainWindow(parent), m_instance(instance), ui(new Ui::ExternalResourcesPage), m_model(model)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
runningStateChanged(m_instance && m_instance->isRunning());
|
||||
|
||||
ui->actionsToolbar->insertSpacer(ui->actionViewConfigs);
|
||||
|
||||
m_filterModel = new SortProxy(this);
|
||||
m_filterModel->setDynamicSortFilter(true);
|
||||
m_filterModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
|
||||
m_filterModel->setSortCaseSensitivity(Qt::CaseInsensitive);
|
||||
m_filterModel->setSourceModel(m_model.get());
|
||||
m_filterModel->setFilterKeyColumn(-1);
|
||||
ui->treeView->setModel(m_filterModel);
|
||||
|
||||
ui->treeView->installEventFilter(this);
|
||||
ui->treeView->sortByColumn(1, Qt::AscendingOrder);
|
||||
ui->treeView->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
|
||||
// The default function names by Qt are pretty ugly, so let's just connect the actions manually,
|
||||
// to make it easier to read :)
|
||||
connect(ui->actionAddItem, &QAction::triggered, this, &ExternalResourcesPage::addItem);
|
||||
connect(ui->actionRemoveItem, &QAction::triggered, this, &ExternalResourcesPage::removeItem);
|
||||
connect(ui->actionEnableItem, &QAction::triggered, this, &ExternalResourcesPage::enableItem);
|
||||
connect(ui->actionDisableItem, &QAction::triggered, this, &ExternalResourcesPage::disableItem);
|
||||
connect(ui->actionViewConfigs, &QAction::triggered, this, &ExternalResourcesPage::viewConfigs);
|
||||
connect(ui->actionViewFolder, &QAction::triggered, this, &ExternalResourcesPage::viewFolder);
|
||||
|
||||
connect(ui->treeView, &ModListView::customContextMenuRequested, this, &ExternalResourcesPage::ShowContextMenu);
|
||||
connect(ui->treeView, &ModListView::activated, this, &ExternalResourcesPage::itemActivated);
|
||||
|
||||
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()
|
||||
{
|
||||
m_model->stopWatching();
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void ExternalResourcesPage::itemActivated(const QModelIndex&)
|
||||
{
|
||||
if (!m_controlsEnabled)
|
||||
return;
|
||||
|
||||
auto selection = m_filterModel->mapSelectionToSource(ui->treeView->selectionModel()->selection());
|
||||
m_model->setModStatus(selection.indexes(), ModFolderModel::Toggle);
|
||||
}
|
||||
|
||||
QMenu* ExternalResourcesPage::createPopupMenu()
|
||||
{
|
||||
QMenu* filteredMenu = QMainWindow::createPopupMenu();
|
||||
filteredMenu->removeAction(ui->actionsToolbar->toggleViewAction());
|
||||
return filteredMenu;
|
||||
}
|
||||
|
||||
void ExternalResourcesPage::ShowContextMenu(const QPoint& pos)
|
||||
{
|
||||
auto menu = ui->actionsToolbar->createContextMenu(this, tr("Context menu"));
|
||||
menu->exec(ui->treeView->mapToGlobal(pos));
|
||||
delete menu;
|
||||
}
|
||||
|
||||
void ExternalResourcesPage::openedImpl()
|
||||
{
|
||||
m_model->startWatching();
|
||||
}
|
||||
|
||||
void ExternalResourcesPage::closedImpl()
|
||||
{
|
||||
m_model->stopWatching();
|
||||
}
|
||||
|
||||
void ExternalResourcesPage::retranslate()
|
||||
{
|
||||
ui->retranslateUi(this);
|
||||
}
|
||||
|
||||
void ExternalResourcesPage::filterTextChanged(const QString& newContents)
|
||||
{
|
||||
m_viewFilter = newContents;
|
||||
m_filterModel->setFilterFixedString(m_viewFilter);
|
||||
}
|
||||
|
||||
void ExternalResourcesPage::runningStateChanged(bool running)
|
||||
{
|
||||
if (m_controlsEnabled == !running)
|
||||
return;
|
||||
|
||||
m_controlsEnabled = !running;
|
||||
ui->actionAddItem->setEnabled(m_controlsEnabled);
|
||||
ui->actionDisableItem->setEnabled(m_controlsEnabled);
|
||||
ui->actionEnableItem->setEnabled(m_controlsEnabled);
|
||||
ui->actionRemoveItem->setEnabled(m_controlsEnabled);
|
||||
}
|
||||
|
||||
bool ExternalResourcesPage::shouldDisplay() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ExternalResourcesPage::listFilter(QKeyEvent* keyEvent)
|
||||
{
|
||||
switch (keyEvent->key()) {
|
||||
case Qt::Key_Delete:
|
||||
removeItem();
|
||||
return true;
|
||||
case Qt::Key_Plus:
|
||||
addItem();
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return QWidget::eventFilter(ui->treeView, keyEvent);
|
||||
}
|
||||
|
||||
bool ExternalResourcesPage::eventFilter(QObject* obj, QEvent* ev)
|
||||
{
|
||||
if (ev->type() != QEvent::KeyPress)
|
||||
return QWidget::eventFilter(obj, ev);
|
||||
|
||||
QKeyEvent* keyEvent = static_cast<QKeyEvent*>(ev);
|
||||
if (obj == ui->treeView)
|
||||
return listFilter(keyEvent);
|
||||
|
||||
return QWidget::eventFilter(obj, ev);
|
||||
}
|
||||
|
||||
void ExternalResourcesPage::addItem()
|
||||
{
|
||||
if (!m_controlsEnabled)
|
||||
return;
|
||||
|
||||
|
||||
auto list = GuiUtil::BrowseForFiles(
|
||||
helpPage(), tr("Select %1", "Select whatever type of files the page contains. Example: 'Loader Mods'").arg(displayName()),
|
||||
m_fileSelectionFilter.arg(displayName()), APPLICATION->settings()->get("CentralModsDir").toString(), this->parentWidget());
|
||||
|
||||
if (!list.isEmpty()) {
|
||||
for (auto filename : list) {
|
||||
m_model->installMod(filename);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ExternalResourcesPage::removeItem()
|
||||
{
|
||||
if (!m_controlsEnabled)
|
||||
return;
|
||||
|
||||
auto selection = m_filterModel->mapSelectionToSource(ui->treeView->selectionModel()->selection());
|
||||
m_model->deleteMods(selection.indexes());
|
||||
}
|
||||
|
||||
void ExternalResourcesPage::enableItem()
|
||||
{
|
||||
if (!m_controlsEnabled)
|
||||
return;
|
||||
|
||||
auto selection = m_filterModel->mapSelectionToSource(ui->treeView->selectionModel()->selection());
|
||||
m_model->setModStatus(selection.indexes(), ModFolderModel::Enable);
|
||||
}
|
||||
|
||||
void ExternalResourcesPage::disableItem()
|
||||
{
|
||||
if (!m_controlsEnabled)
|
||||
return;
|
||||
|
||||
auto selection = m_filterModel->mapSelectionToSource(ui->treeView->selectionModel()->selection());
|
||||
m_model->setModStatus(selection.indexes(), ModFolderModel::Disable);
|
||||
}
|
||||
|
||||
void ExternalResourcesPage::viewConfigs()
|
||||
{
|
||||
DesktopServices::openDirectory(m_instance->instanceConfigFolder(), true);
|
||||
}
|
||||
|
||||
void ExternalResourcesPage::viewFolder()
|
||||
{
|
||||
DesktopServices::openDirectory(m_model->dir().absolutePath(), true);
|
||||
}
|
||||
|
||||
void ExternalResourcesPage::current(const QModelIndex& current, const QModelIndex& previous)
|
||||
{
|
||||
if (!current.isValid()) {
|
||||
ui->frame->clear();
|
||||
return;
|
||||
}
|
||||
|
||||
auto sourceCurrent = m_filterModel->mapToSource(current);
|
||||
int row = sourceCurrent.row();
|
||||
Mod& m = m_model->operator[](row);
|
||||
ui->frame->updateWithMod(m);
|
||||
}
|
73
launcher/ui/pages/instance/ExternalResourcesPage.h
Normal file
73
launcher/ui/pages/instance/ExternalResourcesPage.h
Normal file
@@ -0,0 +1,73 @@
|
||||
#pragma once
|
||||
|
||||
#include <QMainWindow>
|
||||
#include <QSortFilterProxyModel>
|
||||
|
||||
#include "Application.h"
|
||||
#include "minecraft/MinecraftInstance.h"
|
||||
#include "ui/pages/BasePage.h"
|
||||
|
||||
class ModFolderModel;
|
||||
|
||||
namespace Ui {
|
||||
class ExternalResourcesPage;
|
||||
}
|
||||
|
||||
/* This page is used as a base for pages in which the user can manage external resources
|
||||
* related to the game, such as mods, shaders or resource packs. */
|
||||
class ExternalResourcesPage : public QMainWindow, public BasePage {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
// FIXME: Switch to different model (or change the name of this one)
|
||||
explicit ExternalResourcesPage(BaseInstance* instance, std::shared_ptr<ModFolderModel> model, QWidget* parent = nullptr);
|
||||
virtual ~ExternalResourcesPage();
|
||||
|
||||
virtual QString displayName() const override = 0;
|
||||
virtual QIcon icon() const override = 0;
|
||||
virtual QString id() const override = 0;
|
||||
virtual QString helpPage() const override = 0;
|
||||
|
||||
virtual bool shouldDisplay() const override = 0;
|
||||
|
||||
void openedImpl() override;
|
||||
void closedImpl() override;
|
||||
|
||||
void retranslate() override;
|
||||
|
||||
protected:
|
||||
bool eventFilter(QObject* obj, QEvent* ev) override;
|
||||
bool listFilter(QKeyEvent* ev);
|
||||
QMenu* createPopupMenu() override;
|
||||
|
||||
public slots:
|
||||
void current(const QModelIndex& current, const QModelIndex& previous);
|
||||
|
||||
protected slots:
|
||||
void itemActivated(const QModelIndex& index);
|
||||
void filterTextChanged(const QString& newContents);
|
||||
void runningStateChanged(bool running);
|
||||
|
||||
virtual void addItem();
|
||||
virtual void removeItem();
|
||||
|
||||
virtual void enableItem();
|
||||
virtual void disableItem();
|
||||
|
||||
virtual void viewFolder();
|
||||
virtual void viewConfigs();
|
||||
|
||||
void ShowContextMenu(const QPoint& pos);
|
||||
|
||||
protected:
|
||||
BaseInstance* m_instance = nullptr;
|
||||
|
||||
Ui::ExternalResourcesPage* ui = nullptr;
|
||||
std::shared_ptr<ModFolderModel> m_model;
|
||||
QSortFilterProxyModel* m_filterModel = nullptr;
|
||||
|
||||
QString m_fileSelectionFilter;
|
||||
QString m_viewFilter;
|
||||
|
||||
bool m_controlsEnabled = true;
|
||||
};
|
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>ModFolderPage</class>
|
||||
<widget class="QMainWindow" name="ModFolderPage">
|
||||
<class>ExternalResourcesPage</class>
|
||||
<widget class="QMainWindow" name="ExternalResourcesPage">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
@@ -53,7 +53,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1" colspan="3">
|
||||
<widget class="ModListView" name="modTreeView">
|
||||
<widget class="ModListView" name="treeView">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
@@ -83,15 +83,15 @@
|
||||
<attribute name="toolBarBreak">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
<addaction name="actionAdd"/>
|
||||
<addaction name="actionAddItem"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionRemove"/>
|
||||
<addaction name="actionEnable"/>
|
||||
<addaction name="actionDisable"/>
|
||||
<addaction name="actionView_configs"/>
|
||||
<addaction name="actionView_Folder"/>
|
||||
<addaction name="actionRemoveItem"/>
|
||||
<addaction name="actionEnableItem"/>
|
||||
<addaction name="actionDisableItem"/>
|
||||
<addaction name="actionViewConfigs"/>
|
||||
<addaction name="actionViewFolder"/>
|
||||
</widget>
|
||||
<action name="actionAdd">
|
||||
<action name="actionAddItem">
|
||||
<property name="text">
|
||||
<string>&Add</string>
|
||||
</property>
|
||||
@@ -99,31 +99,31 @@
|
||||
<string>Add</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionRemove">
|
||||
<action name="actionRemoveItem">
|
||||
<property name="text">
|
||||
<string>&Remove</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Remove selected mods</string>
|
||||
<string>Remove selected item</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionEnable">
|
||||
<action name="actionEnableItem">
|
||||
<property name="text">
|
||||
<string>&Enable</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Enable selected mods</string>
|
||||
<string>Enable selected item</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionDisable">
|
||||
<action name="actionDisableItem">
|
||||
<property name="text">
|
||||
<string>&Disable</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Disable selected mods</string>
|
||||
<string>Disable selected item</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionView_configs">
|
||||
<action name="actionViewConfigs">
|
||||
<property name="text">
|
||||
<string>View &Configs</string>
|
||||
</property>
|
||||
@@ -131,11 +131,22 @@
|
||||
<string>Open the 'config' folder in the system file manager.</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionView_Folder">
|
||||
<action name="actionViewFolder">
|
||||
<property name="text">
|
||||
<string>View &Folder</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionDownloadItem">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Download</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Download a new resource</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
@@ -156,7 +167,7 @@
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<tabstops>
|
||||
<tabstop>modTreeView</tabstop>
|
||||
<tabstop>treeView</tabstop>
|
||||
<tabstop>filterEdit</tabstop>
|
||||
</tabstops>
|
||||
<resources/>
|
@@ -2,7 +2,7 @@
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
|
||||
* Copyright (c) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.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
|
||||
@@ -50,6 +50,7 @@
|
||||
#include "Application.h"
|
||||
|
||||
#include "java/JavaInstallList.h"
|
||||
#include "java/JavaUtils.h"
|
||||
#include "FileSystem.h"
|
||||
|
||||
|
||||
@@ -232,6 +233,22 @@ void InstanceSettingsPage::applySettings()
|
||||
m_settings->reset("UseNativeGLFW");
|
||||
}
|
||||
|
||||
// Performance
|
||||
bool performance = ui->perfomanceGroupBox->isChecked();
|
||||
m_settings->set("OverridePerformance", performance);
|
||||
if(performance)
|
||||
{
|
||||
m_settings->set("EnableFeralGamemode", ui->enableFeralGamemodeCheck->isChecked());
|
||||
m_settings->set("EnableMangoHud", ui->enableMangoHud->isChecked());
|
||||
m_settings->set("UseDiscreteGpu", ui->useDiscreteGpuCheck->isChecked());
|
||||
}
|
||||
else
|
||||
{
|
||||
m_settings->reset("EnableFeralGamemode");
|
||||
m_settings->reset("EnableMangoHud");
|
||||
m_settings->reset("UseDiscreteGpu");
|
||||
}
|
||||
|
||||
// Game time
|
||||
bool gameTime = ui->gameTimeGroupBox->isChecked();
|
||||
m_settings->set("OverrideGameTime", gameTime);
|
||||
@@ -325,6 +342,16 @@ void InstanceSettingsPage::loadSettings()
|
||||
ui->useNativeGLFWCheck->setChecked(m_settings->get("UseNativeGLFW").toBool());
|
||||
ui->useNativeOpenALCheck->setChecked(m_settings->get("UseNativeOpenAL").toBool());
|
||||
|
||||
// Performance
|
||||
ui->perfomanceGroupBox->setChecked(m_settings->get("OverridePerformance").toBool());
|
||||
ui->enableFeralGamemodeCheck->setChecked(m_settings->get("EnableFeralGamemode").toBool());
|
||||
ui->enableMangoHud->setChecked(m_settings->get("EnableMangoHud").toBool());
|
||||
ui->useDiscreteGpuCheck->setChecked(m_settings->get("UseDiscreteGpu").toBool());
|
||||
|
||||
#if !defined(Q_OS_LINUX)
|
||||
ui->perfomanceGroupBox->setVisible(false);
|
||||
#endif
|
||||
|
||||
// Miscellanous
|
||||
ui->gameTimeGroupBox->setChecked(m_settings->get("OverrideGameTime").toBool());
|
||||
ui->showGameTime->setChecked(m_settings->get("ShowGameTime").toBool());
|
||||
@@ -336,6 +363,11 @@ void InstanceSettingsPage::loadSettings()
|
||||
|
||||
void InstanceSettingsPage::on_javaDetectBtn_clicked()
|
||||
{
|
||||
if (JavaUtils::getJavaCheckPath().isEmpty()) {
|
||||
JavaCommon::javaCheckNotFound(this);
|
||||
return;
|
||||
}
|
||||
|
||||
JavaInstallPtr java;
|
||||
|
||||
VersionSelectDialog vselect(APPLICATION->javalist().get(), tr("Select a Java version"), this, true);
|
||||
|
@@ -455,6 +455,74 @@
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="performancePage">
|
||||
<attribute name="title">
|
||||
<string>Performance</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_14">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="perfomanceGroupBox">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Performance</string>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_13">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="enableFeralGamemodeCheck">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Enable Feral Interactive's GameMode, to potentially improve gaming performance.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Enable Feral GameMode</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="enableMangoHud">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Enable MangoHud's advanced performance overlay.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Enable MangoHud</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="useDiscreteGpuCheck">
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Use the discrete GPU instead of the primary GPU.</p></body></html></string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Use discrete GPU</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="miscellaneousPage">
|
||||
<attribute name="title">
|
||||
<string>Miscellaneous</string>
|
||||
|
@@ -2,6 +2,7 @@
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.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
|
||||
@@ -62,7 +63,7 @@ public:
|
||||
{
|
||||
case Qt::FontRole:
|
||||
return m_font;
|
||||
case Qt::TextColorRole:
|
||||
case Qt::ForegroundRole:
|
||||
{
|
||||
MessageLevel::Enum level = (MessageLevel::Enum) QIdentityProxyModel::data(index, LogModel::LevelRole).toInt();
|
||||
return m_colors->getFront(level);
|
||||
|
@@ -2,6 +2,7 @@
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.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
|
||||
@@ -34,409 +35,123 @@
|
||||
*/
|
||||
|
||||
#include "ModFolderPage.h"
|
||||
#include "ui_ModFolderPage.h"
|
||||
#include "ui_ExternalResourcesPage.h"
|
||||
|
||||
#include <QMessageBox>
|
||||
#include <QAbstractItemModel>
|
||||
#include <QEvent>
|
||||
#include <QKeyEvent>
|
||||
#include <QAbstractItemModel>
|
||||
#include <QMenu>
|
||||
#include <QMessageBox>
|
||||
#include <QSortFilterProxyModel>
|
||||
|
||||
#include "Application.h"
|
||||
|
||||
#include "ui/GuiUtil.h"
|
||||
#include "ui/dialogs/CustomMessageBox.h"
|
||||
#include "ui/dialogs/ModDownloadDialog.h"
|
||||
#include "ui/GuiUtil.h"
|
||||
|
||||
#include "DesktopServices.h"
|
||||
|
||||
#include "minecraft/mod/ModFolderModel.h"
|
||||
#include "minecraft/mod/Mod.h"
|
||||
#include "minecraft/VersionFilterData.h"
|
||||
#include "minecraft/PackProfile.h"
|
||||
#include "minecraft/VersionFilterData.h"
|
||||
#include "minecraft/mod/Mod.h"
|
||||
#include "minecraft/mod/ModFolderModel.h"
|
||||
|
||||
#include "modplatform/ModAPI.h"
|
||||
|
||||
#include "Version.h"
|
||||
#include "tasks/ConcurrentTask.h"
|
||||
#include "ui/dialogs/ProgressDialog.h"
|
||||
#include "tasks/SequentialTask.h"
|
||||
|
||||
namespace {
|
||||
// FIXME: wasteful
|
||||
void RemoveThePrefix(QString & string) {
|
||||
QRegularExpression regex(QStringLiteral("^(([Tt][Hh][eE])|([Tt][eE][Hh])) +"));
|
||||
string.remove(regex);
|
||||
string = string.trimmed();
|
||||
}
|
||||
}
|
||||
|
||||
class ModSortProxy : public QSortFilterProxyModel
|
||||
ModFolderPage::ModFolderPage(BaseInstance* inst, std::shared_ptr<ModFolderModel> mods, QWidget* parent)
|
||||
: ExternalResourcesPage(inst, mods, parent)
|
||||
{
|
||||
public:
|
||||
explicit ModSortProxy(QObject *parent = 0) : QSortFilterProxyModel(parent)
|
||||
{
|
||||
}
|
||||
|
||||
protected:
|
||||
bool filterAcceptsRow(int source_row, const QModelIndex & source_parent) const override {
|
||||
ModFolderModel *model = qobject_cast<ModFolderModel *>(sourceModel());
|
||||
if(!model) {
|
||||
return false;
|
||||
}
|
||||
const auto &mod = model->at(source_row);
|
||||
if(mod.name().contains(filterRegExp())) {
|
||||
return true;
|
||||
}
|
||||
if(mod.description().contains(filterRegExp())) {
|
||||
return true;
|
||||
}
|
||||
for(auto & author: mod.authors()) {
|
||||
if (author.contains(filterRegExp())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool lessThan(const QModelIndex & source_left, const QModelIndex & source_right) const override
|
||||
{
|
||||
ModFolderModel *model = qobject_cast<ModFolderModel *>(sourceModel());
|
||||
if(
|
||||
!model ||
|
||||
!source_left.isValid() ||
|
||||
!source_right.isValid() ||
|
||||
source_left.column() != source_right.column()
|
||||
) {
|
||||
return QSortFilterProxyModel::lessThan(source_left, source_right);
|
||||
}
|
||||
|
||||
// we are now guaranteed to have two valid indexes in the same column... we love the provided invariants unconditionally and proceed.
|
||||
|
||||
auto column = (ModFolderModel::Columns) source_left.column();
|
||||
bool invert = false;
|
||||
switch(column) {
|
||||
// GH-2550 - sort by enabled/disabled
|
||||
case ModFolderModel::ActiveColumn: {
|
||||
auto dataL = source_left.data(Qt::CheckStateRole).toBool();
|
||||
auto dataR = source_right.data(Qt::CheckStateRole).toBool();
|
||||
if(dataL != dataR) {
|
||||
return dataL > dataR;
|
||||
}
|
||||
// fallthrough
|
||||
invert = sortOrder() == Qt::DescendingOrder;
|
||||
}
|
||||
// GH-2722 - sort mod names in a way that discards "The" prefixes
|
||||
case ModFolderModel::NameColumn: {
|
||||
auto dataL = model->data(model->index(source_left.row(), ModFolderModel::NameColumn)).toString();
|
||||
RemoveThePrefix(dataL);
|
||||
auto dataR = model->data(model->index(source_right.row(), ModFolderModel::NameColumn)).toString();
|
||||
RemoveThePrefix(dataR);
|
||||
|
||||
auto less = dataL.compare(dataR, sortCaseSensitivity());
|
||||
if(less != 0) {
|
||||
return invert ? (less > 0) : (less < 0);
|
||||
}
|
||||
// fallthrough
|
||||
invert = sortOrder() == Qt::DescendingOrder;
|
||||
}
|
||||
// GH-2762 - sort versions by parsing them as versions
|
||||
case ModFolderModel::VersionColumn: {
|
||||
auto dataL = Version(model->data(model->index(source_left.row(), ModFolderModel::VersionColumn)).toString());
|
||||
auto dataR = Version(model->data(model->index(source_right.row(), ModFolderModel::VersionColumn)).toString());
|
||||
return invert ? (dataL > dataR) : (dataL < dataR);
|
||||
}
|
||||
default: {
|
||||
return QSortFilterProxyModel::lessThan(source_left, source_right);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
ModFolderPage::ModFolderPage(
|
||||
BaseInstance *inst,
|
||||
std::shared_ptr<ModFolderModel> mods,
|
||||
QString id,
|
||||
QString iconName,
|
||||
QString displayName,
|
||||
QString helpPage,
|
||||
QWidget *parent
|
||||
) :
|
||||
QMainWindow(parent),
|
||||
ui(new Ui::ModFolderPage)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
// This is structured like that so that these changes
|
||||
// do not affect the Resouce pack and Shader pack tabs
|
||||
if(id == "mods") {
|
||||
auto act = new QAction(tr("Download mods"), this);
|
||||
act->setToolTip(tr("Download mods from online mod platforms"));
|
||||
ui->actionsToolbar->insertActionBefore(ui->actionAdd, act);
|
||||
connect(act, &QAction::triggered, this, &ModFolderPage::on_actionInstall_mods_triggered);
|
||||
// do not affect the Resource pack and Shader pack tabs
|
||||
{
|
||||
ui->actionDownloadItem->setText(tr("Download mods"));
|
||||
ui->actionDownloadItem->setToolTip(tr("Download mods from online mod platforms"));
|
||||
ui->actionDownloadItem->setEnabled(true);
|
||||
ui->actionAddItem->setText(tr("Add file"));
|
||||
ui->actionAddItem->setToolTip(tr("Add a locally downloaded file"));
|
||||
|
||||
ui->actionAdd->setText(tr("Add .jar"));
|
||||
ui->actionAdd->setToolTip(tr("Add mods via local file"));
|
||||
ui->actionsToolbar->insertActionBefore(ui->actionAddItem, ui->actionDownloadItem);
|
||||
|
||||
connect(ui->actionDownloadItem, &QAction::triggered, this, &ModFolderPage::installMods);
|
||||
}
|
||||
|
||||
ui->actionsToolbar->insertSpacer(ui->actionView_configs);
|
||||
|
||||
m_inst = inst;
|
||||
on_RunningState_changed(m_inst && m_inst->isRunning());
|
||||
m_mods = mods;
|
||||
m_id = id;
|
||||
m_displayName = displayName;
|
||||
m_iconName = iconName;
|
||||
m_helpName = helpPage;
|
||||
m_fileSelectionFilter = "%1 (*.zip *.jar)";
|
||||
m_filterModel = new ModSortProxy(this);
|
||||
m_filterModel->setDynamicSortFilter(true);
|
||||
m_filterModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
|
||||
m_filterModel->setSortCaseSensitivity(Qt::CaseInsensitive);
|
||||
m_filterModel->setSourceModel(m_mods.get());
|
||||
m_filterModel->setFilterKeyColumn(-1);
|
||||
ui->modTreeView->setModel(m_filterModel);
|
||||
ui->modTreeView->installEventFilter(this);
|
||||
ui->modTreeView->sortByColumn(1, Qt::AscendingOrder);
|
||||
ui->modTreeView->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
connect(ui->modTreeView, &ModListView::customContextMenuRequested, this, &ModFolderPage::ShowContextMenu);
|
||||
connect(ui->modTreeView, &ModListView::activated, this, &ModFolderPage::modItemActivated);
|
||||
|
||||
auto smodel = ui->modTreeView->selectionModel();
|
||||
connect(smodel, &QItemSelectionModel::currentChanged, this, &ModFolderPage::modCurrent);
|
||||
connect(ui->filterEdit, &QLineEdit::textChanged, this, &ModFolderPage::on_filterTextChanged);
|
||||
connect(m_inst, &BaseInstance::runningStatusChanged, this, &ModFolderPage::on_RunningState_changed);
|
||||
}
|
||||
|
||||
void ModFolderPage::modItemActivated(const QModelIndex&)
|
||||
{
|
||||
if(!m_controlsEnabled) {
|
||||
return;
|
||||
}
|
||||
auto selection = m_filterModel->mapSelectionToSource(ui->modTreeView->selectionModel()->selection());
|
||||
m_mods->setModStatus(selection.indexes(), ModFolderModel::Toggle);
|
||||
}
|
||||
|
||||
QMenu * ModFolderPage::createPopupMenu()
|
||||
{
|
||||
QMenu* filteredMenu = QMainWindow::createPopupMenu();
|
||||
filteredMenu->removeAction(ui->actionsToolbar->toggleViewAction() );
|
||||
return filteredMenu;
|
||||
}
|
||||
|
||||
void ModFolderPage::ShowContextMenu(const QPoint& pos)
|
||||
{
|
||||
auto menu = ui->actionsToolbar->createContextMenu(this, tr("Context menu"));
|
||||
menu->exec(ui->modTreeView->mapToGlobal(pos));
|
||||
delete menu;
|
||||
}
|
||||
|
||||
void ModFolderPage::openedImpl()
|
||||
{
|
||||
m_mods->startWatching();
|
||||
}
|
||||
|
||||
void ModFolderPage::closedImpl()
|
||||
{
|
||||
m_mods->stopWatching();
|
||||
}
|
||||
|
||||
void ModFolderPage::on_filterTextChanged(const QString& newContents)
|
||||
{
|
||||
m_viewFilter = newContents;
|
||||
m_filterModel->setFilterFixedString(m_viewFilter);
|
||||
}
|
||||
|
||||
|
||||
CoreModFolderPage::CoreModFolderPage(BaseInstance *inst, std::shared_ptr<ModFolderModel> mods,
|
||||
QString id, QString iconName, QString displayName,
|
||||
QString helpPage, QWidget *parent)
|
||||
: ModFolderPage(inst, mods, id, iconName, displayName, helpPage, parent)
|
||||
{
|
||||
}
|
||||
|
||||
ModFolderPage::~ModFolderPage()
|
||||
{
|
||||
m_mods->stopWatching();
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void ModFolderPage::on_RunningState_changed(bool running)
|
||||
{
|
||||
if(m_controlsEnabled == !running) {
|
||||
return;
|
||||
}
|
||||
m_controlsEnabled = !running;
|
||||
ui->actionsToolbar->setEnabled(m_controlsEnabled);
|
||||
}
|
||||
CoreModFolderPage::CoreModFolderPage(BaseInstance* inst, std::shared_ptr<ModFolderModel> mods, QWidget* parent)
|
||||
: ModFolderPage(inst, mods, parent)
|
||||
{}
|
||||
|
||||
bool ModFolderPage::shouldDisplay() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void ModFolderPage::retranslate()
|
||||
{
|
||||
ui->retranslateUi(this);
|
||||
}
|
||||
|
||||
bool CoreModFolderPage::shouldDisplay() const
|
||||
{
|
||||
if (ModFolderPage::shouldDisplay())
|
||||
{
|
||||
auto inst = dynamic_cast<MinecraftInstance *>(m_inst);
|
||||
if (ModFolderPage::shouldDisplay()) {
|
||||
auto inst = dynamic_cast<MinecraftInstance*>(m_instance);
|
||||
if (!inst)
|
||||
return true;
|
||||
|
||||
auto version = inst->getPackProfile();
|
||||
|
||||
if (!version)
|
||||
return true;
|
||||
if(!version->getComponent("net.minecraftforge"))
|
||||
{
|
||||
if (!version->getComponent("net.minecraftforge"))
|
||||
return false;
|
||||
}
|
||||
if(!version->getComponent("net.minecraft"))
|
||||
{
|
||||
if (!version->getComponent("net.minecraft"))
|
||||
return false;
|
||||
}
|
||||
if(version->getComponent("net.minecraft")->getReleaseDateTime() < g_VersionFilterData.legacyCutoffDate)
|
||||
{
|
||||
if (version->getComponent("net.minecraft")->getReleaseDateTime() < g_VersionFilterData.legacyCutoffDate)
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ModFolderPage::modListFilter(QKeyEvent *keyEvent)
|
||||
void ModFolderPage::installMods()
|
||||
{
|
||||
switch (keyEvent->key())
|
||||
{
|
||||
case Qt::Key_Delete:
|
||||
on_actionRemove_triggered();
|
||||
return true;
|
||||
case Qt::Key_Plus:
|
||||
on_actionAdd_triggered();
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return QWidget::eventFilter(ui->modTreeView, keyEvent);
|
||||
}
|
||||
|
||||
bool ModFolderPage::eventFilter(QObject *obj, QEvent *ev)
|
||||
{
|
||||
if (ev->type() != QEvent::KeyPress)
|
||||
{
|
||||
return QWidget::eventFilter(obj, ev);
|
||||
}
|
||||
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(ev);
|
||||
if (obj == ui->modTreeView)
|
||||
return modListFilter(keyEvent);
|
||||
return QWidget::eventFilter(obj, ev);
|
||||
}
|
||||
|
||||
void ModFolderPage::on_actionAdd_triggered()
|
||||
{
|
||||
if(!m_controlsEnabled) {
|
||||
if (!m_controlsEnabled)
|
||||
return;
|
||||
if (m_instance->typeName() != "Minecraft")
|
||||
return; // this is a null instance or a legacy instance
|
||||
|
||||
auto profile = static_cast<MinecraftInstance*>(m_instance)->getPackProfile();
|
||||
if (profile->getModLoaders() == ModAPI::Unspecified) {
|
||||
QMessageBox::critical(this, tr("Error"), tr("Please install a mod loader first!"));
|
||||
return;
|
||||
}
|
||||
auto list = GuiUtil::BrowseForFiles(
|
||||
m_helpName,
|
||||
tr("Select %1",
|
||||
"Select whatever type of files the page contains. Example: 'Loader Mods'")
|
||||
.arg(m_displayName),
|
||||
m_fileSelectionFilter.arg(m_displayName), APPLICATION->settings()->get("CentralModsDir").toString(),
|
||||
this->parentWidget());
|
||||
if (!list.empty())
|
||||
{
|
||||
for (auto filename : list)
|
||||
{
|
||||
m_mods->installMod(filename);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ModFolderPage::on_actionEnable_triggered()
|
||||
{
|
||||
if(!m_controlsEnabled) {
|
||||
return;
|
||||
}
|
||||
auto selection = m_filterModel->mapSelectionToSource(ui->modTreeView->selectionModel()->selection());
|
||||
m_mods->setModStatus(selection.indexes(), ModFolderModel::Enable);
|
||||
}
|
||||
|
||||
void ModFolderPage::on_actionDisable_triggered()
|
||||
{
|
||||
if(!m_controlsEnabled) {
|
||||
return;
|
||||
}
|
||||
auto selection = m_filterModel->mapSelectionToSource(ui->modTreeView->selectionModel()->selection());
|
||||
m_mods->setModStatus(selection.indexes(), ModFolderModel::Disable);
|
||||
}
|
||||
|
||||
void ModFolderPage::on_actionRemove_triggered()
|
||||
{
|
||||
if(!m_controlsEnabled) {
|
||||
return;
|
||||
}
|
||||
auto selection = m_filterModel->mapSelectionToSource(ui->modTreeView->selectionModel()->selection());
|
||||
m_mods->deleteMods(selection.indexes());
|
||||
}
|
||||
|
||||
void ModFolderPage::on_actionInstall_mods_triggered()
|
||||
{
|
||||
if(!m_controlsEnabled) {
|
||||
return;
|
||||
}
|
||||
if(m_inst->typeName() != "Minecraft"){
|
||||
return; //this is a null instance or a legacy instance
|
||||
}
|
||||
auto profile = ((MinecraftInstance *)m_inst)->getPackProfile();
|
||||
if (profile->getModLoader() == ModAPI::Unspecified) {
|
||||
QMessageBox::critical(this,tr("Error"),tr("Please install a mod loader first!"));
|
||||
return;
|
||||
}
|
||||
ModDownloadDialog mdownload(m_mods, this, m_inst);
|
||||
ModDownloadDialog mdownload(m_model, this, m_instance);
|
||||
if (mdownload.exec()) {
|
||||
SequentialTask* tasks = new SequentialTask(this);
|
||||
ConcurrentTask* tasks = new ConcurrentTask(this);
|
||||
connect(tasks, &Task::failed, [this, tasks](QString reason) {
|
||||
CustomMessageBox::selectable(this, tr("Error"), reason, QMessageBox::Critical)->show();
|
||||
tasks->deleteLater();
|
||||
});
|
||||
connect(tasks, &Task::aborted, [this, tasks]() {
|
||||
CustomMessageBox::selectable(this, tr("Aborted"), tr("Download stopped by user."), QMessageBox::Information)->show();
|
||||
tasks->deleteLater();
|
||||
});
|
||||
connect(tasks, &Task::succeeded, [this, tasks]() {
|
||||
QStringList warnings = tasks->warnings();
|
||||
if (warnings.count()) { CustomMessageBox::selectable(this, tr("Warnings"), warnings.join('\n'), QMessageBox::Warning)->show(); }
|
||||
if (warnings.count())
|
||||
CustomMessageBox::selectable(this, tr("Warnings"), warnings.join('\n'), QMessageBox::Warning)->show();
|
||||
|
||||
tasks->deleteLater();
|
||||
});
|
||||
|
||||
for (auto task : mdownload.getTasks()) {
|
||||
for (auto& task : mdownload.getTasks()) {
|
||||
tasks->addTask(task);
|
||||
}
|
||||
|
||||
ProgressDialog loadDialog(this);
|
||||
loadDialog.setSkipButton(true, tr("Abort"));
|
||||
loadDialog.execWithTask(tasks);
|
||||
m_mods->update();
|
||||
|
||||
m_model->update();
|
||||
}
|
||||
}
|
||||
|
||||
void ModFolderPage::on_actionView_configs_triggered()
|
||||
{
|
||||
DesktopServices::openDirectory(m_inst->instanceConfigFolder(), true);
|
||||
}
|
||||
|
||||
void ModFolderPage::on_actionView_Folder_triggered()
|
||||
{
|
||||
DesktopServices::openDirectory(m_mods->dir().absolutePath(), true);
|
||||
}
|
||||
|
||||
void ModFolderPage::modCurrent(const QModelIndex ¤t, const QModelIndex &previous)
|
||||
{
|
||||
if (!current.isValid())
|
||||
{
|
||||
ui->frame->clear();
|
||||
return;
|
||||
}
|
||||
auto sourceCurrent = m_filterModel->mapToSource(current);
|
||||
int row = sourceCurrent.row();
|
||||
Mod &m = m_mods->operator[](row);
|
||||
ui->frame->updateWithMod(m);
|
||||
}
|
||||
|
@@ -2,6 +2,7 @@
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.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
|
||||
@@ -35,108 +36,31 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QMainWindow>
|
||||
#include "ExternalResourcesPage.h"
|
||||
|
||||
#include "minecraft/MinecraftInstance.h"
|
||||
#include "ui/pages/BasePage.h"
|
||||
|
||||
#include <Application.h>
|
||||
|
||||
class ModFolderModel;
|
||||
namespace Ui
|
||||
{
|
||||
class ModFolderPage;
|
||||
}
|
||||
|
||||
class ModFolderPage : public QMainWindow, public BasePage
|
||||
{
|
||||
class ModFolderPage : public ExternalResourcesPage {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ModFolderPage(
|
||||
BaseInstance *inst,
|
||||
std::shared_ptr<ModFolderModel> mods,
|
||||
QString id,
|
||||
QString iconName,
|
||||
QString displayName,
|
||||
QString helpPage = "",
|
||||
QWidget *parent = 0
|
||||
);
|
||||
virtual ~ModFolderPage();
|
||||
public:
|
||||
explicit ModFolderPage(BaseInstance* inst, std::shared_ptr<ModFolderModel> mods, QWidget* parent = nullptr);
|
||||
virtual ~ModFolderPage() = default;
|
||||
|
||||
void setFilter(const QString & filter)
|
||||
{
|
||||
m_fileSelectionFilter = filter;
|
||||
}
|
||||
void setFilter(const QString& filter) { m_fileSelectionFilter = filter; }
|
||||
|
||||
virtual QString displayName() const override { return tr("Mods"); }
|
||||
virtual QIcon icon() const override { return APPLICATION->getThemedIcon("loadermods"); }
|
||||
virtual QString id() const override { return "mods"; }
|
||||
virtual QString helpPage() const override { return "Loader-mods"; }
|
||||
|
||||
virtual QString displayName() const override
|
||||
{
|
||||
return m_displayName;
|
||||
}
|
||||
virtual QIcon icon() const override
|
||||
{
|
||||
return APPLICATION->getThemedIcon(m_iconName);
|
||||
}
|
||||
virtual QString id() const override
|
||||
{
|
||||
return m_id;
|
||||
}
|
||||
virtual QString helpPage() const override
|
||||
{
|
||||
return m_helpName;
|
||||
}
|
||||
virtual bool shouldDisplay() const override;
|
||||
void retranslate() override;
|
||||
|
||||
virtual void openedImpl() override;
|
||||
virtual void closedImpl() override;
|
||||
protected:
|
||||
bool eventFilter(QObject *obj, QEvent *ev) override;
|
||||
bool modListFilter(QKeyEvent *ev);
|
||||
QMenu * createPopupMenu() override;
|
||||
|
||||
protected:
|
||||
BaseInstance *m_inst = nullptr;
|
||||
|
||||
protected:
|
||||
Ui::ModFolderPage *ui = nullptr;
|
||||
std::shared_ptr<ModFolderModel> m_mods;
|
||||
QSortFilterProxyModel *m_filterModel = nullptr;
|
||||
QString m_iconName;
|
||||
QString m_id;
|
||||
QString m_displayName;
|
||||
QString m_helpName;
|
||||
QString m_fileSelectionFilter;
|
||||
QString m_viewFilter;
|
||||
bool m_controlsEnabled = true;
|
||||
|
||||
public
|
||||
slots:
|
||||
void modCurrent(const QModelIndex ¤t, const QModelIndex &previous);
|
||||
|
||||
private
|
||||
slots:
|
||||
void modItemActivated(const QModelIndex &index);
|
||||
void on_filterTextChanged(const QString & newContents);
|
||||
void on_RunningState_changed(bool running);
|
||||
void on_actionAdd_triggered();
|
||||
void on_actionRemove_triggered();
|
||||
void on_actionEnable_triggered();
|
||||
void on_actionDisable_triggered();
|
||||
void on_actionInstall_mods_triggered();
|
||||
void on_actionView_Folder_triggered();
|
||||
void on_actionView_configs_triggered();
|
||||
void ShowContextMenu(const QPoint &pos);
|
||||
private slots:
|
||||
void installMods();
|
||||
};
|
||||
|
||||
class CoreModFolderPage : public ModFolderPage
|
||||
{
|
||||
public:
|
||||
explicit CoreModFolderPage(BaseInstance *inst, std::shared_ptr<ModFolderModel> mods, QString id,
|
||||
QString iconName, QString displayName, QString helpPage = "",
|
||||
QWidget *parent = 0);
|
||||
virtual ~CoreModFolderPage()
|
||||
{
|
||||
}
|
||||
class CoreModFolderPage : public ModFolderPage {
|
||||
public:
|
||||
explicit CoreModFolderPage(BaseInstance* inst, std::shared_ptr<ModFolderModel> mods, QWidget* parent = 0);
|
||||
virtual ~CoreModFolderPage() = default;
|
||||
virtual bool shouldDisplay() const;
|
||||
};
|
||||
|
@@ -35,24 +35,28 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ModFolderPage.h"
|
||||
#include "ui_ModFolderPage.h"
|
||||
#include "ExternalResourcesPage.h"
|
||||
#include "ui_ExternalResourcesPage.h"
|
||||
|
||||
class ResourcePackPage : public ModFolderPage
|
||||
class ResourcePackPage : public ExternalResourcesPage
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ResourcePackPage(MinecraftInstance *instance, QWidget *parent = 0)
|
||||
: ModFolderPage(instance, instance->resourcePackList(), "resourcepacks",
|
||||
"resourcepacks", tr("Resource packs"), "Resource-packs", parent)
|
||||
: ExternalResourcesPage(instance, instance->resourcePackList(), parent)
|
||||
{
|
||||
ui->actionView_configs->setVisible(false);
|
||||
ui->actionViewConfigs->setVisible(false);
|
||||
}
|
||||
virtual ~ResourcePackPage() {}
|
||||
|
||||
QString displayName() const override { return tr("Resource packs"); }
|
||||
QIcon icon() const override { return APPLICATION->getThemedIcon("resourcepacks"); }
|
||||
QString id() const override { return "resourcepacks"; }
|
||||
QString helpPage() const override { return "Resource-packs"; }
|
||||
|
||||
virtual bool shouldDisplay() const override
|
||||
{
|
||||
return !m_inst->traits().contains("no-texturepacks") &&
|
||||
!m_inst->traits().contains("texturepacks");
|
||||
return !m_instance->traits().contains("no-texturepacks") &&
|
||||
!m_instance->traits().contains("texturepacks");
|
||||
}
|
||||
};
|
||||
|
@@ -2,6 +2,7 @@
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.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 <QClipboard>
|
||||
#include <QKeyEvent>
|
||||
#include <QMenu>
|
||||
#include <QRegularExpression>
|
||||
|
||||
#include <Application.h>
|
||||
|
||||
@@ -153,7 +155,7 @@ public:
|
||||
if (role == Qt::DisplayRole || role == Qt::EditRole)
|
||||
{
|
||||
QVariant result = sourceModel()->data(mapToSource(proxyIndex), role);
|
||||
return result.toString().remove(QRegExp("\\.png$"));
|
||||
return result.toString().remove(QRegularExpression("\\.png$"));
|
||||
}
|
||||
if (role == Qt::DecorationRole)
|
||||
{
|
||||
@@ -269,7 +271,7 @@ ScreenshotsPage::ScreenshotsPage(QString path, QWidget *parent)
|
||||
ui->listView->setViewMode(QListView::IconMode);
|
||||
ui->listView->setResizeMode(QListView::Adjust);
|
||||
ui->listView->installEventFilter(this);
|
||||
ui->listView->setEditTriggers(0);
|
||||
ui->listView->setEditTriggers(QAbstractItemView::NoEditTriggers);
|
||||
ui->listView->setItemDelegate(new CenteredEditingDelegate(this));
|
||||
ui->listView->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
connect(ui->listView, &QListView::customContextMenuRequested, this, &ScreenshotsPage::ShowContextMenu);
|
||||
|
@@ -2,6 +2,7 @@
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.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
|
||||
@@ -287,7 +288,11 @@ public:
|
||||
return false;
|
||||
}
|
||||
beginMoveRows(QModelIndex(), row, row, QModelIndex(), row - 1);
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 13, 0)
|
||||
m_servers.swapItemsAt(row-1, row);
|
||||
#else
|
||||
m_servers.swap(row-1, row);
|
||||
#endif
|
||||
endMoveRows();
|
||||
scheduleSave();
|
||||
return true;
|
||||
@@ -305,7 +310,11 @@ public:
|
||||
return false;
|
||||
}
|
||||
beginMoveRows(QModelIndex(), row, row, QModelIndex(), row + 2);
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 13, 0)
|
||||
m_servers.swapItemsAt(row+1, row);
|
||||
#else
|
||||
m_servers.swap(row+1, row);
|
||||
#endif
|
||||
endMoveRows();
|
||||
scheduleSave();
|
||||
return true;
|
||||
@@ -614,7 +623,7 @@ ServersPage::ServersPage(InstancePtr inst, QWidget* parent)
|
||||
|
||||
auto selectionModel = ui->serversView->selectionModel();
|
||||
connect(selectionModel, &QItemSelectionModel::currentChanged, this, &ServersPage::currentChanged);
|
||||
connect(m_inst.get(), &MinecraftInstance::runningStatusChanged, this, &ServersPage::on_RunningState_changed);
|
||||
connect(m_inst.get(), &MinecraftInstance::runningStatusChanged, this, &ServersPage::runningStateChanged);
|
||||
connect(ui->nameLine, &QLineEdit::textEdited, this, &ServersPage::nameEdited);
|
||||
connect(ui->addressLine, &QLineEdit::textEdited, this, &ServersPage::addressEdited);
|
||||
connect(ui->resourceComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(resourceIndexChanged(int)));
|
||||
@@ -654,7 +663,7 @@ QMenu * ServersPage::createPopupMenu()
|
||||
return filteredMenu;
|
||||
}
|
||||
|
||||
void ServersPage::on_RunningState_changed(bool running)
|
||||
void ServersPage::runningStateChanged(bool running)
|
||||
{
|
||||
if(m_locked == running)
|
||||
{
|
||||
|
@@ -2,6 +2,7 @@
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.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
|
||||
@@ -97,7 +98,7 @@ private slots:
|
||||
void on_actionMove_Down_triggered();
|
||||
void on_actionJoin_triggered();
|
||||
|
||||
void on_RunningState_changed(bool running);
|
||||
void runningStateChanged(bool running);
|
||||
|
||||
void nameEdited(const QString & name);
|
||||
void addressEdited(const QString & address);
|
||||
|
@@ -35,21 +35,25 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ModFolderPage.h"
|
||||
#include "ui_ModFolderPage.h"
|
||||
#include "ExternalResourcesPage.h"
|
||||
#include "ui_ExternalResourcesPage.h"
|
||||
|
||||
class ShaderPackPage : public ModFolderPage
|
||||
class ShaderPackPage : public ExternalResourcesPage
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit ShaderPackPage(MinecraftInstance *instance, QWidget *parent = 0)
|
||||
: ModFolderPage(instance, instance->shaderPackList(), "shaderpacks",
|
||||
"shaderpacks", tr("Shader packs"), "Resource-packs", parent)
|
||||
: ExternalResourcesPage(instance, instance->shaderPackList(), parent)
|
||||
{
|
||||
ui->actionView_configs->setVisible(false);
|
||||
ui->actionViewConfigs->setVisible(false);
|
||||
}
|
||||
virtual ~ShaderPackPage() {}
|
||||
|
||||
QString displayName() const override { return tr("Shader packs"); }
|
||||
QIcon icon() const override { return APPLICATION->getThemedIcon("shaderpacks"); }
|
||||
QString id() const override { return "shaderpacks"; }
|
||||
QString helpPage() const override { return "Resource-packs"; }
|
||||
|
||||
virtual bool shouldDisplay() const override
|
||||
{
|
||||
return true;
|
||||
|
@@ -35,23 +35,27 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ModFolderPage.h"
|
||||
#include "ui_ModFolderPage.h"
|
||||
#include "ExternalResourcesPage.h"
|
||||
#include "ui_ExternalResourcesPage.h"
|
||||
|
||||
class TexturePackPage : public ModFolderPage
|
||||
class TexturePackPage : public ExternalResourcesPage
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit TexturePackPage(MinecraftInstance *instance, QWidget *parent = 0)
|
||||
: ModFolderPage(instance, instance->texturePackList(), "texturepacks", "resourcepacks",
|
||||
tr("Texture packs"), "Texture-packs", parent)
|
||||
: ExternalResourcesPage(instance, instance->texturePackList(), parent)
|
||||
{
|
||||
ui->actionView_configs->setVisible(false);
|
||||
ui->actionViewConfigs->setVisible(false);
|
||||
}
|
||||
virtual ~TexturePackPage() {}
|
||||
|
||||
QString displayName() const override { return tr("Texture packs"); }
|
||||
QIcon icon() const override { return APPLICATION->getThemedIcon("resourcepacks"); }
|
||||
QString id() const override { return "texturepacks"; }
|
||||
QString helpPage() const override { return "Texture-packs"; }
|
||||
|
||||
virtual bool shouldDisplay() const override
|
||||
{
|
||||
return m_inst->traits().contains("texturepacks");
|
||||
return m_instance->traits().contains("texturepacks");
|
||||
}
|
||||
};
|
||||
|
@@ -2,7 +2,7 @@
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
|
||||
* Copyright (c) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.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
|
||||
|
@@ -2,6 +2,7 @@
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.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
|
||||
|
@@ -2,7 +2,7 @@
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
|
||||
* Copyright (c) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.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
|
||||
@@ -110,14 +110,16 @@ void ImportPage::updateState()
|
||||
{
|
||||
// FIXME: actually do some validation of what's inside here... this is fake AF
|
||||
QFileInfo fi(input);
|
||||
// mrpack is a modrinth pack
|
||||
|
||||
// Allow non-latin people to use ZIP files!
|
||||
auto zip = QMimeDatabase().mimeTypeForUrl(url).suffixes().contains("zip");
|
||||
if(fi.exists() && (zip || fi.suffix() == "mrpack"))
|
||||
bool isZip = QMimeDatabase().mimeTypeForUrl(url).suffixes().contains("zip");
|
||||
// mrpack is a modrinth pack
|
||||
bool isMRPack = fi.suffix() == "mrpack";
|
||||
|
||||
if(fi.exists() && (isZip || isMRPack))
|
||||
{
|
||||
QFileInfo fi(url.fileName());
|
||||
dialog->setSuggestedPack(fi.completeBaseName(), new InstanceImportTask(url));
|
||||
dialog->setSuggestedPack(fi.completeBaseName(), new InstanceImportTask(url,this));
|
||||
dialog->setSuggestedIcon("default");
|
||||
}
|
||||
}
|
||||
@@ -130,7 +132,7 @@ void ImportPage::updateState()
|
||||
}
|
||||
// hook, line and sinker.
|
||||
QFileInfo fi(url.fileName());
|
||||
dialog->setSuggestedPack(fi.completeBaseName(), new InstanceImportTask(url));
|
||||
dialog->setSuggestedPack(fi.completeBaseName(), new InstanceImportTask(url,this));
|
||||
dialog->setSuggestedIcon("default");
|
||||
}
|
||||
}
|
||||
@@ -149,7 +151,8 @@ void ImportPage::setUrl(const QString& url)
|
||||
void ImportPage::on_modpackBtn_clicked()
|
||||
{
|
||||
auto filter = QMimeDatabase().mimeTypeForName("application/zip").filterString();
|
||||
filter += ";;" + tr("Modrinth pack (*.mrpack)");
|
||||
//: Option for filtering for *.mrpack files when importing
|
||||
filter += ";;" + tr("Modrinth pack") + " (*.mrpack)";
|
||||
const QUrl url = QFileDialog::getOpenFileUrl(this, tr("Choose modpack"), modpackUrl(), filter);
|
||||
if (url.isValid())
|
||||
{
|
||||
|
@@ -38,27 +38,48 @@ auto ListModel::data(const QModelIndex& index, int role) const -> QVariant
|
||||
}
|
||||
|
||||
ModPlatform::IndexedPack pack = modpacks.at(pos);
|
||||
if (role == Qt::DisplayRole) {
|
||||
return pack.name;
|
||||
} else if (role == Qt::ToolTipRole) {
|
||||
if (pack.description.length() > 100) {
|
||||
// some magic to prevent to long tooltips and replace html linebreaks
|
||||
QString edit = pack.description.left(97);
|
||||
edit = edit.left(edit.lastIndexOf("<br>")).left(edit.lastIndexOf(" ")).append("...");
|
||||
return edit;
|
||||
switch (role) {
|
||||
case Qt::DisplayRole: {
|
||||
return pack.name;
|
||||
}
|
||||
return pack.description;
|
||||
} else if (role == Qt::DecorationRole) {
|
||||
if (m_logoMap.contains(pack.logoName)) {
|
||||
return (m_logoMap.value(pack.logoName));
|
||||
case Qt::ToolTipRole: {
|
||||
if (pack.description.length() > 100) {
|
||||
// some magic to prevent to long tooltips and replace html linebreaks
|
||||
QString edit = pack.description.left(97);
|
||||
edit = edit.left(edit.lastIndexOf("<br>")).left(edit.lastIndexOf(" ")).append("...");
|
||||
return edit;
|
||||
}
|
||||
return pack.description;
|
||||
}
|
||||
QIcon icon = APPLICATION->getThemedIcon("screenshot-placeholder");
|
||||
((ListModel*)this)->requestLogo(pack.logoName, pack.logoUrl);
|
||||
return icon;
|
||||
} else if (role == Qt::UserRole) {
|
||||
QVariant v;
|
||||
v.setValue(pack);
|
||||
return v;
|
||||
case Qt::DecorationRole: {
|
||||
if (m_logoMap.contains(pack.logoName)) {
|
||||
auto icon = m_logoMap.value(pack.logoName);
|
||||
// FIXME: This doesn't really belong here, but Qt doesn't offer a good way right now ;(
|
||||
auto icon_scaled = QIcon(icon.pixmap(48, 48).scaledToWidth(48));
|
||||
|
||||
return icon_scaled;
|
||||
}
|
||||
QIcon icon = APPLICATION->getThemedIcon("screenshot-placeholder");
|
||||
// un-const-ify this
|
||||
((ListModel*)this)->requestLogo(pack.logoName, pack.logoUrl);
|
||||
return icon;
|
||||
}
|
||||
case Qt::UserRole: {
|
||||
QVariant v;
|
||||
v.setValue(pack);
|
||||
return v;
|
||||
}
|
||||
case Qt::FontRole: {
|
||||
QFont font;
|
||||
if (m_parent->getDialog()->isModSelected(pack.name)) {
|
||||
font.setBold(true);
|
||||
font.setUnderline(true);
|
||||
}
|
||||
|
||||
return font;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return {};
|
||||
@@ -68,7 +89,7 @@ void ListModel::requestModVersions(ModPlatform::IndexedPack const& current)
|
||||
{
|
||||
auto profile = (dynamic_cast<MinecraftInstance*>((dynamic_cast<ModPage*>(parent()))->m_instance))->getPackProfile();
|
||||
|
||||
m_parent->apiProvider()->getVersions(this, { current.addonId.toString(), getMineVersions(), profile->getModLoader() });
|
||||
m_parent->apiProvider()->getVersions(this, { current.addonId.toString(), getMineVersions(), profile->getModLoaders() });
|
||||
}
|
||||
|
||||
void ListModel::performPaginatedSearch()
|
||||
@@ -76,7 +97,12 @@ void ListModel::performPaginatedSearch()
|
||||
auto profile = (dynamic_cast<MinecraftInstance*>((dynamic_cast<ModPage*>(parent()))->m_instance))->getPackProfile();
|
||||
|
||||
m_parent->apiProvider()->searchMods(
|
||||
this, { nextSearchOffset, currentSearchTerm, getSorts()[currentSort], profile->getModLoader(), getMineVersions() });
|
||||
this, { nextSearchOffset, currentSearchTerm, getSorts()[currentSort], profile->getModLoaders(), getMineVersions() });
|
||||
}
|
||||
|
||||
void ListModel::requestModInfo(ModPlatform::IndexedPack& current)
|
||||
{
|
||||
m_parent->apiProvider()->getModInfo(this, current);
|
||||
}
|
||||
|
||||
void ListModel::refresh()
|
||||
@@ -193,6 +219,10 @@ void ListModel::searchRequestFinished(QJsonDocument& doc)
|
||||
searchState = CanPossiblyFetchMore;
|
||||
}
|
||||
|
||||
// When you have a Qt build with assertions turned on, proceeding here will abort the application
|
||||
if (newList.size() == 0)
|
||||
return;
|
||||
|
||||
beginInsertRows(QModelIndex(), modpacks.size(), modpacks.size() + newList.size() - 1);
|
||||
modpacks.append(newList);
|
||||
endInsertRows();
|
||||
@@ -225,6 +255,21 @@ void ListModel::searchRequestFailed(QString reason)
|
||||
}
|
||||
}
|
||||
|
||||
void ListModel::infoRequestFinished(QJsonDocument& doc, ModPlatform::IndexedPack& pack)
|
||||
{
|
||||
qDebug() << "Loading mod info";
|
||||
|
||||
try {
|
||||
auto obj = Json::requireObject(doc);
|
||||
loadExtraPackInfo(pack, obj);
|
||||
} catch (const JSONValidationError& e) {
|
||||
qDebug() << doc;
|
||||
qWarning() << "Error while reading " << debugName() << " mod info: " << e.cause();
|
||||
}
|
||||
|
||||
m_parent->updateUi();
|
||||
}
|
||||
|
||||
void ListModel::versionRequestSucceeded(QJsonDocument doc, QString addonId)
|
||||
{
|
||||
auto& current = m_parent->getCurrent();
|
||||
|
@@ -36,9 +36,11 @@ class ListModel : public QAbstractListModel {
|
||||
void fetchMore(const QModelIndex& parent) override;
|
||||
void refresh();
|
||||
void searchWithTerm(const QString& term, const int sort, const bool filter_changed);
|
||||
void requestModInfo(ModPlatform::IndexedPack& current);
|
||||
void requestModVersions(const ModPlatform::IndexedPack& current);
|
||||
|
||||
virtual void loadIndexedPack(ModPlatform::IndexedPack& m, QJsonObject& obj) = 0;
|
||||
virtual void loadExtraPackInfo(ModPlatform::IndexedPack& m, QJsonObject& obj) {};
|
||||
virtual void loadIndexedPackVersions(ModPlatform::IndexedPack& m, QJsonArray& arr) = 0;
|
||||
|
||||
void getLogo(const QString& logo, const QString& logoUrl, LogoCallback callback);
|
||||
@@ -49,6 +51,8 @@ class ListModel : public QAbstractListModel {
|
||||
void searchRequestFinished(QJsonDocument& doc);
|
||||
void searchRequestFailed(QString reason);
|
||||
|
||||
void infoRequestFinished(QJsonDocument& doc, ModPlatform::IndexedPack& pack);
|
||||
|
||||
void versionRequestSucceeded(QJsonDocument doc, QString addonId);
|
||||
|
||||
protected slots:
|
||||
|
@@ -1,4 +1,40 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.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 "ModPage.h"
|
||||
#include "Application.h"
|
||||
#include "ui_ModPage.h"
|
||||
|
||||
#include <QKeyEvent>
|
||||
@@ -94,28 +130,6 @@ void ModPage::onSelectionChanged(QModelIndex first, QModelIndex second)
|
||||
if (!first.isValid()) { return; }
|
||||
|
||||
current = listModel->data(first, Qt::UserRole).value<ModPlatform::IndexedPack>();
|
||||
QString text = "";
|
||||
QString name = current.name;
|
||||
|
||||
if (current.websiteUrl.isEmpty())
|
||||
text = name;
|
||||
else
|
||||
text = "<a href=\"" + current.websiteUrl + "\">" + name + "</a>";
|
||||
|
||||
if (!current.authors.empty()) {
|
||||
auto authorToStr = [](ModPlatform::ModpackAuthor& author) -> QString {
|
||||
if (author.url.isEmpty()) { return author.name; }
|
||||
return QString("<a href=\"%1\">%2</a>").arg(author.url, author.name);
|
||||
};
|
||||
QStringList authorStrs;
|
||||
for (auto& author : current.authors) {
|
||||
authorStrs.push_back(authorToStr(author));
|
||||
}
|
||||
text += "<br>" + tr(" by ") + authorStrs.join(", ");
|
||||
}
|
||||
text += "<br><br>";
|
||||
|
||||
ui->packDescription->setHtml(text + current.description);
|
||||
|
||||
if (!current.versionsLoaded) {
|
||||
qDebug() << QString("Loading %1 mod versions").arg(debugName());
|
||||
@@ -132,6 +146,13 @@ void ModPage::onSelectionChanged(QModelIndex first, QModelIndex second)
|
||||
|
||||
updateSelectionButton();
|
||||
}
|
||||
|
||||
if(!current.extraDataLoaded){
|
||||
qDebug() << QString("Loading %1 mod info").arg(debugName());
|
||||
listModel->requestModInfo(current);
|
||||
}
|
||||
|
||||
updateUi();
|
||||
}
|
||||
|
||||
void ModPage::onVersionSelectionChanged(QString data)
|
||||
@@ -150,7 +171,8 @@ void ModPage::onModSelected()
|
||||
if (dialog->isModSelected(current.name, version.fileName)) {
|
||||
dialog->removeSelectedMod(current.name);
|
||||
} else {
|
||||
dialog->addSelectedMod(current.name, new ModDownloadTask(version.downloadUrl, version.fileName, dialog->mods));
|
||||
bool is_indexed = !APPLICATION->settings()->get("ModMetadataDisabled").toBool();
|
||||
dialog->addSelectedMod(current.name, new ModDownloadTask(current, version, dialog->mods, is_indexed));
|
||||
}
|
||||
|
||||
updateSelectionButton();
|
||||
@@ -175,7 +197,7 @@ void ModPage::updateModVersions(int prev_count)
|
||||
bool valid = false;
|
||||
for(auto& mcVer : m_filter->versions){
|
||||
//NOTE: Flame doesn't care about loader, so passing it changes nothing.
|
||||
if (validateVersion(version, mcVer.toString(), packProfile->getModLoader())) {
|
||||
if (validateVersion(version, mcVer.toString(), packProfile->getModLoaders())) {
|
||||
valid = true;
|
||||
break;
|
||||
}
|
||||
@@ -207,3 +229,61 @@ void ModPage::updateSelectionButton()
|
||||
ui->modSelectionButton->setText(tr("Deselect mod for download"));
|
||||
}
|
||||
}
|
||||
|
||||
void ModPage::updateUi()
|
||||
{
|
||||
QString text = "";
|
||||
QString name = current.name;
|
||||
|
||||
if (current.websiteUrl.isEmpty())
|
||||
text = name;
|
||||
else
|
||||
text = "<a href=\"" + current.websiteUrl + "\">" + name + "</a>";
|
||||
|
||||
if (!current.authors.empty()) {
|
||||
auto authorToStr = [](ModPlatform::ModpackAuthor& author) -> QString {
|
||||
if (author.url.isEmpty()) { return author.name; }
|
||||
return QString("<a href=\"%1\">%2</a>").arg(author.url, author.name);
|
||||
};
|
||||
QStringList authorStrs;
|
||||
for (auto& author : current.authors) {
|
||||
authorStrs.push_back(authorToStr(author));
|
||||
}
|
||||
text += "<br>" + tr(" by ") + authorStrs.join(", ");
|
||||
}
|
||||
|
||||
|
||||
if(current.extraDataLoaded) {
|
||||
if (!current.extraData.donate.isEmpty()) {
|
||||
text += "<br><br>" + tr("Donate information: ");
|
||||
auto donateToStr = [](ModPlatform::DonationData& donate) -> QString {
|
||||
return QString("<a href=\"%1\">%2</a>").arg(donate.url, donate.platform);
|
||||
};
|
||||
QStringList donates;
|
||||
for (auto& donate : current.extraData.donate) {
|
||||
donates.append(donateToStr(donate));
|
||||
}
|
||||
text += donates.join(", ");
|
||||
}
|
||||
|
||||
if (!current.extraData.issuesUrl.isEmpty()
|
||||
|| !current.extraData.sourceUrl.isEmpty()
|
||||
|| !current.extraData.wikiUrl.isEmpty()
|
||||
|| !current.extraData.discordUrl.isEmpty()) {
|
||||
text += "<br><br>" + tr("External links:") + "<br>";
|
||||
}
|
||||
|
||||
if (!current.extraData.issuesUrl.isEmpty())
|
||||
text += "- " + tr("Issues: <a href=%1>%1</a>").arg(current.extraData.issuesUrl) + "<br>";
|
||||
if (!current.extraData.wikiUrl.isEmpty())
|
||||
text += "- " + tr("Wiki: <a href=%1>%1</a>").arg(current.extraData.wikiUrl) + "<br>";
|
||||
if (!current.extraData.sourceUrl.isEmpty())
|
||||
text += "- " + tr("Source code: <a href=%1>%1</a>").arg(current.extraData.sourceUrl) + "<br>";
|
||||
if (!current.extraData.discordUrl.isEmpty())
|
||||
text += "- " + tr("Discord: <a href=%1>%1</a>").arg(current.extraData.discordUrl) + "<br>";
|
||||
}
|
||||
|
||||
text += "<hr>";
|
||||
|
||||
ui->packDescription->setHtml(text + current.description);
|
||||
}
|
||||
|
@@ -36,11 +36,14 @@ class ModPage : public QWidget, public BasePage {
|
||||
|
||||
void retranslate() override;
|
||||
|
||||
auto shouldDisplay() const -> bool override = 0;
|
||||
virtual auto validateVersion(ModPlatform::IndexedVersion& ver, QString mineVer, ModAPI::ModLoaderType loader = ModAPI::Unspecified) const -> bool = 0;
|
||||
void updateUi();
|
||||
|
||||
auto apiProvider() const -> const ModAPI* { return api.get(); };
|
||||
auto shouldDisplay() const -> bool override = 0;
|
||||
virtual auto validateVersion(ModPlatform::IndexedVersion& ver, QString mineVer, ModAPI::ModLoaderTypes loaders = ModAPI::Unspecified) const -> bool = 0;
|
||||
|
||||
auto apiProvider() -> ModAPI* { return api.get(); };
|
||||
auto getFilter() const -> const std::shared_ptr<ModFilterWidget::Filter> { return m_filter; }
|
||||
auto getDialog() const -> const ModDownloadDialog* { return dialog; }
|
||||
|
||||
auto getCurrent() -> ModPlatform::IndexedPack& { return current; }
|
||||
void updateModVersions(int prev_count = -1);
|
||||
|
@@ -43,8 +43,11 @@
|
||||
#include "modplatform/atlauncher/ATLShareCode.h"
|
||||
#include "Application.h"
|
||||
|
||||
AtlOptionalModListModel::AtlOptionalModListModel(QWidget *parent, QVector<ATLauncher::VersionMod> mods)
|
||||
: QAbstractListModel(parent), m_mods(mods) {
|
||||
AtlOptionalModListModel::AtlOptionalModListModel(QWidget* parent, ATLauncher::PackVersion version, QVector<ATLauncher::VersionMod> mods)
|
||||
: QAbstractListModel(parent)
|
||||
, m_version(version)
|
||||
, m_mods(mods)
|
||||
{
|
||||
// fill mod index
|
||||
for (int i = 0; i < m_mods.size(); i++) {
|
||||
auto mod = m_mods.at(i);
|
||||
@@ -97,6 +100,11 @@ QVariant AtlOptionalModListModel::data(const QModelIndex &index, int role) const
|
||||
return mod.description;
|
||||
}
|
||||
}
|
||||
else if (role == Qt::ForegroundRole) {
|
||||
if (!mod.colour.isEmpty() && m_version.colours.contains(mod.colour)) {
|
||||
return QColor(QString("#%1").arg(m_version.colours[mod.colour]));
|
||||
}
|
||||
}
|
||||
else if (role == Qt::CheckStateRole) {
|
||||
if (index.column() == EnabledColumn) {
|
||||
return m_selection[mod.name] ? Qt::Checked : Qt::Unchecked;
|
||||
@@ -223,7 +231,21 @@ void AtlOptionalModListModel::clearAll() {
|
||||
}
|
||||
|
||||
void AtlOptionalModListModel::toggleMod(ATLauncher::VersionMod mod, int index) {
|
||||
setMod(mod, index, !m_selection[mod.name]);
|
||||
auto enable = !m_selection[mod.name];
|
||||
|
||||
// If there is a warning for the mod, display that first (if we would be enabling the mod)
|
||||
if (enable && !mod.warning.isEmpty() && m_version.warnings.contains(mod.warning)) {
|
||||
auto message = QString("%1<br><br>%2")
|
||||
.arg(m_version.warnings[mod.warning], tr("Are you sure that you want to enable this mod?"));
|
||||
|
||||
// fixme: avoid casting here
|
||||
auto result = QMessageBox::warning((QWidget*) this->parent(), tr("Warning"), message, QMessageBox::Yes | QMessageBox::No);
|
||||
if (result != QMessageBox::Yes) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
setMod(mod, index, enable);
|
||||
}
|
||||
|
||||
void AtlOptionalModListModel::setMod(ATLauncher::VersionMod mod, int index, bool enable, bool shouldEmit) {
|
||||
@@ -287,12 +309,13 @@ void AtlOptionalModListModel::setMod(ATLauncher::VersionMod mod, int index, bool
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
AtlOptionalModDialog::AtlOptionalModDialog(QWidget *parent, QVector<ATLauncher::VersionMod> mods)
|
||||
: QDialog(parent), ui(new Ui::AtlOptionalModDialog) {
|
||||
AtlOptionalModDialog::AtlOptionalModDialog(QWidget* parent, ATLauncher::PackVersion version, QVector<ATLauncher::VersionMod> mods)
|
||||
: QDialog(parent)
|
||||
, ui(new Ui::AtlOptionalModDialog)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
listModel = new AtlOptionalModListModel(this, mods);
|
||||
listModel = new AtlOptionalModListModel(this, version, mods);
|
||||
ui->treeView->setModel(listModel);
|
||||
|
||||
ui->treeView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||
|
@@ -56,7 +56,7 @@ public:
|
||||
DescriptionColumn,
|
||||
};
|
||||
|
||||
AtlOptionalModListModel(QWidget *parent, QVector<ATLauncher::VersionMod> mods);
|
||||
AtlOptionalModListModel(QWidget *parent, ATLauncher::PackVersion version, QVector<ATLauncher::VersionMod> mods);
|
||||
|
||||
QVector<QString> getResult();
|
||||
|
||||
@@ -86,7 +86,9 @@ private:
|
||||
NetJob::Ptr m_jobPtr;
|
||||
QByteArray m_response;
|
||||
|
||||
ATLauncher::PackVersion m_version;
|
||||
QVector<ATLauncher::VersionMod> m_mods;
|
||||
|
||||
QMap<QString, bool> m_selection;
|
||||
QMap<QString, int> m_index;
|
||||
QMap<QString, QVector<QString>> m_dependants;
|
||||
@@ -96,7 +98,7 @@ class AtlOptionalModDialog : public QDialog {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
AtlOptionalModDialog(QWidget *parent, QVector<ATLauncher::VersionMod> mods);
|
||||
AtlOptionalModDialog(QWidget *parent, ATLauncher::PackVersion version, QVector<ATLauncher::VersionMod> mods);
|
||||
~AtlOptionalModDialog() override;
|
||||
|
||||
QVector<QString> getResult() {
|
||||
|
@@ -45,8 +45,12 @@
|
||||
|
||||
#include <BuildConfig.h>
|
||||
|
||||
AtlPage::AtlPage(NewInstanceDialog* dialog, QWidget *parent)
|
||||
: QWidget(parent), ui(new Ui::AtlPage), dialog(dialog)
|
||||
#include <QMessageBox>
|
||||
|
||||
AtlPage::AtlPage(NewInstanceDialog* dialog, QWidget* parent)
|
||||
: QWidget(parent)
|
||||
, ui(new Ui::AtlPage)
|
||||
, dialog(dialog)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
@@ -113,7 +117,7 @@ void AtlPage::suggestCurrent()
|
||||
return;
|
||||
}
|
||||
|
||||
dialog->setSuggestedPack(selected.name + " " + selectedVersion, new ATLauncher::PackInstallTask(this, selected.safeName, selectedVersion));
|
||||
dialog->setSuggestedPack(selected.name + " " + selectedVersion, new ATLauncher::PackInstallTask(this, selected.name, selectedVersion));
|
||||
auto editedLogoName = selected.safeName;
|
||||
auto url = QString(BuildConfig.ATL_DOWNLOAD_SERVER_URL + "launcher/images/%1.png").arg(selected.safeName.toLower());
|
||||
listModel->getLogo(selected.safeName, url, [this, editedLogoName](QString logo)
|
||||
@@ -169,8 +173,9 @@ void AtlPage::onVersionSelectionChanged(QString data)
|
||||
suggestCurrent();
|
||||
}
|
||||
|
||||
QVector<QString> AtlPage::chooseOptionalMods(QVector<ATLauncher::VersionMod> mods) {
|
||||
AtlOptionalModDialog optionalModDialog(this, mods);
|
||||
QVector<QString> AtlPage::chooseOptionalMods(ATLauncher::PackVersion version, QVector<ATLauncher::VersionMod> mods)
|
||||
{
|
||||
AtlOptionalModDialog optionalModDialog(this, version, mods);
|
||||
optionalModDialog.exec();
|
||||
return optionalModDialog.getResult();
|
||||
}
|
||||
@@ -210,3 +215,8 @@ QString AtlPage::chooseVersion(Meta::VersionListPtr vlist, QString minecraftVers
|
||||
vselect.exec();
|
||||
return vselect.selectedVersion()->descriptor();
|
||||
}
|
||||
|
||||
void AtlPage::displayMessage(QString message)
|
||||
{
|
||||
QMessageBox::information(this, tr("Installing"), message);
|
||||
}
|
||||
|
@@ -84,7 +84,8 @@ private:
|
||||
void suggestCurrent();
|
||||
|
||||
QString chooseVersion(Meta::VersionListPtr vlist, QString minecraftVersion) override;
|
||||
QVector<QString> chooseOptionalMods(QVector<ATLauncher::VersionMod> mods) override;
|
||||
QVector<QString> chooseOptionalMods(ATLauncher::PackVersion version, QVector<ATLauncher::VersionMod> mods) override;
|
||||
void displayMessage(QString message) override;
|
||||
|
||||
private slots:
|
||||
void triggerSearch();
|
||||
|
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Copyright (c) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.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
|
||||
@@ -61,9 +61,9 @@ FlameModPage::FlameModPage(ModDownloadDialog* dialog, BaseInstance* instance)
|
||||
connect(ui->modSelectionButton, &QPushButton::clicked, this, &FlameModPage::onModSelected);
|
||||
}
|
||||
|
||||
auto FlameModPage::validateVersion(ModPlatform::IndexedVersion& ver, QString mineVer, ModAPI::ModLoaderType loader) const -> bool
|
||||
auto FlameModPage::validateVersion(ModPlatform::IndexedVersion& ver, QString mineVer, ModAPI::ModLoaderTypes loaders) const -> bool
|
||||
{
|
||||
Q_UNUSED(loader);
|
||||
Q_UNUSED(loaders);
|
||||
return ver.mcVersion.contains(mineVer);
|
||||
}
|
||||
|
||||
|
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Copyright (c) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.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
|
||||
@@ -55,7 +55,7 @@ class FlameModPage : public ModPage {
|
||||
inline auto debugName() const -> QString override { return "Flame"; }
|
||||
inline auto metaEntryBase() const -> QString override { return "FlameMods"; };
|
||||
|
||||
auto validateVersion(ModPlatform::IndexedVersion& ver, QString mineVer, ModAPI::ModLoaderType loader = ModAPI::Unspecified) const -> bool override;
|
||||
auto validateVersion(ModPlatform::IndexedVersion& ver, QString mineVer, ModAPI::ModLoaderTypes loaders = ModAPI::Unspecified) const -> bool override;
|
||||
|
||||
auto shouldDisplay() const -> bool override;
|
||||
};
|
||||
|
@@ -57,6 +57,17 @@ QVariant ListModel::data(const QModelIndex& index, int role) const
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
bool ListModel::setData(const QModelIndex &index, const QVariant &value, int role)
|
||||
{
|
||||
int pos = index.row();
|
||||
if (pos >= modpacks.size() || pos < 0 || !index.isValid())
|
||||
return false;
|
||||
|
||||
modpacks[pos] = value.value<Flame::IndexedPack>();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ListModel::logoLoaded(QString logo, QIcon out)
|
||||
{
|
||||
m_loadingLogos.removeAll(logo);
|
||||
@@ -210,6 +221,11 @@ void Flame::ListModel::searchRequestFinished()
|
||||
nextSearchOffset += 25;
|
||||
searchState = CanPossiblyFetchMore;
|
||||
}
|
||||
|
||||
// When you have a Qt build with assertions turned on, proceeding here will abort the application
|
||||
if (newList.size() == 0)
|
||||
return;
|
||||
|
||||
beginInsertRows(QModelIndex(), modpacks.size(), modpacks.size() + newList.size() - 1);
|
||||
modpacks.append(newList);
|
||||
endInsertRows();
|
||||
|
@@ -34,6 +34,7 @@ public:
|
||||
int rowCount(const QModelIndex &parent) const override;
|
||||
int columnCount(const QModelIndex &parent) const override;
|
||||
QVariant data(const QModelIndex &index, int role) const override;
|
||||
bool setData(const QModelIndex &index, const QVariant &value, int role) override;
|
||||
Qt::ItemFlags flags(const QModelIndex &index) const override;
|
||||
bool canFetchMore(const QModelIndex & parent) const override;
|
||||
void fetchMore(const QModelIndex & parent) override;
|
||||
|
@@ -107,41 +107,18 @@ void FlamePage::triggerSearch()
|
||||
listModel->searchWithTerm(ui->searchEdit->text(), ui->sortByBox->currentIndex());
|
||||
}
|
||||
|
||||
void FlamePage::onSelectionChanged(QModelIndex first, QModelIndex second)
|
||||
void FlamePage::onSelectionChanged(QModelIndex curr, QModelIndex prev)
|
||||
{
|
||||
ui->versionSelectionBox->clear();
|
||||
|
||||
if (!first.isValid()) {
|
||||
if (!curr.isValid()) {
|
||||
if (isOpened) {
|
||||
dialog->setSuggestedPack();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
current = listModel->data(first, Qt::UserRole).value<Flame::IndexedPack>();
|
||||
QString text = "";
|
||||
QString name = current.name;
|
||||
|
||||
if (current.websiteUrl.isEmpty())
|
||||
text = name;
|
||||
else
|
||||
text = "<a href=\"" + current.websiteUrl + "\">" + name + "</a>";
|
||||
if (!current.authors.empty()) {
|
||||
auto authorToStr = [](Flame::ModpackAuthor& author) {
|
||||
if (author.url.isEmpty()) {
|
||||
return author.name;
|
||||
}
|
||||
return QString("<a href=\"%1\">%2</a>").arg(author.url, author.name);
|
||||
};
|
||||
QStringList authorStrs;
|
||||
for (auto& author : current.authors) {
|
||||
authorStrs.push_back(authorToStr(author));
|
||||
}
|
||||
text += "<br>" + tr(" by ") + authorStrs.join(", ");
|
||||
}
|
||||
text += "<br><br>";
|
||||
|
||||
ui->packDescription->setHtml(text + current.description);
|
||||
current = listModel->data(curr, Qt::UserRole).value<Flame::IndexedPack>();
|
||||
|
||||
if (current.versionsLoaded == false) {
|
||||
qDebug() << "Loading flame modpack versions";
|
||||
@@ -150,7 +127,7 @@ void FlamePage::onSelectionChanged(QModelIndex first, QModelIndex second)
|
||||
int addonId = current.addonId;
|
||||
netJob->addNetAction(Net::Download::makeByteArray(QString("https://api.curseforge.com/v1/mods/%1/files").arg(addonId), response));
|
||||
|
||||
QObject::connect(netJob, &NetJob::succeeded, this, [this, response, addonId] {
|
||||
QObject::connect(netJob, &NetJob::succeeded, this, [this, response, addonId, curr] {
|
||||
if (addonId != current.addonId) {
|
||||
return; // wrong request
|
||||
}
|
||||
@@ -174,6 +151,16 @@ void FlamePage::onSelectionChanged(QModelIndex first, QModelIndex second)
|
||||
ui->versionSelectionBox->addItem(version.version, QVariant(version.downloadUrl));
|
||||
}
|
||||
|
||||
QVariant current_updated;
|
||||
current_updated.setValue(current);
|
||||
|
||||
if (!listModel->setData(curr, current_updated, Qt::UserRole))
|
||||
qWarning() << "Failed to cache versions for the current pack!";
|
||||
|
||||
// TODO: Check whether it's a connection issue or the project disabled 3rd-party distribution.
|
||||
if (current.versionsLoaded && ui->versionSelectionBox->count() < 1) {
|
||||
ui->versionSelectionBox->addItem(tr("No version is available!"), -1);
|
||||
}
|
||||
suggestCurrent();
|
||||
});
|
||||
QObject::connect(netJob, &NetJob::finished, this, [response, netJob] {
|
||||
@@ -188,6 +175,13 @@ void FlamePage::onSelectionChanged(QModelIndex first, QModelIndex second)
|
||||
|
||||
suggestCurrent();
|
||||
}
|
||||
|
||||
// TODO: Check whether it's a connection issue or the project disabled 3rd-party distribution.
|
||||
if (current.versionsLoaded && ui->versionSelectionBox->count() < 1) {
|
||||
ui->versionSelectionBox->addItem(tr("No version is available!"), -1);
|
||||
}
|
||||
|
||||
updateUi();
|
||||
}
|
||||
|
||||
void FlamePage::suggestCurrent()
|
||||
@@ -196,12 +190,12 @@ void FlamePage::suggestCurrent()
|
||||
return;
|
||||
}
|
||||
|
||||
if (selectedVersion.isEmpty()) {
|
||||
if (selectedVersion.isEmpty() || selectedVersion == "-1") {
|
||||
dialog->setSuggestedPack();
|
||||
return;
|
||||
}
|
||||
|
||||
dialog->setSuggestedPack(current.name, new InstanceImportTask(selectedVersion));
|
||||
dialog->setSuggestedPack(current.name, new InstanceImportTask(selectedVersion,this));
|
||||
QString editedLogoName;
|
||||
editedLogoName = "curseforge_" + current.logoName.section(".", 0, 0);
|
||||
listModel->getLogo(current.logoName, current.logoUrl,
|
||||
@@ -217,3 +211,46 @@ void FlamePage::onVersionSelectionChanged(QString data)
|
||||
selectedVersion = ui->versionSelectionBox->currentData().toString();
|
||||
suggestCurrent();
|
||||
}
|
||||
|
||||
void FlamePage::updateUi()
|
||||
{
|
||||
QString text = "";
|
||||
QString name = current.name;
|
||||
|
||||
if (current.extra.websiteUrl.isEmpty())
|
||||
text = name;
|
||||
else
|
||||
text = "<a href=\"" + current.extra.websiteUrl + "\">" + name + "</a>";
|
||||
if (!current.authors.empty()) {
|
||||
auto authorToStr = [](Flame::ModpackAuthor& author) {
|
||||
if (author.url.isEmpty()) {
|
||||
return author.name;
|
||||
}
|
||||
return QString("<a href=\"%1\">%2</a>").arg(author.url, author.name);
|
||||
};
|
||||
QStringList authorStrs;
|
||||
for (auto& author : current.authors) {
|
||||
authorStrs.push_back(authorToStr(author));
|
||||
}
|
||||
text += "<br>" + tr(" by ") + authorStrs.join(", ");
|
||||
}
|
||||
|
||||
if(current.extraInfoLoaded) {
|
||||
if (!current.extra.issuesUrl.isEmpty()
|
||||
|| !current.extra.sourceUrl.isEmpty()
|
||||
|| !current.extra.wikiUrl.isEmpty()) {
|
||||
text += "<br><br>" + tr("External links:") + "<br>";
|
||||
}
|
||||
|
||||
if (!current.extra.issuesUrl.isEmpty())
|
||||
text += "- " + tr("Issues: <a href=%1>%1</a>").arg(current.extra.issuesUrl) + "<br>";
|
||||
if (!current.extra.wikiUrl.isEmpty())
|
||||
text += "- " + tr("Wiki: <a href=%1>%1</a>").arg(current.extra.wikiUrl) + "<br>";
|
||||
if (!current.extra.sourceUrl.isEmpty())
|
||||
text += "- " + tr("Source code: <a href=%1>%1</a>").arg(current.extra.sourceUrl) + "<br>";
|
||||
}
|
||||
|
||||
text += "<hr>";
|
||||
|
||||
ui->packDescription->setHtml(text + current.description);
|
||||
}
|
||||
|
@@ -79,6 +79,8 @@ public:
|
||||
virtual bool shouldDisplay() const override;
|
||||
void retranslate() override;
|
||||
|
||||
void updateUi();
|
||||
|
||||
void openedImpl() override;
|
||||
|
||||
bool eventFilter(QObject * watched, QEvent * event) override;
|
||||
|
@@ -1,90 +1,110 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>FlamePage</class>
|
||||
<widget class="QWidget" name="FlamePage">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>837</width>
|
||||
<height>685</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="1" column="0" colspan="2">
|
||||
<layout class="QGridLayout" name="gridLayout_3">
|
||||
<item row="1" column="0">
|
||||
<widget class="QListView" name="packView">
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
<width>48</width>
|
||||
<height>48</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="horizontalScrollBarPolicy">
|
||||
<enum>Qt::ScrollBarAlwaysOff</enum>
|
||||
</property>
|
||||
<property name="alternatingRowColors">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QTextBrowser" name="packDescription">
|
||||
<property name="openExternalLinks">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="openLinks">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="2" column="0" colspan="2">
|
||||
<layout class="QGridLayout" name="gridLayout_4" columnstretch="0,0,0" rowminimumheight="0" columnminimumwidth="0,0,0">
|
||||
<item row="0" column="2">
|
||||
<widget class="QComboBox" name="versionSelectionBox"/>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Version selected:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QComboBox" name="sortByBox"/>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QPushButton" name="searchButton">
|
||||
<property name="text">
|
||||
<string>Search</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLineEdit" name="searchEdit">
|
||||
<property name="placeholderText">
|
||||
<string>Search and filter...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<class>FlamePage</class>
|
||||
<widget class="QWidget" name="FlamePage">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>800</width>
|
||||
<height>600</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="font">
|
||||
<font>
|
||||
<italic>true</italic>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Note: CurseForge allows creators to block access to third-party tools like PolyMC. As such, you may need to manually download some mods to be able to install a modpack.</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<layout class="QHBoxLayout">
|
||||
<item>
|
||||
<widget class="QLineEdit" name="searchEdit">
|
||||
<property name="placeholderText">
|
||||
<string>Search and filter...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="searchButton">
|
||||
<property name="text">
|
||||
<string>Search</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<tabstops>
|
||||
<tabstop>searchEdit</tabstop>
|
||||
<tabstop>searchButton</tabstop>
|
||||
<tabstop>packView</tabstop>
|
||||
<tabstop>packDescription</tabstop>
|
||||
<tabstop>sortByBox</tabstop>
|
||||
<tabstop>versionSelectionBox</tabstop>
|
||||
</tabstops>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<layout class="QHBoxLayout">
|
||||
<item>
|
||||
<widget class="QListView" name="packView">
|
||||
<property name="horizontalScrollBarPolicy">
|
||||
<enum>Qt::ScrollBarAlwaysOff</enum>
|
||||
</property>
|
||||
<property name="alternatingRowColors">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
<width>48</width>
|
||||
<height>48</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QTextBrowser" name="packDescription">
|
||||
<property name="openExternalLinks">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="openLinks">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<layout class="QHBoxLayout">
|
||||
<item>
|
||||
<widget class="QComboBox" name="sortByBox"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>Version selected:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="versionSelectionBox"/>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<tabstops>
|
||||
<tabstop>packView</tabstop>
|
||||
<tabstop>packDescription</tabstop>
|
||||
<tabstop>sortByBox</tabstop>
|
||||
<tabstop>versionSelectionBox</tabstop>
|
||||
</tabstops>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
|
@@ -122,10 +122,10 @@ void ListModel::requestFinished()
|
||||
jobPtr.reset();
|
||||
remainingPacks.clear();
|
||||
|
||||
QJsonParseError parse_error;
|
||||
QJsonParseError parse_error {};
|
||||
QJsonDocument doc = QJsonDocument::fromJson(response, &parse_error);
|
||||
if(parse_error.error != QJsonParseError::NoError) {
|
||||
qWarning() << "Error while parsing JSON response from FTB at " << parse_error.offset << " reason: " << parse_error.errorString();
|
||||
qWarning() << "Error while parsing JSON response from ModpacksCH at " << parse_error.offset << " reason: " << parse_error.errorString();
|
||||
qWarning() << response;
|
||||
return;
|
||||
}
|
||||
@@ -169,7 +169,7 @@ void ListModel::packRequestFinished()
|
||||
QJsonDocument doc = QJsonDocument::fromJson(response, &parse_error);
|
||||
|
||||
if(parse_error.error != QJsonParseError::NoError) {
|
||||
qWarning() << "Error while parsing JSON response from FTB at " << parse_error.offset << " reason: " << parse_error.errorString();
|
||||
qWarning() << "Error while parsing JSON response from ModpacksCH at " << parse_error.offset << " reason: " << parse_error.errorString();
|
||||
qWarning() << response;
|
||||
return;
|
||||
}
|
||||
@@ -184,7 +184,7 @@ void ListModel::packRequestFinished()
|
||||
catch (const JSONValidationError &e)
|
||||
{
|
||||
qDebug() << QString::fromUtf8(response);
|
||||
qWarning() << "Error while reading pack manifest from FTB: " << e.cause();
|
||||
qWarning() << "Error while reading pack manifest from ModpacksCH: " << e.cause();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -192,7 +192,7 @@ void ListModel::packRequestFinished()
|
||||
// ignore those "dud" packs.
|
||||
if (pack.versions.empty())
|
||||
{
|
||||
qWarning() << "FTB Pack " << pack.id << " ignored. reason: lacking any versions";
|
||||
qWarning() << "ModpacksCH Pack " << pack.id << " ignored. reason: lacking any versions";
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -270,7 +270,7 @@ void ListModel::requestLogo(QString logo, QString url)
|
||||
|
||||
bool stale = entry->isStale();
|
||||
|
||||
NetJob *job = new NetJob(QString("FTB Icon Download %1").arg(logo), APPLICATION->network());
|
||||
NetJob *job = new NetJob(QString("ModpacksCH Icon Download %1").arg(logo), APPLICATION->network());
|
||||
job->addNetAction(Net::Download::makeCached(QUrl(url), entry));
|
||||
|
||||
auto fullPath = entry->getFullPath();
|
||||
|
@@ -1,3 +1,38 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.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 "ListModel.h"
|
||||
#include "Application.h"
|
||||
|
||||
@@ -133,7 +168,7 @@ QVariant ListModel::data(const QModelIndex &index, int role) const
|
||||
((ListModel *)this)->requestLogo(pack.logo);
|
||||
return icon;
|
||||
}
|
||||
else if(role == Qt::TextColorRole)
|
||||
else if(role == Qt::ForegroundRole)
|
||||
{
|
||||
if(pack.broken)
|
||||
{
|
||||
|
@@ -2,6 +2,7 @@
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.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
|
||||
@@ -151,7 +152,7 @@ void Page::openedImpl()
|
||||
|
||||
ftbFetchTask->fetch();
|
||||
ftbPrivatePacks->load();
|
||||
ftbFetchTask->fetchPrivate(ftbPrivatePacks->getCurrentPackCodes().toList());
|
||||
ftbFetchTask->fetchPrivate(ftbPrivatePacks->getCurrentPackCodes().values());
|
||||
initialized = true;
|
||||
}
|
||||
suggestCurrent();
|
||||
@@ -175,7 +176,7 @@ void Page::suggestCurrent()
|
||||
return;
|
||||
}
|
||||
|
||||
dialog->setSuggestedPack(selected.name, new PackInstallTask(APPLICATION->network(), selected, selectedVersion));
|
||||
dialog->setSuggestedPack(selected.name + " " + selectedVersion, new PackInstallTask(APPLICATION->network(), selected, selectedVersion));
|
||||
QString editedLogoName;
|
||||
if(selected.logo.toLower().startsWith("ftb"))
|
||||
{
|
||||
|
@@ -25,7 +25,7 @@
|
||||
<widget class="QTreeView" name="publicPackList">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>250</width>
|
||||
<width>16777215</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
@@ -51,7 +51,7 @@
|
||||
<widget class="QTreeView" name="thirdPartyPackList">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>250</width>
|
||||
<width>16777215</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
@@ -71,7 +71,7 @@
|
||||
<widget class="QTreeView" name="privatePackList">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>250</width>
|
||||
<width>16777215</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
|
@@ -30,6 +30,11 @@ void ListModel::loadIndexedPack(ModPlatform::IndexedPack& m, QJsonObject& obj)
|
||||
Modrinth::loadIndexedPack(m, obj);
|
||||
}
|
||||
|
||||
void ListModel::loadExtraPackInfo(ModPlatform::IndexedPack& m, QJsonObject& obj)
|
||||
{
|
||||
Modrinth::loadExtraPackData(m, obj);
|
||||
}
|
||||
|
||||
void ListModel::loadIndexedPackVersions(ModPlatform::IndexedPack& m, QJsonArray& arr)
|
||||
{
|
||||
Modrinth::loadIndexedPackVersions(m, arr, APPLICATION->network(), m_parent->m_instance);
|
||||
|
@@ -31,6 +31,7 @@ class ListModel : public ModPlatform::ListModel {
|
||||
|
||||
private:
|
||||
void loadIndexedPack(ModPlatform::IndexedPack& m, QJsonObject& obj) override;
|
||||
void loadExtraPackInfo(ModPlatform::IndexedPack& m, QJsonObject& obj) override;
|
||||
void loadIndexedPackVersions(ModPlatform::IndexedPack& m, QJsonArray& arr) override;
|
||||
|
||||
auto documentToArray(QJsonDocument& obj) const -> QJsonArray override;
|
||||
|
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Copyright (c) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.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
|
||||
@@ -61,9 +61,9 @@ ModrinthModPage::ModrinthModPage(ModDownloadDialog* dialog, BaseInstance* instan
|
||||
connect(ui->modSelectionButton, &QPushButton::clicked, this, &ModrinthModPage::onModSelected);
|
||||
}
|
||||
|
||||
auto ModrinthModPage::validateVersion(ModPlatform::IndexedVersion& ver, QString mineVer, ModAPI::ModLoaderType loader) const -> bool
|
||||
auto ModrinthModPage::validateVersion(ModPlatform::IndexedVersion& ver, QString mineVer, ModAPI::ModLoaderTypes loaders) const -> bool
|
||||
{
|
||||
auto loaderStrings = ModrinthAPI::getModLoaderStrings(loader);
|
||||
auto loaderStrings = ModrinthAPI::getModLoaderStrings(loaders);
|
||||
|
||||
auto loaderCompatible = false;
|
||||
for (auto remoteLoader : ver.loaders)
|
||||
|
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Copyright (c) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.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
|
||||
@@ -55,7 +55,7 @@ class ModrinthModPage : public ModPage {
|
||||
inline auto debugName() const -> QString override { return "Modrinth"; }
|
||||
inline auto metaEntryBase() const -> QString override { return "ModrinthPacks"; };
|
||||
|
||||
auto validateVersion(ModPlatform::IndexedVersion& ver, QString mineVer, ModAPI::ModLoaderType loader = ModAPI::Unspecified) const -> bool override;
|
||||
auto validateVersion(ModPlatform::IndexedVersion& ver, QString mineVer, ModAPI::ModLoaderTypes loaders = ModAPI::Unspecified) const -> bool override;
|
||||
|
||||
auto shouldDisplay() const -> bool override;
|
||||
};
|
||||
|
@@ -2,6 +2,7 @@
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Copyright (c) 2022 flowln <flowlnlnln@gmail.com>
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.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
|
||||
@@ -86,6 +87,7 @@ auto ModpackListModel::data(const QModelIndex& index, int role) const -> QVarian
|
||||
} else if (role == Qt::DecorationRole) {
|
||||
if (m_logoMap.contains(pack.iconName)) {
|
||||
auto icon = m_logoMap.value(pack.iconName);
|
||||
// FIXME: This doesn't really belong here, but Qt doesn't offer a good way right now ;(
|
||||
auto icon_scaled = QIcon(icon.pixmap(48, 48).scaledToWidth(48));
|
||||
|
||||
return icon_scaled;
|
||||
@@ -102,6 +104,17 @@ auto ModpackListModel::data(const QModelIndex& index, int role) const -> QVarian
|
||||
return {};
|
||||
}
|
||||
|
||||
bool ModpackListModel::setData(const QModelIndex &index, const QVariant &value, int role)
|
||||
{
|
||||
int pos = index.row();
|
||||
if (pos >= modpacks.size() || pos < 0 || !index.isValid())
|
||||
return false;
|
||||
|
||||
modpacks[pos] = value.value<Modrinth::Modpack>();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ModpackListModel::performPaginatedSearch()
|
||||
{
|
||||
// TODO: Move to standalone API
|
||||
@@ -159,15 +172,15 @@ static auto sortFromIndex(int index) -> QString
|
||||
{
|
||||
switch(index){
|
||||
default:
|
||||
case 1:
|
||||
case 0:
|
||||
return "relevance";
|
||||
case 2:
|
||||
case 1:
|
||||
return "downloads";
|
||||
case 3:
|
||||
case 2:
|
||||
return "follows";
|
||||
case 4:
|
||||
case 3:
|
||||
return "newest";
|
||||
case 5:
|
||||
case 4:
|
||||
return "updated";
|
||||
}
|
||||
|
||||
@@ -277,6 +290,10 @@ void ModpackListModel::searchRequestFinished(QJsonDocument& doc_all)
|
||||
searchState = CanPossiblyFetchMore;
|
||||
}
|
||||
|
||||
// When you have a Qt build with assertions turned on, proceeding here will abort the application
|
||||
if (newList.size() == 0)
|
||||
return;
|
||||
|
||||
beginInsertRows(QModelIndex(), modpacks.size(), modpacks.size() + newList.size() - 1);
|
||||
modpacks.append(newList);
|
||||
endInsertRows();
|
||||
|
@@ -63,6 +63,7 @@ class ModpackListModel : public QAbstractListModel {
|
||||
|
||||
/* Retrieve information from the model at a given index with the given role */
|
||||
auto data(const QModelIndex& index, int role) const -> QVariant override;
|
||||
bool setData(const QModelIndex &index, const QVariant &value, int role) override;
|
||||
|
||||
inline void setActiveJob(NetJob::Ptr ptr) { jobPtr = ptr; }
|
||||
|
||||
|
@@ -101,18 +101,18 @@ bool ModrinthPage::eventFilter(QObject* watched, QEvent* event)
|
||||
return QObject::eventFilter(watched, event);
|
||||
}
|
||||
|
||||
void ModrinthPage::onSelectionChanged(QModelIndex first, QModelIndex second)
|
||||
void ModrinthPage::onSelectionChanged(QModelIndex curr, QModelIndex prev)
|
||||
{
|
||||
ui->versionSelectionBox->clear();
|
||||
|
||||
if (!first.isValid()) {
|
||||
if (!curr.isValid()) {
|
||||
if (isOpened) {
|
||||
dialog->setSuggestedPack();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
current = m_model->data(first, Qt::UserRole).value<Modrinth::Modpack>();
|
||||
current = m_model->data(curr, Qt::UserRole).value<Modrinth::Modpack>();
|
||||
auto name = current.name;
|
||||
|
||||
if (!current.extraInfoLoaded) {
|
||||
@@ -125,7 +125,7 @@ void ModrinthPage::onSelectionChanged(QModelIndex first, QModelIndex second)
|
||||
|
||||
netJob->addNetAction(Net::Download::makeByteArray(QString("%1/project/%2").arg(BuildConfig.MODRINTH_PROD_URL, id), response));
|
||||
|
||||
QObject::connect(netJob, &NetJob::succeeded, this, [this, response, id] {
|
||||
QObject::connect(netJob, &NetJob::succeeded, this, [this, response, id, curr] {
|
||||
if (id != current.id) {
|
||||
return; // wrong request?
|
||||
}
|
||||
@@ -149,6 +149,13 @@ void ModrinthPage::onSelectionChanged(QModelIndex first, QModelIndex second)
|
||||
}
|
||||
|
||||
updateUI();
|
||||
|
||||
QVariant current_updated;
|
||||
current_updated.setValue(current);
|
||||
|
||||
if (!m_model->setData(curr, current_updated, Qt::UserRole))
|
||||
qWarning() << "Failed to cache extra info for the current pack!";
|
||||
|
||||
suggestCurrent();
|
||||
});
|
||||
QObject::connect(netJob, &NetJob::finished, this, [response, netJob] {
|
||||
@@ -170,7 +177,7 @@ void ModrinthPage::onSelectionChanged(QModelIndex first, QModelIndex second)
|
||||
netJob->addNetAction(
|
||||
Net::Download::makeByteArray(QString("%1/project/%2/version").arg(BuildConfig.MODRINTH_PROD_URL, id), response));
|
||||
|
||||
QObject::connect(netJob, &NetJob::succeeded, this, [this, response, id] {
|
||||
QObject::connect(netJob, &NetJob::succeeded, this, [this, response, id, curr] {
|
||||
if (id != current.id) {
|
||||
return; // wrong request?
|
||||
}
|
||||
@@ -192,9 +199,18 @@ void ModrinthPage::onSelectionChanged(QModelIndex first, QModelIndex second)
|
||||
}
|
||||
|
||||
for (auto version : current.versions) {
|
||||
ui->versionSelectionBox->addItem(version.version, QVariant(version.id));
|
||||
if (!version.name.contains(version.version))
|
||||
ui->versionSelectionBox->addItem(QString("%1 — %2").arg(version.name, version.version), QVariant(version.id));
|
||||
else
|
||||
ui->versionSelectionBox->addItem(version.name, QVariant(version.id));
|
||||
}
|
||||
|
||||
QVariant current_updated;
|
||||
current_updated.setValue(current);
|
||||
|
||||
if (!m_model->setData(curr, current_updated, Qt::UserRole))
|
||||
qWarning() << "Failed to cache versions for the current pack!";
|
||||
|
||||
suggestCurrent();
|
||||
});
|
||||
QObject::connect(netJob, &NetJob::finished, this, [response, netJob] {
|
||||
@@ -205,7 +221,10 @@ void ModrinthPage::onSelectionChanged(QModelIndex first, QModelIndex second)
|
||||
|
||||
} else {
|
||||
for (auto version : current.versions) {
|
||||
ui->versionSelectionBox->addItem(QString("%1 - %2").arg(version.name, version.version), QVariant(version.id));
|
||||
if (!version.name.contains(version.version))
|
||||
ui->versionSelectionBox->addItem(QString("%1 - %2").arg(version.name, version.version), QVariant(version.id));
|
||||
else
|
||||
ui->versionSelectionBox->addItem(version.name, QVariant(version.id));
|
||||
}
|
||||
|
||||
suggestCurrent();
|
||||
@@ -224,7 +243,37 @@ void ModrinthPage::updateUI()
|
||||
// TODO: Implement multiple authors with links
|
||||
text += "<br>" + tr(" by ") + QString("<a href=%1>%2</a>").arg(std::get<1>(current.author).toString(), std::get<0>(current.author));
|
||||
|
||||
text += "<br>";
|
||||
if (current.extraInfoLoaded) {
|
||||
if (!current.extra.donate.isEmpty()) {
|
||||
text += "<br><br>" + tr("Donate information: ");
|
||||
auto donateToStr = [](Modrinth::DonationData& donate) -> QString {
|
||||
return QString("<a href=\"%1\">%2</a>").arg(donate.url, donate.platform);
|
||||
};
|
||||
QStringList donates;
|
||||
for (auto& donate : current.extra.donate) {
|
||||
donates.append(donateToStr(donate));
|
||||
}
|
||||
text += donates.join(", ");
|
||||
}
|
||||
|
||||
if (!current.extra.issuesUrl.isEmpty()
|
||||
|| !current.extra.sourceUrl.isEmpty()
|
||||
|| !current.extra.wikiUrl.isEmpty()
|
||||
|| !current.extra.discordUrl.isEmpty()) {
|
||||
text += "<br><br>" + tr("External links:") + "<br>";
|
||||
}
|
||||
|
||||
if (!current.extra.issuesUrl.isEmpty())
|
||||
text += "- " + tr("Issues: <a href=%1>%1</a>").arg(current.extra.issuesUrl) + "<br>";
|
||||
if (!current.extra.wikiUrl.isEmpty())
|
||||
text += "- " + tr("Wiki: <a href=%1>%1</a>").arg(current.extra.wikiUrl) + "<br>";
|
||||
if (!current.extra.sourceUrl.isEmpty())
|
||||
text += "- " + tr("Source code: <a href=%1>%1</a>").arg(current.extra.sourceUrl) + "<br>";
|
||||
if (!current.extra.discordUrl.isEmpty())
|
||||
text += "- " + tr("Discord: <a href=%1>%1</a>").arg(current.extra.discordUrl) + "<br>";
|
||||
}
|
||||
|
||||
text += "<hr>";
|
||||
|
||||
HoeDown h;
|
||||
text += h.process(current.extra.body.toUtf8());
|
||||
|
@@ -6,8 +6,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>837</width>
|
||||
<height>685</height>
|
||||
<width>800</width>
|
||||
<height>600</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout">
|
||||
@@ -24,6 +24,9 @@
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
@@ -60,9 +63,6 @@
|
||||
<height>48</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="uniformItemSizes">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
|
@@ -217,6 +217,11 @@ void Technic::ListModel::searchRequestFinished()
|
||||
return;
|
||||
}
|
||||
searchState = Finished;
|
||||
|
||||
// When you have a Qt build with assertions turned on, proceeding here will abort the application
|
||||
if (newList.size() == 0)
|
||||
return;
|
||||
|
||||
beginInsertRows(QModelIndex(), modpacks.size(), modpacks.size() + newList.size() - 1);
|
||||
modpacks.append(newList);
|
||||
endInsertRows();
|
||||
|
@@ -60,7 +60,11 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QTextBrowser" name="packDescription"/>
|
||||
<widget class="QTextBrowser" name="packDescription">
|
||||
<property name="openExternalLinks">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
|
42
launcher/ui/setupwizard/PasteWizardPage.cpp
Normal file
42
launcher/ui/setupwizard/PasteWizardPage.cpp
Normal file
@@ -0,0 +1,42 @@
|
||||
#include "PasteWizardPage.h"
|
||||
#include "ui_PasteWizardPage.h"
|
||||
|
||||
#include "Application.h"
|
||||
#include "net/PasteUpload.h"
|
||||
|
||||
PasteWizardPage::PasteWizardPage(QWidget *parent) :
|
||||
BaseWizardPage(parent),
|
||||
ui(new Ui::PasteWizardPage)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
}
|
||||
|
||||
PasteWizardPage::~PasteWizardPage()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void PasteWizardPage::initializePage()
|
||||
{
|
||||
}
|
||||
|
||||
bool PasteWizardPage::validatePage()
|
||||
{
|
||||
auto s = APPLICATION->settings();
|
||||
QString prevPasteURL = s->get("PastebinURL").toString();
|
||||
s->reset("PastebinURL");
|
||||
if (ui->previousSettingsRadioButton->isChecked())
|
||||
{
|
||||
bool usingDefaultBase = prevPasteURL == PasteUpload::PasteTypes.at(PasteUpload::PasteType::NullPointer).defaultBase;
|
||||
s->set("PastebinType", PasteUpload::PasteType::NullPointer);
|
||||
if (!usingDefaultBase)
|
||||
s->set("PastebinCustomAPIBase", prevPasteURL);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void PasteWizardPage::retranslate()
|
||||
{
|
||||
ui->retranslateUi(this);
|
||||
}
|
27
launcher/ui/setupwizard/PasteWizardPage.h
Normal file
27
launcher/ui/setupwizard/PasteWizardPage.h
Normal file
@@ -0,0 +1,27 @@
|
||||
#ifndef PASTEDEFAULTSCONFIRMATIONWIZARD_H
|
||||
#define PASTEDEFAULTSCONFIRMATIONWIZARD_H
|
||||
|
||||
#include <QWidget>
|
||||
#include "BaseWizardPage.h"
|
||||
|
||||
namespace Ui {
|
||||
class PasteWizardPage;
|
||||
}
|
||||
|
||||
class PasteWizardPage : public BaseWizardPage
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit PasteWizardPage(QWidget *parent = nullptr);
|
||||
~PasteWizardPage();
|
||||
|
||||
void initializePage() override;
|
||||
bool validatePage() override;
|
||||
void retranslate() override;
|
||||
|
||||
private:
|
||||
Ui::PasteWizardPage *ui;
|
||||
};
|
||||
|
||||
#endif // PASTEDEFAULTSCONFIRMATIONWIZARD_H
|
80
launcher/ui/setupwizard/PasteWizardPage.ui
Normal file
80
launcher/ui/setupwizard/PasteWizardPage.ui
Normal file
@@ -0,0 +1,80 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>PasteWizardPage</class>
|
||||
<widget class="QWidget" name="PasteWizardPage">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>400</width>
|
||||
<height>300</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>The default paste service has changed to mclo.gs, please choose what you want to do with your settings.</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Line" name="line">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="defaultSettingsRadioButton">
|
||||
<property name="text">
|
||||
<string>Use new default service</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<attribute name="buttonGroup">
|
||||
<string notr="true">buttonGroup</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="previousSettingsRadioButton">
|
||||
<property name="text">
|
||||
<string>Keep previous settings</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<attribute name="buttonGroup">
|
||||
<string notr="true">buttonGroup</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>156</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
<buttongroups>
|
||||
<buttongroup name="buttonGroup"/>
|
||||
</buttongroups>
|
||||
</ui>
|
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Copyright (c) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.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
|
||||
|
@@ -1,7 +1,7 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Copyright (c) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.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
|
||||
|
@@ -11,6 +11,7 @@
|
||||
|
||||
#include <sys.h>
|
||||
|
||||
#include "JavaCommon.h"
|
||||
#include "java/JavaInstall.h"
|
||||
#include "java/JavaUtils.h"
|
||||
#include "FileSystem.h"
|
||||
@@ -133,6 +134,10 @@ void JavaSettingsWidget::initialize()
|
||||
|
||||
void JavaSettingsWidget::refresh()
|
||||
{
|
||||
if (JavaUtils::getJavaCheckPath().isEmpty()) {
|
||||
JavaCommon::javaCheckNotFound(this);
|
||||
return;
|
||||
}
|
||||
m_versionWidget->loadList();
|
||||
}
|
||||
|
||||
|
@@ -1,16 +1,36 @@
|
||||
/* Copyright 2013-2021 MultiMC Contributors
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* PolyMC - Minecraft Launcher
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||
*
|
||||
* 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
|
||||
* 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.
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
* 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 <QLabel>
|
||||
@@ -80,9 +100,7 @@ QSize LabeledToolButton::sizeHint() const
|
||||
if (popupMode() == MenuButtonPopup)
|
||||
w += style()->pixelMetric(QStyle::PM_MenuButtonIndicator, &opt, this);
|
||||
|
||||
QSize rawSize = style()->sizeFromContents(QStyle::CT_ToolButton, &opt, QSize(w, h), this);
|
||||
QSize sizeHint = rawSize.expandedTo(QApplication::globalStrut());
|
||||
return sizeHint;
|
||||
return style()->sizeFromContents(QStyle::CT_ToolButton, &opt, QSize(w, h), this);
|
||||
}
|
||||
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user