Merge branch 'develop' into curseforge-url-handle
This commit is contained in:
@ -35,15 +35,16 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QString>
|
||||
#include <QIcon>
|
||||
#include <QString>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
#include "BasePageContainer.h"
|
||||
|
||||
class BasePage
|
||||
{
|
||||
public:
|
||||
class BasePage {
|
||||
public:
|
||||
using updateExtraInfoFunc = std::function<void(QString, QString)>;
|
||||
virtual ~BasePage() {}
|
||||
virtual QString id() const = 0;
|
||||
virtual QString displayName() const = 0;
|
||||
@ -63,17 +64,16 @@ public:
|
||||
}
|
||||
virtual void openedImpl() {}
|
||||
virtual void closedImpl() {}
|
||||
virtual void setParentContainer(BasePageContainer * container)
|
||||
{
|
||||
m_container = container;
|
||||
};
|
||||
virtual void retranslate() { }
|
||||
virtual void setParentContainer(BasePageContainer* container) { m_container = container; };
|
||||
virtual void retranslate() {}
|
||||
|
||||
public:
|
||||
public:
|
||||
int stackIndex = -1;
|
||||
int listIndex = -1;
|
||||
protected:
|
||||
BasePageContainer * m_container = nullptr;
|
||||
updateExtraInfoFunc updateExtraInfo;
|
||||
|
||||
protected:
|
||||
BasePageContainer* m_container = nullptr;
|
||||
bool isOpened = false;
|
||||
};
|
||||
|
||||
|
@ -81,6 +81,8 @@ APIPage::APIPage(QWidget *parent) :
|
||||
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());
|
||||
// NOTE: this allows http://, but we replace that with https later anyway
|
||||
ui->metaURL->setValidator(new QRegularExpressionValidator(validUrlRegExp, ui->metaURL));
|
||||
ui->baseURLEntry->setValidator(new QRegularExpressionValidator(validUrlRegExp, ui->baseURLEntry));
|
||||
ui->msaClientID->setValidator(new QRegularExpressionValidator(validMSAClientID, ui->msaClientID));
|
||||
ui->flameKey->setValidator(new QRegularExpressionValidator(validFlameKey, ui->flameKey));
|
||||
@ -163,7 +165,7 @@ void APIPage::applySettings()
|
||||
|
||||
QString msaClientID = ui->msaClientID->text();
|
||||
s->set("MSAClientIDOverride", msaClientID);
|
||||
QUrl metaURL = ui->metaURL->text();
|
||||
QUrl metaURL(ui->metaURL->text());
|
||||
// Add required trailing slash
|
||||
if (!metaURL.isEmpty() && !metaURL.path().endsWith('/'))
|
||||
{
|
||||
@ -177,7 +179,7 @@ void APIPage::applySettings()
|
||||
metaURL.setScheme("https");
|
||||
}
|
||||
|
||||
s->set("MetaURLOverride", metaURL);
|
||||
s->set("MetaURLOverride", metaURL.toString());
|
||||
QString flameKey = ui->flameKey->text();
|
||||
s->set("FlameKeyOverride", flameKey);
|
||||
QString modrinthToken = ui->modrinthToken->text();
|
||||
|
@ -169,10 +169,10 @@
|
||||
<item>
|
||||
<widget class="QCheckBox" name="metadataDisableBtn">
|
||||
<property name="toolTip">
|
||||
<string>Disable using metadata provided by mod providers (like Modrinth or Curseforge) for mods.</string>
|
||||
<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>
|
||||
<string>Disable using metadata for mods</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -307,21 +307,21 @@
|
||||
<item>
|
||||
<widget class="QCheckBox" name="showConsoleCheck">
|
||||
<property name="text">
|
||||
<string>Show console while the game is &running?</string>
|
||||
<string>Show console while the game is &running</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="autoCloseConsoleCheck">
|
||||
<property name="text">
|
||||
<string>&Automatically close console when the game quits?</string>
|
||||
<string>&Automatically close console when the game quits</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="showConsoleErrorCheck">
|
||||
<property name="text">
|
||||
<string>Show console when the game &crashes?</string>
|
||||
<string>Show console when the game &crashes</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
@ -51,7 +51,7 @@
|
||||
<item>
|
||||
<widget class="QCheckBox" name="maximizedCheckBox">
|
||||
<property name="text">
|
||||
<string>Start Minecraft &maximized?</string>
|
||||
<string>Start Minecraft &maximized</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
@ -1,3 +1,38 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
/*
|
||||
* Prism Launcher - Minecraft Launcher
|
||||
* Copyright (c) 2023 Trial97 <alexandru.tripon97@gmail.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
* 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 "ExternalResourcesPage.h"
|
||||
#include "ui/dialogs/CustomMessageBox.h"
|
||||
#include "ui_ExternalResourcesPage.h"
|
||||
@ -9,6 +44,7 @@
|
||||
|
||||
#include <QKeyEvent>
|
||||
#include <QMenu>
|
||||
#include <algorithm>
|
||||
|
||||
ExternalResourcesPage::ExternalResourcesPage(BaseInstance* instance, std::shared_ptr<ResourceFolderModel> model, QWidget* parent)
|
||||
: QMainWindow(parent), m_instance(instance), ui(new Ui::ExternalResourcesPage), m_model(model)
|
||||
@ -24,6 +60,8 @@ ExternalResourcesPage::ExternalResourcesPage(BaseInstance* instance, std::shared
|
||||
m_filterModel->setSourceModel(m_model.get());
|
||||
m_filterModel->setFilterKeyColumn(-1);
|
||||
ui->treeView->setModel(m_filterModel);
|
||||
// must come after setModel
|
||||
ui->treeView->setResizeModes(m_model->columnResizeModes());
|
||||
|
||||
ui->treeView->installEventFilter(this);
|
||||
ui->treeView->sortByColumn(1, Qt::AscendingOrder);
|
||||
@ -43,7 +81,21 @@ ExternalResourcesPage::ExternalResourcesPage(BaseInstance* instance, std::shared
|
||||
|
||||
auto selection_model = ui->treeView->selectionModel();
|
||||
connect(selection_model, &QItemSelectionModel::currentChanged, this, &ExternalResourcesPage::current);
|
||||
auto updateExtra = [this]() {
|
||||
if (updateExtraInfo)
|
||||
updateExtraInfo(id(), extraHeaderInfoString());
|
||||
};
|
||||
connect(selection_model, &QItemSelectionModel::selectionChanged, this, updateExtra);
|
||||
connect(model.get(), &ResourceFolderModel::updateFinished, this, updateExtra);
|
||||
|
||||
connect(ui->filterEdit, &QLineEdit::textChanged, this, &ExternalResourcesPage::filterTextChanged);
|
||||
|
||||
auto viewHeader = ui->treeView->header();
|
||||
viewHeader->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
|
||||
connect(viewHeader, &QHeaderView::customContextMenuRequested, this, &ExternalResourcesPage::ShowHeaderContextMenu);
|
||||
|
||||
m_model->loadHiddenColumns(ui->treeView);
|
||||
}
|
||||
|
||||
ExternalResourcesPage::~ExternalResourcesPage()
|
||||
@ -65,6 +117,13 @@ void ExternalResourcesPage::ShowContextMenu(const QPoint& pos)
|
||||
delete menu;
|
||||
}
|
||||
|
||||
void ExternalResourcesPage::ShowHeaderContextMenu(const QPoint& pos)
|
||||
{
|
||||
auto menu = m_model->createHeaderContextMenu(ui->treeView);
|
||||
menu->exec(ui->treeView->mapToGlobal(pos));
|
||||
menu->deleteLater();
|
||||
}
|
||||
|
||||
void ExternalResourcesPage::openedImpl()
|
||||
{
|
||||
m_model->startWatching();
|
||||
@ -92,11 +151,7 @@ void ExternalResourcesPage::retranslate()
|
||||
|
||||
void ExternalResourcesPage::itemActivated(const QModelIndex&)
|
||||
{
|
||||
if (!m_controlsEnabled)
|
||||
return;
|
||||
|
||||
auto selection = m_filterModel->mapSelectionToSource(ui->treeView->selectionModel()->selection());
|
||||
m_model->setResourceEnabled(selection.indexes(), EnableAction::TOGGLE);
|
||||
}
|
||||
|
||||
void ExternalResourcesPage::filterTextChanged(const QString& newContents)
|
||||
@ -139,9 +194,6 @@ bool ExternalResourcesPage::eventFilter(QObject* obj, QEvent* 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());
|
||||
@ -155,9 +207,6 @@ void ExternalResourcesPage::addItem()
|
||||
|
||||
void ExternalResourcesPage::removeItem()
|
||||
{
|
||||
if (!m_controlsEnabled)
|
||||
return;
|
||||
|
||||
auto selection = m_filterModel->mapSelectionToSource(ui->treeView->selectionModel()->selection());
|
||||
|
||||
int count = 0;
|
||||
@ -201,23 +250,37 @@ void ExternalResourcesPage::removeItem()
|
||||
|
||||
void ExternalResourcesPage::removeItems(const QItemSelection& selection)
|
||||
{
|
||||
if (m_instance != nullptr && m_instance->isRunning()) {
|
||||
auto response = CustomMessageBox::selectable(this, "Confirm Delete",
|
||||
"If you remove this resource while the game is running it may crash your game.\n"
|
||||
"Are you sure you want to do this?",
|
||||
QMessageBox::Warning, QMessageBox::Yes | QMessageBox::No, QMessageBox::No)
|
||||
->exec();
|
||||
|
||||
if (response != QMessageBox::Yes)
|
||||
return;
|
||||
}
|
||||
m_model->deleteResources(selection.indexes());
|
||||
}
|
||||
|
||||
void ExternalResourcesPage::enableItem()
|
||||
{
|
||||
if (!m_controlsEnabled)
|
||||
return;
|
||||
|
||||
auto selection = m_filterModel->mapSelectionToSource(ui->treeView->selectionModel()->selection());
|
||||
m_model->setResourceEnabled(selection.indexes(), EnableAction::ENABLE);
|
||||
}
|
||||
|
||||
void ExternalResourcesPage::disableItem()
|
||||
{
|
||||
if (!m_controlsEnabled)
|
||||
return;
|
||||
if (m_instance != nullptr && m_instance->isRunning()) {
|
||||
auto response = CustomMessageBox::selectable(this, "Confirm disable",
|
||||
"If you disable this resource while the game is running it may crash your game.\n"
|
||||
"Are you sure you want to do this?",
|
||||
QMessageBox::Warning, QMessageBox::Yes | QMessageBox::No, QMessageBox::No)
|
||||
->exec();
|
||||
|
||||
if (response != QMessageBox::Yes)
|
||||
return;
|
||||
}
|
||||
auto selection = m_filterModel->mapSelectionToSource(ui->treeView->selectionModel()->selection());
|
||||
m_model->setResourceEnabled(selection.indexes(), EnableAction::DISABLE);
|
||||
}
|
||||
@ -248,6 +311,15 @@ bool ExternalResourcesPage::onSelectionChanged(const QModelIndex& current, const
|
||||
int row = sourceCurrent.row();
|
||||
Resource const& resource = m_model->at(row);
|
||||
ui->frame->updateWithResource(resource);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
QString ExternalResourcesPage::extraHeaderInfoString()
|
||||
{
|
||||
if (ui && ui->treeView && ui->treeView->selectionModel()) {
|
||||
auto selection = m_filterModel->mapSelectionToSource(ui->treeView->selectionModel()->selection()).indexes();
|
||||
if (auto count = std::count_if(selection.cbegin(), selection.cend(), [](auto v) { return v.column() == 0; }); count != 0)
|
||||
return tr(" (%1 installed, %2 selected)").arg(m_model->size()).arg(count);
|
||||
}
|
||||
return tr(" (%1 installed)").arg(m_model->size());
|
||||
}
|
||||
|
@ -29,6 +29,7 @@ class ExternalResourcesPage : public QMainWindow, public BasePage {
|
||||
virtual QString helpPage() const override = 0;
|
||||
|
||||
virtual bool shouldDisplay() const override = 0;
|
||||
QString extraHeaderInfoString();
|
||||
|
||||
void openedImpl() override;
|
||||
void closedImpl() override;
|
||||
@ -60,6 +61,7 @@ class ExternalResourcesPage : public QMainWindow, public BasePage {
|
||||
virtual void viewConfigs();
|
||||
|
||||
void ShowContextMenu(const QPoint& pos);
|
||||
void ShowHeaderContextMenu(const QPoint& pos);
|
||||
|
||||
protected:
|
||||
BaseInstance* m_instance = nullptr;
|
||||
@ -71,7 +73,5 @@ class ExternalResourcesPage : public QMainWindow, public BasePage {
|
||||
QString m_fileSelectionFilter;
|
||||
QString m_viewFilter;
|
||||
|
||||
bool m_controlsEnabled = true;
|
||||
|
||||
std::shared_ptr<Setting> m_wide_bar_setting = nullptr;
|
||||
};
|
||||
|
@ -62,6 +62,9 @@
|
||||
<property name="dragDropMode">
|
||||
<enum>QAbstractItemView::DropOnly</enum>
|
||||
</property>
|
||||
<property name="uniformRowHeights">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
@ -154,6 +157,17 @@
|
||||
<string>Try to check or update all selected resources (all resources if none are selected)</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionVisitItemPage">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Visit mod's page</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Go to mods home page</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
|
@ -60,21 +60,14 @@ InstanceSettingsPage::InstanceSettingsPage(BaseInstance *inst, QWidget *parent)
|
||||
m_settings = inst->settings();
|
||||
ui->setupUi(this);
|
||||
|
||||
accountMenu = new QMenu(this);
|
||||
// Use undocumented property... https://stackoverflow.com/questions/7121718/create-a-scrollbar-in-a-submenu-qt
|
||||
accountMenu->setStyleSheet("QMenu { menu-scrollable: 1; }");
|
||||
ui->instanceAccountSelector->setMenu(accountMenu);
|
||||
|
||||
connect(ui->openGlobalJavaSettingsButton, &QCommandLinkButton::clicked, this, &InstanceSettingsPage::globalSettingsButtonClicked);
|
||||
connect(APPLICATION, &Application::globalSettingsAboutToOpen, this, &InstanceSettingsPage::applySettings);
|
||||
connect(APPLICATION, &Application::globalSettingsClosed, this, &InstanceSettingsPage::loadSettings);
|
||||
connect(ui->instanceAccountSelector, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
|
||||
&InstanceSettingsPage::changeInstanceAccount);
|
||||
loadSettings();
|
||||
updateThresholds();
|
||||
}
|
||||
|
||||
bool InstanceSettingsPage::shouldDisplay() const
|
||||
{
|
||||
return !m_instance->isRunning();
|
||||
updateThresholds();
|
||||
}
|
||||
|
||||
InstanceSettingsPage::~InstanceSettingsPage()
|
||||
@ -88,12 +81,12 @@ void InstanceSettingsPage::globalSettingsButtonClicked(bool)
|
||||
case 0:
|
||||
APPLICATION->ShowGlobalSettings(this, "java-settings");
|
||||
return;
|
||||
case 1:
|
||||
APPLICATION->ShowGlobalSettings(this, "minecraft-settings");
|
||||
return;
|
||||
case 2:
|
||||
APPLICATION->ShowGlobalSettings(this, "custom-commands");
|
||||
return;
|
||||
default:
|
||||
APPLICATION->ShowGlobalSettings(this, "minecraft-settings");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@ -454,36 +447,17 @@ void InstanceSettingsPage::on_javaTestBtn_clicked()
|
||||
|
||||
void InstanceSettingsPage::updateAccountsMenu()
|
||||
{
|
||||
accountMenu->clear();
|
||||
|
||||
ui->instanceAccountSelector->clear();
|
||||
auto accounts = APPLICATION->accounts();
|
||||
int accountIndex = accounts->findAccountByProfileId(m_settings->get("InstanceAccountId").toString());
|
||||
MinecraftAccountPtr defaultAccount = accounts->defaultAccount();
|
||||
|
||||
if (accountIndex != -1 && accounts->at(accountIndex)) {
|
||||
defaultAccount = accounts->at(accountIndex);
|
||||
}
|
||||
|
||||
if (defaultAccount) {
|
||||
ui->instanceAccountSelector->setText(defaultAccount->profileName());
|
||||
ui->instanceAccountSelector->setIcon(getFaceForAccount(defaultAccount));
|
||||
} else {
|
||||
ui->instanceAccountSelector->setText(tr("No default account"));
|
||||
ui->instanceAccountSelector->setIcon(APPLICATION->getThemedIcon("noaccount"));
|
||||
}
|
||||
|
||||
for (int i = 0; i < accounts->count(); i++) {
|
||||
MinecraftAccountPtr account = accounts->at(i);
|
||||
QAction* action = new QAction(account->profileName(), this);
|
||||
action->setData(i);
|
||||
action->setCheckable(true);
|
||||
if (accountIndex == i) {
|
||||
action->setChecked(true);
|
||||
}
|
||||
action->setIcon(getFaceForAccount(account));
|
||||
accountMenu->addAction(action);
|
||||
connect(action, SIGNAL(triggered(bool)), this, SLOT(changeInstanceAccount()));
|
||||
ui->instanceAccountSelector->addItem(getFaceForAccount(account), account->profileName(), i);
|
||||
if (i == accountIndex)
|
||||
ui->instanceAccountSelector->setCurrentIndex(i);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
QIcon InstanceSettingsPage::getFaceForAccount(MinecraftAccountPtr account)
|
||||
@ -495,20 +469,13 @@ QIcon InstanceSettingsPage::getFaceForAccount(MinecraftAccountPtr account)
|
||||
return APPLICATION->getThemedIcon("noaccount");
|
||||
}
|
||||
|
||||
void InstanceSettingsPage::changeInstanceAccount()
|
||||
void InstanceSettingsPage::changeInstanceAccount(int index)
|
||||
{
|
||||
QAction* sAction = (QAction*)sender();
|
||||
|
||||
Q_ASSERT(sAction->data().type() == QVariant::Type::Int);
|
||||
|
||||
QVariant data = sAction->data();
|
||||
int index = data.toInt();
|
||||
auto accounts = APPLICATION->accounts();
|
||||
auto account = accounts->at(index);
|
||||
m_settings->set("InstanceAccountId", account->profileId());
|
||||
|
||||
ui->instanceAccountSelector->setText(account->profileName());
|
||||
ui->instanceAccountSelector->setIcon(getFaceForAccount(account));
|
||||
if (index != -1 && accounts->at(index) && ui->instanceAccountGroupBox->isChecked()) {
|
||||
auto account = accounts->at(index);
|
||||
m_settings->set("InstanceAccountId", account->profileId());
|
||||
}
|
||||
}
|
||||
|
||||
void InstanceSettingsPage::on_maxMemSpinBox_valueChanged(int i)
|
||||
|
@ -75,12 +75,11 @@ public:
|
||||
{
|
||||
return "Instance-settings";
|
||||
}
|
||||
virtual bool shouldDisplay() const override;
|
||||
void retranslate() override;
|
||||
|
||||
void updateThresholds();
|
||||
|
||||
private slots:
|
||||
private slots:
|
||||
void on_javaDetectBtn_clicked();
|
||||
void on_javaTestBtn_clicked();
|
||||
void on_javaBrowseBtn_clicked();
|
||||
@ -95,12 +94,11 @@ private slots:
|
||||
|
||||
void updateAccountsMenu();
|
||||
QIcon getFaceForAccount(MinecraftAccountPtr account);
|
||||
void changeInstanceAccount();
|
||||
void changeInstanceAccount(int index);
|
||||
|
||||
private:
|
||||
Ui::InstanceSettingsPage *ui;
|
||||
BaseInstance *m_instance;
|
||||
SettingsObjectPtr m_settings;
|
||||
unique_qobject_ptr<JavaCommon::TestCheck> checker;
|
||||
QMenu *accountMenu = nullptr;
|
||||
};
|
||||
|
@ -269,7 +269,7 @@
|
||||
<item>
|
||||
<widget class="QCheckBox" name="maximizedCheckBox">
|
||||
<property name="text">
|
||||
<string>Start Minecraft maximized?</string>
|
||||
<string>Start Minecraft maximized</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -341,21 +341,21 @@
|
||||
<item>
|
||||
<widget class="QCheckBox" name="showConsoleCheck">
|
||||
<property name="text">
|
||||
<string>Show console while the game is running?</string>
|
||||
<string>Show console while the game is running</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="autoCloseConsoleCheck">
|
||||
<property name="text">
|
||||
<string>Automatically close console when the game quits?</string>
|
||||
<string>Automatically close console when the game quits</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="showConsoleErrorCheck">
|
||||
<property name="text">
|
||||
<string>Show console when the game crashes?</string>
|
||||
<string>Show console when the game crashes</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -636,14 +636,7 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QToolButton" name="instanceAccountSelector">
|
||||
<property name="popupMode">
|
||||
<enum>QToolButton::InstantPopup</enum>
|
||||
</property>
|
||||
<property name="toolButtonStyle">
|
||||
<enum>Qt::ToolButtonTextBesideIcon</enum>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QComboBox" name="instanceAccountSelector"/>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
|
@ -30,8 +30,6 @@ class NoBigComboBoxStyle : public QProxyStyle {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
NoBigComboBoxStyle(QStyle* style) : QProxyStyle(style) {}
|
||||
|
||||
// clang-format off
|
||||
int styleHint(QStyle::StyleHint hint, const QStyleOption* option = nullptr, const QWidget* widget = nullptr, QStyleHintReturn* returnData = nullptr) const override
|
||||
{
|
||||
@ -41,6 +39,37 @@ class NoBigComboBoxStyle : public QProxyStyle {
|
||||
return QProxyStyle::styleHint(hint, option, widget, returnData);
|
||||
}
|
||||
// clang-format on
|
||||
|
||||
/**
|
||||
* Something about QProxyStyle and QStyle objects means they can't be free'd just
|
||||
* because all the widgets using them are gone.
|
||||
* They seems to be tied to the QApplicaiton lifecycle.
|
||||
* So make singletons tied to the lifetime of the application to clean them up and ensure they aren't
|
||||
* being remade over and over again, thus leaking memory.
|
||||
*/
|
||||
public:
|
||||
static NoBigComboBoxStyle* getInstance(QStyle* style)
|
||||
{
|
||||
static QHash<QStyle*, NoBigComboBoxStyle*> s_singleton_instances_ = {};
|
||||
static std::mutex s_singleton_instances_mutex_;
|
||||
|
||||
std::lock_guard<std::mutex> lock(s_singleton_instances_mutex_);
|
||||
auto inst_iter = s_singleton_instances_.constFind(style);
|
||||
NoBigComboBoxStyle* inst = nullptr;
|
||||
if (inst_iter == s_singleton_instances_.constEnd() || *inst_iter == nullptr) {
|
||||
inst = new NoBigComboBoxStyle(style);
|
||||
inst->setParent(APPLICATION);
|
||||
s_singleton_instances_.insert(style, inst);
|
||||
qDebug() << "QProxyStyle NoBigComboBox created for" << style->objectName() << style;
|
||||
} else {
|
||||
inst = *inst_iter;
|
||||
}
|
||||
return inst;
|
||||
}
|
||||
|
||||
private:
|
||||
NoBigComboBoxStyle(QStyle* style) : QProxyStyle(style) {}
|
||||
|
||||
};
|
||||
|
||||
ManagedPackPage* ManagedPackPage::createPage(BaseInstance* inst, QString type, QWidget* parent)
|
||||
@ -62,8 +91,10 @@ ManagedPackPage::ManagedPackPage(BaseInstance* inst, InstanceWindow* instance_wi
|
||||
|
||||
// NOTE: GTK2 themes crash with the proxy style.
|
||||
// This seems like an upstream bug, so there's not much else that can be done.
|
||||
if (!QStyleFactory::keys().contains("gtk2"))
|
||||
ui->versionsComboBox->setStyle(new NoBigComboBoxStyle(ui->versionsComboBox->style()));
|
||||
if (!QStyleFactory::keys().contains("gtk2")){
|
||||
auto comboStyle = NoBigComboBoxStyle::getInstance(ui->versionsComboBox->style());
|
||||
ui->versionsComboBox->setStyle(comboStyle);
|
||||
}
|
||||
|
||||
ui->reloadButton->setVisible(false);
|
||||
connect(ui->reloadButton, &QPushButton::clicked, this, [this](bool){
|
||||
@ -174,7 +205,7 @@ ModrinthManagedPackPage::ModrinthManagedPackPage(BaseInstance* inst, InstanceWin
|
||||
{
|
||||
Q_ASSERT(inst->isManagedPack());
|
||||
connect(ui->versionsComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(suggestVersion()));
|
||||
connect(ui->updateButton, &QPushButton::pressed, this, &ModrinthManagedPackPage::update);
|
||||
connect(ui->updateButton, &QPushButton::clicked, this, &ModrinthManagedPackPage::update);
|
||||
}
|
||||
|
||||
// MODRINTH
|
||||
@ -195,7 +226,7 @@ void ModrinthManagedPackPage::parseManagedPack()
|
||||
|
||||
QString id = m_inst->getManagedPackID();
|
||||
|
||||
m_fetch_job->addNetAction(Net::Download::makeByteArray(QString("%1/project/%2/version").arg(BuildConfig.MODRINTH_PROD_URL, id), response.get()));
|
||||
m_fetch_job->addNetAction(Net::Download::makeByteArray(QString("%1/project/%2/version").arg(BuildConfig.MODRINTH_PROD_URL, id), response));
|
||||
|
||||
QObject::connect(m_fetch_job.get(), &NetJob::succeeded, this, [this, response, id] {
|
||||
QJsonParseError parse_error{};
|
||||
@ -301,7 +332,7 @@ FlameManagedPackPage::FlameManagedPackPage(BaseInstance* inst, InstanceWindow* i
|
||||
{
|
||||
Q_ASSERT(inst->isManagedPack());
|
||||
connect(ui->versionsComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(suggestVersion()));
|
||||
connect(ui->updateButton, &QPushButton::pressed, this, &FlameManagedPackPage::update);
|
||||
connect(ui->updateButton, &QPushButton::clicked, this, &FlameManagedPackPage::update);
|
||||
}
|
||||
|
||||
void FlameManagedPackPage::parseManagedPack()
|
||||
@ -338,7 +369,7 @@ void FlameManagedPackPage::parseManagedPack()
|
||||
|
||||
QString id = m_inst->getManagedPackID();
|
||||
|
||||
m_fetch_job->addNetAction(Net::Download::makeByteArray(QString("%1/mods/%2/files").arg(BuildConfig.FLAME_BASE_URL, id), response.get()));
|
||||
m_fetch_job->addNetAction(Net::Download::makeByteArray(QString("%1/mods/%2/files").arg(BuildConfig.FLAME_BASE_URL, id), response));
|
||||
|
||||
QObject::connect(m_fetch_job.get(), &NetJob::succeeded, this, [this, response, id] {
|
||||
QJsonParseError parse_error{};
|
||||
|
@ -4,6 +4,7 @@
|
||||
* Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||
* Copyright (C) 2022 TheKodeToad <TheKodeToad@proton.me>
|
||||
* Copyright (c) 2023 Trial97 <alexandru.tripon97@gmail.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@ -44,6 +45,7 @@
|
||||
#include <QMenu>
|
||||
#include <QMessageBox>
|
||||
#include <QSortFilterProxyModel>
|
||||
#include <algorithm>
|
||||
|
||||
#include "Application.h"
|
||||
|
||||
@ -59,6 +61,7 @@
|
||||
#include "minecraft/mod/Mod.h"
|
||||
#include "minecraft/mod/ModFolderModel.h"
|
||||
|
||||
#include "modplatform/ModIndex.h"
|
||||
#include "modplatform/ResourceAPI.h"
|
||||
|
||||
#include "Version.h"
|
||||
@ -85,45 +88,40 @@ ModFolderPage::ModFolderPage(BaseInstance* inst, std::shared_ptr<ModFolderModel>
|
||||
ui->actionsToolbar->insertActionAfter(ui->actionAddItem, ui->actionUpdateItem);
|
||||
connect(ui->actionUpdateItem, &QAction::triggered, this, &ModFolderPage::updateMods);
|
||||
|
||||
auto check_allow_update = [this] {
|
||||
return (!m_instance || !m_instance->isRunning()) &&
|
||||
(ui->treeView->selectionModel()->hasSelection() || !m_model->empty());
|
||||
};
|
||||
ui->actionVisitItemPage->setToolTip(tr("Go to mod's home page"));
|
||||
ui->actionsToolbar->addAction(ui->actionVisitItemPage);
|
||||
connect(ui->actionVisitItemPage, &QAction::triggered, this, &ModFolderPage::visitModPages);
|
||||
|
||||
auto check_allow_update = [this] { return ui->treeView->selectionModel()->hasSelection() || !m_model->empty(); };
|
||||
|
||||
connect(ui->treeView->selectionModel(), &QItemSelectionModel::selectionChanged, this, [this, check_allow_update] {
|
||||
ui->actionUpdateItem->setEnabled(check_allow_update());
|
||||
|
||||
auto selection = m_filterModel->mapSelectionToSource(ui->treeView->selectionModel()->selection()).indexes();
|
||||
auto mods_list = m_model->selectedMods(selection);
|
||||
auto selected = std::count_if(mods_list.cbegin(), mods_list.cend(),
|
||||
[](Mod* v) { return v->metadata() != nullptr || v->homeurl().size() != 0; });
|
||||
if (selected <= 1) {
|
||||
ui->actionVisitItemPage->setText(tr("Visit mod's page"));
|
||||
ui->actionVisitItemPage->setToolTip(tr("Go to mod's home page"));
|
||||
} else {
|
||||
ui->actionVisitItemPage->setText(tr("Visit mods' pages"));
|
||||
ui->actionVisitItemPage->setToolTip(tr("Go to the pages of the selected mods"));
|
||||
}
|
||||
ui->actionVisitItemPage->setEnabled(selected != 0);
|
||||
});
|
||||
|
||||
connect(mods.get(), &ModFolderModel::rowsInserted, this, [this, check_allow_update] {
|
||||
ui->actionUpdateItem->setEnabled(check_allow_update());
|
||||
});
|
||||
connect(mods.get(), &ModFolderModel::rowsInserted, this,
|
||||
[this, check_allow_update] { ui->actionUpdateItem->setEnabled(check_allow_update()); });
|
||||
|
||||
connect(mods.get(), &ModFolderModel::rowsRemoved, this, [this, check_allow_update] {
|
||||
ui->actionUpdateItem->setEnabled(check_allow_update());
|
||||
});
|
||||
connect(mods.get(), &ModFolderModel::rowsRemoved, this,
|
||||
[this, check_allow_update] { ui->actionUpdateItem->setEnabled(check_allow_update()); });
|
||||
|
||||
connect(mods.get(), &ModFolderModel::updateFinished, this, [this, check_allow_update, mods] {
|
||||
ui->actionUpdateItem->setEnabled(check_allow_update());
|
||||
|
||||
// Prevent a weird crash when trying to open the mods page twice in a session o.O
|
||||
disconnect(mods.get(), &ModFolderModel::updateFinished, this, 0);
|
||||
});
|
||||
|
||||
connect(m_instance, &BaseInstance::runningStatusChanged, this, &ModFolderPage::runningStateChanged);
|
||||
ModFolderPage::runningStateChanged(m_instance && m_instance->isRunning());
|
||||
connect(mods.get(), &ModFolderModel::updateFinished, this,
|
||||
[this, check_allow_update] { ui->actionUpdateItem->setEnabled(check_allow_update()); });
|
||||
}
|
||||
}
|
||||
|
||||
void ModFolderPage::runningStateChanged(bool running)
|
||||
{
|
||||
ui->actionDownloadItem->setEnabled(!running);
|
||||
ui->actionUpdateItem->setEnabled(!running);
|
||||
ui->actionAddItem->setEnabled(!running);
|
||||
ui->actionEnableItem->setEnabled(!running);
|
||||
ui->actionDisableItem->setEnabled(!running);
|
||||
ui->actionRemoveItem->setEnabled(!running);
|
||||
}
|
||||
|
||||
bool ModFolderPage::shouldDisplay() const
|
||||
{
|
||||
return true;
|
||||
@ -140,15 +138,23 @@ bool ModFolderPage::onSelectionChanged(const QModelIndex& current, const QModelI
|
||||
return true;
|
||||
}
|
||||
|
||||
void ModFolderPage::removeItems(const QItemSelection &selection)
|
||||
void ModFolderPage::removeItems(const QItemSelection& selection)
|
||||
{
|
||||
if (m_instance != nullptr && m_instance->isRunning()) {
|
||||
auto response = CustomMessageBox::selectable(this, "Confirm Delete",
|
||||
"If you remove mods while the game is running it may crash your game.\n"
|
||||
"Are you sure you want to do this?",
|
||||
QMessageBox::Warning, QMessageBox::Yes | QMessageBox::No, QMessageBox::No)
|
||||
->exec();
|
||||
|
||||
if (response != QMessageBox::Yes)
|
||||
return;
|
||||
}
|
||||
m_model->deleteMods(selection.indexes());
|
||||
}
|
||||
|
||||
void ModFolderPage::installMods()
|
||||
{
|
||||
if (!m_controlsEnabled)
|
||||
return;
|
||||
if (m_instance->typeName() != "Minecraft")
|
||||
return; // this is a null instance or a legacy instance
|
||||
|
||||
@ -214,8 +220,7 @@ void ModFolderPage::updateMods()
|
||||
message = tr("All selected mods are up-to-date! :)");
|
||||
}
|
||||
}
|
||||
CustomMessageBox::selectable(this, tr("Update checker"), message)
|
||||
->exec();
|
||||
CustomMessageBox::selectable(this, tr("Update checker"), message)->exec();
|
||||
return;
|
||||
}
|
||||
|
||||
@ -282,3 +287,13 @@ bool NilModFolderPage::shouldDisplay() const
|
||||
{
|
||||
return m_model->dir().exists();
|
||||
}
|
||||
|
||||
void ModFolderPage::visitModPages()
|
||||
{
|
||||
auto selection = m_filterModel->mapSelectionToSource(ui->treeView->selectionModel()->selection()).indexes();
|
||||
for (auto mod : m_model->selectedMods(selection)) {
|
||||
auto url = mod->metaurl();
|
||||
if (!url.isEmpty())
|
||||
DesktopServices::openUrl(url);
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,7 @@
|
||||
* Copyright (c) 2022 Jamie Mansfield <jmansfield@cadixdev.org>
|
||||
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
|
||||
* Copyright (C) 2022 TheKodeToad <TheKodeToad@proton.me>
|
||||
* Copyright (c) 2023 Trial97 <alexandru.tripon97@gmail.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@ -59,11 +60,11 @@ class ModFolderPage : public ExternalResourcesPage {
|
||||
bool onSelectionChanged(const QModelIndex& current, const QModelIndex& previous) override;
|
||||
|
||||
private slots:
|
||||
void runningStateChanged(bool running);
|
||||
void removeItems(const QItemSelection &selection) override;
|
||||
void removeItems(const QItemSelection& selection) override;
|
||||
|
||||
void installMods();
|
||||
void updateMods();
|
||||
void visitModPages();
|
||||
|
||||
protected:
|
||||
std::shared_ptr<ModFolderModel> m_model;
|
||||
|
@ -67,8 +67,6 @@ bool ResourcePackPage::onSelectionChanged(const QModelIndex& current, const QMod
|
||||
|
||||
void ResourcePackPage::downloadRPs()
|
||||
{
|
||||
if (!m_controlsEnabled)
|
||||
return;
|
||||
if (m_instance->typeName() != "Minecraft")
|
||||
return; // this is a null instance or a legacy instance
|
||||
|
||||
|
@ -36,6 +36,7 @@
|
||||
*/
|
||||
|
||||
#include "ScreenshotsPage.h"
|
||||
#include "BuildConfig.h"
|
||||
#include "ui_ScreenshotsPage.h"
|
||||
|
||||
#include <QModelIndex>
|
||||
@ -96,37 +97,30 @@ public:
|
||||
return;
|
||||
if ((info.suffix().compare("png", Qt::CaseInsensitive) != 0))
|
||||
return;
|
||||
int tries = 5;
|
||||
while (tries)
|
||||
{
|
||||
if (!m_cache->stale(m_path))
|
||||
return;
|
||||
QImage image(m_path);
|
||||
if (image.isNull())
|
||||
{
|
||||
QThread::msleep(500);
|
||||
tries--;
|
||||
continue;
|
||||
}
|
||||
QImage small;
|
||||
if (image.width() > image.height())
|
||||
small = image.scaledToWidth(512).scaledToWidth(256, Qt::SmoothTransformation);
|
||||
else
|
||||
small = image.scaledToHeight(512).scaledToHeight(256, Qt::SmoothTransformation);
|
||||
QPoint offset((256 - small.width()) / 2, (256 - small.height()) / 2);
|
||||
QImage square(QSize(256, 256), QImage::Format_ARGB32);
|
||||
square.fill(Qt::transparent);
|
||||
|
||||
QPainter painter(&square);
|
||||
painter.drawImage(offset, small);
|
||||
painter.end();
|
||||
|
||||
QIcon icon(QPixmap::fromImage(square));
|
||||
m_cache->add(m_path, icon);
|
||||
m_resultEmitter.emitResultsReady(m_path);
|
||||
if (!m_cache->stale(m_path))
|
||||
return;
|
||||
QImage image(m_path);
|
||||
if (image.isNull()) {
|
||||
m_resultEmitter.emitResultsFailed(m_path);
|
||||
qDebug() << "Error loading screenshot: " + m_path + ". Perhaps too large?";
|
||||
return;
|
||||
}
|
||||
m_resultEmitter.emitResultsFailed(m_path);
|
||||
QImage small;
|
||||
if (image.width() > image.height())
|
||||
small = image.scaledToWidth(512).scaledToWidth(256, Qt::SmoothTransformation);
|
||||
else
|
||||
small = image.scaledToHeight(512).scaledToHeight(256, Qt::SmoothTransformation);
|
||||
QPoint offset((256 - small.width()) / 2, (256 - small.height()) / 2);
|
||||
QImage square(QSize(256, 256), QImage::Format_ARGB32);
|
||||
square.fill(Qt::transparent);
|
||||
|
||||
QPainter painter(&square);
|
||||
painter.drawImage(offset, small);
|
||||
painter.end();
|
||||
|
||||
QIcon icon(QPixmap::fromImage(square));
|
||||
m_cache->add(m_path, icon);
|
||||
m_resultEmitter.emitResultsReady(m_path);
|
||||
}
|
||||
QString m_path;
|
||||
SharedIconCachePtr m_cache;
|
||||
@ -145,9 +139,12 @@ public:
|
||||
m_thumbnailCache = std::make_shared<SharedIconCache>();
|
||||
m_thumbnailCache->add("placeholder", APPLICATION->getThemedIcon("screenshot-placeholder"));
|
||||
connect(&watcher, SIGNAL(fileChanged(QString)), SLOT(fileChanged(QString)));
|
||||
// FIXME: the watched file set is not updated when files are removed
|
||||
}
|
||||
virtual ~FilterModel() { m_thumbnailingPool.waitForDone(500); }
|
||||
virtual ~FilterModel() {
|
||||
m_thumbnailingPool.clear();
|
||||
if (!m_thumbnailingPool.waitForDone(500))
|
||||
qDebug() << "Thumbnail pool took longer than 500ms to finish";
|
||||
}
|
||||
virtual QVariant data(const QModelIndex &proxyIndex, int role = Qt::DisplayRole) const
|
||||
{
|
||||
auto model = sourceModel();
|
||||
@ -214,10 +211,12 @@ private slots:
|
||||
void fileChanged(QString filepath)
|
||||
{
|
||||
m_thumbnailCache->setStale(filepath);
|
||||
thumbnailImage(filepath);
|
||||
// reinsert the path...
|
||||
watcher.removePath(filepath);
|
||||
watcher.addPath(filepath);
|
||||
if (QFile::exists(filepath)) {
|
||||
watcher.addPath(filepath);
|
||||
thumbnailImage(filepath);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
@ -380,16 +379,18 @@ void ScreenshotsPage::on_actionUpload_triggered()
|
||||
if (selection.isEmpty())
|
||||
return;
|
||||
|
||||
|
||||
QString text;
|
||||
QUrl baseUrl(BuildConfig.IMGUR_BASE_URL);
|
||||
if (selection.size() > 1)
|
||||
text = tr("You are about to upload %1 screenshots.\n\n"
|
||||
text = tr("You are about to upload %1 screenshots to %2.\n"
|
||||
"You should double-check for personal information.\n\n"
|
||||
"Are you sure?")
|
||||
.arg(selection.size());
|
||||
.arg(QString::number(selection.size()), baseUrl.host());
|
||||
else
|
||||
text =
|
||||
tr("You are about to upload the selected screenshot.\n\n"
|
||||
"Are you sure?");
|
||||
text = tr("You are about to upload the selected screenshot to %1.\n"
|
||||
"You should double-check for personal information.\n\n"
|
||||
"Are you sure?")
|
||||
.arg(baseUrl.host());
|
||||
|
||||
auto response = CustomMessageBox::selectable(this, "Confirm Upload", text, QMessageBox::Warning, QMessageBox::Yes | QMessageBox::No,
|
||||
QMessageBox::No)
|
||||
|
@ -46,7 +46,6 @@
|
||||
#include "ui/dialogs/ProgressDialog.h"
|
||||
#include "ui/dialogs/ResourceDownloadDialog.h"
|
||||
|
||||
|
||||
ShaderPackPage::ShaderPackPage(MinecraftInstance* instance, std::shared_ptr<ShaderPackFolderModel> model, QWidget* parent)
|
||||
: ExternalResourcesPage(instance, model, parent)
|
||||
{
|
||||
@ -61,8 +60,6 @@ ShaderPackPage::ShaderPackPage(MinecraftInstance* instance, std::shared_ptr<Shad
|
||||
|
||||
void ShaderPackPage::downloadShaders()
|
||||
{
|
||||
if (!m_controlsEnabled)
|
||||
return;
|
||||
if (m_instance->typeName() != "Minecraft")
|
||||
return; // this is a null instance or a legacy instance
|
||||
|
||||
|
@ -69,8 +69,6 @@ bool TexturePackPage::onSelectionChanged(const QModelIndex& current, const QMode
|
||||
|
||||
void TexturePackPage::downloadTPs()
|
||||
{
|
||||
if (!m_controlsEnabled)
|
||||
return;
|
||||
if (m_instance->typeName() != "Minecraft")
|
||||
return; // this is a null instance or a legacy instance
|
||||
|
||||
|
@ -40,14 +40,13 @@
|
||||
|
||||
#include "Application.h"
|
||||
|
||||
#include <QMessageBox>
|
||||
#include <QLabel>
|
||||
#include <QAbstractItemModel>
|
||||
#include <QEvent>
|
||||
#include <QKeyEvent>
|
||||
#include <QMenu>
|
||||
#include <QAbstractItemModel>
|
||||
#include <QMessageBox>
|
||||
#include <QLabel>
|
||||
#include <QListView>
|
||||
#include <QMenu>
|
||||
#include <QMessageBox>
|
||||
#include <QString>
|
||||
#include <QUrl>
|
||||
|
||||
@ -55,49 +54,42 @@
|
||||
#include "ui_VersionPage.h"
|
||||
|
||||
#include "ui/dialogs/CustomMessageBox.h"
|
||||
#include "ui/dialogs/VersionSelectDialog.h"
|
||||
#include "ui/dialogs/NewComponentDialog.h"
|
||||
#include "ui/dialogs/ProgressDialog.h"
|
||||
#include "ui/dialogs/VersionSelectDialog.h"
|
||||
|
||||
#include "ui/GuiUtil.h"
|
||||
|
||||
#include "DesktopServices.h"
|
||||
#include "Exception.h"
|
||||
#include "Version.h"
|
||||
#include "icons/IconList.h"
|
||||
#include "minecraft/PackProfile.h"
|
||||
#include "minecraft/auth/AccountList.h"
|
||||
#include "minecraft/mod/Mod.h"
|
||||
#include "icons/IconList.h"
|
||||
#include "Exception.h"
|
||||
#include "Version.h"
|
||||
#include "DesktopServices.h"
|
||||
|
||||
#include "meta/Index.h"
|
||||
#include "meta/VersionList.h"
|
||||
|
||||
class IconProxy : public QIdentityProxyModel
|
||||
{
|
||||
class IconProxy : public QIdentityProxyModel {
|
||||
Q_OBJECT
|
||||
public:
|
||||
|
||||
IconProxy(QWidget *parentWidget) : QIdentityProxyModel(parentWidget)
|
||||
public:
|
||||
IconProxy(QWidget* parentWidget) : QIdentityProxyModel(parentWidget)
|
||||
{
|
||||
connect(parentWidget, &QObject::destroyed, this, &IconProxy::widgetGone);
|
||||
m_parentWidget = parentWidget;
|
||||
}
|
||||
|
||||
virtual QVariant data(const QModelIndex &proxyIndex, int role = Qt::DisplayRole) const override
|
||||
virtual QVariant data(const QModelIndex& proxyIndex, int role = Qt::DisplayRole) const override
|
||||
{
|
||||
QVariant var = QIdentityProxyModel::data(proxyIndex, role);
|
||||
int column = proxyIndex.column();
|
||||
if(column == 0 && role == Qt::DecorationRole && m_parentWidget)
|
||||
{
|
||||
if(!var.isNull())
|
||||
{
|
||||
if (column == 0 && role == Qt::DecorationRole && m_parentWidget) {
|
||||
if (!var.isNull()) {
|
||||
auto string = var.toString();
|
||||
if(string == "warning")
|
||||
{
|
||||
if (string == "warning") {
|
||||
return APPLICATION->getThemedIcon("status-yellow");
|
||||
}
|
||||
else if(string == "error")
|
||||
{
|
||||
} else if (string == "error") {
|
||||
return APPLICATION->getThemedIcon("status-bad");
|
||||
}
|
||||
}
|
||||
@ -105,14 +97,11 @@ public:
|
||||
}
|
||||
return var;
|
||||
}
|
||||
private slots:
|
||||
void widgetGone()
|
||||
{
|
||||
m_parentWidget = nullptr;
|
||||
}
|
||||
private slots:
|
||||
void widgetGone() { m_parentWidget = nullptr; }
|
||||
|
||||
private:
|
||||
QWidget *m_parentWidget = nullptr;
|
||||
private:
|
||||
QWidget* m_parentWidget = nullptr;
|
||||
};
|
||||
|
||||
QIcon VersionPage::icon() const
|
||||
@ -144,15 +133,14 @@ void VersionPage::closedImpl()
|
||||
m_wide_bar_setting->set(ui->toolBar->getVisibilityState());
|
||||
}
|
||||
|
||||
QMenu * VersionPage::createPopupMenu()
|
||||
QMenu* VersionPage::createPopupMenu()
|
||||
{
|
||||
QMenu* filteredMenu = QMainWindow::createPopupMenu();
|
||||
filteredMenu->removeAction( ui->toolBar->toggleViewAction() );
|
||||
filteredMenu->removeAction(ui->toolBar->toggleViewAction());
|
||||
return filteredMenu;
|
||||
}
|
||||
|
||||
VersionPage::VersionPage(MinecraftInstance *inst, QWidget *parent)
|
||||
: QMainWindow(parent), ui(new Ui::VersionPage), m_inst(inst)
|
||||
VersionPage::VersionPage(MinecraftInstance* inst, QWidget* parent) : QMainWindow(parent), ui(new Ui::VersionPage), m_inst(inst)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
@ -165,7 +153,7 @@ VersionPage::VersionPage(MinecraftInstance *inst, QWidget *parent)
|
||||
auto proxy = new IconProxy(ui->packageView);
|
||||
proxy->setSourceModel(m_profile.get());
|
||||
|
||||
m_filterModel = new QSortFilterProxyModel();
|
||||
m_filterModel = new QSortFilterProxyModel(this);
|
||||
m_filterModel->setDynamicSortFilter(true);
|
||||
m_filterModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
|
||||
m_filterModel->setSortCaseSensitivity(Qt::CaseInsensitive);
|
||||
@ -182,10 +170,8 @@ VersionPage::VersionPage(MinecraftInstance *inst, QWidget *parent)
|
||||
connect(smodel, &QItemSelectionModel::currentChanged, this, &VersionPage::packageCurrent);
|
||||
|
||||
connect(m_profile.get(), &PackProfile::minecraftChanged, this, &VersionPage::updateVersionControls);
|
||||
controlsEnabled = !m_inst->isRunning();
|
||||
updateVersionControls();
|
||||
preselect(0);
|
||||
connect(m_inst, &BaseInstance::runningStatusChanged, this, &VersionPage::updateRunningStatus);
|
||||
connect(ui->packageView, &ModListView::customContextMenuRequested, this, &VersionPage::showContextMenu);
|
||||
connect(ui->filterEdit, &QLineEdit::textChanged, this, &VersionPage::onFilterTextChanged);
|
||||
}
|
||||
@ -202,18 +188,16 @@ void VersionPage::showContextMenu(const QPoint& pos)
|
||||
delete menu;
|
||||
}
|
||||
|
||||
void VersionPage::packageCurrent(const QModelIndex ¤t, const QModelIndex &previous)
|
||||
void VersionPage::packageCurrent(const QModelIndex& current, const QModelIndex& previous)
|
||||
{
|
||||
if (!current.isValid())
|
||||
{
|
||||
if (!current.isValid()) {
|
||||
ui->frame->clear();
|
||||
return;
|
||||
}
|
||||
int row = current.row();
|
||||
auto patch = m_profile->getComponent(row);
|
||||
auto severity = patch->getProblemSeverity();
|
||||
switch(severity)
|
||||
{
|
||||
switch (severity) {
|
||||
case ProblemSeverity::Warning:
|
||||
ui->frame->setName(tr("%1 possibly has issues.").arg(patch->getName()));
|
||||
break;
|
||||
@ -226,16 +210,12 @@ void VersionPage::packageCurrent(const QModelIndex ¤t, const QModelIndex &
|
||||
return;
|
||||
}
|
||||
|
||||
auto &problems = patch->getProblems();
|
||||
auto& problems = patch->getProblems();
|
||||
QString problemOut;
|
||||
for (auto &problem: problems)
|
||||
{
|
||||
if(problem.m_severity == ProblemSeverity::Error)
|
||||
{
|
||||
for (auto& problem : problems) {
|
||||
if (problem.m_severity == ProblemSeverity::Error) {
|
||||
problemOut += tr("Error: ");
|
||||
}
|
||||
else if(problem.m_severity == ProblemSeverity::Warning)
|
||||
{
|
||||
} else if (problem.m_severity == ProblemSeverity::Warning) {
|
||||
problemOut += tr("Warning: ");
|
||||
}
|
||||
problemOut += problem.m_description;
|
||||
@ -244,72 +224,47 @@ void VersionPage::packageCurrent(const QModelIndex ¤t, const QModelIndex &
|
||||
ui->frame->setDescription(problemOut);
|
||||
}
|
||||
|
||||
void VersionPage::updateRunningStatus(bool running)
|
||||
{
|
||||
if(controlsEnabled == running) {
|
||||
controlsEnabled = !running;
|
||||
updateVersionControls();
|
||||
}
|
||||
}
|
||||
|
||||
void VersionPage::updateVersionControls()
|
||||
{
|
||||
// FIXME: this is a dirty hack
|
||||
auto minecraftVersion = Version(m_profile->getComponentVersion("net.minecraft"));
|
||||
|
||||
ui->actionInstall_Forge->setEnabled(controlsEnabled);
|
||||
|
||||
bool supportsFabric = minecraftVersion >= Version("1.14");
|
||||
ui->actionInstall_Fabric->setEnabled(controlsEnabled && supportsFabric);
|
||||
ui->actionInstall_Fabric->setEnabled(supportsFabric);
|
||||
|
||||
bool supportsQuilt = minecraftVersion >= Version("1.14");
|
||||
ui->actionInstall_Quilt->setEnabled(controlsEnabled && supportsQuilt);
|
||||
ui->actionInstall_Quilt->setEnabled(supportsQuilt);
|
||||
|
||||
bool supportsLiteLoader = minecraftVersion <= Version("1.12.2");
|
||||
ui->actionInstall_LiteLoader->setEnabled(controlsEnabled && supportsLiteLoader);
|
||||
ui->actionInstall_LiteLoader->setEnabled(supportsLiteLoader);
|
||||
|
||||
updateButtons();
|
||||
}
|
||||
|
||||
void VersionPage::updateButtons(int row)
|
||||
{
|
||||
if(row == -1)
|
||||
if (row == -1)
|
||||
row = currentRow();
|
||||
auto patch = m_profile->getComponent(row);
|
||||
ui->actionRemove->setEnabled(controlsEnabled && patch && patch->isRemovable());
|
||||
ui->actionMove_down->setEnabled(controlsEnabled && patch && patch->isMoveable());
|
||||
ui->actionMove_up->setEnabled(controlsEnabled && patch && patch->isMoveable());
|
||||
ui->actionChange_version->setEnabled(controlsEnabled && patch && patch->isVersionChangeable());
|
||||
ui->actionEdit->setEnabled(controlsEnabled && patch && patch->isCustom());
|
||||
ui->actionCustomize->setEnabled(controlsEnabled && patch && patch->isCustomizable());
|
||||
ui->actionRevert->setEnabled(controlsEnabled && patch && patch->isRevertible());
|
||||
ui->actionDownload_All->setEnabled(controlsEnabled);
|
||||
ui->actionAdd_Empty->setEnabled(controlsEnabled);
|
||||
ui->actionImport_Components->setEnabled(controlsEnabled);
|
||||
ui->actionReload->setEnabled(controlsEnabled);
|
||||
ui->actionInstall_mods->setEnabled(controlsEnabled);
|
||||
ui->actionReplace_Minecraft_jar->setEnabled(controlsEnabled);
|
||||
ui->actionAdd_to_Minecraft_jar->setEnabled(controlsEnabled);
|
||||
ui->actionAdd_Agents->setEnabled(controlsEnabled);
|
||||
ui->actionRemove->setEnabled(patch && patch->isRemovable());
|
||||
ui->actionMove_down->setEnabled(patch && patch->isMoveable());
|
||||
ui->actionMove_up->setEnabled(patch && patch->isMoveable());
|
||||
ui->actionChange_version->setEnabled(patch && patch->isVersionChangeable());
|
||||
ui->actionEdit->setEnabled(patch && patch->isCustom());
|
||||
ui->actionCustomize->setEnabled(patch && patch->isCustomizable());
|
||||
ui->actionRevert->setEnabled(patch && patch->isRevertible());
|
||||
}
|
||||
|
||||
bool VersionPage::reloadPackProfile()
|
||||
{
|
||||
try
|
||||
{
|
||||
try {
|
||||
m_profile->reload(Net::Mode::Online);
|
||||
return true;
|
||||
}
|
||||
catch (const Exception &e)
|
||||
{
|
||||
} catch (const Exception& e) {
|
||||
QMessageBox::critical(this, tr("Error"), e.cause());
|
||||
return false;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
QMessageBox::critical(
|
||||
this, tr("Error"),
|
||||
tr("Couldn't load the instance profile."));
|
||||
} catch (...) {
|
||||
QMessageBox::critical(this, tr("Error"), tr("Couldn't load the instance profile."));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -322,14 +277,12 @@ void VersionPage::on_actionReload_triggered()
|
||||
|
||||
void VersionPage::on_actionRemove_triggered()
|
||||
{
|
||||
if (!ui->packageView->currentIndex().isValid())
|
||||
{
|
||||
if (!ui->packageView->currentIndex().isValid()) {
|
||||
return;
|
||||
}
|
||||
int index = ui->packageView->currentIndex().row();
|
||||
auto component = m_profile->getComponent(index);
|
||||
if (component->isCustom())
|
||||
{
|
||||
if (component->isCustom()) {
|
||||
auto response = CustomMessageBox::selectable(this, tr("Confirm Removal"),
|
||||
tr("You are about to remove \"%1\".\n"
|
||||
"This is permanent and will completely remove the custom component.\n\n"
|
||||
@ -342,8 +295,7 @@ void VersionPage::on_actionRemove_triggered()
|
||||
return;
|
||||
}
|
||||
// FIXME: use actual model, not reloading.
|
||||
if (!m_profile->remove(index))
|
||||
{
|
||||
if (!m_profile->remove(index)) {
|
||||
QMessageBox::critical(this, tr("Error"), tr("Couldn't remove file"));
|
||||
}
|
||||
updateButtons();
|
||||
@ -353,17 +305,16 @@ void VersionPage::on_actionRemove_triggered()
|
||||
|
||||
void VersionPage::on_actionInstall_mods_triggered()
|
||||
{
|
||||
if(m_container)
|
||||
{
|
||||
if (m_container) {
|
||||
m_container->selectPage("mods");
|
||||
}
|
||||
}
|
||||
|
||||
void VersionPage::on_actionAdd_to_Minecraft_jar_triggered()
|
||||
{
|
||||
auto list = GuiUtil::BrowseForFiles("jarmod", tr("Select jar mods"), tr("Minecraft.jar mods (*.zip *.jar)"), APPLICATION->settings()->get("CentralModsDir").toString(), this->parentWidget());
|
||||
if(!list.empty())
|
||||
{
|
||||
auto list = GuiUtil::BrowseForFiles("jarmod", tr("Select jar mods"), tr("Minecraft.jar mods (*.zip *.jar)"),
|
||||
APPLICATION->settings()->get("CentralModsDir").toString(), this->parentWidget());
|
||||
if (!list.empty()) {
|
||||
m_profile->installJarMods(list);
|
||||
}
|
||||
updateButtons();
|
||||
@ -371,9 +322,9 @@ void VersionPage::on_actionAdd_to_Minecraft_jar_triggered()
|
||||
|
||||
void VersionPage::on_actionReplace_Minecraft_jar_triggered()
|
||||
{
|
||||
auto jarPath = GuiUtil::BrowseForFile("jar", tr("Select jar"), tr("Minecraft.jar replacement (*.jar)"), APPLICATION->settings()->get("CentralModsDir").toString(), this->parentWidget());
|
||||
if(!jarPath.isEmpty())
|
||||
{
|
||||
auto jarPath = GuiUtil::BrowseForFile("jar", tr("Select jar"), tr("Minecraft.jar replacement (*.jar)"),
|
||||
APPLICATION->settings()->get("CentralModsDir").toString(), this->parentWidget());
|
||||
if (!jarPath.isEmpty()) {
|
||||
m_profile->installCustomJar(jarPath);
|
||||
}
|
||||
updateButtons();
|
||||
@ -407,12 +358,9 @@ void VersionPage::on_actionAdd_Agents_triggered()
|
||||
|
||||
void VersionPage::on_actionMove_up_triggered()
|
||||
{
|
||||
try
|
||||
{
|
||||
try {
|
||||
m_profile->move(currentRow(), PackProfile::MoveUp);
|
||||
}
|
||||
catch (const Exception &e)
|
||||
{
|
||||
} catch (const Exception& e) {
|
||||
QMessageBox::critical(this, tr("Error"), e.cause());
|
||||
}
|
||||
updateButtons();
|
||||
@ -420,12 +368,9 @@ void VersionPage::on_actionMove_up_triggered()
|
||||
|
||||
void VersionPage::on_actionMove_down_triggered()
|
||||
{
|
||||
try
|
||||
{
|
||||
try {
|
||||
m_profile->move(currentRow(), PackProfile::MoveDown);
|
||||
}
|
||||
catch (const Exception &e)
|
||||
{
|
||||
} catch (const Exception& e) {
|
||||
QMessageBox::critical(this, tr("Error"), e.cause());
|
||||
}
|
||||
updateButtons();
|
||||
@ -434,39 +379,32 @@ void VersionPage::on_actionMove_down_triggered()
|
||||
void VersionPage::on_actionChange_version_triggered()
|
||||
{
|
||||
auto versionRow = currentRow();
|
||||
if(versionRow == -1)
|
||||
{
|
||||
if (versionRow == -1) {
|
||||
return;
|
||||
}
|
||||
auto patch = m_profile->getComponent(versionRow);
|
||||
auto name = patch->getName();
|
||||
auto list = patch->getVersionList();
|
||||
if(!list)
|
||||
{
|
||||
if (!list) {
|
||||
return;
|
||||
}
|
||||
auto uid = list->uid();
|
||||
// FIXME: this is a horrible HACK. Get version filtering information from the actual metadata...
|
||||
if(uid == "net.minecraftforge")
|
||||
{
|
||||
if (uid == "net.minecraftforge") {
|
||||
on_actionInstall_Forge_triggered();
|
||||
return;
|
||||
}
|
||||
else if (uid == "com.mumfrey.liteloader")
|
||||
{
|
||||
} else if (uid == "com.mumfrey.liteloader") {
|
||||
on_actionInstall_LiteLoader_triggered();
|
||||
return;
|
||||
}
|
||||
VersionSelectDialog vselect(list.get(), tr("Change %1 version").arg(name), this);
|
||||
if (uid == "net.fabricmc.intermediary" || uid == "org.quiltmc.hashed")
|
||||
{
|
||||
if (uid == "net.fabricmc.intermediary" || uid == "org.quiltmc.hashed") {
|
||||
vselect.setEmptyString(tr("No intermediary mappings versions are currently available."));
|
||||
vselect.setEmptyErrorString(tr("Couldn't load or download the intermediary mappings version lists!"));
|
||||
vselect.setExactFilter(BaseVersionList::ParentVersionRole, m_profile->getComponentVersion("net.minecraft"));
|
||||
}
|
||||
auto currentVersion = patch->getVersion();
|
||||
if(!currentVersion.isEmpty())
|
||||
{
|
||||
if (!currentVersion.isEmpty()) {
|
||||
vselect.setCurrentVersion(currentVersion);
|
||||
}
|
||||
if (!vselect.exec() || !vselect.selectedVersion())
|
||||
@ -474,8 +412,7 @@ void VersionPage::on_actionChange_version_triggered()
|
||||
|
||||
qDebug() << "Change" << uid << "to" << vselect.selectedVersion()->descriptor();
|
||||
bool important = false;
|
||||
if(uid == "net.minecraft")
|
||||
{
|
||||
if (uid == "net.minecraft") {
|
||||
important = true;
|
||||
}
|
||||
m_profile->setComponentVersion(uid, vselect.selectedVersion()->descriptor(), important);
|
||||
@ -485,23 +422,21 @@ void VersionPage::on_actionChange_version_triggered()
|
||||
|
||||
void VersionPage::on_actionDownload_All_triggered()
|
||||
{
|
||||
if (!APPLICATION->accounts()->anyAccountIsValid())
|
||||
{
|
||||
CustomMessageBox::selectable(
|
||||
this, tr("Error"),
|
||||
tr("Cannot download Minecraft or update instances unless you have at least "
|
||||
"one account added.\nPlease add your Mojang or Minecraft account."),
|
||||
QMessageBox::Warning)->show();
|
||||
if (!APPLICATION->accounts()->anyAccountIsValid()) {
|
||||
CustomMessageBox::selectable(this, tr("Error"),
|
||||
tr("Cannot download Minecraft or update instances unless you have at least "
|
||||
"one account added.\nPlease add your Mojang or Minecraft account."),
|
||||
QMessageBox::Warning)
|
||||
->show();
|
||||
return;
|
||||
}
|
||||
|
||||
auto updateTask = m_inst->createUpdateTask(Net::Mode::Online);
|
||||
if (!updateTask)
|
||||
{
|
||||
if (!updateTask) {
|
||||
return;
|
||||
}
|
||||
ProgressDialog tDialog(this);
|
||||
connect(updateTask.get(), SIGNAL(failed(QString)), SLOT(onGameUpdateError(QString)));
|
||||
connect(updateTask.get(), &Task::failed, this, &VersionPage::onGameUpdateError);
|
||||
// FIXME: unused return value
|
||||
tDialog.execWithTask(updateTask.get());
|
||||
updateButtons();
|
||||
@ -511,28 +446,26 @@ void VersionPage::on_actionDownload_All_triggered()
|
||||
void VersionPage::on_actionInstall_Forge_triggered()
|
||||
{
|
||||
auto vlist = APPLICATION->metadataIndex()->get("net.minecraftforge");
|
||||
if(!vlist)
|
||||
{
|
||||
if (!vlist) {
|
||||
return;
|
||||
}
|
||||
VersionSelectDialog vselect(vlist.get(), tr("Select Forge version"), this);
|
||||
vselect.setExactFilter(BaseVersionList::ParentVersionRole, m_profile->getComponentVersion("net.minecraft"));
|
||||
vselect.setEmptyString(tr("No Forge versions are currently available for Minecraft ") + m_profile->getComponentVersion("net.minecraft"));
|
||||
vselect.setEmptyString(tr("No Forge versions are currently available for Minecraft ") +
|
||||
m_profile->getComponentVersion("net.minecraft"));
|
||||
vselect.setEmptyErrorString(tr("Couldn't load or download the Forge version lists!"));
|
||||
|
||||
auto currentVersion = m_profile->getComponentVersion("net.minecraftforge");
|
||||
if(!currentVersion.isEmpty())
|
||||
{
|
||||
if (!currentVersion.isEmpty()) {
|
||||
vselect.setCurrentVersion(currentVersion);
|
||||
}
|
||||
|
||||
if (vselect.exec() && vselect.selectedVersion())
|
||||
{
|
||||
if (vselect.exec() && vselect.selectedVersion()) {
|
||||
auto vsn = vselect.selectedVersion();
|
||||
m_profile->setComponentVersion("net.minecraftforge", vsn->descriptor());
|
||||
m_profile->resolve(Net::Mode::Online);
|
||||
// m_profile->installVersion();
|
||||
preselect(m_profile->rowCount(QModelIndex())-1);
|
||||
preselect(m_profile->rowCount(QModelIndex()) - 1);
|
||||
m_container->refreshContainer();
|
||||
}
|
||||
}
|
||||
@ -540,8 +473,7 @@ void VersionPage::on_actionInstall_Forge_triggered()
|
||||
void VersionPage::on_actionInstall_Fabric_triggered()
|
||||
{
|
||||
auto vlist = APPLICATION->metadataIndex()->get("net.fabricmc.fabric-loader");
|
||||
if(!vlist)
|
||||
{
|
||||
if (!vlist) {
|
||||
return;
|
||||
}
|
||||
VersionSelectDialog vselect(vlist.get(), tr("Select Fabric Loader version"), this);
|
||||
@ -549,17 +481,15 @@ void VersionPage::on_actionInstall_Fabric_triggered()
|
||||
vselect.setEmptyErrorString(tr("Couldn't load or download the Fabric Loader version lists!"));
|
||||
|
||||
auto currentVersion = m_profile->getComponentVersion("net.fabricmc.fabric-loader");
|
||||
if(!currentVersion.isEmpty())
|
||||
{
|
||||
if (!currentVersion.isEmpty()) {
|
||||
vselect.setCurrentVersion(currentVersion);
|
||||
}
|
||||
|
||||
if (vselect.exec() && vselect.selectedVersion())
|
||||
{
|
||||
if (vselect.exec() && vselect.selectedVersion()) {
|
||||
auto vsn = vselect.selectedVersion();
|
||||
m_profile->setComponentVersion("net.fabricmc.fabric-loader", vsn->descriptor());
|
||||
m_profile->resolve(Net::Mode::Online);
|
||||
preselect(m_profile->rowCount(QModelIndex())-1);
|
||||
preselect(m_profile->rowCount(QModelIndex()) - 1);
|
||||
m_container->refreshContainer();
|
||||
}
|
||||
}
|
||||
@ -567,8 +497,7 @@ void VersionPage::on_actionInstall_Fabric_triggered()
|
||||
void VersionPage::on_actionInstall_Quilt_triggered()
|
||||
{
|
||||
auto vlist = APPLICATION->metadataIndex()->get("org.quiltmc.quilt-loader");
|
||||
if(!vlist)
|
||||
{
|
||||
if (!vlist) {
|
||||
return;
|
||||
}
|
||||
VersionSelectDialog vselect(vlist.get(), tr("Select Quilt Loader version"), this);
|
||||
@ -576,17 +505,15 @@ void VersionPage::on_actionInstall_Quilt_triggered()
|
||||
vselect.setEmptyErrorString(tr("Couldn't load or download the Quilt Loader version lists!"));
|
||||
|
||||
auto currentVersion = m_profile->getComponentVersion("org.quiltmc.quilt-loader");
|
||||
if(!currentVersion.isEmpty())
|
||||
{
|
||||
if (!currentVersion.isEmpty()) {
|
||||
vselect.setCurrentVersion(currentVersion);
|
||||
}
|
||||
|
||||
if (vselect.exec() && vselect.selectedVersion())
|
||||
{
|
||||
if (vselect.exec() && vselect.selectedVersion()) {
|
||||
auto vsn = vselect.selectedVersion();
|
||||
m_profile->setComponentVersion("org.quiltmc.quilt-loader", vsn->descriptor());
|
||||
m_profile->resolve(Net::Mode::Online);
|
||||
preselect(m_profile->rowCount(QModelIndex())-1);
|
||||
preselect(m_profile->rowCount(QModelIndex()) - 1);
|
||||
m_container->refreshContainer();
|
||||
}
|
||||
}
|
||||
@ -595,14 +522,12 @@ void VersionPage::on_actionAdd_Empty_triggered()
|
||||
{
|
||||
NewComponentDialog compdialog(QString(), QString(), this);
|
||||
QStringList blacklist;
|
||||
for(int i = 0; i < m_profile->rowCount(); i++)
|
||||
{
|
||||
for (int i = 0; i < m_profile->rowCount(); i++) {
|
||||
auto comp = m_profile->getComponent(i);
|
||||
blacklist.push_back(comp->getID());
|
||||
}
|
||||
compdialog.setBlacklist(blacklist);
|
||||
if (compdialog.exec())
|
||||
{
|
||||
if (compdialog.exec()) {
|
||||
qDebug() << "name:" << compdialog.name();
|
||||
qDebug() << "uid:" << compdialog.uid();
|
||||
m_profile->installEmpty(compdialog.uid(), compdialog.name());
|
||||
@ -612,28 +537,26 @@ void VersionPage::on_actionAdd_Empty_triggered()
|
||||
void VersionPage::on_actionInstall_LiteLoader_triggered()
|
||||
{
|
||||
auto vlist = APPLICATION->metadataIndex()->get("com.mumfrey.liteloader");
|
||||
if(!vlist)
|
||||
{
|
||||
if (!vlist) {
|
||||
return;
|
||||
}
|
||||
VersionSelectDialog vselect(vlist.get(), tr("Select LiteLoader version"), this);
|
||||
vselect.setExactFilter(BaseVersionList::ParentVersionRole, m_profile->getComponentVersion("net.minecraft"));
|
||||
vselect.setEmptyString(tr("No LiteLoader versions are currently available for Minecraft ") + m_profile->getComponentVersion("net.minecraft"));
|
||||
vselect.setEmptyString(tr("No LiteLoader versions are currently available for Minecraft ") +
|
||||
m_profile->getComponentVersion("net.minecraft"));
|
||||
vselect.setEmptyErrorString(tr("Couldn't load or download the LiteLoader version lists!"));
|
||||
|
||||
auto currentVersion = m_profile->getComponentVersion("com.mumfrey.liteloader");
|
||||
if(!currentVersion.isEmpty())
|
||||
{
|
||||
if (!currentVersion.isEmpty()) {
|
||||
vselect.setCurrentVersion(currentVersion);
|
||||
}
|
||||
|
||||
if (vselect.exec() && vselect.selectedVersion())
|
||||
{
|
||||
if (vselect.exec() && vselect.selectedVersion()) {
|
||||
auto vsn = vselect.selectedVersion();
|
||||
m_profile->setComponentVersion("com.mumfrey.liteloader", vsn->descriptor());
|
||||
m_profile->resolve(Net::Mode::Online);
|
||||
// m_profile->installVersion(vselect.selectedVersion());
|
||||
preselect(m_profile->rowCount(QModelIndex())-1);
|
||||
preselect(m_profile->rowCount(QModelIndex()) - 1);
|
||||
m_container->refreshContainer();
|
||||
}
|
||||
}
|
||||
@ -648,7 +571,7 @@ void VersionPage::on_actionMinecraftFolder_triggered()
|
||||
DesktopServices::openDirectory(m_inst->gameRoot(), true);
|
||||
}
|
||||
|
||||
void VersionPage::versionCurrent(const QModelIndex ¤t, const QModelIndex &previous)
|
||||
void VersionPage::versionCurrent(const QModelIndex& current, const QModelIndex& previous)
|
||||
{
|
||||
currentIdx = current.row();
|
||||
updateButtons(currentIdx);
|
||||
@ -656,16 +579,13 @@ void VersionPage::versionCurrent(const QModelIndex ¤t, const QModelIndex &
|
||||
|
||||
void VersionPage::preselect(int row)
|
||||
{
|
||||
if(row < 0)
|
||||
{
|
||||
if (row < 0) {
|
||||
row = 0;
|
||||
}
|
||||
if(row >= m_profile->rowCount(QModelIndex()))
|
||||
{
|
||||
if (row >= m_profile->rowCount(QModelIndex())) {
|
||||
row = m_profile->rowCount(QModelIndex()) - 1;
|
||||
}
|
||||
if(row < 0)
|
||||
{
|
||||
if (row < 0) {
|
||||
return;
|
||||
}
|
||||
auto model_index = m_profile->index(row);
|
||||
@ -681,8 +601,7 @@ void VersionPage::onGameUpdateError(QString error)
|
||||
ComponentPtr VersionPage::current()
|
||||
{
|
||||
auto row = currentRow();
|
||||
if(row < 0)
|
||||
{
|
||||
if (row < 0) {
|
||||
return nullptr;
|
||||
}
|
||||
return m_profile->getComponent(row);
|
||||
@ -690,8 +609,7 @@ ComponentPtr VersionPage::current()
|
||||
|
||||
int VersionPage::currentRow()
|
||||
{
|
||||
if (ui->packageView->selectionModel()->selectedRows().isEmpty())
|
||||
{
|
||||
if (ui->packageView->selectionModel()->selectedRows().isEmpty()) {
|
||||
return -1;
|
||||
}
|
||||
return ui->packageView->selectionModel()->selectedRows().first().row();
|
||||
@ -700,18 +618,15 @@ int VersionPage::currentRow()
|
||||
void VersionPage::on_actionCustomize_triggered()
|
||||
{
|
||||
auto version = currentRow();
|
||||
if(version == -1)
|
||||
{
|
||||
if (version == -1) {
|
||||
return;
|
||||
}
|
||||
auto patch = m_profile->getComponent(version);
|
||||
if(!patch->getVersionFile())
|
||||
{
|
||||
if (!patch->getVersionFile()) {
|
||||
// TODO: wait for the update task to finish here...
|
||||
return;
|
||||
}
|
||||
if(!m_profile->customize(version))
|
||||
{
|
||||
if (!m_profile->customize(version)) {
|
||||
// TODO: some error box here
|
||||
}
|
||||
updateButtons();
|
||||
@ -721,13 +636,11 @@ void VersionPage::on_actionCustomize_triggered()
|
||||
void VersionPage::on_actionEdit_triggered()
|
||||
{
|
||||
auto version = current();
|
||||
if(!version)
|
||||
{
|
||||
if (!version) {
|
||||
return;
|
||||
}
|
||||
auto filename = version->getFilename();
|
||||
if(!QFileInfo::exists(filename))
|
||||
{
|
||||
if (!QFileInfo::exists(filename)) {
|
||||
qWarning() << "file" << filename << "can't be opened for editing, doesn't exist!";
|
||||
return;
|
||||
}
|
||||
@ -737,8 +650,7 @@ void VersionPage::on_actionEdit_triggered()
|
||||
void VersionPage::on_actionRevert_triggered()
|
||||
{
|
||||
auto version = currentRow();
|
||||
if(version == -1)
|
||||
{
|
||||
if (version == -1) {
|
||||
return;
|
||||
}
|
||||
auto component = m_profile->getComponent(version);
|
||||
@ -754,8 +666,7 @@ void VersionPage::on_actionRevert_triggered()
|
||||
if (response != QMessageBox::Yes)
|
||||
return;
|
||||
|
||||
if(!m_profile->revertToBase(version))
|
||||
{
|
||||
if (!m_profile->revertToBase(version)) {
|
||||
// TODO: some error box here
|
||||
}
|
||||
updateButtons();
|
||||
@ -763,7 +674,7 @@ void VersionPage::on_actionRevert_triggered()
|
||||
m_container->refreshContainer();
|
||||
}
|
||||
|
||||
void VersionPage::onFilterTextChanged(const QString &newContents)
|
||||
void VersionPage::onFilterTextChanged(const QString& newContents)
|
||||
{
|
||||
m_filterModel->setFilterFixedString(newContents);
|
||||
}
|
||||
|
@ -46,38 +46,27 @@
|
||||
#include "minecraft/PackProfile.h"
|
||||
#include "ui/pages/BasePage.h"
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
namespace Ui {
|
||||
class VersionPage;
|
||||
}
|
||||
|
||||
class VersionPage : public QMainWindow, public BasePage
|
||||
{
|
||||
class VersionPage : public QMainWindow, public BasePage {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit VersionPage(MinecraftInstance *inst, QWidget *parent = 0);
|
||||
public:
|
||||
explicit VersionPage(MinecraftInstance* inst, QWidget* parent = 0);
|
||||
virtual ~VersionPage();
|
||||
virtual QString displayName() const override
|
||||
{
|
||||
return tr("Version");
|
||||
}
|
||||
virtual QString displayName() const override { return tr("Version"); }
|
||||
virtual QIcon icon() const override;
|
||||
virtual QString id() const override
|
||||
{
|
||||
return "version";
|
||||
}
|
||||
virtual QString helpPage() const override
|
||||
{
|
||||
return "Instance-Version";
|
||||
}
|
||||
virtual QString id() const override { return "version"; }
|
||||
virtual QString helpPage() const override { return "Instance-Version"; }
|
||||
virtual bool shouldDisplay() const override;
|
||||
void retranslate() override;
|
||||
|
||||
void openedImpl() override;
|
||||
void closedImpl() override;
|
||||
|
||||
private slots:
|
||||
private slots:
|
||||
void on_actionChange_version_triggered();
|
||||
void on_actionInstall_Forge_triggered();
|
||||
void on_actionInstall_Fabric_triggered();
|
||||
@ -103,36 +92,34 @@ private slots:
|
||||
|
||||
void updateVersionControls();
|
||||
|
||||
private:
|
||||
private:
|
||||
ComponentPtr current();
|
||||
int currentRow();
|
||||
void updateButtons(int row = -1);
|
||||
void preselect(int row = 0);
|
||||
int doUpdate();
|
||||
|
||||
protected:
|
||||
QMenu * createPopupMenu() override;
|
||||
protected:
|
||||
QMenu* createPopupMenu() override;
|
||||
|
||||
/// FIXME: this shouldn't be necessary!
|
||||
bool reloadPackProfile();
|
||||
|
||||
private:
|
||||
Ui::VersionPage *ui;
|
||||
QSortFilterProxyModel *m_filterModel;
|
||||
private:
|
||||
Ui::VersionPage* ui;
|
||||
QSortFilterProxyModel* m_filterModel;
|
||||
std::shared_ptr<PackProfile> m_profile;
|
||||
MinecraftInstance *m_inst;
|
||||
MinecraftInstance* m_inst;
|
||||
int currentIdx = 0;
|
||||
bool controlsEnabled = false;
|
||||
|
||||
std::shared_ptr<Setting> m_wide_bar_setting = nullptr;
|
||||
|
||||
public slots:
|
||||
void versionCurrent(const QModelIndex ¤t, const QModelIndex &previous);
|
||||
public slots:
|
||||
void versionCurrent(const QModelIndex& current, const QModelIndex& previous);
|
||||
|
||||
private slots:
|
||||
void updateRunningStatus(bool running);
|
||||
private slots:
|
||||
void onGameUpdateError(QString error);
|
||||
void packageCurrent(const QModelIndex ¤t, const QModelIndex &previous);
|
||||
void showContextMenu(const QPoint &pos);
|
||||
void onFilterTextChanged(const QString & newContents);
|
||||
void packageCurrent(const QModelIndex& current, const QModelIndex& previous);
|
||||
void showContextMenu(const QPoint& pos);
|
||||
void onFilterTextChanged(const QString& newContents);
|
||||
};
|
||||
|
@ -102,7 +102,6 @@
|
||||
<addaction name="actionInstall_Fabric"/>
|
||||
<addaction name="actionInstall_Quilt"/>
|
||||
<addaction name="actionInstall_LiteLoader"/>
|
||||
<addaction name="actionInstall_mods"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionAdd_to_Minecraft_jar"/>
|
||||
<addaction name="actionReplace_Minecraft_jar"/>
|
||||
@ -112,7 +111,6 @@
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionMinecraftFolder"/>
|
||||
<addaction name="actionLibrariesFolder"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionReload"/>
|
||||
<addaction name="actionDownload_All"/>
|
||||
</widget>
|
||||
@ -204,14 +202,6 @@
|
||||
<string>Install the LiteLoader package.</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionInstall_mods">
|
||||
<property name="text">
|
||||
<string>Install mods</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Install normal mods.</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionAdd_to_Minecraft_jar">
|
||||
<property name="text">
|
||||
<string>Add to Minecraft.jar</string>
|
||||
|
@ -339,6 +339,7 @@ void WorldListPage::mceditState(LoggedProcess::State state)
|
||||
{
|
||||
failed = true;
|
||||
}
|
||||
/* fallthrough */
|
||||
case LoggedProcess::Running:
|
||||
case LoggedProcess::Finished:
|
||||
{
|
||||
|
@ -33,8 +33,8 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "VanillaPage.h"
|
||||
#include "ui_VanillaPage.h"
|
||||
#include "CustomPage.h"
|
||||
#include "ui_CustomPage.h"
|
||||
|
||||
#include <QTabBar>
|
||||
|
||||
@ -46,32 +46,32 @@
|
||||
#include "minecraft/VanillaInstanceCreationTask.h"
|
||||
#include "ui/dialogs/NewInstanceDialog.h"
|
||||
|
||||
VanillaPage::VanillaPage(NewInstanceDialog *dialog, QWidget *parent)
|
||||
: QWidget(parent), dialog(dialog), ui(new Ui::VanillaPage)
|
||||
CustomPage::CustomPage(NewInstanceDialog *dialog, QWidget *parent)
|
||||
: QWidget(parent), dialog(dialog), ui(new Ui::CustomPage)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
ui->tabWidget->tabBar()->hide();
|
||||
connect(ui->versionList, &VersionSelectWidget::selectedVersionChanged, this, &VanillaPage::setSelectedVersion);
|
||||
connect(ui->versionList, &VersionSelectWidget::selectedVersionChanged, this, &CustomPage::setSelectedVersion);
|
||||
filterChanged();
|
||||
connect(ui->alphaFilter, &QCheckBox::stateChanged, this, &VanillaPage::filterChanged);
|
||||
connect(ui->betaFilter, &QCheckBox::stateChanged, this, &VanillaPage::filterChanged);
|
||||
connect(ui->snapshotFilter, &QCheckBox::stateChanged, this, &VanillaPage::filterChanged);
|
||||
connect(ui->oldSnapshotFilter, &QCheckBox::stateChanged, this, &VanillaPage::filterChanged);
|
||||
connect(ui->releaseFilter, &QCheckBox::stateChanged, this, &VanillaPage::filterChanged);
|
||||
connect(ui->experimentsFilter, &QCheckBox::stateChanged, this, &VanillaPage::filterChanged);
|
||||
connect(ui->refreshBtn, &QPushButton::clicked, this, &VanillaPage::refresh);
|
||||
connect(ui->alphaFilter, &QCheckBox::stateChanged, this, &CustomPage::filterChanged);
|
||||
connect(ui->betaFilter, &QCheckBox::stateChanged, this, &CustomPage::filterChanged);
|
||||
connect(ui->snapshotFilter, &QCheckBox::stateChanged, this, &CustomPage::filterChanged);
|
||||
connect(ui->oldSnapshotFilter, &QCheckBox::stateChanged, this, &CustomPage::filterChanged);
|
||||
connect(ui->releaseFilter, &QCheckBox::stateChanged, this, &CustomPage::filterChanged);
|
||||
connect(ui->experimentsFilter, &QCheckBox::stateChanged, this, &CustomPage::filterChanged);
|
||||
connect(ui->refreshBtn, &QPushButton::clicked, this, &CustomPage::refresh);
|
||||
|
||||
connect(ui->loaderVersionList, &VersionSelectWidget::selectedVersionChanged, this, &VanillaPage::setSelectedLoaderVersion);
|
||||
connect(ui->noneFilter, &QRadioButton::toggled, this, &VanillaPage::loaderFilterChanged);
|
||||
connect(ui->forgeFilter, &QRadioButton::toggled, this, &VanillaPage::loaderFilterChanged);
|
||||
connect(ui->fabricFilter, &QRadioButton::toggled, this, &VanillaPage::loaderFilterChanged);
|
||||
connect(ui->quiltFilter, &QRadioButton::toggled, this, &VanillaPage::loaderFilterChanged);
|
||||
connect(ui->liteLoaderFilter, &QRadioButton::toggled, this, &VanillaPage::loaderFilterChanged);
|
||||
connect(ui->loaderRefreshBtn, &QPushButton::clicked, this, &VanillaPage::loaderRefresh);
|
||||
connect(ui->loaderVersionList, &VersionSelectWidget::selectedVersionChanged, this, &CustomPage::setSelectedLoaderVersion);
|
||||
connect(ui->noneFilter, &QRadioButton::toggled, this, &CustomPage::loaderFilterChanged);
|
||||
connect(ui->forgeFilter, &QRadioButton::toggled, this, &CustomPage::loaderFilterChanged);
|
||||
connect(ui->fabricFilter, &QRadioButton::toggled, this, &CustomPage::loaderFilterChanged);
|
||||
connect(ui->quiltFilter, &QRadioButton::toggled, this, &CustomPage::loaderFilterChanged);
|
||||
connect(ui->liteLoaderFilter, &QRadioButton::toggled, this, &CustomPage::loaderFilterChanged);
|
||||
connect(ui->loaderRefreshBtn, &QPushButton::clicked, this, &CustomPage::loaderRefresh);
|
||||
|
||||
}
|
||||
|
||||
void VanillaPage::openedImpl()
|
||||
void CustomPage::openedImpl()
|
||||
{
|
||||
if(!initialized)
|
||||
{
|
||||
@ -85,19 +85,19 @@ void VanillaPage::openedImpl()
|
||||
}
|
||||
}
|
||||
|
||||
void VanillaPage::refresh()
|
||||
void CustomPage::refresh()
|
||||
{
|
||||
ui->versionList->loadList();
|
||||
}
|
||||
|
||||
void VanillaPage::loaderRefresh()
|
||||
void CustomPage::loaderRefresh()
|
||||
{
|
||||
if(ui->noneFilter->isChecked())
|
||||
return;
|
||||
ui->loaderVersionList->loadList();
|
||||
}
|
||||
|
||||
void VanillaPage::filterChanged()
|
||||
void CustomPage::filterChanged()
|
||||
{
|
||||
QStringList out;
|
||||
if(ui->alphaFilter->isChecked())
|
||||
@ -116,7 +116,7 @@ void VanillaPage::filterChanged()
|
||||
ui->versionList->setFilter(BaseVersionList::TypeRole, new RegexpFilter(regexp, false));
|
||||
}
|
||||
|
||||
void VanillaPage::loaderFilterChanged()
|
||||
void CustomPage::loaderFilterChanged()
|
||||
{
|
||||
QString minecraftVersion;
|
||||
if (m_selectedVersion)
|
||||
@ -172,37 +172,37 @@ void VanillaPage::loaderFilterChanged()
|
||||
ui->loaderVersionList->setEmptyString(tr("No versions are currently available for Minecraft %1").arg(minecraftVersion));
|
||||
}
|
||||
|
||||
VanillaPage::~VanillaPage()
|
||||
CustomPage::~CustomPage()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
bool VanillaPage::shouldDisplay() const
|
||||
bool CustomPage::shouldDisplay() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void VanillaPage::retranslate()
|
||||
void CustomPage::retranslate()
|
||||
{
|
||||
ui->retranslateUi(this);
|
||||
}
|
||||
|
||||
BaseVersion::Ptr VanillaPage::selectedVersion() const
|
||||
BaseVersion::Ptr CustomPage::selectedVersion() const
|
||||
{
|
||||
return m_selectedVersion;
|
||||
}
|
||||
|
||||
BaseVersion::Ptr VanillaPage::selectedLoaderVersion() const
|
||||
BaseVersion::Ptr CustomPage::selectedLoaderVersion() const
|
||||
{
|
||||
return m_selectedLoaderVersion;
|
||||
}
|
||||
|
||||
QString VanillaPage::selectedLoader() const
|
||||
QString CustomPage::selectedLoader() const
|
||||
{
|
||||
return m_selectedLoader;
|
||||
}
|
||||
|
||||
void VanillaPage::suggestCurrent()
|
||||
void CustomPage::suggestCurrent()
|
||||
{
|
||||
if (!isOpened)
|
||||
{
|
||||
@ -227,14 +227,14 @@ void VanillaPage::suggestCurrent()
|
||||
dialog->setSuggestedIcon("default");
|
||||
}
|
||||
|
||||
void VanillaPage::setSelectedVersion(BaseVersion::Ptr version)
|
||||
void CustomPage::setSelectedVersion(BaseVersion::Ptr version)
|
||||
{
|
||||
m_selectedVersion = version;
|
||||
suggestCurrent();
|
||||
loaderFilterChanged();
|
||||
}
|
||||
|
||||
void VanillaPage::setSelectedLoaderVersion(BaseVersion::Ptr version)
|
||||
void CustomPage::setSelectedLoaderVersion(BaseVersion::Ptr version)
|
||||
{
|
||||
m_selectedLoaderVersion = version;
|
||||
suggestCurrent();
|
@ -43,21 +43,21 @@
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class VanillaPage;
|
||||
class CustomPage;
|
||||
}
|
||||
|
||||
class NewInstanceDialog;
|
||||
|
||||
class VanillaPage : public QWidget, public BasePage
|
||||
class CustomPage : public QWidget, public BasePage
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit VanillaPage(NewInstanceDialog *dialog, QWidget *parent = 0);
|
||||
virtual ~VanillaPage();
|
||||
explicit CustomPage(NewInstanceDialog *dialog, QWidget *parent = 0);
|
||||
virtual ~CustomPage();
|
||||
virtual QString displayName() const override
|
||||
{
|
||||
return tr("Vanilla");
|
||||
return tr("Custom");
|
||||
}
|
||||
virtual QIcon icon() const override
|
||||
{
|
||||
@ -96,7 +96,7 @@ private:
|
||||
private:
|
||||
bool initialized = false;
|
||||
NewInstanceDialog *dialog = nullptr;
|
||||
Ui::VanillaPage *ui = nullptr;
|
||||
Ui::CustomPage *ui = nullptr;
|
||||
bool m_versionSetByUser = false;
|
||||
BaseVersion::Ptr m_selectedVersion;
|
||||
BaseVersion::Ptr m_selectedLoaderVersion;
|
@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>VanillaPage</class>
|
||||
<widget class="QWidget" name="VanillaPage">
|
||||
<class>CustomPage</class>
|
||||
<widget class="QWidget" name="CustomPage">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
@ -57,7 +57,7 @@ public:
|
||||
virtual ~ImportPage();
|
||||
virtual QString displayName() const override
|
||||
{
|
||||
return tr("Import from zip");
|
||||
return tr("Import");
|
||||
}
|
||||
virtual QIcon icon() const override
|
||||
{
|
||||
|
@ -6,12 +6,14 @@
|
||||
|
||||
#include "minecraft/MinecraftInstance.h"
|
||||
#include "minecraft/PackProfile.h"
|
||||
#include "minecraft/mod/ModFolderModel.h"
|
||||
|
||||
#include <QMessageBox>
|
||||
#include <algorithm>
|
||||
|
||||
namespace ResourceDownload {
|
||||
|
||||
ModModel::ModModel(BaseInstance const& base_inst, ResourceAPI* api) : ResourceModel(api), m_base_instance(base_inst) {}
|
||||
ModModel::ModModel(BaseInstance& base_inst, ResourceAPI* api) : ResourceModel(api), m_base_instance(base_inst) {}
|
||||
|
||||
/******** Make data requests ********/
|
||||
|
||||
@ -24,7 +26,7 @@ ResourceAPI::SearchArgs ModModel::createSearchArguments()
|
||||
|
||||
std::optional<std::list<Version>> versions{};
|
||||
|
||||
{ // Version filter
|
||||
{ // Version filter
|
||||
if (!m_filter->versions.empty())
|
||||
versions = m_filter->versions;
|
||||
}
|
||||
@ -36,7 +38,7 @@ ResourceAPI::SearchArgs ModModel::createSearchArguments()
|
||||
|
||||
ResourceAPI::VersionSearchArgs ModModel::createVersionsArguments(QModelIndex& entry)
|
||||
{
|
||||
auto& pack = m_packs[entry.row()];
|
||||
auto& pack = *m_packs[entry.row()];
|
||||
auto profile = static_cast<MinecraftInstance const&>(m_base_instance).getPackProfile();
|
||||
|
||||
Q_ASSERT(profile);
|
||||
@ -51,7 +53,7 @@ ResourceAPI::VersionSearchArgs ModModel::createVersionsArguments(QModelIndex& en
|
||||
|
||||
ResourceAPI::ProjectInfoArgs ModModel::createInfoArguments(QModelIndex& entry)
|
||||
{
|
||||
auto& pack = m_packs[entry.row()];
|
||||
auto& pack = *m_packs[entry.row()];
|
||||
return { pack };
|
||||
}
|
||||
|
||||
@ -67,4 +69,14 @@ void ModModel::searchWithTerm(const QString& term, unsigned int sort, bool filte
|
||||
refresh();
|
||||
}
|
||||
|
||||
bool ModModel::isPackInstalled(ModPlatform::IndexedPack::Ptr pack) const
|
||||
{
|
||||
auto allMods = static_cast<MinecraftInstance&>(m_base_instance).loaderModList()->allMods();
|
||||
return std::any_of(allMods.cbegin(), allMods.cend(), [pack](Mod* mod) {
|
||||
if (auto meta = mod->metadata(); meta)
|
||||
return meta->provider == pack->provider && meta->project_id == pack->addonId;
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace ResourceDownload
|
||||
|
@ -24,7 +24,7 @@ class ModModel : public ResourceModel {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ModModel(const BaseInstance&, ResourceAPI* api);
|
||||
ModModel(BaseInstance&, ResourceAPI* api);
|
||||
|
||||
/* Ask the API for more information */
|
||||
void searchWithTerm(const QString& term, unsigned int sort, bool filter_changed);
|
||||
@ -32,6 +32,7 @@ class ModModel : public ResourceModel {
|
||||
void loadIndexedPack(ModPlatform::IndexedPack& m, QJsonObject& obj) override = 0;
|
||||
void loadExtraPackInfo(ModPlatform::IndexedPack& m, QJsonObject& obj) override = 0;
|
||||
void loadIndexedPackVersions(ModPlatform::IndexedPack& m, QJsonArray& arr) override = 0;
|
||||
virtual ModPlatform::IndexedVersion loadDependencyVersions(const ModPlatform::Dependency& m, QJsonArray& arr) = 0;
|
||||
|
||||
void setFilter(std::shared_ptr<ModFilterWidget::Filter> filter) { m_filter = filter; }
|
||||
|
||||
@ -42,9 +43,10 @@ class ModModel : public ResourceModel {
|
||||
|
||||
protected:
|
||||
auto documentToArray(QJsonDocument& obj) const -> QJsonArray override = 0;
|
||||
virtual bool isPackInstalled(ModPlatform::IndexedPack::Ptr) const override;
|
||||
|
||||
protected:
|
||||
const BaseInstance& m_base_instance;
|
||||
BaseInstance& m_base_instance;
|
||||
|
||||
std::shared_ptr<ModFilterWidget::Filter> m_filter = nullptr;
|
||||
};
|
||||
|
@ -55,8 +55,7 @@
|
||||
|
||||
namespace ResourceDownload {
|
||||
|
||||
ModPage::ModPage(ModDownloadDialog* dialog, BaseInstance& instance)
|
||||
: ResourcePage(dialog, instance)
|
||||
ModPage::ModPage(ModDownloadDialog* dialog, BaseInstance& instance) : ResourcePage(dialog, instance)
|
||||
{
|
||||
connect(m_ui->searchButton, &QPushButton::clicked, this, &ModPage::triggerSearch);
|
||||
connect(m_ui->resourceFilterButton, &QPushButton::clicked, this, &ModPage::filterMods);
|
||||
@ -75,12 +74,10 @@ void ModPage::setFilterWidget(unique_qobject_ptr<ModFilterWidget>& widget)
|
||||
m_filter_widget->setInstance(&static_cast<MinecraftInstance&>(m_base_instance));
|
||||
m_filter = m_filter_widget->getFilter();
|
||||
|
||||
connect(m_filter_widget.get(), &ModFilterWidget::filterChanged, this, [&]{
|
||||
m_ui->searchButton->setStyleSheet("text-decoration: underline");
|
||||
});
|
||||
connect(m_filter_widget.get(), &ModFilterWidget::filterUnchanged, this, [&]{
|
||||
m_ui->searchButton->setStyleSheet("text-decoration: none");
|
||||
});
|
||||
connect(m_filter_widget.get(), &ModFilterWidget::filterChanged, this,
|
||||
[&] { m_ui->searchButton->setStyleSheet("text-decoration: underline"); });
|
||||
connect(m_filter_widget.get(), &ModFilterWidget::filterUnchanged, this,
|
||||
[&] { m_ui->searchButton->setStyleSheet("text-decoration: none"); });
|
||||
}
|
||||
|
||||
/******** Callbacks to events in the UI (set up in the derived classes) ********/
|
||||
@ -92,17 +89,13 @@ void ModPage::filterMods()
|
||||
|
||||
void ModPage::triggerSearch()
|
||||
{
|
||||
auto changed = m_filter_widget->changed();
|
||||
m_filter = m_filter_widget->getFilter();
|
||||
m_ui->packView->clearSelection();
|
||||
m_ui->packDescription->clear();
|
||||
m_ui->versionSelectionBox->clear();
|
||||
updateSelectionButton();
|
||||
|
||||
if (changed) {
|
||||
m_ui->packView->clearSelection();
|
||||
m_ui->packDescription->clear();
|
||||
m_ui->versionSelectionBox->clear();
|
||||
updateSelectionButton();
|
||||
}
|
||||
|
||||
static_cast<ModModel*>(m_model)->searchWithTerm(getSearchTerm(), m_ui->sortByBox->currentData().toUInt(), changed);
|
||||
static_cast<ModModel*>(m_model)->searchWithTerm(getSearchTerm(), m_ui->sortByBox->currentData().toUInt(), m_filter_widget->changed());
|
||||
m_fetch_progress.watch(m_model->activeSearchJob().get());
|
||||
}
|
||||
|
||||
@ -125,11 +118,13 @@ void ModPage::updateVersionList()
|
||||
QString mcVersion = packProfile->getComponentVersion("net.minecraft");
|
||||
|
||||
auto current_pack = getCurrentPack();
|
||||
for (int i = 0; i < current_pack.versions.size(); i++) {
|
||||
auto version = current_pack.versions[i];
|
||||
if (!current_pack)
|
||||
return;
|
||||
for (int i = 0; i < current_pack->versions.size(); i++) {
|
||||
auto version = current_pack->versions[i];
|
||||
bool valid = false;
|
||||
for(auto& mcVer : m_filter->versions){
|
||||
//NOTE: Flame doesn't care about loader, so passing it changes nothing.
|
||||
for (auto& mcVer : m_filter->versions) {
|
||||
// NOTE: Flame doesn't care about loader, so passing it changes nothing.
|
||||
if (validateVersion(version, mcVer.toString(), packProfile->getModLoaders())) {
|
||||
valid = true;
|
||||
break;
|
||||
@ -148,10 +143,12 @@ void ModPage::updateVersionList()
|
||||
updateSelectionButton();
|
||||
}
|
||||
|
||||
void ModPage::addResourceToDialog(ModPlatform::IndexedPack& pack, ModPlatform::IndexedVersion& version)
|
||||
void ModPage::addResourceToPage(ModPlatform::IndexedPack::Ptr pack,
|
||||
ModPlatform::IndexedVersion& version,
|
||||
const std::shared_ptr<ResourceFolderModel> base_model)
|
||||
{
|
||||
bool is_indexed = !APPLICATION->settings()->get("ModMetadataDisabled").toBool();
|
||||
m_parent_dialog->addResource(pack, version, is_indexed);
|
||||
m_model->addPack(pack, version, base_model, is_indexed);
|
||||
}
|
||||
|
||||
} // namespace ResourceDownload
|
||||
|
@ -8,8 +8,8 @@
|
||||
|
||||
#include "modplatform/ModIndex.h"
|
||||
|
||||
#include "ui/pages/modplatform/ResourcePage.h"
|
||||
#include "ui/pages/modplatform/ModModel.h"
|
||||
#include "ui/pages/modplatform/ResourcePage.h"
|
||||
#include "ui/widgets/ModFilterWidget.h"
|
||||
|
||||
namespace Ui {
|
||||
@ -25,13 +25,14 @@ class ModPage : public ResourcePage {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
template<typename T>
|
||||
template <typename T>
|
||||
static T* create(ModDownloadDialog* dialog, BaseInstance& instance)
|
||||
{
|
||||
auto page = new T(dialog, instance);
|
||||
auto model = static_cast<ModModel*>(page->getModel());
|
||||
|
||||
auto filter_widget = ModFilterWidget::create(static_cast<MinecraftInstance&>(instance).getPackProfile()->getComponentVersion("net.minecraft"), page);
|
||||
auto filter_widget =
|
||||
ModFilterWidget::create(static_cast<MinecraftInstance&>(instance).getPackProfile()->getComponentVersion("net.minecraft"), page);
|
||||
page->setFilterWidget(filter_widget);
|
||||
model->setFilter(page->getFilter());
|
||||
|
||||
@ -41,8 +42,6 @@ class ModPage : public ResourcePage {
|
||||
return page;
|
||||
}
|
||||
|
||||
~ModPage() override = default;
|
||||
|
||||
//: The plural version of 'mod'
|
||||
[[nodiscard]] inline QString resourcesString() const override { return tr("mods"); }
|
||||
//: The singular version of 'mods'
|
||||
@ -50,9 +49,13 @@ class ModPage : public ResourcePage {
|
||||
|
||||
[[nodiscard]] QMap<QString, QString> urlHandlers() const override;
|
||||
|
||||
void addResourceToDialog(ModPlatform::IndexedPack&, ModPlatform::IndexedVersion&) override;
|
||||
void addResourceToPage(ModPlatform::IndexedPack::Ptr,
|
||||
ModPlatform::IndexedVersion&,
|
||||
const std::shared_ptr<ResourceFolderModel>) override;
|
||||
|
||||
virtual auto validateVersion(ModPlatform::IndexedVersion& ver, QString mineVer, std::optional<ResourceAPI::ModLoaderTypes> loaders = {}) const -> bool = 0;
|
||||
virtual auto validateVersion(ModPlatform::IndexedVersion& ver,
|
||||
QString mineVer,
|
||||
std::optional<ResourceAPI::ModLoaderTypes> loaders = {}) const -> bool = 0;
|
||||
|
||||
[[nodiscard]] bool supportsFiltering() const override { return true; };
|
||||
auto getFilter() const -> const std::shared_ptr<ModFilterWidget::Filter> { return m_filter; }
|
||||
|
@ -6,9 +6,12 @@
|
||||
|
||||
#include <QCryptographicHash>
|
||||
#include <QIcon>
|
||||
#include <QList>
|
||||
#include <QMessageBox>
|
||||
#include <QPixmapCache>
|
||||
#include <QUrl>
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
|
||||
#include "Application.h"
|
||||
#include "BuildConfig.h"
|
||||
@ -45,16 +48,16 @@ auto ResourceModel::data(const QModelIndex& index, int role) const -> QVariant
|
||||
auto pack = m_packs.at(pos);
|
||||
switch (role) {
|
||||
case Qt::ToolTipRole: {
|
||||
if (pack.description.length() > 100) {
|
||||
if (pack->description.length() > 100) {
|
||||
// some magic to prevent to long tooltips and replace html linebreaks
|
||||
QString edit = pack.description.left(97);
|
||||
QString edit = pack->description.left(97);
|
||||
edit = edit.left(edit.lastIndexOf("<br>")).left(edit.lastIndexOf(" ")).append("...");
|
||||
return edit;
|
||||
}
|
||||
return pack.description;
|
||||
return pack->description;
|
||||
}
|
||||
case Qt::DecorationRole: {
|
||||
if (auto icon_or_none = const_cast<ResourceModel*>(this)->getIcon(const_cast<QModelIndex&>(index), pack.logoUrl);
|
||||
if (auto icon_or_none = const_cast<ResourceModel*>(this)->getIcon(const_cast<QModelIndex&>(index), pack->logoUrl);
|
||||
icon_or_none.has_value())
|
||||
return icon_or_none.value();
|
||||
|
||||
@ -69,11 +72,13 @@ auto ResourceModel::data(const QModelIndex& index, int role) const -> QVariant
|
||||
}
|
||||
// Custom data
|
||||
case UserDataTypes::TITLE:
|
||||
return pack.name;
|
||||
return pack->name;
|
||||
case UserDataTypes::DESCRIPTION:
|
||||
return pack.description;
|
||||
return pack->description;
|
||||
case UserDataTypes::SELECTED:
|
||||
return pack.isAnyVersionSelected();
|
||||
return pack->isAnyVersionSelected();
|
||||
case UserDataTypes::INSTALLED:
|
||||
return this->isPackInstalled(pack);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -92,6 +97,7 @@ QHash<int, QByteArray> ResourceModel::roleNames() const
|
||||
roles[UserDataTypes::TITLE] = "title";
|
||||
roles[UserDataTypes::DESCRIPTION] = "description";
|
||||
roles[UserDataTypes::SELECTED] = "selected";
|
||||
roles[UserDataTypes::INSTALLED] = "installed";
|
||||
|
||||
return roles;
|
||||
}
|
||||
@ -102,7 +108,7 @@ bool ResourceModel::setData(const QModelIndex& index, const QVariant& value, int
|
||||
if (pos >= m_packs.size() || pos < 0 || !index.isValid())
|
||||
return false;
|
||||
|
||||
m_packs[pos] = value.value<ModPlatform::IndexedPack>();
|
||||
m_packs[pos] = value.value<ModPlatform::IndexedPack::Ptr>();
|
||||
emit dataChanged(index, index);
|
||||
|
||||
return true;
|
||||
@ -161,7 +167,7 @@ void ResourceModel::loadEntry(QModelIndex& entry)
|
||||
if (!hasActiveInfoJob())
|
||||
m_current_info_job.clear();
|
||||
|
||||
if (!pack.versionsLoaded) {
|
||||
if (!pack->versionsLoaded) {
|
||||
auto args{ createVersionsArguments(entry) };
|
||||
auto callbacks{ createVersionsCallbacks(entry) };
|
||||
|
||||
@ -177,7 +183,7 @@ void ResourceModel::loadEntry(QModelIndex& entry)
|
||||
runInfoJob(job);
|
||||
}
|
||||
|
||||
if (!pack.extraDataLoaded) {
|
||||
if (!pack->extraDataLoaded) {
|
||||
auto args{ createInfoArguments(entry) };
|
||||
auto callbacks{ createInfoCallbacks(entry) };
|
||||
|
||||
@ -229,7 +235,7 @@ void ResourceModel::clearData()
|
||||
|
||||
void ResourceModel::runSearchJob(Task::Ptr ptr)
|
||||
{
|
||||
m_current_search_job = ptr;
|
||||
m_current_search_job.reset(ptr); // clean up first
|
||||
m_current_search_job->start();
|
||||
}
|
||||
void ResourceModel::runInfoJob(Task::Ptr ptr)
|
||||
@ -326,16 +332,24 @@ void ResourceModel::loadIndexedPackVersions(ModPlatform::IndexedPack&, QJsonArra
|
||||
|
||||
void ResourceModel::searchRequestSucceeded(QJsonDocument& doc)
|
||||
{
|
||||
QList<ModPlatform::IndexedPack> newList;
|
||||
QList<ModPlatform::IndexedPack::Ptr> newList;
|
||||
auto packs = documentToArray(doc);
|
||||
|
||||
for (auto packRaw : packs) {
|
||||
auto packObj = packRaw.toObject();
|
||||
|
||||
ModPlatform::IndexedPack pack;
|
||||
ModPlatform::IndexedPack::Ptr pack = std::make_shared<ModPlatform::IndexedPack>();
|
||||
try {
|
||||
loadIndexedPack(pack, packObj);
|
||||
newList.append(pack);
|
||||
loadIndexedPack(*pack, packObj);
|
||||
if (auto sel = std::find_if(m_selected.begin(), m_selected.end(),
|
||||
[&pack](const DownloadTaskPtr i) {
|
||||
const auto ipack = i->getPack();
|
||||
return ipack->provider == pack->provider && ipack->addonId == pack->addonId;
|
||||
});
|
||||
sel != m_selected.end()) {
|
||||
newList.append(sel->get()->getPack());
|
||||
} else
|
||||
newList.append(pack);
|
||||
} catch (const JSONValidationError& e) {
|
||||
qWarning() << "Error while loading resource from " << debugName() << ": " << e.cause();
|
||||
continue;
|
||||
@ -389,15 +403,15 @@ void ResourceModel::searchRequestAborted()
|
||||
|
||||
void ResourceModel::versionRequestSucceeded(QJsonDocument& doc, ModPlatform::IndexedPack& pack, const QModelIndex& index)
|
||||
{
|
||||
auto current_pack = data(index, Qt::UserRole).value<ModPlatform::IndexedPack>();
|
||||
auto current_pack = data(index, Qt::UserRole).value<ModPlatform::IndexedPack::Ptr>();
|
||||
|
||||
// Check if the index is still valid for this resource or not
|
||||
if (pack.addonId != current_pack.addonId)
|
||||
if (pack.addonId != current_pack->addonId)
|
||||
return;
|
||||
|
||||
try {
|
||||
auto arr = doc.isObject() ? Json::ensureArray(doc.object(), "data") : doc.array();
|
||||
loadIndexedPackVersions(current_pack, arr);
|
||||
loadIndexedPackVersions(*current_pack, arr);
|
||||
} catch (const JSONValidationError& e) {
|
||||
qDebug() << doc;
|
||||
qWarning() << "Error while reading " << debugName() << " resource version: " << e.cause();
|
||||
@ -416,15 +430,15 @@ void ResourceModel::versionRequestSucceeded(QJsonDocument& doc, ModPlatform::Ind
|
||||
|
||||
void ResourceModel::infoRequestSucceeded(QJsonDocument& doc, ModPlatform::IndexedPack& pack, const QModelIndex& index)
|
||||
{
|
||||
auto current_pack = data(index, Qt::UserRole).value<ModPlatform::IndexedPack>();
|
||||
auto current_pack = data(index, Qt::UserRole).value<ModPlatform::IndexedPack::Ptr>();
|
||||
|
||||
// Check if the index is still valid for this resource or not
|
||||
if (pack.addonId != current_pack.addonId)
|
||||
if (pack.addonId != current_pack->addonId)
|
||||
return;
|
||||
|
||||
try {
|
||||
auto obj = Json::requireObject(doc);
|
||||
loadExtraPackInfo(current_pack, obj);
|
||||
loadExtraPackInfo(*current_pack, obj);
|
||||
} catch (const JSONValidationError& e) {
|
||||
qDebug() << doc;
|
||||
qWarning() << "Error while reading " << debugName() << " resource info: " << e.cause();
|
||||
@ -441,4 +455,39 @@ void ResourceModel::infoRequestSucceeded(QJsonDocument& doc, ModPlatform::Indexe
|
||||
emit projectInfoUpdated();
|
||||
}
|
||||
|
||||
void ResourceModel::addPack(ModPlatform::IndexedPack::Ptr pack,
|
||||
ModPlatform::IndexedVersion& version,
|
||||
const std::shared_ptr<ResourceFolderModel> packs,
|
||||
bool is_indexed,
|
||||
QString custom_target_folder)
|
||||
{
|
||||
version.is_currently_selected = true;
|
||||
m_selected.append(makeShared<ResourceDownloadTask>(pack, version, packs, is_indexed, custom_target_folder));
|
||||
}
|
||||
|
||||
void ResourceModel::removePack(const QString& rem)
|
||||
{
|
||||
auto pred = [&rem](const DownloadTaskPtr i) { return rem == i->getName(); };
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 1, 0)
|
||||
m_selected.removeIf(pred);
|
||||
#else
|
||||
{
|
||||
for (auto it = m_selected.begin(); it != m_selected.end();)
|
||||
if (pred(*it))
|
||||
it = m_selected.erase(it);
|
||||
else
|
||||
++it;
|
||||
}
|
||||
#endif
|
||||
auto pack = std::find_if(m_packs.begin(), m_packs.end(), [&rem](const ModPlatform::IndexedPack::Ptr i) { return rem == i->name; });
|
||||
if (pack == m_packs.end()) { // ignore it if is not in the current search
|
||||
return;
|
||||
}
|
||||
if (!pack->get()->versionsLoaded) {
|
||||
return;
|
||||
}
|
||||
for (auto& ver : pack->get()->versions)
|
||||
ver.is_currently_selected = false;
|
||||
}
|
||||
|
||||
} // namespace ResourceDownload
|
||||
|
@ -10,6 +10,7 @@
|
||||
|
||||
#include "QObjectPtr.h"
|
||||
|
||||
#include "ResourceDownloadTask.h"
|
||||
#include "modplatform/ResourceAPI.h"
|
||||
|
||||
#include "tasks/ConcurrentTask.h"
|
||||
@ -29,6 +30,8 @@ class ResourceModel : public QAbstractListModel {
|
||||
Q_PROPERTY(QString search_term MEMBER m_search_term WRITE setSearchTerm)
|
||||
|
||||
public:
|
||||
using DownloadTaskPtr = shared_qobject_ptr<ResourceDownloadTask>;
|
||||
|
||||
ResourceModel(ResourceAPI* api);
|
||||
~ResourceModel() override;
|
||||
|
||||
@ -80,6 +83,14 @@ class ResourceModel : public QAbstractListModel {
|
||||
/** Gets the icon at the URL for the given index. If it's not fetched yet, fetch it and update when fisinhed. */
|
||||
std::optional<QIcon> getIcon(QModelIndex&, const QUrl&);
|
||||
|
||||
void addPack(ModPlatform::IndexedPack::Ptr pack,
|
||||
ModPlatform::IndexedVersion& version,
|
||||
const std::shared_ptr<ResourceFolderModel> packs,
|
||||
bool is_indexed = false,
|
||||
QString custom_target_folder = {});
|
||||
void removePack(const QString& rem);
|
||||
QList<DownloadTaskPtr> selectedPacks() { return m_selected; }
|
||||
|
||||
protected:
|
||||
/** Resets the model's data. */
|
||||
void clearData();
|
||||
@ -105,6 +116,8 @@ class ResourceModel : public QAbstractListModel {
|
||||
virtual void loadExtraPackInfo(ModPlatform::IndexedPack&, QJsonObject&);
|
||||
virtual void loadIndexedPackVersions(ModPlatform::IndexedPack&, QJsonArray&);
|
||||
|
||||
virtual bool isPackInstalled(ModPlatform::IndexedPack::Ptr) const { return false; }
|
||||
|
||||
protected:
|
||||
/* Basic search parameters */
|
||||
enum class SearchState { None, CanFetchMore, ResetRequested, Finished } m_search_state = SearchState::None;
|
||||
@ -123,7 +136,8 @@ class ResourceModel : public QAbstractListModel {
|
||||
QSet<QUrl> m_currently_running_icon_actions;
|
||||
QSet<QUrl> m_failed_icon_actions;
|
||||
|
||||
QList<ModPlatform::IndexedPack> m_packs;
|
||||
QList<ModPlatform::IndexedPack::Ptr> m_packs;
|
||||
QList<DownloadTaskPtr> m_selected;
|
||||
|
||||
// HACK: We need this to prevent callbacks from calling the model after it has already been deleted.
|
||||
// This leaks a tiny bit of memory per time the user has opened a resource dialog. How to make this better?
|
||||
|
@ -22,13 +22,13 @@ ResourceAPI::SearchArgs ResourcePackResourceModel::createSearchArguments()
|
||||
ResourceAPI::VersionSearchArgs ResourcePackResourceModel::createVersionsArguments(QModelIndex& entry)
|
||||
{
|
||||
auto& pack = m_packs[entry.row()];
|
||||
return { pack };
|
||||
return { *pack };
|
||||
}
|
||||
|
||||
ResourceAPI::ProjectInfoArgs ResourcePackResourceModel::createInfoArguments(QModelIndex& entry)
|
||||
{
|
||||
auto& pack = m_packs[entry.row()];
|
||||
return { pack };
|
||||
return { *pack };
|
||||
}
|
||||
|
||||
void ResourcePackResourceModel::searchWithTerm(const QString& term, unsigned int sort)
|
||||
|
@ -31,8 +31,6 @@ class ResourcePackResourcePage : public ResourcePage {
|
||||
return page;
|
||||
}
|
||||
|
||||
~ResourcePackResourcePage() override = default;
|
||||
|
||||
//: The plural version of 'resource pack'
|
||||
[[nodiscard]] inline QString resourcesString() const override { return tr("resource packs"); }
|
||||
//: The singular version of 'resource packs'
|
||||
|
@ -37,6 +37,7 @@
|
||||
*/
|
||||
|
||||
#include "ResourcePage.h"
|
||||
#include "modplatform/ModIndex.h"
|
||||
#include "ui_ResourcePage.h"
|
||||
|
||||
#include <QDesktopServices>
|
||||
@ -83,6 +84,8 @@ ResourcePage::ResourcePage(ResourceDownloadDialog* parent, BaseInstance& base_in
|
||||
ResourcePage::~ResourcePage()
|
||||
{
|
||||
delete m_ui;
|
||||
if (m_model)
|
||||
delete m_model;
|
||||
}
|
||||
|
||||
void ResourcePage::retranslate()
|
||||
@ -156,31 +159,35 @@ void ResourcePage::addSortings()
|
||||
m_ui->sortByBox->addItem(sorting.readable_name, QVariant(sorting.index));
|
||||
}
|
||||
|
||||
bool ResourcePage::setCurrentPack(ModPlatform::IndexedPack pack)
|
||||
bool ResourcePage::setCurrentPack(ModPlatform::IndexedPack::Ptr pack)
|
||||
{
|
||||
QVariant v;
|
||||
v.setValue(pack);
|
||||
return m_model->setData(m_ui->packView->currentIndex(), v, Qt::UserRole);
|
||||
}
|
||||
|
||||
ModPlatform::IndexedPack ResourcePage::getCurrentPack() const
|
||||
ModPlatform::IndexedPack::Ptr ResourcePage::getCurrentPack() const
|
||||
{
|
||||
return m_model->data(m_ui->packView->currentIndex(), Qt::UserRole).value<ModPlatform::IndexedPack>();
|
||||
return m_model->data(m_ui->packView->currentIndex(), Qt::UserRole).value<ModPlatform::IndexedPack::Ptr>();
|
||||
}
|
||||
|
||||
void ResourcePage::updateUi()
|
||||
{
|
||||
auto current_pack = getCurrentPack();
|
||||
|
||||
if (!current_pack) {
|
||||
m_ui->packDescription->setHtml({});
|
||||
m_ui->packDescription->flush();
|
||||
return;
|
||||
}
|
||||
QString text = "";
|
||||
QString name = current_pack.name;
|
||||
QString name = current_pack->name;
|
||||
|
||||
if (current_pack.websiteUrl.isEmpty())
|
||||
if (current_pack->websiteUrl.isEmpty())
|
||||
text = name;
|
||||
else
|
||||
text = "<a href=\"" + current_pack.websiteUrl + "\">" + name + "</a>";
|
||||
text = "<a href=\"" + current_pack->websiteUrl + "\">" + name + "</a>";
|
||||
|
||||
if (!current_pack.authors.empty()) {
|
||||
if (!current_pack->authors.empty()) {
|
||||
auto authorToStr = [](ModPlatform::ModpackAuthor& author) -> QString {
|
||||
if (author.url.isEmpty()) {
|
||||
return author.name;
|
||||
@ -188,44 +195,44 @@ void ResourcePage::updateUi()
|
||||
return QString("<a href=\"%1\">%2</a>").arg(author.url, author.name);
|
||||
};
|
||||
QStringList authorStrs;
|
||||
for (auto& author : current_pack.authors) {
|
||||
for (auto& author : current_pack->authors) {
|
||||
authorStrs.push_back(authorToStr(author));
|
||||
}
|
||||
text += "<br>" + tr(" by ") + authorStrs.join(", ");
|
||||
}
|
||||
|
||||
if (current_pack.extraDataLoaded) {
|
||||
if (!current_pack.extraData.donate.isEmpty()) {
|
||||
if (current_pack->extraDataLoaded) {
|
||||
if (!current_pack->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_pack.extraData.donate) {
|
||||
for (auto& donate : current_pack->extraData.donate) {
|
||||
donates.append(donateToStr(donate));
|
||||
}
|
||||
text += donates.join(", ");
|
||||
}
|
||||
|
||||
if (!current_pack.extraData.issuesUrl.isEmpty() || !current_pack.extraData.sourceUrl.isEmpty() ||
|
||||
!current_pack.extraData.wikiUrl.isEmpty() || !current_pack.extraData.discordUrl.isEmpty()) {
|
||||
if (!current_pack->extraData.issuesUrl.isEmpty() || !current_pack->extraData.sourceUrl.isEmpty() ||
|
||||
!current_pack->extraData.wikiUrl.isEmpty() || !current_pack->extraData.discordUrl.isEmpty()) {
|
||||
text += "<br><br>" + tr("External links:") + "<br>";
|
||||
}
|
||||
|
||||
if (!current_pack.extraData.issuesUrl.isEmpty())
|
||||
text += "- " + tr("Issues: <a href=%1>%1</a>").arg(current_pack.extraData.issuesUrl) + "<br>";
|
||||
if (!current_pack.extraData.wikiUrl.isEmpty())
|
||||
text += "- " + tr("Wiki: <a href=%1>%1</a>").arg(current_pack.extraData.wikiUrl) + "<br>";
|
||||
if (!current_pack.extraData.sourceUrl.isEmpty())
|
||||
text += "- " + tr("Source code: <a href=%1>%1</a>").arg(current_pack.extraData.sourceUrl) + "<br>";
|
||||
if (!current_pack.extraData.discordUrl.isEmpty())
|
||||
text += "- " + tr("Discord: <a href=%1>%1</a>").arg(current_pack.extraData.discordUrl) + "<br>";
|
||||
if (!current_pack->extraData.issuesUrl.isEmpty())
|
||||
text += "- " + tr("Issues: <a href=%1>%1</a>").arg(current_pack->extraData.issuesUrl) + "<br>";
|
||||
if (!current_pack->extraData.wikiUrl.isEmpty())
|
||||
text += "- " + tr("Wiki: <a href=%1>%1</a>").arg(current_pack->extraData.wikiUrl) + "<br>";
|
||||
if (!current_pack->extraData.sourceUrl.isEmpty())
|
||||
text += "- " + tr("Source code: <a href=%1>%1</a>").arg(current_pack->extraData.sourceUrl) + "<br>";
|
||||
if (!current_pack->extraData.discordUrl.isEmpty())
|
||||
text += "- " + tr("Discord: <a href=%1>%1</a>").arg(current_pack->extraData.discordUrl) + "<br>";
|
||||
}
|
||||
|
||||
text += "<hr>";
|
||||
|
||||
m_ui->packDescription->setHtml(
|
||||
text + (current_pack.extraData.body.isEmpty() ? current_pack.description : markdownToHTML(current_pack.extraData.body)));
|
||||
text + (current_pack->extraData.body.isEmpty() ? current_pack->description : markdownToHTML(current_pack->extraData.body)));
|
||||
m_ui->packDescription->flush();
|
||||
}
|
||||
|
||||
@ -237,10 +244,13 @@ void ResourcePage::updateSelectionButton()
|
||||
}
|
||||
|
||||
m_ui->resourceSelectionButton->setEnabled(true);
|
||||
if (!getCurrentPack().isVersionSelected(m_selected_version_index)) {
|
||||
m_ui->resourceSelectionButton->setText(tr("Select %1 for download").arg(resourceString()));
|
||||
if (auto current_pack = getCurrentPack(); current_pack) {
|
||||
if (!current_pack->isVersionSelected(m_selected_version_index))
|
||||
m_ui->resourceSelectionButton->setText(tr("Select %1 for download").arg(resourceString()));
|
||||
else
|
||||
m_ui->resourceSelectionButton->setText(tr("Deselect %1 for download").arg(resourceString()));
|
||||
} else {
|
||||
m_ui->resourceSelectionButton->setText(tr("Deselect %1 for download").arg(resourceString()));
|
||||
qWarning() << "Tried to update the selected button but there is not a pack selected";
|
||||
}
|
||||
}
|
||||
|
||||
@ -252,13 +262,14 @@ void ResourcePage::updateVersionList()
|
||||
m_ui->versionSelectionBox->clear();
|
||||
m_ui->versionSelectionBox->blockSignals(false);
|
||||
|
||||
for (int i = 0; i < current_pack.versions.size(); i++) {
|
||||
auto& version = current_pack.versions[i];
|
||||
if (optedOut(version))
|
||||
continue;
|
||||
if (current_pack)
|
||||
for (int i = 0; i < current_pack->versions.size(); i++) {
|
||||
auto& version = current_pack->versions[i];
|
||||
if (optedOut(version))
|
||||
continue;
|
||||
|
||||
m_ui->versionSelectionBox->addItem(current_pack.versions[i].version, QVariant(i));
|
||||
}
|
||||
m_ui->versionSelectionBox->addItem(current_pack->versions[i].version, QVariant(i));
|
||||
}
|
||||
|
||||
if (m_ui->versionSelectionBox->count() == 0) {
|
||||
m_ui->versionSelectionBox->addItem(tr("No valid version found."), QVariant(-1));
|
||||
@ -277,7 +288,7 @@ void ResourcePage::onSelectionChanged(QModelIndex curr, QModelIndex prev)
|
||||
auto current_pack = getCurrentPack();
|
||||
|
||||
bool request_load = false;
|
||||
if (!current_pack.versionsLoaded) {
|
||||
if (!current_pack || !current_pack->versionsLoaded) {
|
||||
m_ui->resourceSelectionButton->setText(tr("Loading versions..."));
|
||||
m_ui->resourceSelectionButton->setEnabled(false);
|
||||
|
||||
@ -286,7 +297,7 @@ void ResourcePage::onSelectionChanged(QModelIndex curr, QModelIndex prev)
|
||||
updateVersionList();
|
||||
}
|
||||
|
||||
if (!current_pack.extraDataLoaded)
|
||||
if (current_pack && !current_pack->extraDataLoaded)
|
||||
request_load = true;
|
||||
|
||||
if (request_load)
|
||||
@ -306,14 +317,26 @@ void ResourcePage::onVersionSelectionChanged(QString data)
|
||||
updateSelectionButton();
|
||||
}
|
||||
|
||||
void ResourcePage::addResourceToDialog(ModPlatform::IndexedPack& pack, ModPlatform::IndexedVersion& version)
|
||||
void ResourcePage::addResourceToDialog(ModPlatform::IndexedPack::Ptr pack, ModPlatform::IndexedVersion& version)
|
||||
{
|
||||
m_parent_dialog->addResource(pack, version);
|
||||
}
|
||||
|
||||
void ResourcePage::removeResourceFromDialog(ModPlatform::IndexedPack& pack, ModPlatform::IndexedVersion& version)
|
||||
void ResourcePage::removeResourceFromDialog(const QString& pack_name)
|
||||
{
|
||||
m_parent_dialog->removeResource(pack, version);
|
||||
m_parent_dialog->removeResource(pack_name);
|
||||
}
|
||||
|
||||
void ResourcePage::addResourceToPage(ModPlatform::IndexedPack::Ptr pack,
|
||||
ModPlatform::IndexedVersion& ver,
|
||||
const std::shared_ptr<ResourceFolderModel> base_model)
|
||||
{
|
||||
m_model->addPack(pack, ver, base_model);
|
||||
}
|
||||
|
||||
void ResourcePage::removeResourceFromPage(const QString& name)
|
||||
{
|
||||
m_model->removePack(name);
|
||||
}
|
||||
|
||||
void ResourcePage::onResourceSelected()
|
||||
@ -322,12 +345,12 @@ void ResourcePage::onResourceSelected()
|
||||
return;
|
||||
|
||||
auto current_pack = getCurrentPack();
|
||||
if (!current_pack.versionsLoaded)
|
||||
if (!current_pack || !current_pack->versionsLoaded)
|
||||
return;
|
||||
|
||||
auto& version = current_pack.versions[m_selected_version_index];
|
||||
auto& version = current_pack->versions[m_selected_version_index];
|
||||
if (version.is_currently_selected)
|
||||
removeResourceFromDialog(current_pack, version);
|
||||
removeResourceFromDialog(current_pack->name);
|
||||
else
|
||||
addResourceToDialog(current_pack, version);
|
||||
|
||||
@ -338,7 +361,7 @@ void ResourcePage::onResourceSelected()
|
||||
updateSelectionButton();
|
||||
|
||||
/* Force redraw on the resource list when the selection changes */
|
||||
m_ui->packView->adjustSize();
|
||||
m_ui->packView->repaint();
|
||||
}
|
||||
|
||||
void ResourcePage::openUrl(const QUrl& url)
|
||||
@ -368,7 +391,7 @@ void ResourcePage::openUrl(const QUrl& url)
|
||||
const QString slug = match.captured(1);
|
||||
|
||||
// ensure the user isn't opening the same mod
|
||||
if (slug != getCurrentPack().slug) {
|
||||
if (auto current_pack = getCurrentPack(); current_pack && slug != current_pack->slug) {
|
||||
m_parent_dialog->selectPage(page);
|
||||
|
||||
auto newPage = m_parent_dialog->getSelectedPage();
|
||||
|
@ -7,10 +7,12 @@
|
||||
#include <QTimer>
|
||||
#include <QWidget>
|
||||
|
||||
#include "ResourceDownloadTask.h"
|
||||
#include "modplatform/ModIndex.h"
|
||||
#include "modplatform/ResourceAPI.h"
|
||||
|
||||
#include "ui/pages/BasePage.h"
|
||||
#include "ui/pages/modplatform/ResourceModel.h"
|
||||
#include "ui/widgets/ProgressWidget.h"
|
||||
|
||||
namespace Ui {
|
||||
@ -27,6 +29,7 @@ class ResourceModel;
|
||||
class ResourcePage : public QWidget, public BasePage {
|
||||
Q_OBJECT
|
||||
public:
|
||||
using DownloadTaskPtr = shared_qobject_ptr<ResourceDownloadTask>;
|
||||
~ResourcePage() override;
|
||||
|
||||
/* Affects what the user sees */
|
||||
@ -57,8 +60,8 @@ class ResourcePage : public QWidget, public BasePage {
|
||||
/** Programatically set the term in the search bar. */
|
||||
void setSearchTerm(QString);
|
||||
|
||||
[[nodiscard]] bool setCurrentPack(ModPlatform::IndexedPack);
|
||||
[[nodiscard]] auto getCurrentPack() const -> ModPlatform::IndexedPack;
|
||||
[[nodiscard]] bool setCurrentPack(ModPlatform::IndexedPack::Ptr);
|
||||
[[nodiscard]] auto getCurrentPack() const -> ModPlatform::IndexedPack::Ptr;
|
||||
[[nodiscard]] auto getDialog() const -> const ResourceDownloadDialog* { return m_parent_dialog; }
|
||||
[[nodiscard]] auto getModel() const -> ResourceModel* { return m_model; }
|
||||
|
||||
@ -72,12 +75,17 @@ class ResourcePage : public QWidget, public BasePage {
|
||||
virtual void updateSelectionButton();
|
||||
virtual void updateVersionList();
|
||||
|
||||
virtual void addResourceToDialog(ModPlatform::IndexedPack&, ModPlatform::IndexedVersion&);
|
||||
virtual void removeResourceFromDialog(ModPlatform::IndexedPack&, ModPlatform::IndexedVersion&);
|
||||
void addResourceToDialog(ModPlatform::IndexedPack::Ptr, ModPlatform::IndexedVersion&);
|
||||
void removeResourceFromDialog(const QString& pack_name);
|
||||
virtual void removeResourceFromPage(const QString& name);
|
||||
virtual void addResourceToPage(ModPlatform::IndexedPack::Ptr, ModPlatform::IndexedVersion&, const std::shared_ptr<ResourceFolderModel>);
|
||||
|
||||
QList<DownloadTaskPtr> selectedPacks() { return m_model->selectedPacks(); }
|
||||
bool hasSelectedPacks() { return !(m_model->selectedPacks().isEmpty()); }
|
||||
|
||||
protected slots:
|
||||
virtual void triggerSearch() {}
|
||||
|
||||
|
||||
void onSelectionChanged(QModelIndex first, QModelIndex second);
|
||||
void onVersionSelectionChanged(QString data);
|
||||
void onResourceSelected();
|
||||
|
@ -22,13 +22,13 @@ ResourceAPI::SearchArgs ShaderPackResourceModel::createSearchArguments()
|
||||
ResourceAPI::VersionSearchArgs ShaderPackResourceModel::createVersionsArguments(QModelIndex& entry)
|
||||
{
|
||||
auto& pack = m_packs[entry.row()];
|
||||
return { pack };
|
||||
return { *pack };
|
||||
}
|
||||
|
||||
ResourceAPI::ProjectInfoArgs ShaderPackResourceModel::createInfoArguments(QModelIndex& entry)
|
||||
{
|
||||
auto& pack = m_packs[entry.row()];
|
||||
return { pack };
|
||||
return { *pack };
|
||||
}
|
||||
|
||||
void ShaderPackResourceModel::searchWithTerm(const QString& term, unsigned int sort)
|
||||
|
@ -13,8 +13,7 @@
|
||||
|
||||
namespace ResourceDownload {
|
||||
|
||||
ShaderPackResourcePage::ShaderPackResourcePage(ShaderPackDownloadDialog* dialog, BaseInstance& instance)
|
||||
: ResourcePage(dialog, instance)
|
||||
ShaderPackResourcePage::ShaderPackResourcePage(ShaderPackDownloadDialog* dialog, BaseInstance& instance) : ResourcePage(dialog, instance)
|
||||
{
|
||||
connect(m_ui->searchButton, &QPushButton::clicked, this, &ShaderPackResourcePage::triggerSearch);
|
||||
connect(m_ui->packView, &QListView::doubleClicked, this, &ShaderPackResourcePage::onResourceSelected);
|
||||
@ -38,17 +37,20 @@ QMap<QString, QString> ShaderPackResourcePage::urlHandlers() const
|
||||
{
|
||||
QMap<QString, QString> map;
|
||||
map.insert(QRegularExpression::anchoredPattern("(?:www\\.)?modrinth\\.com\\/shaders\\/([^\\/]+)\\/?"), "modrinth");
|
||||
map.insert(QRegularExpression::anchoredPattern("(?:www\\.)?curseforge\\.com\\/minecraft\\/customization\\/([^\\/]+)\\/?"), "curseforge");
|
||||
map.insert(QRegularExpression::anchoredPattern("(?:www\\.)?curseforge\\.com\\/minecraft\\/customization\\/([^\\/]+)\\/?"),
|
||||
"curseforge");
|
||||
map.insert(QRegularExpression::anchoredPattern("minecraft\\.curseforge\\.com\\/projects\\/([^\\/]+)\\/?"), "curseforge");
|
||||
return map;
|
||||
}
|
||||
|
||||
void ShaderPackResourcePage::addResourceToDialog(ModPlatform::IndexedPack& pack, ModPlatform::IndexedVersion& version)
|
||||
void ShaderPackResourcePage::addResourceToPage(ModPlatform::IndexedPack::Ptr pack,
|
||||
ModPlatform::IndexedVersion& version,
|
||||
const std::shared_ptr<ResourceFolderModel> base_model)
|
||||
{
|
||||
QString custom_target_folder;
|
||||
if (version.loaders.contains(QStringLiteral("canvas")))
|
||||
version.custom_target_folder = QStringLiteral("resourcepacks");
|
||||
|
||||
m_parent_dialog->addResource(pack, version);
|
||||
custom_target_folder = QStringLiteral("resourcepacks");
|
||||
m_model->addPack(pack, version, base_model, false, custom_target_folder);
|
||||
}
|
||||
|
||||
} // namespace ResourceDownload
|
||||
|
@ -31,8 +31,6 @@ class ShaderPackResourcePage : public ResourcePage {
|
||||
return page;
|
||||
}
|
||||
|
||||
~ShaderPackResourcePage() override = default;
|
||||
|
||||
//: The plural version of 'shader pack'
|
||||
[[nodiscard]] inline QString resourcesString() const override { return tr("shader packs"); }
|
||||
//: The singular version of 'shader packs'
|
||||
@ -40,7 +38,9 @@ class ShaderPackResourcePage : public ResourcePage {
|
||||
|
||||
[[nodiscard]] bool supportsFiltering() const override { return false; };
|
||||
|
||||
void addResourceToDialog(ModPlatform::IndexedPack&, ModPlatform::IndexedVersion&) override;
|
||||
void addResourceToPage(ModPlatform::IndexedPack::Ptr,
|
||||
ModPlatform::IndexedVersion&,
|
||||
const std::shared_ptr<ResourceFolderModel>) override;
|
||||
|
||||
[[nodiscard]] QMap<QString, QString> urlHandlers() const override;
|
||||
|
||||
|
@ -16,62 +16,49 @@
|
||||
|
||||
#include "AtlListModel.h"
|
||||
|
||||
#include <BuildConfig.h>
|
||||
#include <Application.h>
|
||||
#include <BuildConfig.h>
|
||||
#include <Json.h>
|
||||
|
||||
namespace Atl {
|
||||
|
||||
ListModel::ListModel(QObject *parent) : QAbstractListModel(parent)
|
||||
{
|
||||
}
|
||||
ListModel::ListModel(QObject* parent) : QAbstractListModel(parent) {}
|
||||
|
||||
ListModel::~ListModel()
|
||||
{
|
||||
}
|
||||
ListModel::~ListModel() {}
|
||||
|
||||
int ListModel::rowCount(const QModelIndex &parent) const
|
||||
int ListModel::rowCount(const QModelIndex& parent) const
|
||||
{
|
||||
return parent.isValid() ? 0 : modpacks.size();
|
||||
}
|
||||
|
||||
int ListModel::columnCount(const QModelIndex &parent) const
|
||||
int ListModel::columnCount(const QModelIndex& parent) const
|
||||
{
|
||||
return parent.isValid() ? 0 : 1;
|
||||
}
|
||||
|
||||
QVariant ListModel::data(const QModelIndex &index, int role) const
|
||||
QVariant ListModel::data(const QModelIndex& index, int role) const
|
||||
{
|
||||
int pos = index.row();
|
||||
if(pos >= modpacks.size() || pos < 0 || !index.isValid())
|
||||
{
|
||||
if (pos >= modpacks.size() || pos < 0 || !index.isValid()) {
|
||||
return QString("INVALID INDEX %1").arg(pos);
|
||||
}
|
||||
|
||||
ATLauncher::IndexedPack pack = modpacks.at(pos);
|
||||
if(role == Qt::DisplayRole)
|
||||
{
|
||||
if (role == Qt::DisplayRole) {
|
||||
return pack.name;
|
||||
}
|
||||
else if (role == Qt::ToolTipRole)
|
||||
{
|
||||
} else if (role == Qt::ToolTipRole) {
|
||||
return pack.name;
|
||||
}
|
||||
else if(role == Qt::DecorationRole)
|
||||
{
|
||||
if(m_logoMap.contains(pack.safeName))
|
||||
{
|
||||
} else if (role == Qt::DecorationRole) {
|
||||
if (m_logoMap.contains(pack.safeName)) {
|
||||
return (m_logoMap.value(pack.safeName));
|
||||
}
|
||||
auto icon = APPLICATION->getThemedIcon("atlauncher-placeholder");
|
||||
|
||||
auto url = QString(BuildConfig.ATL_DOWNLOAD_SERVER_URL + "launcher/images/%1.png").arg(pack.safeName.toLower());
|
||||
((ListModel *)this)->requestLogo(pack.safeName, url);
|
||||
((ListModel*)this)->requestLogo(pack.safeName, url);
|
||||
|
||||
return icon;
|
||||
}
|
||||
else if(role == Qt::UserRole)
|
||||
{
|
||||
} else if (role == Qt::UserRole) {
|
||||
QVariant v;
|
||||
v.setValue(pack);
|
||||
return v;
|
||||
@ -88,7 +75,7 @@ void ListModel::request()
|
||||
|
||||
auto netJob = makeShared<NetJob>("Atl::Request", APPLICATION->network());
|
||||
auto url = QString(BuildConfig.ATL_DOWNLOAD_SERVER_URL + "launcher/json/packsnew.json");
|
||||
netJob->addNetAction(Net::Download::makeByteArray(QUrl(url), &response));
|
||||
netJob->addNetAction(Net::Download::makeByteArray(QUrl(url), response));
|
||||
jobPtr = netJob;
|
||||
jobPtr->start();
|
||||
|
||||
@ -101,36 +88,38 @@ void ListModel::requestFinished()
|
||||
jobPtr.reset();
|
||||
|
||||
QJsonParseError parse_error;
|
||||
QJsonDocument doc = QJsonDocument::fromJson(response, &parse_error);
|
||||
if(parse_error.error != QJsonParseError::NoError) {
|
||||
QJsonDocument doc = QJsonDocument::fromJson(*response, &parse_error);
|
||||
if (parse_error.error != QJsonParseError::NoError) {
|
||||
qWarning() << "Error while parsing JSON response from ATL at " << parse_error.offset << " reason: " << parse_error.errorString();
|
||||
qWarning() << response;
|
||||
qWarning() << *response;
|
||||
return;
|
||||
}
|
||||
|
||||
QList<ATLauncher::IndexedPack> newList;
|
||||
|
||||
auto packs = doc.array();
|
||||
for(auto packRaw : packs) {
|
||||
for (auto packRaw : packs) {
|
||||
auto packObj = packRaw.toObject();
|
||||
|
||||
ATLauncher::IndexedPack pack;
|
||||
|
||||
try {
|
||||
ATLauncher::loadIndexedPack(pack, packObj);
|
||||
}
|
||||
catch (const JSONValidationError &e) {
|
||||
qDebug() << QString::fromUtf8(response);
|
||||
} catch (const JSONValidationError& e) {
|
||||
qDebug() << QString::fromUtf8(*response);
|
||||
qWarning() << "Error while reading pack manifest from ATLauncher: " << e.cause();
|
||||
return;
|
||||
}
|
||||
|
||||
// ignore packs without a published version
|
||||
if(pack.versions.length() == 0) continue;
|
||||
if (pack.versions.length() == 0)
|
||||
continue;
|
||||
// only display public packs (for now)
|
||||
if(pack.type != ATLauncher::PackType::Public) continue;
|
||||
if (pack.type != ATLauncher::PackType::Public)
|
||||
continue;
|
||||
// ignore "system" packs (Vanilla, Vanilla with Forge, etc)
|
||||
if(pack.system) continue;
|
||||
if (pack.system)
|
||||
continue;
|
||||
|
||||
newList.append(pack);
|
||||
}
|
||||
@ -145,14 +134,12 @@ void ListModel::requestFailed(QString reason)
|
||||
jobPtr.reset();
|
||||
}
|
||||
|
||||
void ListModel::getLogo(const QString &logo, const QString &logoUrl, LogoCallback callback)
|
||||
void ListModel::getLogo(const QString& logo, const QString& logoUrl, LogoCallback callback)
|
||||
{
|
||||
if(m_logoMap.contains(logo))
|
||||
{
|
||||
callback(APPLICATION->metacache()->resolveEntry("ATLauncherPacks", QString("logos/%1").arg(logo.section(".", 0, 0)))->getFullPath());
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_logoMap.contains(logo)) {
|
||||
callback(
|
||||
APPLICATION->metacache()->resolveEntry("ATLauncherPacks", QString("logos/%1").arg(logo.section(".", 0, 0)))->getFullPath());
|
||||
} else {
|
||||
requestLogo(logo, logoUrl);
|
||||
}
|
||||
}
|
||||
@ -168,36 +155,34 @@ void ListModel::logoLoaded(QString logo, QIcon out)
|
||||
m_loadingLogos.removeAll(logo);
|
||||
m_logoMap.insert(logo, out);
|
||||
|
||||
for(int i = 0; i < modpacks.size(); i++) {
|
||||
if(modpacks[i].safeName == logo) {
|
||||
emit dataChanged(createIndex(i, 0), createIndex(i, 0), {Qt::DecorationRole});
|
||||
for (int i = 0; i < modpacks.size(); i++) {
|
||||
if (modpacks[i].safeName == logo) {
|
||||
emit dataChanged(createIndex(i, 0), createIndex(i, 0), { Qt::DecorationRole });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ListModel::requestLogo(QString file, QString url)
|
||||
{
|
||||
if(m_loadingLogos.contains(file) || m_failedLogos.contains(file))
|
||||
{
|
||||
if (m_loadingLogos.contains(file) || m_failedLogos.contains(file)) {
|
||||
return;
|
||||
}
|
||||
|
||||
MetaEntryPtr entry = APPLICATION->metacache()->resolveEntry("ATLauncherPacks", QString("logos/%1").arg(file.section(".", 0, 0)));
|
||||
NetJob *job = new NetJob(QString("ATLauncher Icon Download %1").arg(file), APPLICATION->network());
|
||||
auto job = new NetJob(QString("ATLauncher Icon Download %1").arg(file), APPLICATION->network());
|
||||
job->addNetAction(Net::Download::makeCached(QUrl(url), entry));
|
||||
|
||||
auto fullPath = entry->getFullPath();
|
||||
QObject::connect(job, &NetJob::succeeded, this, [this, file, fullPath]
|
||||
{
|
||||
QObject::connect(job, &NetJob::succeeded, this, [this, file, fullPath, job] {
|
||||
job->deleteLater();
|
||||
emit logoLoaded(file, QIcon(fullPath));
|
||||
if(waitingCallbacks.contains(file))
|
||||
{
|
||||
if (waitingCallbacks.contains(file)) {
|
||||
waitingCallbacks.value(file)(fullPath);
|
||||
}
|
||||
});
|
||||
|
||||
QObject::connect(job, &NetJob::failed, this, [this, file]
|
||||
{
|
||||
QObject::connect(job, &NetJob::failed, this, [this, file, job] {
|
||||
job->deleteLater();
|
||||
emit logoFailed(file);
|
||||
});
|
||||
|
||||
@ -206,4 +191,4 @@ void ListModel::requestLogo(QString file, QString url)
|
||||
m_loadingLogos.append(file);
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace Atl
|
||||
|
@ -18,42 +18,41 @@
|
||||
|
||||
#include <QAbstractListModel>
|
||||
|
||||
#include "net/NetJob.h"
|
||||
#include <QIcon>
|
||||
#include <modplatform/atlauncher/ATLPackIndex.h>
|
||||
#include <QIcon>
|
||||
#include "net/NetJob.h"
|
||||
|
||||
namespace Atl {
|
||||
|
||||
typedef QMap<QString, QIcon> LogoMap;
|
||||
typedef std::function<void(QString)> LogoCallback;
|
||||
|
||||
class ListModel : public QAbstractListModel
|
||||
{
|
||||
class ListModel : public QAbstractListModel {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ListModel(QObject *parent);
|
||||
public:
|
||||
ListModel(QObject* parent);
|
||||
virtual ~ListModel();
|
||||
|
||||
int rowCount(const QModelIndex &parent) const override;
|
||||
int columnCount(const QModelIndex &parent) const override;
|
||||
QVariant data(const QModelIndex &index, int role) const override;
|
||||
int rowCount(const QModelIndex& parent) const override;
|
||||
int columnCount(const QModelIndex& parent) const override;
|
||||
QVariant data(const QModelIndex& index, int role) const override;
|
||||
|
||||
void request();
|
||||
|
||||
void getLogo(const QString &logo, const QString &logoUrl, LogoCallback callback);
|
||||
void getLogo(const QString& logo, const QString& logoUrl, LogoCallback callback);
|
||||
|
||||
private slots:
|
||||
private slots:
|
||||
void requestFinished();
|
||||
void requestFailed(QString reason);
|
||||
|
||||
void logoFailed(QString logo);
|
||||
void logoLoaded(QString logo, QIcon out);
|
||||
|
||||
private:
|
||||
private:
|
||||
void requestLogo(QString file, QString url);
|
||||
|
||||
private:
|
||||
private:
|
||||
QList<ATLauncher::IndexedPack> modpacks;
|
||||
|
||||
QStringList m_failedLogos;
|
||||
@ -62,7 +61,7 @@ private:
|
||||
QMap<QString, LogoCallback> waitingCallbacks;
|
||||
|
||||
NetJob::Ptr jobPtr;
|
||||
QByteArray response;
|
||||
std::shared_ptr<QByteArray> response = std::make_shared<QByteArray>();
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace Atl
|
||||
|
@ -152,7 +152,7 @@ Qt::ItemFlags AtlOptionalModListModel::flags(const QModelIndex &index) const {
|
||||
void AtlOptionalModListModel::useShareCode(const QString& code) {
|
||||
m_jobPtr.reset(new NetJob("Atl::Request", APPLICATION->network()));
|
||||
auto url = QString(BuildConfig.ATL_API_BASE_URL + "share-codes/" + code);
|
||||
m_jobPtr->addNetAction(Net::Download::makeByteArray(QUrl(url), &m_response));
|
||||
m_jobPtr->addNetAction(Net::Download::makeByteArray(QUrl(url), m_response));
|
||||
|
||||
connect(m_jobPtr.get(), &NetJob::succeeded,
|
||||
this, &AtlOptionalModListModel::shareCodeSuccess);
|
||||
@ -166,10 +166,10 @@ void AtlOptionalModListModel::shareCodeSuccess() {
|
||||
m_jobPtr.reset();
|
||||
|
||||
QJsonParseError parse_error {};
|
||||
auto doc = QJsonDocument::fromJson(m_response, &parse_error);
|
||||
auto doc = QJsonDocument::fromJson(*m_response, &parse_error);
|
||||
if (parse_error.error != QJsonParseError::NoError) {
|
||||
qWarning() << "Error while parsing JSON response from ATL at " << parse_error.offset << " reason: " << parse_error.errorString();
|
||||
qWarning() << m_response;
|
||||
qWarning() << *m_response;
|
||||
return;
|
||||
}
|
||||
auto obj = doc.object();
|
||||
@ -179,7 +179,7 @@ void AtlOptionalModListModel::shareCodeSuccess() {
|
||||
ATLauncher::loadShareCodeResponse(response, obj);
|
||||
}
|
||||
catch (const JSONValidationError& e) {
|
||||
qDebug() << QString::fromUtf8(m_response);
|
||||
qDebug() << QString::fromUtf8(*m_response);
|
||||
qWarning() << "Error while reading response from ATLauncher: " << e.cause();
|
||||
return;
|
||||
}
|
||||
|
@ -82,9 +82,9 @@ private:
|
||||
void toggleMod(ATLauncher::VersionMod mod, int index);
|
||||
void setMod(ATLauncher::VersionMod mod, int index, bool enable, bool shouldEmit = true);
|
||||
|
||||
private:
|
||||
private:
|
||||
NetJob::Ptr m_jobPtr;
|
||||
QByteArray m_response;
|
||||
std::shared_ptr<QByteArray> m_response = std::make_shared<QByteArray>();
|
||||
|
||||
ATLauncher::PackVersion m_version;
|
||||
QVector<ATLauncher::VersionMod> m_mods;
|
||||
|
@ -68,7 +68,7 @@ QString AtlUserInteractionSupportImpl::chooseVersion(Meta::VersionList::Ptr vlis
|
||||
// select recommended build
|
||||
for (int i = 0; i < vlist->versions().size(); i++) {
|
||||
auto version = vlist->versions().at(i);
|
||||
auto reqs = version->requires();
|
||||
auto reqs = version->requiredSet();
|
||||
|
||||
// filter by minecraft version, if the loader depends on a certain version.
|
||||
if (minecraftVersion != nullptr) {
|
||||
|
@ -42,15 +42,15 @@
|
||||
class AtlUserInteractionSupportImpl : public QObject, public ATLauncher::UserInteractionSupport {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
public:
|
||||
AtlUserInteractionSupportImpl(QWidget* parent);
|
||||
virtual ~AtlUserInteractionSupportImpl() = default;
|
||||
|
||||
private:
|
||||
private:
|
||||
QString chooseVersion(Meta::VersionList::Ptr vlist, QString minecraftVersion) override;
|
||||
std::optional<QVector<QString>> chooseOptionalMods(ATLauncher::PackVersion version, QVector<ATLauncher::VersionMod> mods) override;
|
||||
void displayMessage(QString message) override;
|
||||
|
||||
private:
|
||||
private:
|
||||
QWidget* m_parent;
|
||||
|
||||
};
|
||||
|
@ -60,6 +60,8 @@ QVariant ListModel::data(const QModelIndex& index, int role) const
|
||||
return pack.description;
|
||||
case UserDataTypes::SELECTED:
|
||||
return false;
|
||||
case UserDataTypes::INSTALLED:
|
||||
return false;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -169,7 +171,7 @@ void ListModel::performPaginatedSearch()
|
||||
.arg(currentSearchTerm)
|
||||
.arg(currentSort + 1);
|
||||
|
||||
netJob->addNetAction(Net::Download::makeByteArray(QUrl(searchUrl), &response));
|
||||
netJob->addNetAction(Net::Download::makeByteArray(QUrl(searchUrl), response));
|
||||
jobPtr = netJob;
|
||||
jobPtr->start();
|
||||
QObject::connect(netJob.get(), &NetJob::succeeded, this, &ListModel::searchRequestFinished);
|
||||
@ -202,11 +204,11 @@ void Flame::ListModel::searchRequestFinished()
|
||||
jobPtr.reset();
|
||||
|
||||
QJsonParseError parse_error;
|
||||
QJsonDocument doc = QJsonDocument::fromJson(response, &parse_error);
|
||||
QJsonDocument doc = QJsonDocument::fromJson(*response, &parse_error);
|
||||
if (parse_error.error != QJsonParseError::NoError) {
|
||||
qWarning() << "Error while parsing JSON response from CurseForge at " << parse_error.offset
|
||||
<< " reason: " << parse_error.errorString();
|
||||
qWarning() << response;
|
||||
qWarning() << *response;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -3,46 +3,44 @@
|
||||
#include <RWStorage.h>
|
||||
|
||||
#include <QAbstractListModel>
|
||||
#include <QSortFilterProxyModel>
|
||||
#include <QThreadPool>
|
||||
#include <QIcon>
|
||||
#include <QStyledItemDelegate>
|
||||
#include <QList>
|
||||
#include <QMetaType>
|
||||
#include <QSortFilterProxyModel>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QMetaType>
|
||||
#include <QStyledItemDelegate>
|
||||
#include <QThreadPool>
|
||||
|
||||
#include <functional>
|
||||
#include <net/NetJob.h>
|
||||
#include <functional>
|
||||
|
||||
#include <modplatform/flame/FlamePackIndex.h>
|
||||
|
||||
namespace Flame {
|
||||
|
||||
|
||||
typedef QMap<QString, QIcon> LogoMap;
|
||||
typedef std::function<void(QString)> LogoCallback;
|
||||
|
||||
class ListModel : public QAbstractListModel
|
||||
{
|
||||
class ListModel : public QAbstractListModel {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ListModel(QObject *parent);
|
||||
public:
|
||||
ListModel(QObject* parent);
|
||||
virtual ~ListModel();
|
||||
|
||||
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;
|
||||
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;
|
||||
|
||||
void getLogo(const QString &logo, const QString &logoUrl, LogoCallback callback);
|
||||
void searchWithTerm(const QString & term, const int sort);
|
||||
void getLogo(const QString& logo, const QString& logoUrl, LogoCallback callback);
|
||||
void searchWithTerm(const QString& term, const int sort);
|
||||
|
||||
private slots:
|
||||
private slots:
|
||||
void performPaginatedSearch();
|
||||
|
||||
void logoFailed(QString logo);
|
||||
@ -51,10 +49,10 @@ private slots:
|
||||
void searchRequestFinished();
|
||||
void searchRequestFailed(QString reason);
|
||||
|
||||
private:
|
||||
private:
|
||||
void requestLogo(QString file, QString url);
|
||||
|
||||
private:
|
||||
private:
|
||||
QList<IndexedPack> modpacks;
|
||||
QStringList m_failedLogos;
|
||||
QStringList m_loadingLogos;
|
||||
@ -64,14 +62,9 @@ private:
|
||||
QString currentSearchTerm;
|
||||
int currentSort = 0;
|
||||
int nextSearchOffset = 0;
|
||||
enum SearchState {
|
||||
None,
|
||||
CanPossiblyFetchMore,
|
||||
ResetRequested,
|
||||
Finished
|
||||
} searchState = None;
|
||||
enum SearchState { None, CanPossiblyFetchMore, ResetRequested, Finished } searchState = None;
|
||||
NetJob::Ptr jobPtr;
|
||||
QByteArray response;
|
||||
std::shared_ptr<QByteArray> response = std::make_shared<QByteArray>();
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace Flame
|
||||
|
@ -130,7 +130,7 @@ void FlamePage::onSelectionChanged(QModelIndex curr, QModelIndex prev)
|
||||
if (current.versionsLoaded == false) {
|
||||
qDebug() << "Loading flame modpack versions";
|
||||
auto netJob = new NetJob(QString("Flame::PackVersions(%1)").arg(current.name), APPLICATION->network());
|
||||
auto response = new QByteArray();
|
||||
auto response = std::make_shared<QByteArray>();
|
||||
int addonId = current.addonId;
|
||||
netJob->addNetAction(Net::Download::makeByteArray(QString("https://api.curseforge.com/v1/mods/%1/files").arg(addonId), response));
|
||||
|
||||
@ -170,10 +170,7 @@ void FlamePage::onSelectionChanged(QModelIndex curr, QModelIndex prev)
|
||||
}
|
||||
suggestCurrent();
|
||||
});
|
||||
QObject::connect(netJob, &NetJob::finished, this, [response, netJob] {
|
||||
netJob->deleteLater();
|
||||
delete response;
|
||||
});
|
||||
QObject::connect(netJob, &NetJob::finished, this, [response, netJob] { netJob->deleteLater(); });
|
||||
netJob->start();
|
||||
} else {
|
||||
for (auto version : current.versions) {
|
||||
|
@ -11,7 +11,7 @@
|
||||
|
||||
namespace ResourceDownload {
|
||||
|
||||
FlameModModel::FlameModModel(BaseInstance const& base) : ModModel(base, new FlameAPI) {}
|
||||
FlameModModel::FlameModModel(BaseInstance& base) : ModModel(base, new FlameAPI) {}
|
||||
|
||||
void FlameModModel::loadIndexedPack(ModPlatform::IndexedPack& m, QJsonObject& obj)
|
||||
{
|
||||
@ -29,6 +29,11 @@ void FlameModModel::loadIndexedPackVersions(ModPlatform::IndexedPack& m, QJsonAr
|
||||
FlameMod::loadIndexedPackVersions(m, arr, APPLICATION->network(), &m_base_instance);
|
||||
}
|
||||
|
||||
auto FlameModModel::loadDependencyVersions(const ModPlatform::Dependency& m, QJsonArray& arr) -> ModPlatform::IndexedVersion
|
||||
{
|
||||
return FlameMod::loadDependencyVersions(m, arr);
|
||||
};
|
||||
|
||||
auto FlameModModel::documentToArray(QJsonDocument& obj) const -> QJsonArray
|
||||
{
|
||||
return Json::ensureArray(obj.object(), "data");
|
||||
@ -81,7 +86,7 @@ void FlameTexturePackModel::loadIndexedPackVersions(ModPlatform::IndexedPack& m,
|
||||
auto const& mc_versions = version.mcVersion;
|
||||
|
||||
if (std::any_of(mc_versions.constBegin(), mc_versions.constEnd(),
|
||||
[this](auto const& mc_version){ return Version(mc_version) <= maximumTexturePackVersion(); }))
|
||||
[this](auto const& mc_version) { return Version(mc_version) <= maximumTexturePackVersion(); }))
|
||||
filtered_versions.push_back(version);
|
||||
}
|
||||
|
||||
|
@ -14,7 +14,7 @@ class FlameModModel : public ModModel {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
FlameModModel(const BaseInstance&);
|
||||
FlameModModel(BaseInstance&);
|
||||
~FlameModModel() override = default;
|
||||
|
||||
private:
|
||||
@ -24,6 +24,7 @@ class FlameModModel : public ModModel {
|
||||
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 loadDependencyVersions(const ModPlatform::Dependency& m, QJsonArray& arr) -> ModPlatform::IndexedVersion override;
|
||||
|
||||
auto documentToArray(QJsonDocument& obj) const -> QJsonArray override;
|
||||
};
|
||||
|
@ -38,11 +38,11 @@
|
||||
#include "net/HttpMetaCache.h"
|
||||
#include "net/NetJob.h"
|
||||
|
||||
#include "StringUtils.h"
|
||||
#include <Version.h>
|
||||
#include "StringUtils.h"
|
||||
|
||||
#include <QtMath>
|
||||
#include <QLabel>
|
||||
#include <QtMath>
|
||||
|
||||
#include <RWStorage.h>
|
||||
|
||||
@ -50,33 +50,33 @@
|
||||
|
||||
namespace LegacyFTB {
|
||||
|
||||
FilterModel::FilterModel(QObject *parent) : QSortFilterProxyModel(parent)
|
||||
FilterModel::FilterModel(QObject* parent) : QSortFilterProxyModel(parent)
|
||||
{
|
||||
currentSorting = Sorting::ByGameVersion;
|
||||
sortings.insert(tr("Sort by Name"), Sorting::ByName);
|
||||
sortings.insert(tr("Sort by Game Version"), Sorting::ByGameVersion);
|
||||
}
|
||||
|
||||
bool FilterModel::lessThan(const QModelIndex &left, const QModelIndex &right) const
|
||||
bool FilterModel::lessThan(const QModelIndex& left, const QModelIndex& right) const
|
||||
{
|
||||
Modpack leftPack = sourceModel()->data(left, Qt::UserRole).value<Modpack>();
|
||||
Modpack rightPack = sourceModel()->data(right, Qt::UserRole).value<Modpack>();
|
||||
|
||||
if(currentSorting == Sorting::ByGameVersion) {
|
||||
if (currentSorting == Sorting::ByGameVersion) {
|
||||
Version lv(leftPack.mcVersion);
|
||||
Version rv(rightPack.mcVersion);
|
||||
return lv < rv;
|
||||
|
||||
} else if(currentSorting == Sorting::ByName) {
|
||||
} else if (currentSorting == Sorting::ByName) {
|
||||
return StringUtils::naturalCompare(leftPack.name, rightPack.name, Qt::CaseSensitive) >= 0;
|
||||
}
|
||||
|
||||
//UHM, some inavlid value set?!
|
||||
// UHM, some inavlid value set?!
|
||||
qWarning() << "Invalid sorting set!";
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FilterModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
|
||||
bool FilterModel::filterAcceptsRow(int sourceRow, const QModelIndex& sourceParent) const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@ -102,18 +102,13 @@ FilterModel::Sorting FilterModel::getCurrentSorting()
|
||||
return currentSorting;
|
||||
}
|
||||
|
||||
ListModel::ListModel(QObject *parent) : QAbstractListModel(parent)
|
||||
{
|
||||
}
|
||||
ListModel::ListModel(QObject* parent) : QAbstractListModel(parent) {}
|
||||
|
||||
ListModel::~ListModel()
|
||||
{
|
||||
}
|
||||
ListModel::~ListModel() {}
|
||||
|
||||
QString ListModel::translatePackType(PackType type) const
|
||||
{
|
||||
switch(type)
|
||||
{
|
||||
switch (type) {
|
||||
case PackType::Public:
|
||||
return tr("Public Modpack");
|
||||
case PackType::ThirdParty:
|
||||
@ -125,67 +120,51 @@ QString ListModel::translatePackType(PackType type) const
|
||||
return QString();
|
||||
}
|
||||
|
||||
int ListModel::rowCount(const QModelIndex &parent) const
|
||||
int ListModel::rowCount(const QModelIndex& parent) const
|
||||
{
|
||||
return parent.isValid() ? 0 : modpacks.size();
|
||||
}
|
||||
|
||||
int ListModel::columnCount(const QModelIndex &parent) const
|
||||
int ListModel::columnCount(const QModelIndex& parent) const
|
||||
{
|
||||
return parent.isValid() ? 0 : 1;
|
||||
}
|
||||
|
||||
QVariant ListModel::data(const QModelIndex &index, int role) const
|
||||
QVariant ListModel::data(const QModelIndex& index, int role) const
|
||||
{
|
||||
int pos = index.row();
|
||||
if(pos >= modpacks.size() || pos < 0 || !index.isValid())
|
||||
{
|
||||
if (pos >= modpacks.size() || pos < 0 || !index.isValid()) {
|
||||
return QString("INVALID INDEX %1").arg(pos);
|
||||
}
|
||||
|
||||
Modpack pack = modpacks.at(pos);
|
||||
if(role == Qt::DisplayRole)
|
||||
{
|
||||
if (role == Qt::DisplayRole) {
|
||||
return pack.name + "\n" + translatePackType(pack.type);
|
||||
}
|
||||
else if (role == Qt::ToolTipRole)
|
||||
{
|
||||
if(pack.description.length() > 100)
|
||||
{
|
||||
//some magic to prevent to long tooltips and replace html linebreaks
|
||||
} 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;
|
||||
|
||||
}
|
||||
return pack.description;
|
||||
}
|
||||
else if(role == Qt::DecorationRole)
|
||||
{
|
||||
if(m_logoMap.contains(pack.logo))
|
||||
{
|
||||
} else if (role == Qt::DecorationRole) {
|
||||
if (m_logoMap.contains(pack.logo)) {
|
||||
return (m_logoMap.value(pack.logo));
|
||||
}
|
||||
QIcon icon = APPLICATION->getThemedIcon("screenshot-placeholder");
|
||||
((ListModel *)this)->requestLogo(pack.logo);
|
||||
((ListModel*)this)->requestLogo(pack.logo);
|
||||
return icon;
|
||||
}
|
||||
else if(role == Qt::ForegroundRole)
|
||||
{
|
||||
if(pack.broken)
|
||||
{
|
||||
//FIXME: Hardcoded color
|
||||
} else if (role == Qt::ForegroundRole) {
|
||||
if (pack.broken) {
|
||||
// FIXME: Hardcoded color
|
||||
return QColor(255, 0, 50);
|
||||
}
|
||||
else if(pack.bugged)
|
||||
{
|
||||
//FIXME: Hardcoded color
|
||||
//bugged pack, currently only indicates bugged xml
|
||||
} else if (pack.bugged) {
|
||||
// FIXME: Hardcoded color
|
||||
// bugged pack, currently only indicates bugged xml
|
||||
return QColor(244, 229, 66);
|
||||
}
|
||||
}
|
||||
else if(role == Qt::UserRole)
|
||||
{
|
||||
} else if (role == Qt::UserRole) {
|
||||
QVariant v;
|
||||
v.setValue(pack);
|
||||
return v;
|
||||
@ -222,8 +201,7 @@ Modpack ListModel::at(int row)
|
||||
|
||||
void ListModel::remove(int row)
|
||||
{
|
||||
if(row < 0 || row >= modpacks.size())
|
||||
{
|
||||
if (row < 0 || row >= modpacks.size()) {
|
||||
qWarning() << "Attempt to remove FTB modpacks with invalid row" << row;
|
||||
return;
|
||||
}
|
||||
@ -247,27 +225,25 @@ void ListModel::logoFailed(QString logo)
|
||||
|
||||
void ListModel::requestLogo(QString file)
|
||||
{
|
||||
if(m_loadingLogos.contains(file) || m_failedLogos.contains(file))
|
||||
{
|
||||
if (m_loadingLogos.contains(file) || m_failedLogos.contains(file)) {
|
||||
return;
|
||||
}
|
||||
|
||||
MetaEntryPtr entry = APPLICATION->metacache()->resolveEntry("FTBPacks", QString("logos/%1").arg(file.section(".", 0, 0)));
|
||||
NetJob *job = new NetJob(QString("FTB Icon Download for %1").arg(file), APPLICATION->network());
|
||||
NetJob* job = new NetJob(QString("FTB Icon Download for %1").arg(file), APPLICATION->network());
|
||||
job->addNetAction(Net::Download::makeCached(QUrl(QString(BuildConfig.LEGACY_FTB_CDN_BASE_URL + "static/%1").arg(file)), entry));
|
||||
|
||||
auto fullPath = entry->getFullPath();
|
||||
QObject::connect(job, &NetJob::finished, this, [this, file, fullPath]
|
||||
{
|
||||
QObject::connect(job, &NetJob::finished, this, [this, file, fullPath, job] {
|
||||
job->deleteLater();
|
||||
emit logoLoaded(file, QIcon(fullPath));
|
||||
if(waitingCallbacks.contains(file))
|
||||
{
|
||||
if (waitingCallbacks.contains(file)) {
|
||||
waitingCallbacks.value(file)(fullPath);
|
||||
}
|
||||
});
|
||||
|
||||
QObject::connect(job, &NetJob::failed, this, [this, file]
|
||||
{
|
||||
QObject::connect(job, &NetJob::failed, this, [this, file, job] {
|
||||
job->deleteLater();
|
||||
emit logoFailed(file);
|
||||
});
|
||||
|
||||
@ -276,21 +252,18 @@ void ListModel::requestLogo(QString file)
|
||||
m_loadingLogos.append(file);
|
||||
}
|
||||
|
||||
void ListModel::getLogo(const QString &logo, LogoCallback callback)
|
||||
void ListModel::getLogo(const QString& logo, LogoCallback callback)
|
||||
{
|
||||
if(m_logoMap.contains(logo))
|
||||
{
|
||||
if (m_logoMap.contains(logo)) {
|
||||
callback(APPLICATION->metacache()->resolveEntry("FTBPacks", QString("logos/%1").arg(logo.section(".", 0, 0)))->getFullPath());
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
requestLogo(logo);
|
||||
}
|
||||
}
|
||||
|
||||
Qt::ItemFlags ListModel::flags(const QModelIndex &index) const
|
||||
Qt::ItemFlags ListModel::flags(const QModelIndex& index) const
|
||||
{
|
||||
return QAbstractListModel::flags(index);
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace LegacyFTB
|
||||
|
@ -116,8 +116,8 @@ Page::Page(NewInstanceDialog* dialog, QWidget *parent)
|
||||
connect(ui->thirdPartyPackList->selectionModel(), &QItemSelectionModel::currentChanged, this, &Page::onThirdPartyPackSelectionChanged);
|
||||
connect(ui->privatePackList->selectionModel(), &QItemSelectionModel::currentChanged, this, &Page::onPrivatePackSelectionChanged);
|
||||
|
||||
connect(ui->addPackBtn, &QPushButton::pressed, this, &Page::onAddPackClicked);
|
||||
connect(ui->removePackBtn, &QPushButton::pressed, this, &Page::onRemovePackClicked);
|
||||
connect(ui->addPackBtn, &QPushButton::clicked, this, &Page::onAddPackClicked);
|
||||
connect(ui->removePackBtn, &QPushButton::clicked, this, &Page::onRemovePackClicked);
|
||||
|
||||
connect(ui->tabWidget, &QTabWidget::currentChanged, this, &Page::onTabChanged);
|
||||
|
||||
|
@ -106,6 +106,8 @@ auto ModpackListModel::data(const QModelIndex& index, int role) const -> QVarian
|
||||
return pack.description;
|
||||
case UserDataTypes::SELECTED:
|
||||
return false;
|
||||
case UserDataTypes::INSTALLED:
|
||||
return false;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -129,27 +131,27 @@ void ModpackListModel::performPaginatedSearch()
|
||||
// TODO: Move to standalone API
|
||||
auto netJob = makeShared<NetJob>("Modrinth::SearchModpack", APPLICATION->network());
|
||||
auto searchAllUrl = QString(BuildConfig.MODRINTH_PROD_URL +
|
||||
"/search?"
|
||||
"offset=%1&"
|
||||
"limit=%2&"
|
||||
"query=%3&"
|
||||
"index=%4&"
|
||||
"facets=[[\"project_type:modpack\"]]")
|
||||
"/search?"
|
||||
"offset=%1&"
|
||||
"limit=%2&"
|
||||
"query=%3&"
|
||||
"index=%4&"
|
||||
"facets=[[\"project_type:modpack\"]]")
|
||||
.arg(nextSearchOffset)
|
||||
.arg(m_modpacks_per_page)
|
||||
.arg(currentSearchTerm)
|
||||
.arg(currentSort);
|
||||
|
||||
netJob->addNetAction(Net::Download::makeByteArray(QUrl(searchAllUrl), &m_all_response));
|
||||
netJob->addNetAction(Net::Download::makeByteArray(QUrl(searchAllUrl), m_all_response));
|
||||
|
||||
QObject::connect(netJob.get(), &NetJob::succeeded, this, [this] {
|
||||
QJsonParseError parse_error_all{};
|
||||
|
||||
QJsonDocument doc_all = QJsonDocument::fromJson(m_all_response, &parse_error_all);
|
||||
QJsonDocument doc_all = QJsonDocument::fromJson(*m_all_response, &parse_error_all);
|
||||
if (parse_error_all.error != QJsonParseError::NoError) {
|
||||
qWarning() << "Error while parsing JSON response from " << debugName() << " at " << parse_error_all.offset
|
||||
<< " reason: " << parse_error_all.errorString();
|
||||
qWarning() << m_all_response;
|
||||
qWarning() << *m_all_response;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -110,9 +110,9 @@ class ModpackListModel : public QAbstractListModel {
|
||||
|
||||
NetJob::Ptr jobPtr;
|
||||
|
||||
QByteArray m_all_response;
|
||||
std::shared_ptr<QByteArray> m_all_response = std::make_shared<QByteArray>();
|
||||
QByteArray m_specific_response;
|
||||
|
||||
int m_modpacks_per_page = 20;
|
||||
};
|
||||
} // namespace ModPlatform
|
||||
} // namespace Modrinth
|
||||
|
@ -123,7 +123,7 @@ void ModrinthPage::onSelectionChanged(QModelIndex curr, QModelIndex prev)
|
||||
qDebug() << "Loading modrinth modpack information";
|
||||
|
||||
auto netJob = new NetJob(QString("Modrinth::PackInformation(%1)").arg(current.name), APPLICATION->network());
|
||||
auto response = new QByteArray();
|
||||
auto response = std::make_shared<QByteArray>();
|
||||
|
||||
QString id = current.id;
|
||||
|
||||
@ -162,10 +162,7 @@ void ModrinthPage::onSelectionChanged(QModelIndex curr, QModelIndex prev)
|
||||
|
||||
suggestCurrent();
|
||||
});
|
||||
QObject::connect(netJob, &NetJob::finished, this, [response, netJob] {
|
||||
netJob->deleteLater();
|
||||
delete response;
|
||||
});
|
||||
QObject::connect(netJob, &NetJob::finished, this, [response, netJob] { netJob->deleteLater(); });
|
||||
netJob->start();
|
||||
} else
|
||||
updateUI();
|
||||
@ -174,7 +171,7 @@ void ModrinthPage::onSelectionChanged(QModelIndex curr, QModelIndex prev)
|
||||
qDebug() << "Loading modrinth modpack versions";
|
||||
|
||||
auto netJob = new NetJob(QString("Modrinth::PackVersions(%1)").arg(current.name), APPLICATION->network());
|
||||
auto response = new QByteArray();
|
||||
auto response = std::make_shared<QByteArray>();
|
||||
|
||||
QString id = current.id;
|
||||
|
||||
@ -217,10 +214,7 @@ void ModrinthPage::onSelectionChanged(QModelIndex curr, QModelIndex prev)
|
||||
|
||||
suggestCurrent();
|
||||
});
|
||||
QObject::connect(netJob, &NetJob::finished, this, [response, netJob] {
|
||||
netJob->deleteLater();
|
||||
delete response;
|
||||
});
|
||||
QObject::connect(netJob, &NetJob::finished, this, [response, netJob] { netJob->deleteLater(); });
|
||||
netJob->start();
|
||||
|
||||
} else {
|
||||
@ -260,10 +254,8 @@ void ModrinthPage::updateUI()
|
||||
text += donates.join(", ");
|
||||
}
|
||||
|
||||
if (!current.extra.issuesUrl.isEmpty()
|
||||
|| !current.extra.sourceUrl.isEmpty()
|
||||
|| !current.extra.wikiUrl.isEmpty()
|
||||
|| !current.extra.discordUrl.isEmpty()) {
|
||||
if (!current.extra.issuesUrl.isEmpty() || !current.extra.sourceUrl.isEmpty() || !current.extra.wikiUrl.isEmpty() ||
|
||||
!current.extra.discordUrl.isEmpty()) {
|
||||
text += "<br><br>" + tr("External links:") + "<br>";
|
||||
}
|
||||
|
||||
|
@ -25,7 +25,7 @@
|
||||
|
||||
namespace ResourceDownload {
|
||||
|
||||
ModrinthModModel::ModrinthModModel(BaseInstance const& base) : ModModel(base, new ModrinthAPI) {}
|
||||
ModrinthModModel::ModrinthModModel(BaseInstance& base) : ModModel(base, new ModrinthAPI) {}
|
||||
|
||||
void ModrinthModModel::loadIndexedPack(ModPlatform::IndexedPack& m, QJsonObject& obj)
|
||||
{
|
||||
@ -42,12 +42,17 @@ void ModrinthModModel::loadIndexedPackVersions(ModPlatform::IndexedPack& m, QJso
|
||||
::Modrinth::loadIndexedPackVersions(m, arr, APPLICATION->network(), &m_base_instance);
|
||||
}
|
||||
|
||||
auto ModrinthModModel::loadDependencyVersions(const ModPlatform::Dependency& m, QJsonArray& arr) -> ModPlatform::IndexedVersion
|
||||
{
|
||||
return ::Modrinth::loadDependencyVersions(m, arr);
|
||||
};
|
||||
|
||||
auto ModrinthModModel::documentToArray(QJsonDocument& obj) const -> QJsonArray
|
||||
{
|
||||
return obj.object().value("hits").toArray();
|
||||
}
|
||||
|
||||
ModrinthResourcePackModel::ModrinthResourcePackModel(const BaseInstance& base) : ResourcePackResourceModel(base, new ModrinthAPI){}
|
||||
ModrinthResourcePackModel::ModrinthResourcePackModel(const BaseInstance& base) : ResourcePackResourceModel(base, new ModrinthAPI) {}
|
||||
|
||||
void ModrinthResourcePackModel::loadIndexedPack(ModPlatform::IndexedPack& m, QJsonObject& obj)
|
||||
{
|
||||
@ -69,7 +74,7 @@ auto ModrinthResourcePackModel::documentToArray(QJsonDocument& obj) const -> QJs
|
||||
return obj.object().value("hits").toArray();
|
||||
}
|
||||
|
||||
ModrinthTexturePackModel::ModrinthTexturePackModel(const BaseInstance& base) : TexturePackResourceModel(base, new ModrinthAPI){}
|
||||
ModrinthTexturePackModel::ModrinthTexturePackModel(const BaseInstance& base) : TexturePackResourceModel(base, new ModrinthAPI) {}
|
||||
|
||||
void ModrinthTexturePackModel::loadIndexedPack(ModPlatform::IndexedPack& m, QJsonObject& obj)
|
||||
{
|
||||
@ -91,7 +96,7 @@ auto ModrinthTexturePackModel::documentToArray(QJsonDocument& obj) const -> QJso
|
||||
return obj.object().value("hits").toArray();
|
||||
}
|
||||
|
||||
ModrinthShaderPackModel::ModrinthShaderPackModel(const BaseInstance& base) : ShaderPackResourceModel(base, new ModrinthAPI){}
|
||||
ModrinthShaderPackModel::ModrinthShaderPackModel(const BaseInstance& base) : ShaderPackResourceModel(base, new ModrinthAPI) {}
|
||||
|
||||
void ModrinthShaderPackModel::loadIndexedPack(ModPlatform::IndexedPack& m, QJsonObject& obj)
|
||||
{
|
||||
|
@ -30,7 +30,7 @@ class ModrinthModModel : public ModModel {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ModrinthModModel(const BaseInstance&);
|
||||
ModrinthModModel(BaseInstance&);
|
||||
~ModrinthModModel() override = default;
|
||||
|
||||
private:
|
||||
@ -40,6 +40,7 @@ class ModrinthModModel : public ModModel {
|
||||
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 loadDependencyVersions(const ModPlatform::Dependency& m, QJsonArray& arr) -> ModPlatform::IndexedVersion override;
|
||||
|
||||
auto documentToArray(QJsonDocument& obj) const -> QJsonArray override;
|
||||
};
|
||||
|
@ -40,39 +40,28 @@
|
||||
|
||||
#include <QIcon>
|
||||
|
||||
Technic::ListModel::ListModel(QObject *parent) : QAbstractListModel(parent)
|
||||
{
|
||||
}
|
||||
Technic::ListModel::ListModel(QObject* parent) : QAbstractListModel(parent) {}
|
||||
|
||||
Technic::ListModel::~ListModel()
|
||||
{
|
||||
}
|
||||
Technic::ListModel::~ListModel() {}
|
||||
|
||||
QVariant Technic::ListModel::data(const QModelIndex& index, int role) const
|
||||
{
|
||||
int pos = index.row();
|
||||
if(pos >= modpacks.size() || pos < 0 || !index.isValid())
|
||||
{
|
||||
if (pos >= modpacks.size() || pos < 0 || !index.isValid()) {
|
||||
return QString("INVALID INDEX %1").arg(pos);
|
||||
}
|
||||
|
||||
Modpack pack = modpacks.at(pos);
|
||||
if(role == Qt::DisplayRole)
|
||||
{
|
||||
if (role == Qt::DisplayRole) {
|
||||
return pack.name;
|
||||
}
|
||||
else if(role == Qt::DecorationRole)
|
||||
{
|
||||
if(m_logoMap.contains(pack.logoName))
|
||||
{
|
||||
} else if (role == Qt::DecorationRole) {
|
||||
if (m_logoMap.contains(pack.logoName)) {
|
||||
return (m_logoMap.value(pack.logoName));
|
||||
}
|
||||
QIcon icon = APPLICATION->getThemedIcon("screenshot-placeholder");
|
||||
((ListModel *)this)->requestLogo(pack.logoName, pack.logoUrl);
|
||||
((ListModel*)this)->requestLogo(pack.logoName, pack.logoUrl);
|
||||
return icon;
|
||||
}
|
||||
else if(role == Qt::UserRole)
|
||||
{
|
||||
} else if (role == Qt::UserRole) {
|
||||
QVariant v;
|
||||
v.setValue(pack);
|
||||
return v;
|
||||
@ -92,16 +81,15 @@ int Technic::ListModel::rowCount(const QModelIndex& parent) const
|
||||
|
||||
void Technic::ListModel::searchWithTerm(const QString& term)
|
||||
{
|
||||
if(currentSearchTerm == term && currentSearchTerm.isNull() == term.isNull()) {
|
||||
if (currentSearchTerm == term && currentSearchTerm.isNull() == term.isNull()) {
|
||||
return;
|
||||
}
|
||||
currentSearchTerm = term;
|
||||
if(jobPtr) {
|
||||
if (jobPtr) {
|
||||
jobPtr->abort();
|
||||
searchState = ResetRequested;
|
||||
return;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
beginResetModel();
|
||||
modpacks.clear();
|
||||
endResetModel();
|
||||
@ -115,26 +103,20 @@ void Technic::ListModel::performSearch()
|
||||
auto netJob = makeShared<NetJob>("Technic::Search", APPLICATION->network());
|
||||
QString searchUrl = "";
|
||||
if (currentSearchTerm.isEmpty()) {
|
||||
searchUrl = QString("%1trending?build=%2")
|
||||
.arg(BuildConfig.TECHNIC_API_BASE_URL, BuildConfig.TECHNIC_API_BUILD);
|
||||
searchUrl = QString("%1trending?build=%2").arg(BuildConfig.TECHNIC_API_BASE_URL, BuildConfig.TECHNIC_API_BUILD);
|
||||
searchMode = List;
|
||||
}
|
||||
else if (currentSearchTerm.startsWith("http://api.technicpack.net/modpack/")) {
|
||||
searchUrl = QString("https://%1?build=%2")
|
||||
.arg(currentSearchTerm.mid(7), BuildConfig.TECHNIC_API_BUILD);
|
||||
} else if (currentSearchTerm.startsWith("http://api.technicpack.net/modpack/")) {
|
||||
searchUrl = QString("https://%1?build=%2").arg(currentSearchTerm.mid(7), BuildConfig.TECHNIC_API_BUILD);
|
||||
searchMode = Single;
|
||||
}
|
||||
else if (currentSearchTerm.startsWith("https://api.technicpack.net/modpack/")) {
|
||||
} else if (currentSearchTerm.startsWith("https://api.technicpack.net/modpack/")) {
|
||||
searchUrl = QString("%1?build=%2").arg(currentSearchTerm, BuildConfig.TECHNIC_API_BUILD);
|
||||
searchMode = Single;
|
||||
}
|
||||
else {
|
||||
searchUrl = QString(
|
||||
"%1search?build=%2&q=%3"
|
||||
).arg(BuildConfig.TECHNIC_API_BASE_URL, BuildConfig.TECHNIC_API_BUILD, currentSearchTerm);
|
||||
} else {
|
||||
searchUrl =
|
||||
QString("%1search?build=%2&q=%3").arg(BuildConfig.TECHNIC_API_BASE_URL, BuildConfig.TECHNIC_API_BUILD, currentSearchTerm);
|
||||
searchMode = List;
|
||||
}
|
||||
netJob->addNetAction(Net::Download::makeByteArray(QUrl(searchUrl), &response));
|
||||
netJob->addNetAction(Net::Download::makeByteArray(QUrl(searchUrl), response));
|
||||
jobPtr = netJob;
|
||||
jobPtr->start();
|
||||
QObject::connect(netJob.get(), &NetJob::succeeded, this, &ListModel::searchRequestFinished);
|
||||
@ -146,11 +128,11 @@ void Technic::ListModel::searchRequestFinished()
|
||||
jobPtr.reset();
|
||||
|
||||
QJsonParseError parse_error;
|
||||
QJsonDocument doc = QJsonDocument::fromJson(response, &parse_error);
|
||||
if(parse_error.error != QJsonParseError::NoError)
|
||||
{
|
||||
qWarning() << "Error while parsing JSON response from Technic at " << parse_error.offset << " reason: " << parse_error.errorString();
|
||||
qWarning() << response;
|
||||
QJsonDocument doc = QJsonDocument::fromJson(*response, &parse_error);
|
||||
if (parse_error.error != QJsonParseError::NoError) {
|
||||
qWarning() << "Error while parsing JSON response from Technic at " << parse_error.offset
|
||||
<< " reason: " << parse_error.errorString();
|
||||
qWarning() << *response;
|
||||
return;
|
||||
}
|
||||
|
||||
@ -161,7 +143,7 @@ void Technic::ListModel::searchRequestFinished()
|
||||
switch (searchMode) {
|
||||
case List: {
|
||||
auto objs = Json::requireArray(root, "modpacks");
|
||||
for (auto technicPack: objs) {
|
||||
for (auto technicPack : objs) {
|
||||
Modpack pack;
|
||||
auto technicPackObject = Json::requireObject(technicPack);
|
||||
pack.name = Json::requireString(technicPackObject, "name");
|
||||
@ -170,11 +152,10 @@ void Technic::ListModel::searchRequestFinished()
|
||||
continue;
|
||||
|
||||
auto rawURL = Json::ensureString(technicPackObject, "iconUrl", "null");
|
||||
if(rawURL == "null") {
|
||||
if (rawURL == "null") {
|
||||
pack.logoUrl = "null";
|
||||
pack.logoName = "null";
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
pack.logoUrl = rawURL;
|
||||
pack.logoName = rawURL.section(QLatin1Char('/'), -1).section(QLatin1Char('.'), 0, 0);
|
||||
}
|
||||
@ -199,8 +180,7 @@ void Technic::ListModel::searchRequestFinished()
|
||||
|
||||
pack.logoUrl = iconUrl;
|
||||
pack.logoName = iconUrl.section(QLatin1Char('/'), -1).section(QLatin1Char('.'), 0, 0);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
pack.logoUrl = "null";
|
||||
pack.logoName = "null";
|
||||
}
|
||||
@ -210,10 +190,8 @@ void Technic::ListModel::searchRequestFinished()
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (const JSONValidationError &err)
|
||||
{
|
||||
qCritical() << "Couldn't parse technic search results:" << err.cause() ;
|
||||
} catch (const JSONValidationError& err) {
|
||||
qCritical() << "Couldn't parse technic search results:" << err.cause();
|
||||
return;
|
||||
}
|
||||
searchState = Finished;
|
||||
@ -229,12 +207,9 @@ void Technic::ListModel::searchRequestFinished()
|
||||
|
||||
void Technic::ListModel::getLogo(const QString& logo, const QString& logoUrl, Technic::LogoCallback callback)
|
||||
{
|
||||
if(m_logoMap.contains(logo))
|
||||
{
|
||||
if (m_logoMap.contains(logo)) {
|
||||
callback(APPLICATION->metacache()->resolveEntry("TechnicPacks", QString("logos/%1").arg(logo))->getFullPath());
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
requestLogo(logo, logoUrl);
|
||||
}
|
||||
}
|
||||
@ -243,30 +218,24 @@ void Technic::ListModel::searchRequestFailed()
|
||||
{
|
||||
jobPtr.reset();
|
||||
|
||||
if(searchState == ResetRequested)
|
||||
{
|
||||
if (searchState == ResetRequested) {
|
||||
beginResetModel();
|
||||
modpacks.clear();
|
||||
endResetModel();
|
||||
|
||||
performSearch();
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
searchState = Finished;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Technic::ListModel::logoLoaded(QString logo, QString out)
|
||||
{
|
||||
m_loadingLogos.removeAll(logo);
|
||||
m_logoMap.insert(logo, QIcon(out));
|
||||
for(int i = 0; i < modpacks.size(); i++)
|
||||
{
|
||||
if(modpacks[i].logoName == logo)
|
||||
{
|
||||
emit dataChanged(createIndex(i, 0), createIndex(i, 0), {Qt::DecorationRole});
|
||||
for (int i = 0; i < modpacks.size(); i++) {
|
||||
if (modpacks[i].logoName == logo) {
|
||||
emit dataChanged(createIndex(i, 0), createIndex(i, 0), { Qt::DecorationRole });
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -279,24 +248,23 @@ void Technic::ListModel::logoFailed(QString logo)
|
||||
|
||||
void Technic::ListModel::requestLogo(QString logo, QString url)
|
||||
{
|
||||
if(m_loadingLogos.contains(logo) || m_failedLogos.contains(logo) || logo == "null")
|
||||
{
|
||||
if (m_loadingLogos.contains(logo) || m_failedLogos.contains(logo) || logo == "null") {
|
||||
return;
|
||||
}
|
||||
|
||||
MetaEntryPtr entry = APPLICATION->metacache()->resolveEntry("TechnicPacks", QString("logos/%1").arg(logo));
|
||||
NetJob *job = new NetJob(QString("Technic Icon Download %1").arg(logo), APPLICATION->network());
|
||||
auto job = new NetJob(QString("Technic Icon Download %1").arg(logo), APPLICATION->network());
|
||||
job->addNetAction(Net::Download::makeCached(QUrl(url), entry));
|
||||
|
||||
auto fullPath = entry->getFullPath();
|
||||
|
||||
QObject::connect(job, &NetJob::succeeded, this, [this, logo, fullPath]
|
||||
{
|
||||
QObject::connect(job, &NetJob::succeeded, this, [this, logo, fullPath, job] {
|
||||
job->deleteLater();
|
||||
logoLoaded(logo, fullPath);
|
||||
});
|
||||
|
||||
QObject::connect(job, &NetJob::failed, this, [this, logo]
|
||||
{
|
||||
QObject::connect(job, &NetJob::failed, this, [this, logo, job] {
|
||||
job->deleteLater();
|
||||
logoFailed(logo);
|
||||
});
|
||||
|
||||
|
@ -44,33 +44,32 @@ namespace Technic {
|
||||
|
||||
typedef std::function<void(QString)> LogoCallback;
|
||||
|
||||
class ListModel : public QAbstractListModel
|
||||
{
|
||||
class ListModel : public QAbstractListModel {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ListModel(QObject *parent);
|
||||
public:
|
||||
ListModel(QObject* parent);
|
||||
virtual ~ListModel();
|
||||
|
||||
virtual QVariant data(const QModelIndex& index, int role) const;
|
||||
virtual int columnCount(const QModelIndex& parent) const;
|
||||
virtual int rowCount(const QModelIndex& parent) const;
|
||||
|
||||
void getLogo(const QString &logo, const QString &logoUrl, LogoCallback callback);
|
||||
void searchWithTerm(const QString & term);
|
||||
void getLogo(const QString& logo, const QString& logoUrl, LogoCallback callback);
|
||||
void searchWithTerm(const QString& term);
|
||||
|
||||
private slots:
|
||||
private slots:
|
||||
void searchRequestFinished();
|
||||
void searchRequestFailed();
|
||||
|
||||
void logoFailed(QString logo);
|
||||
void logoLoaded(QString logo, QString out);
|
||||
|
||||
private:
|
||||
private:
|
||||
void performSearch();
|
||||
void requestLogo(QString logo, QString url);
|
||||
|
||||
private:
|
||||
private:
|
||||
QList<Modpack> modpacks;
|
||||
QStringList m_failedLogos;
|
||||
QStringList m_loadingLogos;
|
||||
@ -78,17 +77,13 @@ private:
|
||||
QMap<QString, LogoCallback> waitingCallbacks;
|
||||
|
||||
QString currentSearchTerm;
|
||||
enum SearchState {
|
||||
None,
|
||||
ResetRequested,
|
||||
Finished
|
||||
} searchState = None;
|
||||
enum SearchState { None, ResetRequested, Finished } searchState = None;
|
||||
enum SearchMode {
|
||||
List,
|
||||
Single,
|
||||
} searchMode = List;
|
||||
NetJob::Ptr jobPtr;
|
||||
QByteArray response;
|
||||
std::shared_ptr<QByteArray> response = std::make_shared<QByteArray>();
|
||||
};
|
||||
|
||||
}
|
||||
} // namespace Technic
|
||||
|
@ -143,7 +143,7 @@ void TechnicPage::suggestCurrent()
|
||||
|
||||
auto netJob = makeShared<NetJob>(QString("Technic::PackMeta(%1)").arg(current.name), APPLICATION->network());
|
||||
QString slug = current.slug;
|
||||
netJob->addNetAction(Net::Download::makeByteArray(QString("%1modpack/%2?build=%3").arg(BuildConfig.TECHNIC_API_BASE_URL, slug, BuildConfig.TECHNIC_API_BUILD), &response));
|
||||
netJob->addNetAction(Net::Download::makeByteArray(QString("%1modpack/%2?build=%3").arg(BuildConfig.TECHNIC_API_BASE_URL, slug, BuildConfig.TECHNIC_API_BUILD), response));
|
||||
QObject::connect(netJob.get(), &NetJob::succeeded, this, [this, slug]
|
||||
{
|
||||
jobPtr.reset();
|
||||
@ -154,7 +154,7 @@ void TechnicPage::suggestCurrent()
|
||||
}
|
||||
|
||||
QJsonParseError parse_error {};
|
||||
QJsonDocument doc = QJsonDocument::fromJson(response, &parse_error);
|
||||
QJsonDocument doc = QJsonDocument::fromJson(*response, &parse_error);
|
||||
QJsonObject obj = doc.object();
|
||||
if(parse_error.error != QJsonParseError::NoError)
|
||||
{
|
||||
@ -249,7 +249,7 @@ void TechnicPage::metadataLoaded()
|
||||
|
||||
auto netJob = makeShared<NetJob>(QString("Technic::SolderMeta(%1)").arg(current.name), APPLICATION->network());
|
||||
auto url = QString("%1/modpack/%2").arg(current.url, current.slug);
|
||||
netJob->addNetAction(Net::Download::makeByteArray(QUrl(url), &response));
|
||||
netJob->addNetAction(Net::Download::makeByteArray(QUrl(url), response));
|
||||
|
||||
QObject::connect(netJob.get(), &NetJob::succeeded, this, &TechnicPage::onSolderLoaded);
|
||||
|
||||
@ -291,11 +291,11 @@ void TechnicPage::onSolderLoaded() {
|
||||
|
||||
current.versions.clear();
|
||||
|
||||
QJsonParseError parse_error {};
|
||||
auto doc = QJsonDocument::fromJson(response, &parse_error);
|
||||
QJsonParseError parse_error{};
|
||||
auto doc = QJsonDocument::fromJson(*response, &parse_error);
|
||||
if (parse_error.error != QJsonParseError::NoError) {
|
||||
qWarning() << "Error while parsing JSON response from Solder at " << parse_error.offset << " reason: " << parse_error.errorString();
|
||||
qWarning() << response;
|
||||
qWarning() << *response;
|
||||
fallback();
|
||||
return;
|
||||
}
|
||||
@ -304,8 +304,7 @@ void TechnicPage::onSolderLoaded() {
|
||||
TechnicSolder::Pack pack;
|
||||
try {
|
||||
TechnicSolder::loadPack(pack, obj);
|
||||
}
|
||||
catch (const JSONValidationError& err) {
|
||||
} catch (const JSONValidationError& err) {
|
||||
qCritical() << "Couldn't parse Solder pack metadata:" << err.cause();
|
||||
fallback();
|
||||
return;
|
||||
|
@ -104,5 +104,5 @@ private:
|
||||
QString selectedVersion;
|
||||
|
||||
NetJob::Ptr jobPtr;
|
||||
QByteArray response;
|
||||
std::shared_ptr<QByteArray> response = std::make_shared<QByteArray>();
|
||||
};
|
||||
|
Reference in New Issue
Block a user