diff options
Diffstat (limited to 'application/pages/modplatform')
39 files changed, 0 insertions, 4811 deletions
diff --git a/application/pages/modplatform/ImportPage.cpp b/application/pages/modplatform/ImportPage.cpp deleted file mode 100644 index c2369bdc..00000000 --- a/application/pages/modplatform/ImportPage.cpp +++ /dev/null @@ -1,130 +0,0 @@ -#include "ImportPage.h" -#include "ui_ImportPage.h" - -#include "MultiMC.h" -#include "dialogs/NewInstanceDialog.h" -#include <QFileDialog> -#include <QValidator> -#include <InstanceImportTask.h> - -class UrlValidator : public QValidator -{ -public: - using QValidator::QValidator; - - State validate(QString &in, int &pos) const - { - const QUrl url(in); - if (url.isValid() && !url.isRelative() && !url.isEmpty()) - { - return Acceptable; - } - else if (QFile::exists(in)) - { - return Acceptable; - } - else - { - return Intermediate; - } - } -}; - -ImportPage::ImportPage(NewInstanceDialog* dialog, QWidget *parent) - : QWidget(parent), ui(new Ui::ImportPage), dialog(dialog) -{ - ui->setupUi(this); - ui->modpackEdit->setValidator(new UrlValidator(ui->modpackEdit)); - connect(ui->modpackEdit, &QLineEdit::textChanged, this, &ImportPage::updateState); -} - -ImportPage::~ImportPage() -{ - delete ui; -} - -bool ImportPage::shouldDisplay() const -{ - return true; -} - -void ImportPage::openedImpl() -{ - updateState(); -} - -void ImportPage::updateState() -{ - if(!isOpened) - { - return; - } - if(ui->modpackEdit->hasAcceptableInput()) - { - QString input = ui->modpackEdit->text(); - auto url = QUrl::fromUserInput(input); - if(url.isLocalFile()) - { - // FIXME: actually do some validation of what's inside here... this is fake AF - QFileInfo fi(input); - if(fi.exists() && fi.suffix() == "zip") - { - QFileInfo fi(url.fileName()); - dialog->setSuggestedPack(fi.completeBaseName(), new InstanceImportTask(url)); - dialog->setSuggestedIcon("default"); - } - } - else - { - if(input.endsWith("?client=y")) { - input.chop(9); - input.append("/file"); - url = QUrl::fromUserInput(input); - } - // hook, line and sinker. - QFileInfo fi(url.fileName()); - dialog->setSuggestedPack(fi.completeBaseName(), new InstanceImportTask(url)); - dialog->setSuggestedIcon("default"); - } - } - else - { - dialog->setSuggestedPack(); - } -} - -void ImportPage::setUrl(const QString& url) -{ - ui->modpackEdit->setText(url); - updateState(); -} - -void ImportPage::on_modpackBtn_clicked() -{ - const QUrl url = QFileDialog::getOpenFileUrl(this, tr("Choose modpack"), modpackUrl(), tr("Zip (*.zip)")); - if (url.isValid()) - { - if (url.isLocalFile()) - { - ui->modpackEdit->setText(url.toLocalFile()); - } - else - { - ui->modpackEdit->setText(url.toString()); - } - } -} - - -QUrl ImportPage::modpackUrl() const -{ - const QUrl url(ui->modpackEdit->text()); - if (url.isValid() && !url.isRelative() && !url.host().isEmpty()) - { - return url; - } - else - { - return QUrl::fromLocalFile(ui->modpackEdit->text()); - } -} diff --git a/application/pages/modplatform/ImportPage.h b/application/pages/modplatform/ImportPage.h deleted file mode 100644 index 67e3c201..00000000 --- a/application/pages/modplatform/ImportPage.h +++ /dev/null @@ -1,70 +0,0 @@ -/* Copyright 2013-2021 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include <QWidget> - -#include "pages/BasePage.h" -#include <MultiMC.h> -#include "tasks/Task.h" - -namespace Ui -{ -class ImportPage; -} - -class NewInstanceDialog; - -class ImportPage : public QWidget, public BasePage -{ - Q_OBJECT - -public: - explicit ImportPage(NewInstanceDialog* dialog, QWidget *parent = 0); - virtual ~ImportPage(); - virtual QString displayName() const override - { - return tr("Import from zip"); - } - virtual QIcon icon() const override - { - return MMC->getThemedIcon("viewfolder"); - } - virtual QString id() const override - { - return "import"; - } - virtual QString helpPage() const override - { - return "Zip-import"; - } - virtual bool shouldDisplay() const override; - - void setUrl(const QString & url); - void openedImpl() override; - -private slots: - void on_modpackBtn_clicked(); - void updateState(); - -private: - QUrl modpackUrl() const; - -private: - Ui::ImportPage *ui = nullptr; - NewInstanceDialog* dialog = nullptr; -}; - diff --git a/application/pages/modplatform/ImportPage.ui b/application/pages/modplatform/ImportPage.ui deleted file mode 100644 index eb63cbe9..00000000 --- a/application/pages/modplatform/ImportPage.ui +++ /dev/null @@ -1,52 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<ui version="4.0"> - <class>ImportPage</class> - <widget class="QWidget" name="ImportPage"> - <property name="geometry"> - <rect> - <x>0</x> - <y>0</y> - <width>546</width> - <height>405</height> - </rect> - </property> - <layout class="QGridLayout" name="gridLayout"> - <item row="1" column="1"> - <widget class="QPushButton" name="modpackBtn"> - <property name="text"> - <string>Browse</string> - </property> - </widget> - </item> - <item row="1" column="0"> - <widget class="QLineEdit" name="modpackEdit"> - <property name="placeholderText"> - <string notr="true">http://</string> - </property> - </widget> - </item> - <item row="0" column="0" colspan="2"> - <widget class="QLabel" name="modpackLabel"> - <property name="text"> - <string>Local file or link to a direct download:</string> - </property> - </widget> - </item> - <item row="2" column="0" colspan="2"> - <spacer name="verticalSpacer"> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>20</width> - <height>40</height> - </size> - </property> - </spacer> - </item> - </layout> - </widget> - <resources/> - <connections/> -</ui> diff --git a/application/pages/modplatform/VanillaPage.cpp b/application/pages/modplatform/VanillaPage.cpp deleted file mode 100644 index 02638315..00000000 --- a/application/pages/modplatform/VanillaPage.cpp +++ /dev/null @@ -1,104 +0,0 @@ -#include "VanillaPage.h" -#include "ui_VanillaPage.h" - -#include "MultiMC.h" - -#include <meta/Index.h> -#include <meta/VersionList.h> -#include <dialogs/NewInstanceDialog.h> -#include <Filter.h> -#include <Env.h> -#include <InstanceCreationTask.h> -#include <QTabBar> - -VanillaPage::VanillaPage(NewInstanceDialog *dialog, QWidget *parent) - : QWidget(parent), dialog(dialog), ui(new Ui::VanillaPage) -{ - ui->setupUi(this); - ui->tabWidget->tabBar()->hide(); - connect(ui->versionList, &VersionSelectWidget::selectedVersionChanged, this, &VanillaPage::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); -} - -void VanillaPage::openedImpl() -{ - if(!initialized) - { - auto vlist = ENV.metadataIndex()->get("net.minecraft"); - ui->versionList->initialize(vlist.get()); - initialized = true; - } - else - { - suggestCurrent(); - } -} - -void VanillaPage::refresh() -{ - ui->versionList->loadList(); -} - -void VanillaPage::filterChanged() -{ - QStringList out; - if(ui->alphaFilter->isChecked()) - out << "(old_alpha)"; - if(ui->betaFilter->isChecked()) - out << "(old_beta)"; - if(ui->snapshotFilter->isChecked()) - out << "(snapshot)"; - if(ui->oldSnapshotFilter->isChecked()) - out << "(old_snapshot)"; - if(ui->releaseFilter->isChecked()) - out << "(release)"; - if(ui->experimentsFilter->isChecked()) - out << "(experiment)"; - auto regexp = out.join('|'); - ui->versionList->setFilter(BaseVersionList::TypeRole, new RegexpFilter(regexp, false)); -} - -VanillaPage::~VanillaPage() -{ - delete ui; -} - -bool VanillaPage::shouldDisplay() const -{ - return true; -} - -BaseVersionPtr VanillaPage::selectedVersion() const -{ - return m_selectedVersion; -} - -void VanillaPage::suggestCurrent() -{ - if (!isOpened) - { - return; - } - - if(!m_selectedVersion) - { - dialog->setSuggestedPack(); - return; - } - - dialog->setSuggestedPack(m_selectedVersion->descriptor(), new InstanceCreationTask(m_selectedVersion)); - dialog->setSuggestedIcon("default"); -} - -void VanillaPage::setSelectedVersion(BaseVersionPtr version) -{ - m_selectedVersion = version; - suggestCurrent(); -} diff --git a/application/pages/modplatform/VanillaPage.h b/application/pages/modplatform/VanillaPage.h deleted file mode 100644 index af6fd392..00000000 --- a/application/pages/modplatform/VanillaPage.h +++ /dev/null @@ -1,75 +0,0 @@ -/* Copyright 2013-2021 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include <QWidget> - -#include "pages/BasePage.h" -#include <MultiMC.h> -#include "tasks/Task.h" - -namespace Ui -{ -class VanillaPage; -} - -class NewInstanceDialog; - -class VanillaPage : public QWidget, public BasePage -{ - Q_OBJECT - -public: - explicit VanillaPage(NewInstanceDialog *dialog, QWidget *parent = 0); - virtual ~VanillaPage(); - virtual QString displayName() const override - { - return tr("Vanilla"); - } - virtual QIcon icon() const override - { - return MMC->getThemedIcon("minecraft"); - } - virtual QString id() const override - { - return "vanilla"; - } - virtual QString helpPage() const override - { - return "Vanilla-platform"; - } - virtual bool shouldDisplay() const override; - void openedImpl() override; - - BaseVersionPtr selectedVersion() const; - -public slots: - void setSelectedVersion(BaseVersionPtr version); - -private slots: - void filterChanged(); - -private: - void refresh(); - void suggestCurrent(); - -private: - bool initialized = false; - NewInstanceDialog *dialog = nullptr; - Ui::VanillaPage *ui = nullptr; - bool m_versionSetByUser = false; - BaseVersionPtr m_selectedVersion; -}; diff --git a/application/pages/modplatform/VanillaPage.ui b/application/pages/modplatform/VanillaPage.ui deleted file mode 100644 index 47effc86..00000000 --- a/application/pages/modplatform/VanillaPage.ui +++ /dev/null @@ -1,169 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<ui version="4.0"> - <class>VanillaPage</class> - <widget class="QWidget" name="VanillaPage"> - <property name="geometry"> - <rect> - <x>0</x> - <y>0</y> - <width>815</width> - <height>607</height> - </rect> - </property> - <layout class="QVBoxLayout" name="verticalLayout_5"> - <property name="leftMargin"> - <number>0</number> - </property> - <property name="topMargin"> - <number>0</number> - </property> - <property name="rightMargin"> - <number>0</number> - </property> - <property name="bottomMargin"> - <number>0</number> - </property> - <item> - <widget class="QTabWidget" name="tabWidget"> - <property name="currentIndex"> - <number>0</number> - </property> - <widget class="QWidget" name="tab"> - <attribute name="title"> - <string notr="true"/> - </attribute> - <layout class="QGridLayout" name="gridLayout_2"> - <item row="0" column="1"> - <layout class="QVBoxLayout" name="verticalLayout"> - <item> - <widget class="QLabel" name="label"> - <property name="text"> - <string>Filter</string> - </property> - <property name="alignment"> - <set>Qt::AlignCenter</set> - </property> - </widget> - </item> - <item> - <widget class="QCheckBox" name="releaseFilter"> - <property name="text"> - <string>Releases</string> - </property> - <property name="checkable"> - <bool>true</bool> - </property> - <property name="checked"> - <bool>true</bool> - </property> - </widget> - </item> - <item> - <widget class="QCheckBox" name="snapshotFilter"> - <property name="text"> - <string>Snapshots</string> - </property> - <property name="checkable"> - <bool>true</bool> - </property> - </widget> - </item> - <item> - <widget class="QCheckBox" name="oldSnapshotFilter"> - <property name="text"> - <string>Old Snapshots</string> - </property> - <property name="checkable"> - <bool>true</bool> - </property> - </widget> - </item> - <item> - <widget class="QCheckBox" name="betaFilter"> - <property name="text"> - <string>Betas</string> - </property> - <property name="checkable"> - <bool>true</bool> - </property> - </widget> - </item> - <item> - <widget class="QCheckBox" name="alphaFilter"> - <property name="text"> - <string>Alphas</string> - </property> - <property name="checkable"> - <bool>true</bool> - </property> - </widget> - </item> - <item> - <widget class="QCheckBox" name="experimentsFilter"> - <property name="text"> - <string>Experiments</string> - </property> - <property name="checkable"> - <bool>true</bool> - </property> - </widget> - </item> - <item> - <spacer name="verticalSpacer"> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>20</width> - <height>40</height> - </size> - </property> - </spacer> - </item> - <item> - <widget class="QPushButton" name="refreshBtn"> - <property name="text"> - <string>Refresh</string> - </property> - </widget> - </item> - </layout> - </item> - <item row="0" column="0"> - <widget class="VersionSelectWidget" name="versionList" native="true"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Expanding" vsizetype="Expanding"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - </widget> - </item> - </layout> - </widget> - </widget> - </item> - </layout> - </widget> - <customwidgets> - <customwidget> - <class>VersionSelectWidget</class> - <extends>QWidget</extends> - <header>widgets/VersionSelectWidget.h</header> - <container>1</container> - </customwidget> - </customwidgets> - <tabstops> - <tabstop>tabWidget</tabstop> - <tabstop>releaseFilter</tabstop> - <tabstop>snapshotFilter</tabstop> - <tabstop>oldSnapshotFilter</tabstop> - <tabstop>betaFilter</tabstop> - <tabstop>alphaFilter</tabstop> - <tabstop>experimentsFilter</tabstop> - <tabstop>refreshBtn</tabstop> - </tabstops> - <resources/> - <connections/> -</ui> diff --git a/application/pages/modplatform/atlauncher/AtlFilterModel.cpp b/application/pages/modplatform/atlauncher/AtlFilterModel.cpp deleted file mode 100644 index b5d8f22b..00000000 --- a/application/pages/modplatform/atlauncher/AtlFilterModel.cpp +++ /dev/null @@ -1,81 +0,0 @@ -#include "AtlFilterModel.h" - -#include <QDebug> - -#include <modplatform/atlauncher/ATLPackIndex.h> -#include <Version.h> -#include <MMCStrings.h> - -namespace Atl { - -FilterModel::FilterModel(QObject *parent) : QSortFilterProxyModel(parent) -{ - currentSorting = Sorting::ByPopularity; - sortings.insert(tr("Sort by popularity"), Sorting::ByPopularity); - sortings.insert(tr("Sort by name"), Sorting::ByName); - sortings.insert(tr("Sort by game version"), Sorting::ByGameVersion); - - searchTerm = ""; -} - -const QMap<QString, FilterModel::Sorting> FilterModel::getAvailableSortings() -{ - return sortings; -} - -QString FilterModel::translateCurrentSorting() -{ - return sortings.key(currentSorting); -} - -void FilterModel::setSorting(Sorting sorting) -{ - currentSorting = sorting; - invalidate(); -} - -FilterModel::Sorting FilterModel::getCurrentSorting() -{ - return currentSorting; -} - -void FilterModel::setSearchTerm(const QString term) -{ - searchTerm = term.trimmed(); - invalidate(); -} - -bool FilterModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const -{ - if (searchTerm.isEmpty()) { - return true; - } - - QModelIndex index = sourceModel()->index(sourceRow, 0, sourceParent); - ATLauncher::IndexedPack pack = sourceModel()->data(index, Qt::UserRole).value<ATLauncher::IndexedPack>(); - return pack.name.contains(searchTerm, Qt::CaseInsensitive); -} - -bool FilterModel::lessThan(const QModelIndex &left, const QModelIndex &right) const -{ - ATLauncher::IndexedPack leftPack = sourceModel()->data(left, Qt::UserRole).value<ATLauncher::IndexedPack>(); - ATLauncher::IndexedPack rightPack = sourceModel()->data(right, Qt::UserRole).value<ATLauncher::IndexedPack>(); - - if (currentSorting == ByPopularity) { - return leftPack.position > rightPack.position; - } - else if (currentSorting == ByGameVersion) { - Version lv(leftPack.versions.at(0).minecraft); - Version rv(rightPack.versions.at(0).minecraft); - return lv < rv; - } - else if (currentSorting == ByName) { - return Strings::naturalCompare(leftPack.name, rightPack.name, Qt::CaseSensitive) >= 0; - } - - // Invalid sorting set, somehow... - qWarning() << "Invalid sorting set!"; - return true; -} - -} diff --git a/application/pages/modplatform/atlauncher/AtlFilterModel.h b/application/pages/modplatform/atlauncher/AtlFilterModel.h deleted file mode 100644 index bd72ad91..00000000 --- a/application/pages/modplatform/atlauncher/AtlFilterModel.h +++ /dev/null @@ -1,34 +0,0 @@ -#pragma once - -#include <QtCore/QSortFilterProxyModel> - -namespace Atl { - -class FilterModel : public QSortFilterProxyModel -{ - Q_OBJECT -public: - FilterModel(QObject* parent = Q_NULLPTR); - enum Sorting { - ByPopularity, - ByGameVersion, - ByName, - }; - const QMap<QString, Sorting> getAvailableSortings(); - QString translateCurrentSorting(); - void setSorting(Sorting sorting); - Sorting getCurrentSorting(); - void setSearchTerm(QString term); - -protected: - bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override; - bool lessThan(const QModelIndex &left, const QModelIndex &right) const override; - -private: - QMap<QString, Sorting> sortings; - Sorting currentSorting; - QString searchTerm; - -}; - -} diff --git a/application/pages/modplatform/atlauncher/AtlListModel.cpp b/application/pages/modplatform/atlauncher/AtlListModel.cpp deleted file mode 100644 index f3be6198..00000000 --- a/application/pages/modplatform/atlauncher/AtlListModel.cpp +++ /dev/null @@ -1,194 +0,0 @@ -#include "AtlListModel.h" - -#include <BuildConfig.h> -#include <MultiMC.h> -#include <Env.h> -#include <Json.h> - -namespace Atl { - -ListModel::ListModel(QObject *parent) : QAbstractListModel(parent) -{ -} - -ListModel::~ListModel() -{ -} - -int ListModel::rowCount(const QModelIndex &parent) const -{ - return modpacks.size(); -} - -int ListModel::columnCount(const QModelIndex &parent) const -{ - return 1; -} - -QVariant ListModel::data(const QModelIndex &index, int role) const -{ - int pos = index.row(); - 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) - { - return pack.name; - } - else if (role == Qt::ToolTipRole) - { - return pack.name; - } - else if(role == Qt::DecorationRole) - { - if(m_logoMap.contains(pack.safeName)) - { - return (m_logoMap.value(pack.safeName)); - } - auto icon = MMC->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); - - return icon; - } - else if(role == Qt::UserRole) - { - QVariant v; - v.setValue(pack); - return v; - } - - return QVariant(); -} - -void ListModel::request() -{ - beginResetModel(); - modpacks.clear(); - endResetModel(); - - auto *netJob = new NetJob("Atl::Request"); - auto url = QString(BuildConfig.ATL_DOWNLOAD_SERVER_URL + "launcher/json/packsnew.json"); - netJob->addNetAction(Net::Download::makeByteArray(QUrl(url), &response)); - jobPtr = netJob; - jobPtr->start(); - - QObject::connect(netJob, &NetJob::succeeded, this, &ListModel::requestFinished); - QObject::connect(netJob, &NetJob::failed, this, &ListModel::requestFailed); -} - -void ListModel::requestFinished() -{ - 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 ATL at " << parse_error.offset << " reason: " << parse_error.errorString(); - qWarning() << response; - return; - } - - QList<ATLauncher::IndexedPack> newList; - - auto packs = doc.array(); - for(auto packRaw : packs) { - auto packObj = packRaw.toObject(); - - ATLauncher::IndexedPack pack; - - try { - ATLauncher::loadIndexedPack(pack, packObj); - } - 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; - // only display public packs (for now) - if(pack.type != ATLauncher::PackType::Public) continue; - // ignore "system" packs (Vanilla, Vanilla with Forge, etc) - if(pack.system) continue; - - newList.append(pack); - } - - beginInsertRows(QModelIndex(), modpacks.size(), modpacks.size() + newList.size() - 1); - modpacks.append(newList); - endInsertRows(); -} - -void ListModel::requestFailed(QString reason) -{ - jobPtr.reset(); -} - -void ListModel::getLogo(const QString &logo, const QString &logoUrl, LogoCallback callback) -{ - if(m_logoMap.contains(logo)) - { - callback(ENV.metacache()->resolveEntry("ATLauncherPacks", QString("logos/%1").arg(logo.section(".", 0, 0)))->getFullPath()); - } - else - { - requestLogo(logo, logoUrl); - } -} - -void ListModel::logoFailed(QString logo) -{ - m_failedLogos.append(logo); - m_loadingLogos.removeAll(logo); -} - -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}); - } - } -} - -void ListModel::requestLogo(QString file, QString url) -{ - if(m_loadingLogos.contains(file) || m_failedLogos.contains(file)) - { - return; - } - - MetaEntryPtr entry = ENV.metacache()->resolveEntry("ATLauncherPacks", QString("logos/%1").arg(file.section(".", 0, 0))); - NetJob *job = new NetJob(QString("ATLauncher Icon Download %1").arg(file)); - job->addNetAction(Net::Download::makeCached(QUrl(url), entry)); - - auto fullPath = entry->getFullPath(); - QObject::connect(job, &NetJob::succeeded, this, [this, file, fullPath] - { - emit logoLoaded(file, QIcon(fullPath)); - if(waitingCallbacks.contains(file)) - { - waitingCallbacks.value(file)(fullPath); - } - }); - - QObject::connect(job, &NetJob::failed, this, [this, file] - { - emit logoFailed(file); - }); - - job->start(); - - m_loadingLogos.append(file); -} - -} diff --git a/application/pages/modplatform/atlauncher/AtlListModel.h b/application/pages/modplatform/atlauncher/AtlListModel.h deleted file mode 100644 index 2d30a64e..00000000 --- a/application/pages/modplatform/atlauncher/AtlListModel.h +++ /dev/null @@ -1,52 +0,0 @@ -#pragma once - -#include <QAbstractListModel> - -#include "net/NetJob.h" -#include <QIcon> -#include <modplatform/atlauncher/ATLPackIndex.h> - -namespace Atl { - -typedef QMap<QString, QIcon> LogoMap; -typedef std::function<void(QString)> LogoCallback; - -class ListModel : public QAbstractListModel -{ - Q_OBJECT - -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; - - void request(); - - void getLogo(const QString &logo, const QString &logoUrl, LogoCallback callback); - -private slots: - void requestFinished(); - void requestFailed(QString reason); - - void logoFailed(QString logo); - void logoLoaded(QString logo, QIcon out); - -private: - void requestLogo(QString file, QString url); - -private: - QList<ATLauncher::IndexedPack> modpacks; - - QStringList m_failedLogos; - QStringList m_loadingLogos; - LogoMap m_logoMap; - QMap<QString, LogoCallback> waitingCallbacks; - - NetJobPtr jobPtr; - QByteArray response; -}; - -} diff --git a/application/pages/modplatform/atlauncher/AtlOptionalModDialog.cpp b/application/pages/modplatform/atlauncher/AtlOptionalModDialog.cpp deleted file mode 100644 index 14bbd18b..00000000 --- a/application/pages/modplatform/atlauncher/AtlOptionalModDialog.cpp +++ /dev/null @@ -1,209 +0,0 @@ -#include "AtlOptionalModDialog.h" -#include "ui_AtlOptionalModDialog.h" - -AtlOptionalModListModel::AtlOptionalModListModel(QWidget *parent, QVector<ATLauncher::VersionMod> mods) - : QAbstractListModel(parent), m_mods(mods) { - - // fill mod index - for (int i = 0; i < m_mods.size(); i++) { - auto mod = m_mods.at(i); - m_index[mod.name] = i; - } - // set initial state - for (int i = 0; i < m_mods.size(); i++) { - auto mod = m_mods.at(i); - m_selection[mod.name] = false; - setMod(mod, i, mod.selected, false); - } -} - -QVector<QString> AtlOptionalModListModel::getResult() { - QVector<QString> result; - - for (const auto& mod : m_mods) { - if (m_selection[mod.name]) { - result.push_back(mod.name); - } - } - - return result; -} - -int AtlOptionalModListModel::rowCount(const QModelIndex &parent) const { - return m_mods.size(); -} - -int AtlOptionalModListModel::columnCount(const QModelIndex &parent) const { - // Enabled, Name, Description - return 3; -} - -QVariant AtlOptionalModListModel::data(const QModelIndex &index, int role) const { - auto row = index.row(); - auto mod = m_mods.at(row); - - if (role == Qt::DisplayRole) { - if (index.column() == NameColumn) { - return mod.name; - } - if (index.column() == DescriptionColumn) { - return mod.description; - } - } - else if (role == Qt::ToolTipRole) { - if (index.column() == DescriptionColumn) { - return mod.description; - } - } - else if (role == Qt::CheckStateRole) { - if (index.column() == EnabledColumn) { - return m_selection[mod.name] ? Qt::Checked : Qt::Unchecked; - } - } - - return QVariant(); -} - -bool AtlOptionalModListModel::setData(const QModelIndex &index, const QVariant &value, int role) { - if (role == Qt::CheckStateRole) { - auto row = index.row(); - auto mod = m_mods.at(row); - - toggleMod(mod, row); - return true; - } - - return false; -} - -QVariant AtlOptionalModListModel::headerData(int section, Qt::Orientation orientation, int role) const { - if (role == Qt::DisplayRole && orientation == Qt::Horizontal) { - switch (section) { - case EnabledColumn: - return QString(); - case NameColumn: - return QString("Name"); - case DescriptionColumn: - return QString("Description"); - } - } - - return QVariant(); -} - -Qt::ItemFlags AtlOptionalModListModel::flags(const QModelIndex &index) const { - auto flags = QAbstractListModel::flags(index); - if (index.isValid() && index.column() == EnabledColumn) { - flags |= Qt::ItemIsUserCheckable; - } - return flags; -} - -void AtlOptionalModListModel::selectRecommended() { - for (const auto& mod : m_mods) { - m_selection[mod.name] = mod.recommended; - } - - emit dataChanged(AtlOptionalModListModel::index(0, EnabledColumn), - AtlOptionalModListModel::index(m_mods.size() - 1, EnabledColumn)); -} - -void AtlOptionalModListModel::clearAll() { - for (const auto& mod : m_mods) { - m_selection[mod.name] = false; - } - - emit dataChanged(AtlOptionalModListModel::index(0, EnabledColumn), - AtlOptionalModListModel::index(m_mods.size() - 1, EnabledColumn)); -} - -void AtlOptionalModListModel::toggleMod(ATLauncher::VersionMod mod, int index) { - setMod(mod, index, !m_selection[mod.name]); -} - -void AtlOptionalModListModel::setMod(ATLauncher::VersionMod mod, int index, bool enable, bool shouldEmit) { - if (m_selection[mod.name] == enable) return; - - m_selection[mod.name] = enable; - - // disable other mods in the group, if applicable - if (enable && !mod.group.isEmpty()) { - for (int i = 0; i < m_mods.size(); i++) { - if (index == i) continue; - auto other = m_mods.at(i); - - if (mod.group == other.group) { - setMod(other, i, false, shouldEmit); - } - } - } - - for (const auto& dependencyName : mod.depends) { - auto dependencyIndex = m_index[dependencyName]; - auto dependencyMod = m_mods.at(dependencyIndex); - - // enable/disable dependencies - if (enable) { - setMod(dependencyMod, dependencyIndex, true, shouldEmit); - } - - // if the dependency is 'effectively hidden', then track which mods - // depend on it - so we can efficiently disable it when no more dependents - // depend on it. - auto dependants = m_dependants[dependencyName]; - - if (enable) { - dependants.append(mod.name); - } - else { - dependants.removeAll(mod.name); - - // if there are no longer any dependents, let's disable the mod - if (dependencyMod.effectively_hidden && dependants.isEmpty()) { - setMod(dependencyMod, dependencyIndex, false, shouldEmit); - } - } - } - - // disable mods that depend on this one, if disabling - if (!enable) { - auto dependants = m_dependants[mod.name]; - for (const auto& dependencyName : dependants) { - auto dependencyIndex = m_index[dependencyName]; - auto dependencyMod = m_mods.at(dependencyIndex); - - setMod(dependencyMod, dependencyIndex, false, shouldEmit); - } - } - - if (shouldEmit) { - emit dataChanged(AtlOptionalModListModel::index(index, EnabledColumn), - AtlOptionalModListModel::index(index, EnabledColumn)); - } -} - - -AtlOptionalModDialog::AtlOptionalModDialog(QWidget *parent, QVector<ATLauncher::VersionMod> mods) - : QDialog(parent), ui(new Ui::AtlOptionalModDialog) { - ui->setupUi(this); - - listModel = new AtlOptionalModListModel(this, mods); - ui->treeView->setModel(listModel); - - ui->treeView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); - ui->treeView->header()->setSectionResizeMode( - AtlOptionalModListModel::NameColumn, QHeaderView::ResizeToContents); - ui->treeView->header()->setSectionResizeMode( - AtlOptionalModListModel::DescriptionColumn, QHeaderView::Stretch); - - connect(ui->selectRecommendedButton, &QPushButton::pressed, - listModel, &AtlOptionalModListModel::selectRecommended); - connect(ui->clearAllButton, &QPushButton::pressed, - listModel, &AtlOptionalModListModel::clearAll); - connect(ui->installButton, &QPushButton::pressed, - this, &QDialog::close); -} - -AtlOptionalModDialog::~AtlOptionalModDialog() { - delete ui; -} diff --git a/application/pages/modplatform/atlauncher/AtlOptionalModDialog.h b/application/pages/modplatform/atlauncher/AtlOptionalModDialog.h deleted file mode 100644 index a1df43f6..00000000 --- a/application/pages/modplatform/atlauncher/AtlOptionalModDialog.h +++ /dev/null @@ -1,66 +0,0 @@ -#pragma once - -#include <QDialog> -#include <QAbstractListModel> - -#include "modplatform/atlauncher/ATLPackIndex.h" - -namespace Ui { -class AtlOptionalModDialog; -} - -class AtlOptionalModListModel : public QAbstractListModel { - Q_OBJECT - -public: - enum Columns - { - EnabledColumn = 0, - NameColumn, - DescriptionColumn, - }; - - AtlOptionalModListModel(QWidget *parent, QVector<ATLauncher::VersionMod> mods); - - QVector<QString> getResult(); - - 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; - QVariant headerData(int section, Qt::Orientation orientation, int role) const override; - - Qt::ItemFlags flags(const QModelIndex &index) const override; - -public slots: - void selectRecommended(); - void clearAll(); - -private: - void toggleMod(ATLauncher::VersionMod mod, int index); - void setMod(ATLauncher::VersionMod mod, int index, bool enable, bool shouldEmit = true); - -private: - QVector<ATLauncher::VersionMod> m_mods; - QMap<QString, bool> m_selection; - QMap<QString, int> m_index; - QMap<QString, QVector<QString>> m_dependants; -}; - -class AtlOptionalModDialog : public QDialog { - Q_OBJECT - -public: - AtlOptionalModDialog(QWidget *parent, QVector<ATLauncher::VersionMod> mods); - ~AtlOptionalModDialog() override; - - QVector<QString> getResult() { - return listModel->getResult(); - } - -private: - Ui::AtlOptionalModDialog *ui; - - AtlOptionalModListModel *listModel; -}; diff --git a/application/pages/modplatform/atlauncher/AtlOptionalModDialog.ui b/application/pages/modplatform/atlauncher/AtlOptionalModDialog.ui deleted file mode 100644 index 5d3193a4..00000000 --- a/application/pages/modplatform/atlauncher/AtlOptionalModDialog.ui +++ /dev/null @@ -1,65 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<ui version="4.0"> - <class>AtlOptionalModDialog</class> - <widget class="QDialog" name="AtlOptionalModDialog"> - <property name="geometry"> - <rect> - <x>0</x> - <y>0</y> - <width>550</width> - <height>310</height> - </rect> - </property> - <property name="windowTitle"> - <string>Select Mods To Install</string> - </property> - <layout class="QGridLayout" name="gridLayout_2"> - <item row="1" column="3"> - <widget class="QPushButton" name="installButton"> - <property name="text"> - <string>Install</string> - </property> - <property name="default"> - <bool>true</bool> - </property> - </widget> - </item> - <item row="1" column="1"> - <widget class="QPushButton" name="selectRecommendedButton"> - <property name="text"> - <string>Select Recommended</string> - </property> - </widget> - </item> - <item row="1" column="0"> - <widget class="QPushButton" name="shareCodeButton"> - <property name="enabled"> - <bool>false</bool> - </property> - <property name="text"> - <string>Use Share Code</string> - </property> - </widget> - </item> - <item row="1" column="2"> - <widget class="QPushButton" name="clearAllButton"> - <property name="text"> - <string>Clear All</string> - </property> - </widget> - </item> - <item row="0" column="0" colspan="4"> - <widget class="ModListView" name="treeView"/> - </item> - </layout> - </widget> - <customwidgets> - <customwidget> - <class>ModListView</class> - <extends>QTreeView</extends> - <header>widgets/ModListView.h</header> - </customwidget> - </customwidgets> - <resources/> - <connections/> -</ui> diff --git a/application/pages/modplatform/atlauncher/AtlPage.cpp b/application/pages/modplatform/atlauncher/AtlPage.cpp deleted file mode 100644 index 9fdf111f..00000000 --- a/application/pages/modplatform/atlauncher/AtlPage.cpp +++ /dev/null @@ -1,175 +0,0 @@ -#include "AtlPage.h" -#include "ui_AtlPage.h" - -#include "dialogs/NewInstanceDialog.h" -#include "AtlOptionalModDialog.h" -#include <modplatform/atlauncher/ATLPackInstallTask.h> -#include <BuildConfig.h> -#include <dialogs/VersionSelectDialog.h> - -AtlPage::AtlPage(NewInstanceDialog* dialog, QWidget *parent) - : QWidget(parent), ui(new Ui::AtlPage), dialog(dialog) -{ - ui->setupUi(this); - - filterModel = new Atl::FilterModel(this); - listModel = new Atl::ListModel(this); - filterModel->setSourceModel(listModel); - ui->packView->setModel(filterModel); - ui->packView->setSortingEnabled(true); - - ui->packView->header()->hide(); - ui->packView->setIndentation(0); - - ui->versionSelectionBox->view()->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); - ui->versionSelectionBox->view()->parentWidget()->setMaximumHeight(300); - - for(int i = 0; i < filterModel->getAvailableSortings().size(); i++) - { - ui->sortByBox->addItem(filterModel->getAvailableSortings().keys().at(i)); - } - ui->sortByBox->setCurrentText(filterModel->translateCurrentSorting()); - - connect(ui->searchEdit, &QLineEdit::textChanged, this, &AtlPage::triggerSearch); - connect(ui->resetButton, &QPushButton::clicked, this, &AtlPage::resetSearch); - connect(ui->sortByBox, &QComboBox::currentTextChanged, this, &AtlPage::onSortingSelectionChanged); - connect(ui->packView->selectionModel(), &QItemSelectionModel::currentChanged, this, &AtlPage::onSelectionChanged); - connect(ui->versionSelectionBox, &QComboBox::currentTextChanged, this, &AtlPage::onVersionSelectionChanged); -} - -AtlPage::~AtlPage() -{ - delete ui; -} - -bool AtlPage::shouldDisplay() const -{ - return true; -} - -void AtlPage::openedImpl() -{ - if(!initialized) - { - listModel->request(); - initialized = true; - } - - suggestCurrent(); -} - -void AtlPage::suggestCurrent() -{ - if(!isOpened) - { - return; - } - - if (selectedVersion.isEmpty()) - { - dialog->setSuggestedPack(); - return; - } - - dialog->setSuggestedPack(selected.name, new ATLauncher::PackInstallTask(this, selected.safeName, selectedVersion)); - auto editedLogoName = selected.safeName; - auto url = QString(BuildConfig.ATL_DOWNLOAD_SERVER_URL + "launcher/images/%1.png").arg(selected.safeName.toLower()); - listModel->getLogo(selected.safeName, url, [this, editedLogoName](QString logo) - { - dialog->setSuggestedIconFromFile(logo, editedLogoName); - }); -} - -void AtlPage::triggerSearch() -{ - filterModel->setSearchTerm(ui->searchEdit->text()); -} - -void AtlPage::resetSearch() -{ - ui->searchEdit->setText(""); -} - -void AtlPage::onSortingSelectionChanged(QString data) -{ - auto toSet = filterModel->getAvailableSortings().value(data); - filterModel->setSorting(toSet); -} - -void AtlPage::onSelectionChanged(QModelIndex first, QModelIndex second) -{ - ui->versionSelectionBox->clear(); - - if(!first.isValid()) - { - if(isOpened) - { - dialog->setSuggestedPack(); - } - return; - } - - selected = filterModel->data(first, Qt::UserRole).value<ATLauncher::IndexedPack>(); - - ui->packDescription->setHtml(selected.description.replace("\n", "<br>")); - - for(const auto& version : selected.versions) { - ui->versionSelectionBox->addItem(version.version); - } - - suggestCurrent(); -} - -void AtlPage::onVersionSelectionChanged(QString data) -{ - if(data.isNull() || data.isEmpty()) - { - selectedVersion = ""; - return; - } - - selectedVersion = data; - suggestCurrent(); -} - -QVector<QString> AtlPage::chooseOptionalMods(QVector<ATLauncher::VersionMod> mods) { - AtlOptionalModDialog optionalModDialog(this, mods); - optionalModDialog.exec(); - return optionalModDialog.getResult(); -} - -QString AtlPage::chooseVersion(Meta::VersionListPtr vlist, QString minecraftVersion) { - VersionSelectDialog vselect(vlist.get(), "Choose Version", MMC->activeWindow(), false); - if (minecraftVersion != Q_NULLPTR) { - vselect.setExactFilter(BaseVersionList::ParentVersionRole, minecraftVersion); - vselect.setEmptyString(tr("No versions are currently available for Minecraft %1").arg(minecraftVersion)); - } - else { - vselect.setEmptyString(tr("No versions are currently available")); - } - vselect.setEmptyErrorString(tr("Couldn't load or download the version lists!")); - - // select recommended build - for (int i = 0; i < vlist->versions().size(); i++) { - auto version = vlist->versions().at(i); - auto reqs = version->requires(); - - // filter by minecraft version, if the loader depends on a certain version. - if (minecraftVersion != Q_NULLPTR) { - auto iter = std::find_if(reqs.begin(), reqs.end(), [](const Meta::Require &req) { - return req.uid == "net.minecraft"; - }); - if (iter == reqs.end()) continue; - if (iter->equalsVersion != minecraftVersion) continue; - } - - // first recommended build we find, we use. - if (version->isRecommended()) { - vselect.setCurrentVersion(version->descriptor()); - break; - } - } - - vselect.exec(); - return vselect.selectedVersion()->descriptor(); -} diff --git a/application/pages/modplatform/atlauncher/AtlPage.h b/application/pages/modplatform/atlauncher/AtlPage.h deleted file mode 100644 index 932ec6a6..00000000 --- a/application/pages/modplatform/atlauncher/AtlPage.h +++ /dev/null @@ -1,87 +0,0 @@ -/* Copyright 2013-2019 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include "AtlFilterModel.h" -#include "AtlListModel.h" - -#include <QWidget> -#include <modplatform/atlauncher/ATLPackInstallTask.h> - -#include "MultiMC.h" -#include "pages/BasePage.h" -#include "tasks/Task.h" - -namespace Ui -{ - class AtlPage; -} - -class NewInstanceDialog; - -class AtlPage : public QWidget, public BasePage, public ATLauncher::UserInteractionSupport -{ -Q_OBJECT - -public: - explicit AtlPage(NewInstanceDialog* dialog, QWidget *parent = 0); - virtual ~AtlPage(); - virtual QString displayName() const override - { - return tr("ATLauncher"); - } - virtual QIcon icon() const override - { - return MMC->getThemedIcon("atlauncher"); - } - virtual QString id() const override - { - return "atl"; - } - virtual QString helpPage() const override - { - return "ATL-platform"; - } - virtual bool shouldDisplay() const override; - - void openedImpl() override; - -private: - void suggestCurrent(); - - QString chooseVersion(Meta::VersionListPtr vlist, QString minecraftVersion) override; - QVector<QString> chooseOptionalMods(QVector<ATLauncher::VersionMod> mods) override; - -private slots: - void triggerSearch(); - void resetSearch(); - - void onSortingSelectionChanged(QString data); - - void onSelectionChanged(QModelIndex first, QModelIndex second); - void onVersionSelectionChanged(QString data); - -private: - Ui::AtlPage *ui = nullptr; - NewInstanceDialog* dialog = nullptr; - Atl::ListModel* listModel = nullptr; - Atl::FilterModel* filterModel = nullptr; - - ATLauncher::IndexedPack selected; - QString selectedVersion; - - bool initialized = false; -}; diff --git a/application/pages/modplatform/atlauncher/AtlPage.ui b/application/pages/modplatform/atlauncher/AtlPage.ui deleted file mode 100644 index f16c24b8..00000000 --- a/application/pages/modplatform/atlauncher/AtlPage.ui +++ /dev/null @@ -1,97 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<ui version="4.0"> - <class>AtlPage</class> - <widget class="QWidget" name="AtlPage"> - <property name="geometry"> - <rect> - <x>0</x> - <y>0</y> - <width>837</width> - <height>685</height> - </rect> - </property> - <layout class="QGridLayout" name="gridLayout"> - <item row="1" column="0" colspan="2"> - <layout class="QGridLayout" name="gridLayout_3"> - <item row="1" column="0"> - <widget class="QTreeView" name="packView"> - <property name="iconSize"> - <size> - <width>96</width> - <height>48</height> - </size> - </property> - <property name="alternatingRowColors"> - <bool>true</bool> - </property> - </widget> - </item> - <item row="1" column="1"> - <widget class="QTextBrowser" name="packDescription"> - <property name="openExternalLinks"> - <bool>true</bool> - </property> - <property name="openLinks"> - <bool>true</bool> - </property> - </widget> - </item> - <item row="0" column="0" colspan="2"> - <widget class="QLabel" name="label_2"> - <property name="text"> - <string>Warning: This is still a work in progress. If you run into issues with the imported modpack, it may be a bug.</string> - </property> - <property name="wordWrap"> - <bool>true</bool> - </property> - </widget> - </item> - </layout> - </item> - <item row="2" column="0" colspan="2"> - <layout class="QGridLayout" name="gridLayout_4" columnstretch="0,0,0" rowminimumheight="0" columnminimumwidth="0,0,0"> - <item row="0" column="2"> - <widget class="QComboBox" name="versionSelectionBox"/> - </item> - <item row="0" column="1"> - <widget class="QLabel" name="label"> - <property name="text"> - <string>Version selected:</string> - </property> - <property name="alignment"> - <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> - </property> - </widget> - </item> - <item row="0" column="0"> - <widget class="QComboBox" name="sortByBox"/> - </item> - </layout> - </item> - <item row="0" column="1"> - <widget class="QPushButton" name="resetButton"> - <property name="text"> - <string>Reset</string> - </property> - </widget> - </item> - <item row="0" column="0"> - <widget class="QLineEdit" name="searchEdit"> - <property name="placeholderText"> - <string>Search and filter ...</string> - </property> - </widget> - </item> - </layout> - </widget> - <tabstops> - <tabstop>searchEdit</tabstop> - <tabstop>resetButton</tabstop> - <tabstop>packView</tabstop> - <tabstop>packDescription</tabstop> - <tabstop>sortByBox</tabstop> - <tabstop>versionSelectionBox</tabstop> - </tabstops> - <resources/> - <connections/> -</ui> diff --git a/application/pages/modplatform/flame/FlameModel.cpp b/application/pages/modplatform/flame/FlameModel.cpp deleted file mode 100644 index 228a88c5..00000000 --- a/application/pages/modplatform/flame/FlameModel.cpp +++ /dev/null @@ -1,259 +0,0 @@ -#include "FlameModel.h" -#include "MultiMC.h" -#include <Json.h> - -#include <MMCStrings.h> -#include <Version.h> - -#include <QtMath> -#include <QLabel> - -#include <RWStorage.h> -#include <Env.h> - -namespace Flame { - -ListModel::ListModel(QObject *parent) : QAbstractListModel(parent) -{ -} - -ListModel::~ListModel() -{ -} - -int ListModel::rowCount(const QModelIndex &parent) const -{ - return modpacks.size(); -} - -int ListModel::columnCount(const QModelIndex &parent) const -{ - return 1; -} - -QVariant ListModel::data(const QModelIndex &index, int role) const -{ - int pos = index.row(); - if(pos >= modpacks.size() || pos < 0 || !index.isValid()) - { - return QString("INVALID INDEX %1").arg(pos); - } - - IndexedPack pack = modpacks.at(pos); - if(role == Qt::DisplayRole) - { - return pack.name; - } - else if (role == Qt::ToolTipRole) - { - if(pack.description.length() > 100) - { - //some magic to prevent to long tooltips and replace html linebreaks - QString edit = pack.description.left(97); - edit = edit.left(edit.lastIndexOf("<br>")).left(edit.lastIndexOf(" ")).append("..."); - return edit; - - } - return pack.description; - } - else if(role == Qt::DecorationRole) - { - if(m_logoMap.contains(pack.logoName)) - { - return (m_logoMap.value(pack.logoName)); - } - QIcon icon = MMC->getThemedIcon("screenshot-placeholder"); - ((ListModel *)this)->requestLogo(pack.logoName, pack.logoUrl); - return icon; - } - else if(role == Qt::UserRole) - { - QVariant v; - v.setValue(pack); - return v; - } - - return QVariant(); -} - -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].logoName == logo) { - emit dataChanged(createIndex(i, 0), createIndex(i, 0), {Qt::DecorationRole}); - } - } -} - -void ListModel::logoFailed(QString logo) -{ - m_failedLogos.append(logo); - m_loadingLogos.removeAll(logo); -} - -void ListModel::requestLogo(QString logo, QString url) -{ - if(m_loadingLogos.contains(logo) || m_failedLogos.contains(logo)) - { - return; - } - - MetaEntryPtr entry = ENV.metacache()->resolveEntry("FlamePacks", QString("logos/%1").arg(logo.section(".", 0, 0))); - NetJob *job = new NetJob(QString("Flame Icon Download %1").arg(logo)); - job->addNetAction(Net::Download::makeCached(QUrl(url), entry)); - - auto fullPath = entry->getFullPath(); - QObject::connect(job, &NetJob::succeeded, this, [this, logo, fullPath] - { - emit logoLoaded(logo, QIcon(fullPath)); - if(waitingCallbacks.contains(logo)) - { - waitingCallbacks.value(logo)(fullPath); - } - }); - - QObject::connect(job, &NetJob::failed, this, [this, logo] - { - emit logoFailed(logo); - }); - - job->start(); - - m_loadingLogos.append(logo); -} - -void ListModel::getLogo(const QString &logo, const QString &logoUrl, LogoCallback callback) -{ - if(m_logoMap.contains(logo)) - { - callback(ENV.metacache()->resolveEntry("FlamePacks", QString("logos/%1").arg(logo.section(".", 0, 0)))->getFullPath()); - } - else - { - requestLogo(logo, logoUrl); - } -} - -Qt::ItemFlags ListModel::flags(const QModelIndex &index) const -{ - return QAbstractListModel::flags(index); -} - -bool ListModel::canFetchMore(const QModelIndex& parent) const -{ - return searchState == CanPossiblyFetchMore; -} - -void ListModel::fetchMore(const QModelIndex& parent) -{ - if (parent.isValid()) - return; - if(nextSearchOffset == 0) { - qWarning() << "fetchMore with 0 offset is wrong..."; - return; - } - performPaginatedSearch(); -} - -void ListModel::performPaginatedSearch() -{ - NetJob *netJob = new NetJob("Flame::Search"); - auto searchUrl = QString( - "https://addons-ecs.forgesvc.net/api/v2/addon/search?" - "categoryId=0&" - "gameId=432&" - "index=%1&" - "pageSize=25&" - "searchFilter=%2&" - "sectionId=4471&" - "sort=%3" - ).arg(nextSearchOffset).arg(currentSearchTerm).arg(currentSort); - netJob->addNetAction(Net::Download::makeByteArray(QUrl(searchUrl), &response)); - jobPtr = netJob; - jobPtr->start(); - QObject::connect(netJob, &NetJob::succeeded, this, &ListModel::searchRequestFinished); - QObject::connect(netJob, &NetJob::failed, this, &ListModel::searchRequestFailed); -} - -void ListModel::searchWithTerm(const QString& term, int sort) -{ - if(currentSearchTerm == term && currentSearchTerm.isNull() == term.isNull() && currentSort == sort) { - return; - } - currentSearchTerm = term; - currentSort = sort; - if(jobPtr) { - jobPtr->abort(); - searchState = ResetRequested; - return; - } - else { - beginResetModel(); - modpacks.clear(); - endResetModel(); - searchState = None; - } - nextSearchOffset = 0; - performPaginatedSearch(); -} - -void Flame::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 CurseForge at " << parse_error.offset << " reason: " << parse_error.errorString(); - qWarning() << response; - return; - } - - QList<Flame::IndexedPack> newList; - auto packs = doc.array(); - for(auto packRaw : packs) { - auto packObj = packRaw.toObject(); - - Flame::IndexedPack pack; - try - { - Flame::loadIndexedPack(pack, packObj); - newList.append(pack); - } - catch(const JSONValidationError &e) - { - qWarning() << "Error while loading pack from CurseForge: " << e.cause(); - continue; - } - } - if(packs.size() < 25) { - searchState = Finished; - } else { - nextSearchOffset += 25; - searchState = CanPossiblyFetchMore; - } - beginInsertRows(QModelIndex(), modpacks.size(), modpacks.size() + newList.size() - 1); - modpacks.append(newList); - endInsertRows(); -} - -void Flame::ListModel::searchRequestFailed(QString reason) -{ - jobPtr.reset(); - - if(searchState == ResetRequested) { - beginResetModel(); - modpacks.clear(); - endResetModel(); - - nextSearchOffset = 0; - performPaginatedSearch(); - } else { - searchState = Finished; - } -} - -} - diff --git a/application/pages/modplatform/flame/FlameModel.h b/application/pages/modplatform/flame/FlameModel.h deleted file mode 100644 index 24383db0..00000000 --- a/application/pages/modplatform/flame/FlameModel.h +++ /dev/null @@ -1,76 +0,0 @@ -#pragma once - -#include <RWStorage.h> - -#include <QAbstractListModel> -#include <QSortFilterProxyModel> -#include <QThreadPool> -#include <QIcon> -#include <QStyledItemDelegate> -#include <QList> -#include <QString> -#include <QStringList> -#include <QMetaType> - -#include <functional> -#include <net/NetJob.h> - -#include <modplatform/flame/FlamePackIndex.h> - -namespace Flame { - - -typedef QMap<QString, QIcon> LogoMap; -typedef std::function<void(QString)> LogoCallback; - -class ListModel : public QAbstractListModel -{ - Q_OBJECT - -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; - 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); - -private slots: - void performPaginatedSearch(); - - void logoFailed(QString logo); - void logoLoaded(QString logo, QIcon out); - - void searchRequestFinished(); - void searchRequestFailed(QString reason); - -private: - void requestLogo(QString file, QString url); - -private: - QList<IndexedPack> modpacks; - QStringList m_failedLogos; - QStringList m_loadingLogos; - LogoMap m_logoMap; - QMap<QString, LogoCallback> waitingCallbacks; - - QString currentSearchTerm; - int currentSort = 0; - int nextSearchOffset = 0; - enum SearchState { - None, - CanPossiblyFetchMore, - ResetRequested, - Finished - } searchState = None; - NetJobPtr jobPtr; - QByteArray response; -}; - -} diff --git a/application/pages/modplatform/flame/FlamePage.cpp b/application/pages/modplatform/flame/FlamePage.cpp deleted file mode 100644 index ade58431..00000000 --- a/application/pages/modplatform/flame/FlamePage.cpp +++ /dev/null @@ -1,185 +0,0 @@ -#include "FlamePage.h" -#include "ui_FlamePage.h" - -#include "MultiMC.h" -#include <Json.h> -#include "dialogs/NewInstanceDialog.h" -#include <InstanceImportTask.h> -#include "FlameModel.h" -#include <QKeyEvent> - -FlamePage::FlamePage(NewInstanceDialog* dialog, QWidget *parent) - : QWidget(parent), ui(new Ui::FlamePage), dialog(dialog) -{ - ui->setupUi(this); - connect(ui->searchButton, &QPushButton::clicked, this, &FlamePage::triggerSearch); - ui->searchEdit->installEventFilter(this); - listModel = new Flame::ListModel(this); - ui->packView->setModel(listModel); - - ui->versionSelectionBox->view()->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); - ui->versionSelectionBox->view()->parentWidget()->setMaximumHeight(300); - - // index is used to set the sorting with the curseforge api - ui->sortByBox->addItem(tr("Sort by featured")); - ui->sortByBox->addItem(tr("Sort by popularity")); - ui->sortByBox->addItem(tr("Sort by last updated")); - ui->sortByBox->addItem(tr("Sort by name")); - ui->sortByBox->addItem(tr("Sort by author")); - ui->sortByBox->addItem(tr("Sort by total downloads")); - - connect(ui->sortByBox, SIGNAL(currentIndexChanged(int)), this, SLOT(triggerSearch())); - connect(ui->packView->selectionModel(), &QItemSelectionModel::currentChanged, this, &FlamePage::onSelectionChanged); - connect(ui->versionSelectionBox, &QComboBox::currentTextChanged, this, &FlamePage::onVersionSelectionChanged); -} - -FlamePage::~FlamePage() -{ - delete ui; -} - -bool FlamePage::eventFilter(QObject* watched, QEvent* event) -{ - if (watched == ui->searchEdit && event->type() == QEvent::KeyPress) { - QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event); - if (keyEvent->key() == Qt::Key_Return) { - triggerSearch(); - keyEvent->accept(); - return true; - } - } - return QWidget::eventFilter(watched, event); -} - -bool FlamePage::shouldDisplay() const -{ - return true; -} - -void FlamePage::openedImpl() -{ - suggestCurrent(); - triggerSearch(); -} - -void FlamePage::triggerSearch() -{ - listModel->searchWithTerm(ui->searchEdit->text(), ui->sortByBox->currentIndex()); -} - -void FlamePage::onSelectionChanged(QModelIndex first, QModelIndex second) -{ - ui->versionSelectionBox->clear(); - - if(!first.isValid()) - { - if(isOpened) - { - dialog->setSuggestedPack(); - } - return; - } - - current = listModel->data(first, Qt::UserRole).value<Flame::IndexedPack>(); - QString text = ""; - QString name = current.name; - - if (current.websiteUrl.isEmpty()) - text = name; - else - text = "<a href=\"" + current.websiteUrl + "\">" + name + "</a>"; - if (!current.authors.empty()) { - auto authorToStr = [](Flame::ModpackAuthor & author) { - if(author.url.isEmpty()) { - return author.name; - } - return QString("<a href=\"%1\">%2</a>").arg(author.url, author.name); - }; - QStringList authorStrs; - for(auto & author: current.authors) { - authorStrs.push_back(authorToStr(author)); - } - text += "<br>" + tr(" by ") + authorStrs.join(", "); - } - text += "<br><br>"; - - ui->packDescription->setHtml(text + current.description); - - if (current.versionsLoaded == false) - { - qDebug() << "Loading flame modpack versions"; - NetJob *netJob = new NetJob(QString("Flame::PackVersions(%1)").arg(current.name)); - std::shared_ptr<QByteArray> response = std::make_shared<QByteArray>(); - int addonId = current.addonId; - netJob->addNetAction(Net::Download::makeByteArray(QString("https://addons-ecs.forgesvc.net/api/v2/addon/%1/files").arg(addonId), response.get())); - - QObject::connect(netJob, &NetJob::succeeded, this, [this, response] - { - QJsonParseError 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; - return; - } - QJsonArray arr = doc.array(); - try - { - Flame::loadIndexedPackVersions(current, arr); - } - catch(const JSONValidationError &e) - { - qDebug() << *response; - qWarning() << "Error while reading flame modpack version: " << e.cause(); - } - - for(auto version : current.versions) { - ui->versionSelectionBox->addItem(version.version, QVariant(version.downloadUrl)); - } - - suggestCurrent(); - }); - netJob->start(); - } - else - { - for(auto version : current.versions) { - ui->versionSelectionBox->addItem(version.version, QVariant(version.downloadUrl)); - } - - suggestCurrent(); - } -} - -void FlamePage::suggestCurrent() -{ - if(!isOpened) - { - return; - } - - if (selectedVersion.isEmpty()) - { - dialog->setSuggestedPack(); - return; - } - - dialog->setSuggestedPack(current.name, new InstanceImportTask(selectedVersion)); - QString editedLogoName; - editedLogoName = "curseforge_" + current.logoName.section(".", 0, 0); - listModel->getLogo(current.logoName, current.logoUrl, [this, editedLogoName](QString logo) - { - dialog->setSuggestedIconFromFile(logo, editedLogoName); - }); -} - -void FlamePage::onVersionSelectionChanged(QString data) -{ - if(data.isNull() || data.isEmpty()) - { - selectedVersion = ""; - return; - } - selectedVersion = ui->versionSelectionBox->currentData().toString(); - suggestCurrent(); -} diff --git a/application/pages/modplatform/flame/FlamePage.h b/application/pages/modplatform/flame/FlamePage.h deleted file mode 100644 index 467bb44b..00000000 --- a/application/pages/modplatform/flame/FlamePage.h +++ /dev/null @@ -1,80 +0,0 @@ -/* Copyright 2013-2021 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include <QWidget> - -#include "pages/BasePage.h" -#include <MultiMC.h> -#include "tasks/Task.h" -#include <modplatform/flame/FlamePackIndex.h> - -namespace Ui -{ -class FlamePage; -} - -class NewInstanceDialog; - -namespace Flame { - class ListModel; -} - -class FlamePage : public QWidget, public BasePage -{ - Q_OBJECT - -public: - explicit FlamePage(NewInstanceDialog* dialog, QWidget *parent = 0); - virtual ~FlamePage(); - virtual QString displayName() const override - { - return tr("CurseForge"); - } - virtual QIcon icon() const override - { - return MMC->getThemedIcon("flame"); - } - virtual QString id() const override - { - return "flame"; - } - virtual QString helpPage() const override - { - return "Flame-platform"; - } - virtual bool shouldDisplay() const override; - - void openedImpl() override; - - bool eventFilter(QObject * watched, QEvent * event) override; - -private: - void suggestCurrent(); - -private slots: - void triggerSearch(); - void onSelectionChanged(QModelIndex first, QModelIndex second); - void onVersionSelectionChanged(QString data); - -private: - Ui::FlamePage *ui = nullptr; - NewInstanceDialog* dialog = nullptr; - Flame::ListModel* listModel = nullptr; - Flame::IndexedPack current; - - QString selectedVersion; -}; diff --git a/application/pages/modplatform/flame/FlamePage.ui b/application/pages/modplatform/flame/FlamePage.ui deleted file mode 100644 index 9723815a..00000000 --- a/application/pages/modplatform/flame/FlamePage.ui +++ /dev/null @@ -1,90 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<ui version="4.0"> - <class>FlamePage</class> - <widget class="QWidget" name="FlamePage"> - <property name="geometry"> - <rect> - <x>0</x> - <y>0</y> - <width>837</width> - <height>685</height> - </rect> - </property> - <layout class="QGridLayout" name="gridLayout"> - <item row="1" column="0" colspan="2"> - <layout class="QGridLayout" name="gridLayout_3"> - <item row="1" column="0"> - <widget class="QListView" name="packView"> - <property name="iconSize"> - <size> - <width>48</width> - <height>48</height> - </size> - </property> - <property name="horizontalScrollBarPolicy"> - <enum>Qt::ScrollBarAlwaysOff</enum> - </property> - <property name="alternatingRowColors"> - <bool>true</bool> - </property> - </widget> - </item> - <item row="1" column="1"> - <widget class="QTextBrowser" name="packDescription"> - <property name="openExternalLinks"> - <bool>true</bool> - </property> - <property name="openLinks"> - <bool>true</bool> - </property> - </widget> - </item> - </layout> - </item> - <item row="2" column="0" colspan="2"> - <layout class="QGridLayout" name="gridLayout_4" columnstretch="0,0,0" rowminimumheight="0" columnminimumwidth="0,0,0"> - <item row="0" column="2"> - <widget class="QComboBox" name="versionSelectionBox"/> - </item> - <item row="0" column="1"> - <widget class="QLabel" name="label"> - <property name="text"> - <string>Version selected:</string> - </property> - <property name="alignment"> - <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> - </property> - </widget> - </item> - <item row="0" column="0"> - <widget class="QComboBox" name="sortByBox"/> - </item> - </layout> - </item> - <item row="0" column="1"> - <widget class="QPushButton" name="searchButton"> - <property name="text"> - <string>Search</string> - </property> - </widget> - </item> - <item row="0" column="0"> - <widget class="QLineEdit" name="searchEdit"> - <property name="placeholderText"> - <string>Search and filter ...</string> - </property> - </widget> - </item> - </layout> - </widget> - <tabstops> - <tabstop>searchEdit</tabstop> - <tabstop>searchButton</tabstop> - <tabstop>packView</tabstop> - <tabstop>packDescription</tabstop> - <tabstop>sortByBox</tabstop> - <tabstop>versionSelectionBox</tabstop> - </tabstops> - <resources/> - <connections/> -</ui> diff --git a/application/pages/modplatform/ftb/FtbFilterModel.cpp b/application/pages/modplatform/ftb/FtbFilterModel.cpp deleted file mode 100644 index dec3a017..00000000 --- a/application/pages/modplatform/ftb/FtbFilterModel.cpp +++ /dev/null @@ -1,64 +0,0 @@ -#include "FtbFilterModel.h" - -#include <QDebug> - -#include "modplatform/modpacksch/FTBPackManifest.h" -#include <MMCStrings.h> - -namespace Ftb { - -FilterModel::FilterModel(QObject *parent) : QSortFilterProxyModel(parent) -{ - currentSorting = Sorting::ByPlays; - sortings.insert(tr("Sort by plays"), Sorting::ByPlays); - sortings.insert(tr("Sort by installs"), Sorting::ByInstalls); - sortings.insert(tr("Sort by name"), Sorting::ByName); -} - -const QMap<QString, FilterModel::Sorting> FilterModel::getAvailableSortings() -{ - return sortings; -} - -QString FilterModel::translateCurrentSorting() -{ - return sortings.key(currentSorting); -} - -void FilterModel::setSorting(Sorting sorting) -{ - currentSorting = sorting; - invalidate(); -} - -FilterModel::Sorting FilterModel::getCurrentSorting() -{ - return currentSorting; -} - -bool FilterModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const -{ - return true; -} - -bool FilterModel::lessThan(const QModelIndex &left, const QModelIndex &right) const -{ - ModpacksCH::Modpack leftPack = sourceModel()->data(left, Qt::UserRole).value<ModpacksCH::Modpack>(); - ModpacksCH::Modpack rightPack = sourceModel()->data(right, Qt::UserRole).value<ModpacksCH::Modpack>(); - - if (currentSorting == ByPlays) { - return leftPack.plays < rightPack.plays; - } - else if (currentSorting == ByInstalls) { - return leftPack.installs < rightPack.installs; - } - else if (currentSorting == ByName) { - return Strings::naturalCompare(leftPack.name, rightPack.name, Qt::CaseSensitive) >= 0; - } - - // Invalid sorting set, somehow... - qWarning() << "Invalid sorting set!"; - return true; -} - -} diff --git a/application/pages/modplatform/ftb/FtbFilterModel.h b/application/pages/modplatform/ftb/FtbFilterModel.h deleted file mode 100644 index 4fe2a274..00000000 --- a/application/pages/modplatform/ftb/FtbFilterModel.h +++ /dev/null @@ -1,33 +0,0 @@ -#pragma once - -#include <QtCore/QSortFilterProxyModel> - -namespace Ftb { - -class FilterModel : public QSortFilterProxyModel -{ - Q_OBJECT - -public: - FilterModel(QObject* parent = Q_NULLPTR); - enum Sorting { - ByPlays, - ByInstalls, - ByName, - }; - const QMap<QString, Sorting> getAvailableSortings(); - QString translateCurrentSorting(); - void setSorting(Sorting sorting); - Sorting getCurrentSorting(); - -protected: - bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override; - bool lessThan(const QModelIndex &left, const QModelIndex &right) const override; - -private: - QMap<QString, Sorting> sortings; - Sorting currentSorting; - -}; - -} diff --git a/application/pages/modplatform/ftb/FtbListModel.cpp b/application/pages/modplatform/ftb/FtbListModel.cpp deleted file mode 100644 index 98973f2e..00000000 --- a/application/pages/modplatform/ftb/FtbListModel.cpp +++ /dev/null @@ -1,304 +0,0 @@ -#include "FtbListModel.h" - -#include "BuildConfig.h" -#include "Env.h" -#include "MultiMC.h" -#include "Json.h" - -#include <QPainter> - -namespace Ftb { - -ListModel::ListModel(QObject *parent) : QAbstractListModel(parent) -{ -} - -ListModel::~ListModel() -{ -} - -int ListModel::rowCount(const QModelIndex &parent) const -{ - return modpacks.size(); -} - -int ListModel::columnCount(const QModelIndex &parent) const -{ - return 1; -} - -QVariant ListModel::data(const QModelIndex &index, int role) const -{ - int pos = index.row(); - if(pos >= modpacks.size() || pos < 0 || !index.isValid()) - { - return QString("INVALID INDEX %1").arg(pos); - } - - ModpacksCH::Modpack pack = modpacks.at(pos); - if(role == Qt::DisplayRole) - { - return pack.name; - } - else if (role == Qt::ToolTipRole) - { - return pack.synopsis; - } - else if(role == Qt::DecorationRole) - { - QIcon placeholder = MMC->getThemedIcon("screenshot-placeholder"); - - auto iter = m_logoMap.find(pack.name); - if (iter != m_logoMap.end()) { - auto & logo = *iter; - if(!logo.result.isNull()) { - return logo.result; - } - return placeholder; - } - - for(auto art : pack.art) { - if(art.type == "square") { - ((ListModel *)this)->requestLogo(pack.name, art.url); - } - } - return placeholder; - } - else if(role == Qt::UserRole) - { - QVariant v; - v.setValue(pack); - return v; - } - - return QVariant(); -} - -void ListModel::performSearch() -{ - auto *netJob = new NetJob("Ftb::Search"); - QString searchUrl; - if(currentSearchTerm.isEmpty()) { - searchUrl = BuildConfig.MODPACKSCH_API_BASE_URL + "public/modpack/all"; - } - else { - searchUrl = QString(BuildConfig.MODPACKSCH_API_BASE_URL + "public/modpack/search/25?term=%1") - .arg(currentSearchTerm); - } - netJob->addNetAction(Net::Download::makeByteArray(QUrl(searchUrl), &response)); - jobPtr = netJob; - jobPtr->start(); - QObject::connect(netJob, &NetJob::succeeded, this, &ListModel::searchRequestFinished); - QObject::connect(netJob, &NetJob::failed, this, &ListModel::searchRequestFailed); -} - -void ListModel::getLogo(const QString &logo, const QString &logoUrl, LogoCallback callback) -{ - if(m_logoMap.contains(logo)) - { - callback(ENV.metacache()->resolveEntry("ModpacksCHPacks", QString("logos/%1").arg(logo.section(".", 0, 0)))->getFullPath()); - } - else - { - requestLogo(logo, logoUrl); - } -} - -void ListModel::searchWithTerm(const QString &term) -{ - if(searchState != Failed && currentSearchTerm == term && currentSearchTerm.isNull() == term.isNull()) { - // unless the search has failed, then there is no need to perform an identical search. - return; - } - currentSearchTerm = term; - - if(jobPtr) { - jobPtr->abort(); - jobPtr.reset(); - } - - beginResetModel(); - modpacks.clear(); - endResetModel(); - searchState = None; - - performSearch(); -} - -void ListModel::searchRequestFinished() -{ - jobPtr.reset(); - remainingPacks.clear(); - - QJsonParseError parse_error; - QJsonDocument doc = QJsonDocument::fromJson(response, &parse_error); - if(parse_error.error != QJsonParseError::NoError) { - qWarning() << "Error while parsing JSON response from FTB at " << parse_error.offset << " reason: " << parse_error.errorString(); - qWarning() << response; - return; - } - - auto packs = doc.object().value("packs").toArray(); - for(auto pack : packs) { - auto packId = pack.toInt(); - remainingPacks.append(packId); - } - - if(!remainingPacks.isEmpty()) { - currentPack = remainingPacks.at(0); - requestPack(); - } -} - -void ListModel::searchRequestFailed(QString reason) -{ - jobPtr.reset(); - remainingPacks.clear(); - - searchState = Failed; -} - -void ListModel::requestPack() -{ - auto *netJob = new NetJob("Ftb::Search"); - auto searchUrl = QString(BuildConfig.MODPACKSCH_API_BASE_URL + "public/modpack/%1") - .arg(currentPack); - netJob->addNetAction(Net::Download::makeByteArray(QUrl(searchUrl), &response)); - jobPtr = netJob; - jobPtr->start(); - - QObject::connect(netJob, &NetJob::succeeded, this, &ListModel::packRequestFinished); - QObject::connect(netJob, &NetJob::failed, this, &ListModel::packRequestFailed); -} - -void ListModel::packRequestFinished() -{ - jobPtr.reset(); - remainingPacks.removeOne(currentPack); - - QJsonParseError parse_error; - QJsonDocument doc = QJsonDocument::fromJson(response, &parse_error); - - if(parse_error.error != QJsonParseError::NoError) { - qWarning() << "Error while parsing JSON response from FTB at " << parse_error.offset << " reason: " << parse_error.errorString(); - qWarning() << response; - return; - } - - auto obj = doc.object(); - - ModpacksCH::Modpack pack; - try - { - ModpacksCH::loadModpack(pack, obj); - } - catch (const JSONValidationError &e) - { - qDebug() << QString::fromUtf8(response); - qWarning() << "Error while reading pack manifest from FTB: " << e.cause(); - return; - } - - // Since there is no guarantee that packs have a version, this will just - // ignore those "dud" packs. - if (pack.versions.empty()) - { - qWarning() << "FTB Pack " << pack.id << " ignored. reason: lacking any versions"; - } - else - { - beginInsertRows(QModelIndex(), modpacks.size(), modpacks.size()); - modpacks.append(pack); - endInsertRows(); - } - - if(!remainingPacks.isEmpty()) { - currentPack = remainingPacks.at(0); - requestPack(); - } -} - -void ListModel::packRequestFailed(QString reason) -{ - jobPtr.reset(); - remainingPacks.removeOne(currentPack); -} - -void ListModel::logoLoaded(QString logo, bool stale) -{ - auto & logoObj = m_logoMap[logo]; - logoObj.downloadJob.reset(); - QString smallPath = logoObj.fullpath + ".small"; - - QFileInfo smallInfo(smallPath); - - if(stale || !smallInfo.exists()) { - QImage image(logoObj.fullpath); - if (image.isNull()) - { - logoObj.failed = true; - return; - } - 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(); - - square.save(logoObj.fullpath + ".small", "PNG"); - } - - logoObj.result = QIcon(logoObj.fullpath + ".small"); - for(int i = 0; i < modpacks.size(); i++) { - if(modpacks[i].name == logo) { - emit dataChanged(createIndex(i, 0), createIndex(i, 0), {Qt::DecorationRole}); - } - } -} - -void ListModel::logoFailed(QString logo) -{ - m_logoMap[logo].failed = true; - m_logoMap[logo].downloadJob.reset(); -} - -void ListModel::requestLogo(QString logo, QString url) -{ - if(m_logoMap.contains(logo)) { - return; - } - - MetaEntryPtr entry = ENV.metacache()->resolveEntry("ModpacksCHPacks", QString("logos/%1").arg(logo.section(".", 0, 0))); - - bool stale = entry->isStale(); - - NetJob *job = new NetJob(QString("FTB Icon Download %1").arg(logo)); - job->addNetAction(Net::Download::makeCached(QUrl(url), entry)); - - auto fullPath = entry->getFullPath(); - QObject::connect(job, &NetJob::finished, this, [this, logo, fullPath, stale] - { - logoLoaded(logo, stale); - }); - - QObject::connect(job, &NetJob::failed, this, [this, logo] - { - logoFailed(logo); - }); - - auto &newLogoEntry = m_logoMap[logo]; - newLogoEntry.downloadJob = job; - newLogoEntry.fullpath = fullPath; - job->start(); -} - -} diff --git a/application/pages/modplatform/ftb/FtbListModel.h b/application/pages/modplatform/ftb/FtbListModel.h deleted file mode 100644 index de94e6ba..00000000 --- a/application/pages/modplatform/ftb/FtbListModel.h +++ /dev/null @@ -1,69 +0,0 @@ -#pragma once - -#include <QAbstractListModel> - -#include "modplatform/modpacksch/FTBPackManifest.h" -#include "net/NetJob.h" -#include <QIcon> - -namespace Ftb { - -struct Logo { - QString fullpath; - NetJobPtr downloadJob; - QIcon result; - bool failed = false; -}; - -typedef QMap<QString, Logo> LogoMap; -typedef std::function<void(QString)> LogoCallback; - -class ListModel : public QAbstractListModel -{ - Q_OBJECT - -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; - - void getLogo(const QString &logo, const QString &logoUrl, LogoCallback callback); - void searchWithTerm(const QString & term); - -private slots: - void performSearch(); - void searchRequestFinished(); - void searchRequestFailed(QString reason); - - void requestPack(); - void packRequestFinished(); - void packRequestFailed(QString reason); - - void logoFailed(QString logo); - void logoLoaded(QString logo, bool stale); - -private: - void requestLogo(QString file, QString url); - -private: - QList<ModpacksCH::Modpack> modpacks; - LogoMap m_logoMap; - - QString currentSearchTerm; - enum SearchState { - None, - CanPossiblyFetchMore, - ResetRequested, - Finished, - Failed, - } searchState = None; - NetJobPtr jobPtr; - int currentPack; - QList<int> remainingPacks; - QByteArray response; -}; - -} diff --git a/application/pages/modplatform/ftb/FtbPage.cpp b/application/pages/modplatform/ftb/FtbPage.cpp deleted file mode 100644 index b7f35c5d..00000000 --- a/application/pages/modplatform/ftb/FtbPage.cpp +++ /dev/null @@ -1,145 +0,0 @@ -#include "FtbPage.h" -#include "ui_FtbPage.h" - -#include <QKeyEvent> - -#include "dialogs/NewInstanceDialog.h" -#include "modplatform/modpacksch/FTBPackInstallTask.h" - -#include "HoeDown.h" - -FtbPage::FtbPage(NewInstanceDialog* dialog, QWidget *parent) - : QWidget(parent), ui(new Ui::FtbPage), dialog(dialog) -{ - ui->setupUi(this); - - filterModel = new Ftb::FilterModel(this); - listModel = new Ftb::ListModel(this); - filterModel->setSourceModel(listModel); - ui->packView->setModel(filterModel); - ui->packView->setSortingEnabled(true); - ui->packView->header()->hide(); - ui->packView->setIndentation(0); - - ui->searchEdit->installEventFilter(this); - - ui->versionSelectionBox->view()->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); - ui->versionSelectionBox->view()->parentWidget()->setMaximumHeight(300); - - for(int i = 0; i < filterModel->getAvailableSortings().size(); i++) - { - ui->sortByBox->addItem(filterModel->getAvailableSortings().keys().at(i)); - } - ui->sortByBox->setCurrentText(filterModel->translateCurrentSorting()); - - connect(ui->searchButton, &QPushButton::clicked, this, &FtbPage::triggerSearch); - connect(ui->sortByBox, &QComboBox::currentTextChanged, this, &FtbPage::onSortingSelectionChanged); - connect(ui->packView->selectionModel(), &QItemSelectionModel::currentChanged, this, &FtbPage::onSelectionChanged); - connect(ui->versionSelectionBox, &QComboBox::currentTextChanged, this, &FtbPage::onVersionSelectionChanged); -} - -FtbPage::~FtbPage() -{ - delete ui; -} - -bool FtbPage::eventFilter(QObject* watched, QEvent* event) -{ - if (watched == ui->searchEdit && event->type() == QEvent::KeyPress) { - QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event); - if (keyEvent->key() == Qt::Key_Return) { - triggerSearch(); - keyEvent->accept(); - return true; - } - } - return QWidget::eventFilter(watched, event); -} - -bool FtbPage::shouldDisplay() const -{ - return true; -} - -void FtbPage::openedImpl() -{ - triggerSearch(); - suggestCurrent(); -} - -void FtbPage::suggestCurrent() -{ - if(!isOpened) - { - return; - } - - if (selectedVersion.isEmpty()) - { - dialog->setSuggestedPack(); - return; - } - - dialog->setSuggestedPack(selected.name, new ModpacksCH::PackInstallTask(selected, selectedVersion)); - for(auto art : selected.art) { - if(art.type == "square") { - QString editedLogoName; - editedLogoName = selected.name; - - listModel->getLogo(selected.name, art.url, [this, editedLogoName](QString logo) - { - dialog->setSuggestedIconFromFile(logo + ".small", editedLogoName); - }); - } - } -} - -void FtbPage::triggerSearch() -{ - listModel->searchWithTerm(ui->searchEdit->text()); -} - -void FtbPage::onSortingSelectionChanged(QString data) -{ - auto toSet = filterModel->getAvailableSortings().value(data); - filterModel->setSorting(toSet); -} - -void FtbPage::onSelectionChanged(QModelIndex first, QModelIndex second) -{ - ui->versionSelectionBox->clear(); - - if(!first.isValid()) - { - if(isOpened) - { - dialog->setSuggestedPack(); - } - return; - } - - selected = filterModel->data(first, Qt::UserRole).value<ModpacksCH::Modpack>(); - - HoeDown hoedown; - QString output = hoedown.process(selected.description.toUtf8()); - ui->packDescription->setHtml(output); - - // reverse foreach, so that the newest versions are first - for (auto i = selected.versions.size(); i--;) { - ui->versionSelectionBox->addItem(selected.versions.at(i).name); - } - - suggestCurrent(); -} - -void FtbPage::onVersionSelectionChanged(QString data) -{ - if(data.isNull() || data.isEmpty()) - { - selectedVersion = ""; - return; - } - - selectedVersion = data; - suggestCurrent(); -} diff --git a/application/pages/modplatform/ftb/FtbPage.h b/application/pages/modplatform/ftb/FtbPage.h deleted file mode 100644 index c9c93897..00000000 --- a/application/pages/modplatform/ftb/FtbPage.h +++ /dev/null @@ -1,80 +0,0 @@ -/* Copyright 2013-2021 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include "FtbFilterModel.h" -#include "FtbListModel.h" - -#include <QWidget> - -#include "MultiMC.h" -#include "pages/BasePage.h" -#include "tasks/Task.h" - -namespace Ui -{ - class FtbPage; -} - -class NewInstanceDialog; - -class FtbPage : public QWidget, public BasePage -{ -Q_OBJECT - -public: - explicit FtbPage(NewInstanceDialog* dialog, QWidget *parent = 0); - virtual ~FtbPage(); - virtual QString displayName() const override - { - return tr("FTB"); - } - virtual QIcon icon() const override - { - return MMC->getThemedIcon("ftb_logo"); - } - virtual QString id() const override - { - return "ftb"; - } - virtual QString helpPage() const override - { - return "FTB-platform"; - } - virtual bool shouldDisplay() const override; - - void openedImpl() override; - - bool eventFilter(QObject * watched, QEvent * event) override; - -private: - void suggestCurrent(); - -private slots: - void triggerSearch(); - void onSortingSelectionChanged(QString data); - void onSelectionChanged(QModelIndex first, QModelIndex second); - void onVersionSelectionChanged(QString data); - -private: - Ui::FtbPage *ui = nullptr; - NewInstanceDialog* dialog = nullptr; - Ftb::ListModel* listModel = nullptr; - Ftb::FilterModel* filterModel = nullptr; - - ModpacksCH::Modpack selected; - QString selectedVersion; -}; diff --git a/application/pages/modplatform/ftb/FtbPage.ui b/application/pages/modplatform/ftb/FtbPage.ui deleted file mode 100644 index 135afc6d..00000000 --- a/application/pages/modplatform/ftb/FtbPage.ui +++ /dev/null @@ -1,84 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<ui version="4.0"> - <class>FtbPage</class> - <widget class="QWidget" name="FtbPage"> - <property name="geometry"> - <rect> - <x>0</x> - <y>0</y> - <width>875</width> - <height>745</height> - </rect> - </property> - <layout class="QGridLayout" name="gridLayout"> - <item row="2" column="0" colspan="2"> - <layout class="QGridLayout" name="gridLayout_4" columnstretch="0,0,0" rowminimumheight="0" columnminimumwidth="0,0,0"> - <item row="0" column="2"> - <widget class="QComboBox" name="versionSelectionBox"/> - </item> - <item row="0" column="1"> - <widget class="QLabel" name="label"> - <property name="text"> - <string>Version selected:</string> - </property> - <property name="alignment"> - <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> - </property> - </widget> - </item> - <item row="0" column="0"> - <widget class="QComboBox" name="sortByBox"/> - </item> - </layout> - </item> - <item row="0" column="0"> - <widget class="QLineEdit" name="searchEdit"> - <property name="placeholderText"> - <string>Search and filter ...</string> - </property> - </widget> - </item> - <item row="0" column="1"> - <widget class="QPushButton" name="searchButton"> - <property name="text"> - <string>Search</string> - </property> - </widget> - </item> - <item row="1" column="0" colspan="2"> - <layout class="QGridLayout" name="gridLayout_3"> - <item row="0" column="0"> - <widget class="QTreeView" name="packView"> - <property name="iconSize"> - <size> - <width>48</width> - <height>48</height> - </size> - </property> - <property name="alternatingRowColors"> - <bool>true</bool> - </property> - </widget> - </item> - <item row="0" column="1"> - <widget class="QTextBrowser" name="packDescription"> - <property name="openExternalLinks"> - <bool>true</bool> - </property> - <property name="openLinks"> - <bool>true</bool> - </property> - </widget> - </item> - </layout> - </item> - </layout> - </widget> - <tabstops> - <tabstop>searchEdit</tabstop> - <tabstop>searchButton</tabstop> - <tabstop>versionSelectionBox</tabstop> - </tabstops> - <resources/> - <connections/> -</ui> diff --git a/application/pages/modplatform/legacy_ftb/ListModel.cpp b/application/pages/modplatform/legacy_ftb/ListModel.cpp deleted file mode 100644 index 32596fb3..00000000 --- a/application/pages/modplatform/legacy_ftb/ListModel.cpp +++ /dev/null @@ -1,260 +0,0 @@ -#include "ListModel.h" -#include "MultiMC.h" - -#include <MMCStrings.h> -#include <Version.h> - -#include <QtMath> -#include <QLabel> - -#include <RWStorage.h> -#include <Env.h> - -#include <BuildConfig.h> - -namespace LegacyFTB { - -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 -{ - Modpack leftPack = sourceModel()->data(left, Qt::UserRole).value<Modpack>(); - Modpack rightPack = sourceModel()->data(right, Qt::UserRole).value<Modpack>(); - - if(currentSorting == Sorting::ByGameVersion) { - Version lv(leftPack.mcVersion); - Version rv(rightPack.mcVersion); - return lv < rv; - - } else if(currentSorting == Sorting::ByName) { - return Strings::naturalCompare(leftPack.name, rightPack.name, Qt::CaseSensitive) >= 0; - } - - //UHM, some inavlid value set?! - qWarning() << "Invalid sorting set!"; - return true; -} - -bool FilterModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const -{ - return true; -} - -const QMap<QString, FilterModel::Sorting> FilterModel::getAvailableSortings() -{ - return sortings; -} - -QString FilterModel::translateCurrentSorting() -{ - return sortings.key(currentSorting); -} - -void FilterModel::setSorting(Sorting s) -{ - currentSorting = s; - invalidate(); -} - -FilterModel::Sorting FilterModel::getCurrentSorting() -{ - return currentSorting; -} - -ListModel::ListModel(QObject *parent) : QAbstractListModel(parent) -{ -} - -ListModel::~ListModel() -{ -} - -QString ListModel::translatePackType(PackType type) const -{ - switch(type) - { - case PackType::Public: - return tr("Public Modpack"); - case PackType::ThirdParty: - return tr("Third Party Modpack"); - case PackType::Private: - return tr("Private Modpack"); - } - qWarning() << "Unknown FTB modpack type:" << int(type); - return QString(); -} - -int ListModel::rowCount(const QModelIndex &parent) const -{ - return modpacks.size(); -} - -int ListModel::columnCount(const QModelIndex &parent) const -{ - return 1; -} - -QVariant ListModel::data(const QModelIndex &index, int role) const -{ - int pos = index.row(); - if(pos >= modpacks.size() || pos < 0 || !index.isValid()) - { - return QString("INVALID INDEX %1").arg(pos); - } - - Modpack pack = modpacks.at(pos); - 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 - 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)) - { - return (m_logoMap.value(pack.logo)); - } - QIcon icon = MMC->getThemedIcon("screenshot-placeholder"); - ((ListModel *)this)->requestLogo(pack.logo); - return icon; - } - else if(role == Qt::TextColorRole) - { - 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 - return QColor(244, 229, 66); - } - } - else if(role == Qt::UserRole) - { - QVariant v; - v.setValue(pack); - return v; - } - - return QVariant(); -} - -void ListModel::fill(ModpackList modpacks) -{ - beginResetModel(); - this->modpacks = modpacks; - endResetModel(); -} - -void ListModel::addPack(Modpack modpack) -{ - beginResetModel(); - this->modpacks.append(modpack); - endResetModel(); -} - -void ListModel::clear() -{ - beginResetModel(); - modpacks.clear(); - endResetModel(); -} - -Modpack ListModel::at(int row) -{ - return modpacks.at(row); -} - -void ListModel::remove(int row) -{ - if(row < 0 || row >= modpacks.size()) - { - qWarning() << "Attempt to remove FTB modpacks with invalid row" << row; - return; - } - beginRemoveRows(QModelIndex(), row, row); - modpacks.removeAt(row); - endRemoveRows(); -} - -void ListModel::logoLoaded(QString logo, QIcon out) -{ - m_loadingLogos.removeAll(logo); - m_logoMap.insert(logo, out); - emit dataChanged(createIndex(0, 0), createIndex(1, 0)); -} - -void ListModel::logoFailed(QString logo) -{ - m_failedLogos.append(logo); - m_loadingLogos.removeAll(logo); -} - -void ListModel::requestLogo(QString file) -{ - if(m_loadingLogos.contains(file) || m_failedLogos.contains(file)) - { - return; - } - - MetaEntryPtr entry = ENV.metacache()->resolveEntry("FTBPacks", QString("logos/%1").arg(file.section(".", 0, 0))); - NetJob *job = new NetJob(QString("FTB Icon Download for %1").arg(file)); - 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] - { - emit logoLoaded(file, QIcon(fullPath)); - if(waitingCallbacks.contains(file)) - { - waitingCallbacks.value(file)(fullPath); - } - }); - - QObject::connect(job, &NetJob::failed, this, [this, file] - { - emit logoFailed(file); - }); - - job->start(); - - m_loadingLogos.append(file); -} - -void ListModel::getLogo(const QString &logo, LogoCallback callback) -{ - if(m_logoMap.contains(logo)) - { - callback(ENV.metacache()->resolveEntry("FTBPacks", QString("logos/%1").arg(logo.section(".", 0, 0)))->getFullPath()); - } - else - { - requestLogo(logo); - } -} - -Qt::ItemFlags ListModel::flags(const QModelIndex &index) const -{ - return QAbstractListModel::flags(index); -} - -} diff --git a/application/pages/modplatform/legacy_ftb/ListModel.h b/application/pages/modplatform/legacy_ftb/ListModel.h deleted file mode 100644 index c55df000..00000000 --- a/application/pages/modplatform/legacy_ftb/ListModel.h +++ /dev/null @@ -1,78 +0,0 @@ -#pragma once - -#include <modplatform/legacy_ftb/PackHelpers.h> -#include <RWStorage.h> - -#include <QAbstractListModel> -#include <QSortFilterProxyModel> -#include <QThreadPool> -#include <QIcon> -#include <QStyledItemDelegate> - -#include <functional> - -namespace LegacyFTB { - -typedef QMap<QString, QIcon> FTBLogoMap; -typedef std::function<void(QString)> LogoCallback; - -class FilterModel : public QSortFilterProxyModel -{ - Q_OBJECT -public: - FilterModel(QObject* parent = Q_NULLPTR); - enum Sorting { - ByName, - ByGameVersion - }; - const QMap<QString, Sorting> getAvailableSortings(); - QString translateCurrentSorting(); - void setSorting(Sorting sorting); - Sorting getCurrentSorting(); - -protected: - bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override; - bool lessThan(const QModelIndex &left, const QModelIndex &right) const override; - -private: - QMap<QString, Sorting> sortings; - Sorting currentSorting; - -}; - -class ListModel : public QAbstractListModel -{ - Q_OBJECT -private: - ModpackList modpacks; - QStringList m_failedLogos; - QStringList m_loadingLogos; - FTBLogoMap m_logoMap; - QMap<QString, LogoCallback> waitingCallbacks; - - void requestLogo(QString file); - QString translatePackType(PackType type) const; - - -private slots: - void logoFailed(QString logo); - void logoLoaded(QString logo, QIcon out); - -public: - ListModel(QObject *parent); - ~ListModel(); - int rowCount(const QModelIndex &parent) const override; - int columnCount(const QModelIndex &parent) const override; - QVariant data(const QModelIndex &index, int role) const override; - Qt::ItemFlags flags(const QModelIndex &index) const override; - - void fill(ModpackList modpacks); - void addPack(Modpack modpack); - void clear(); - void remove(int row); - - Modpack at(int row); - void getLogo(const QString &logo, LogoCallback callback); -}; - -} diff --git a/application/pages/modplatform/legacy_ftb/Page.cpp b/application/pages/modplatform/legacy_ftb/Page.cpp deleted file mode 100644 index a438f76c..00000000 --- a/application/pages/modplatform/legacy_ftb/Page.cpp +++ /dev/null @@ -1,369 +0,0 @@ -#include "Page.h" -#include "ui_Page.h" - -#include <QInputDialog> - -#include "MultiMC.h" -#include "dialogs/CustomMessageBox.h" -#include "dialogs/NewInstanceDialog.h" -#include "modplatform/legacy_ftb/PackFetchTask.h" -#include "modplatform/legacy_ftb/PackInstallTask.h" -#include "modplatform/legacy_ftb/PrivatePackManager.h" -#include "ListModel.h" - -namespace LegacyFTB { - -Page::Page(NewInstanceDialog* dialog, QWidget *parent) - : QWidget(parent), dialog(dialog), ui(new Ui::Page) -{ - ftbFetchTask.reset(new PackFetchTask()); - ftbPrivatePacks.reset(new PrivatePackManager()); - - ui->setupUi(this); - - { - publicFilterModel = new FilterModel(this); - publicListModel = new ListModel(this); - publicFilterModel->setSourceModel(publicListModel); - - ui->publicPackList->setModel(publicFilterModel); - ui->publicPackList->setSortingEnabled(true); - ui->publicPackList->header()->hide(); - ui->publicPackList->setIndentation(0); - ui->publicPackList->setIconSize(QSize(42, 42)); - - for(int i = 0; i < publicFilterModel->getAvailableSortings().size(); i++) - { - ui->sortByBox->addItem(publicFilterModel->getAvailableSortings().keys().at(i)); - } - - ui->sortByBox->setCurrentText(publicFilterModel->translateCurrentSorting()); - } - - { - thirdPartyFilterModel = new FilterModel(this); - thirdPartyModel = new ListModel(this); - thirdPartyFilterModel->setSourceModel(thirdPartyModel); - - ui->thirdPartyPackList->setModel(thirdPartyFilterModel); - ui->thirdPartyPackList->setSortingEnabled(true); - ui->thirdPartyPackList->header()->hide(); - ui->thirdPartyPackList->setIndentation(0); - ui->thirdPartyPackList->setIconSize(QSize(42, 42)); - - thirdPartyFilterModel->setSorting(publicFilterModel->getCurrentSorting()); - } - - { - privateFilterModel = new FilterModel(this); - privateListModel = new ListModel(this); - privateFilterModel->setSourceModel(privateListModel); - - ui->privatePackList->setModel(privateFilterModel); - ui->privatePackList->setSortingEnabled(true); - ui->privatePackList->header()->hide(); - ui->privatePackList->setIndentation(0); - ui->privatePackList->setIconSize(QSize(42, 42)); - - privateFilterModel->setSorting(publicFilterModel->getCurrentSorting()); - } - - ui->versionSelectionBox->view()->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); - ui->versionSelectionBox->view()->parentWidget()->setMaximumHeight(300); - - connect(ui->sortByBox, &QComboBox::currentTextChanged, this, &Page::onSortingSelectionChanged); - connect(ui->versionSelectionBox, &QComboBox::currentTextChanged, this, &Page::onVersionSelectionItemChanged); - - connect(ui->publicPackList->selectionModel(), &QItemSelectionModel::currentChanged, this, &Page::onPublicPackSelectionChanged); - 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->tabWidget, &QTabWidget::currentChanged, this, &Page::onTabChanged); - - // ui->modpackInfo->setOpenExternalLinks(true); - - ui->publicPackList->selectionModel()->reset(); - ui->thirdPartyPackList->selectionModel()->reset(); - ui->privatePackList->selectionModel()->reset(); - - onTabChanged(ui->tabWidget->currentIndex()); -} - -Page::~Page() -{ - delete ui; -} - -bool Page::shouldDisplay() const -{ - return true; -} - -void Page::openedImpl() -{ - if(!initialized) - { - connect(ftbFetchTask.get(), &PackFetchTask::finished, this, &Page::ftbPackDataDownloadSuccessfully); - connect(ftbFetchTask.get(), &PackFetchTask::failed, this, &Page::ftbPackDataDownloadFailed); - - connect(ftbFetchTask.get(), &PackFetchTask::privateFileDownloadFinished, this, &Page::ftbPrivatePackDataDownloadSuccessfully); - connect(ftbFetchTask.get(), &PackFetchTask::privateFileDownloadFailed, this, &Page::ftbPrivatePackDataDownloadFailed); - - ftbFetchTask->fetch(); - ftbPrivatePacks->load(); - ftbFetchTask->fetchPrivate(ftbPrivatePacks->getCurrentPackCodes().toList()); - initialized = true; - } - suggestCurrent(); -} - -void Page::suggestCurrent() -{ - if(!isOpened) - { - return; - } - - if(selected.broken || selectedVersion.isEmpty()) - { - dialog->setSuggestedPack(); - return; - } - - dialog->setSuggestedPack(selected.name, new PackInstallTask(selected, selectedVersion)); - QString editedLogoName; - if(selected.logo.toLower().startsWith("ftb")) - { - editedLogoName = selected.logo; - } - else - { - editedLogoName = "ftb_" + selected.logo; - } - - editedLogoName = editedLogoName.left(editedLogoName.lastIndexOf(".png")); - - if(selected.type == PackType::Public) - { - publicListModel->getLogo(selected.logo, [this, editedLogoName](QString logo) - { - dialog->setSuggestedIconFromFile(logo, editedLogoName); - }); - } - else if (selected.type == PackType::ThirdParty) - { - thirdPartyModel->getLogo(selected.logo, [this, editedLogoName](QString logo) - { - dialog->setSuggestedIconFromFile(logo, editedLogoName); - }); - } - else if (selected.type == PackType::Private) - { - privateListModel->getLogo(selected.logo, [this, editedLogoName](QString logo) - { - dialog->setSuggestedIconFromFile(logo, editedLogoName); - }); - } -} - -void Page::ftbPackDataDownloadSuccessfully(ModpackList publicPacks, ModpackList thirdPartyPacks) -{ - publicListModel->fill(publicPacks); - thirdPartyModel->fill(thirdPartyPacks); -} - -void Page::ftbPackDataDownloadFailed(QString reason) -{ - //TODO: Display the error -} - -void Page::ftbPrivatePackDataDownloadSuccessfully(Modpack pack) -{ - privateListModel->addPack(pack); -} - -void Page::ftbPrivatePackDataDownloadFailed(QString reason, QString packCode) -{ - auto reply = QMessageBox::question( - this, - tr("FTB private packs"), - tr("Failed to download pack information for code %1.\nShould it be removed now?").arg(packCode) - ); - if(reply == QMessageBox::Yes) - { - ftbPrivatePacks->remove(packCode); - } -} - -void Page::onPublicPackSelectionChanged(QModelIndex now, QModelIndex prev) -{ - if(!now.isValid()) - { - onPackSelectionChanged(); - return; - } - Modpack selectedPack = publicFilterModel->data(now, Qt::UserRole).value<Modpack>(); - onPackSelectionChanged(&selectedPack); -} - -void Page::onThirdPartyPackSelectionChanged(QModelIndex now, QModelIndex prev) -{ - if(!now.isValid()) - { - onPackSelectionChanged(); - return; - } - Modpack selectedPack = thirdPartyFilterModel->data(now, Qt::UserRole).value<Modpack>(); - onPackSelectionChanged(&selectedPack); -} - -void Page::onPrivatePackSelectionChanged(QModelIndex now, QModelIndex prev) -{ - if(!now.isValid()) - { - onPackSelectionChanged(); - return; - } - Modpack selectedPack = privateFilterModel->data(now, Qt::UserRole).value<Modpack>(); - onPackSelectionChanged(&selectedPack); -} - -void Page::onPackSelectionChanged(Modpack* pack) -{ - ui->versionSelectionBox->clear(); - if(pack) - { - currentModpackInfo->setHtml("Pack by <b>" + pack->author + "</b>" + - "<br>Minecraft " + pack->mcVersion + "<br>" + "<br>" + pack->description + "<ul><li>" + pack->mods.replace(";", "</li><li>") - + "</li></ul>"); - bool currentAdded = false; - - for(int i = 0; i < pack->oldVersions.size(); i++) - { - if(pack->currentVersion == pack->oldVersions.at(i)) - { - currentAdded = true; - } - ui->versionSelectionBox->addItem(pack->oldVersions.at(i)); - } - - if(!currentAdded) - { - ui->versionSelectionBox->addItem(pack->currentVersion); - } - selected = *pack; - } - else - { - currentModpackInfo->setHtml(""); - ui->versionSelectionBox->clear(); - if(isOpened) - { - dialog->setSuggestedPack(); - } - return; - } - suggestCurrent(); -} - -void Page::onVersionSelectionItemChanged(QString data) -{ - if(data.isNull() || data.isEmpty()) - { - selectedVersion = ""; - return; - } - - selectedVersion = data; - suggestCurrent(); -} - -void Page::onSortingSelectionChanged(QString data) -{ - FilterModel::Sorting toSet = publicFilterModel->getAvailableSortings().value(data); - publicFilterModel->setSorting(toSet); - thirdPartyFilterModel->setSorting(toSet); - privateFilterModel->setSorting(toSet); -} - -void Page::onTabChanged(int tab) -{ - if(tab == 1) - { - currentModel = thirdPartyFilterModel; - currentList = ui->thirdPartyPackList; - currentModpackInfo = ui->thirdPartyPackDescription; - } - else if(tab == 2) - { - currentModel = privateFilterModel; - currentList = ui->privatePackList; - currentModpackInfo = ui->privatePackDescription; - } - else - { - currentModel = publicFilterModel; - currentList = ui->publicPackList; - currentModpackInfo = ui->publicPackDescription; - } - - currentList->selectionModel()->reset(); - QModelIndex idx = currentList->currentIndex(); - if(idx.isValid()) - { - auto pack = currentModel->data(idx, Qt::UserRole).value<Modpack>(); - onPackSelectionChanged(&pack); - } - else - { - onPackSelectionChanged(); - } -} - -void Page::onAddPackClicked() -{ - bool ok; - QString text = QInputDialog::getText( - this, - tr("Add FTB pack"), - tr("Enter pack code:"), - QLineEdit::Normal, - QString(), - &ok - ); - if(ok && !text.isEmpty()) - { - ftbPrivatePacks->add(text); - ftbFetchTask->fetchPrivate({text}); - } -} - -void Page::onRemovePackClicked() -{ - auto index = ui->privatePackList->currentIndex(); - if(!index.isValid()) - { - return; - } - auto row = index.row(); - Modpack pack = privateListModel->at(row); - auto answer = QMessageBox::question( - this, - tr("Remove pack"), - tr("Are you sure you want to remove pack %1?").arg(pack.name), - QMessageBox::Yes | QMessageBox::No - ); - if(answer != QMessageBox::Yes) - { - return; - } - - ftbPrivatePacks->remove(pack.packCode); - privateListModel->remove(row); - onPackSelectionChanged(); -} - -} diff --git a/application/pages/modplatform/legacy_ftb/Page.h b/application/pages/modplatform/legacy_ftb/Page.h deleted file mode 100644 index e840216e..00000000 --- a/application/pages/modplatform/legacy_ftb/Page.h +++ /dev/null @@ -1,119 +0,0 @@ -/* Copyright 2013-2021 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include <QWidget> -#include <QTreeView> -#include <QTextBrowser> - -#include "pages/BasePage.h" -#include <MultiMC.h> -#include "tasks/Task.h" -#include "modplatform/legacy_ftb/PackHelpers.h" -#include "modplatform/legacy_ftb/PackFetchTask.h" -#include "QObjectPtr.h" - -class NewInstanceDialog; - -namespace LegacyFTB { - -namespace Ui -{ -class Page; -} - -class ListModel; -class FilterModel; -class PrivatePackListModel; -class PrivatePackFilterModel; -class PrivatePackManager; - -class Page : public QWidget, public BasePage -{ - Q_OBJECT - -public: - explicit Page(NewInstanceDialog * dialog, QWidget *parent = 0); - virtual ~Page(); - QString displayName() const override - { - return tr("FTB Legacy"); - } - QIcon icon() const override - { - return MMC->getThemedIcon("ftb_logo"); - } - QString id() const override - { - return "legacy_ftb"; - } - QString helpPage() const override - { - return "FTB-platform"; - } - bool shouldDisplay() const override; - void openedImpl() override; - -private: - void suggestCurrent(); - void onPackSelectionChanged(Modpack *pack = nullptr); - -private slots: - void ftbPackDataDownloadSuccessfully(ModpackList publicPacks, ModpackList thirdPartyPacks); - void ftbPackDataDownloadFailed(QString reason); - - void ftbPrivatePackDataDownloadSuccessfully(Modpack pack); - void ftbPrivatePackDataDownloadFailed(QString reason, QString packCode); - - void onSortingSelectionChanged(QString data); - void onVersionSelectionItemChanged(QString data); - - void onPublicPackSelectionChanged(QModelIndex first, QModelIndex second); - void onThirdPartyPackSelectionChanged(QModelIndex first, QModelIndex second); - void onPrivatePackSelectionChanged(QModelIndex first, QModelIndex second); - - void onTabChanged(int tab); - - void onAddPackClicked(); - void onRemovePackClicked(); - -private: - FilterModel* currentModel = nullptr; - QTreeView* currentList = nullptr; - QTextBrowser* currentModpackInfo = nullptr; - - bool initialized = false; - Modpack selected; - QString selectedVersion; - - ListModel* publicListModel = nullptr; - FilterModel* publicFilterModel = nullptr; - - ListModel *thirdPartyModel = nullptr; - FilterModel *thirdPartyFilterModel = nullptr; - - ListModel *privateListModel = nullptr; - FilterModel *privateFilterModel = nullptr; - - unique_qobject_ptr<PackFetchTask> ftbFetchTask; - std::unique_ptr<PrivatePackManager> ftbPrivatePacks; - - NewInstanceDialog* dialog = nullptr; - - Ui::Page *ui = nullptr; -}; - -} diff --git a/application/pages/modplatform/legacy_ftb/Page.ui b/application/pages/modplatform/legacy_ftb/Page.ui deleted file mode 100644 index 15e5d432..00000000 --- a/application/pages/modplatform/legacy_ftb/Page.ui +++ /dev/null @@ -1,135 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<ui version="4.0"> - <class>LegacyFTB::Page</class> - <widget class="QWidget" name="LegacyFTB::Page"> - <property name="geometry"> - <rect> - <x>0</x> - <y>0</y> - <width>709</width> - <height>602</height> - </rect> - </property> - <layout class="QVBoxLayout" name="verticalLayout"> - <item> - <widget class="QTabWidget" name="tabWidget"> - <property name="currentIndex"> - <number>0</number> - </property> - <widget class="QWidget" name="tab"> - <attribute name="title"> - <string>Public</string> - </attribute> - <layout class="QGridLayout" name="gridLayout"> - <item row="0" column="0"> - <widget class="QTreeView" name="publicPackList"> - <property name="maximumSize"> - <size> - <width>250</width> - <height>16777215</height> - </size> - </property> - <property name="alternatingRowColors"> - <bool>true</bool> - </property> - </widget> - </item> - <item row="0" column="1"> - <widget class="QTextBrowser" name="publicPackDescription"/> - </item> - </layout> - </widget> - <widget class="QWidget" name="tab_2"> - <attribute name="title"> - <string>3rd Party</string> - </attribute> - <layout class="QGridLayout" name="gridLayout_3"> - <item row="0" column="1"> - <widget class="QTextBrowser" name="thirdPartyPackDescription"/> - </item> - <item row="0" column="0"> - <widget class="QTreeView" name="thirdPartyPackList"> - <property name="maximumSize"> - <size> - <width>250</width> - <height>16777215</height> - </size> - </property> - <property name="alternatingRowColors"> - <bool>true</bool> - </property> - </widget> - </item> - </layout> - </widget> - <widget class="QWidget" name="tab_3"> - <attribute name="title"> - <string>Private</string> - </attribute> - <layout class="QGridLayout" name="gridLayout_2"> - <item row="0" column="0"> - <widget class="QTreeView" name="privatePackList"> - <property name="maximumSize"> - <size> - <width>250</width> - <height>16777215</height> - </size> - </property> - <property name="alternatingRowColors"> - <bool>true</bool> - </property> - </widget> - </item> - <item row="1" column="0"> - <widget class="QPushButton" name="addPackBtn"> - <property name="text"> - <string>Add pack</string> - </property> - </widget> - </item> - <item row="2" column="0"> - <widget class="QPushButton" name="removePackBtn"> - <property name="text"> - <string>Remove selected pack</string> - </property> - </widget> - </item> - <item row="0" column="1" rowspan="3"> - <widget class="QTextBrowser" name="privatePackDescription"/> - </item> - </layout> - </widget> - </widget> - </item> - <item> - <layout class="QGridLayout" name="gridLayout_4"> - <item row="0" column="1"> - <widget class="QLabel" name="label"> - <property name="text"> - <string>Version selected:</string> - </property> - <property name="alignment"> - <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> - </property> - </widget> - </item> - <item row="0" column="2"> - <widget class="QComboBox" name="versionSelectionBox"/> - </item> - <item row="0" column="0"> - <widget class="QComboBox" name="sortByBox"> - <property name="minimumSize"> - <size> - <width>265</width> - <height>0</height> - </size> - </property> - </widget> - </item> - </layout> - </item> - </layout> - </widget> - <resources/> - <connections/> -</ui> diff --git a/application/pages/modplatform/technic/TechnicData.h b/application/pages/modplatform/technic/TechnicData.h deleted file mode 100644 index 50fd75e8..00000000 --- a/application/pages/modplatform/technic/TechnicData.h +++ /dev/null @@ -1,42 +0,0 @@ -/* Copyright 2020-2021 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include <QList> -#include <QString> - -namespace Technic { -struct Modpack { - QString slug; - - QString name; - QString logoUrl; - QString logoName; - - bool broken = true; - - QString url; - bool isSolder = false; - QString minecraftVersion; - - bool metadataLoaded = false; - QString websiteUrl; - QString author; - QString description; -}; -} - -Q_DECLARE_METATYPE(Technic::Modpack) diff --git a/application/pages/modplatform/technic/TechnicModel.cpp b/application/pages/modplatform/technic/TechnicModel.cpp deleted file mode 100644 index def30783..00000000 --- a/application/pages/modplatform/technic/TechnicModel.cpp +++ /dev/null @@ -1,238 +0,0 @@ -/* Copyright 2020-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 "TechnicModel.h" -#include "Env.h" -#include "MultiMC.h" -#include "Json.h" - -#include <QIcon> - -Technic::ListModel::ListModel(QObject *parent) : QAbstractListModel(parent) -{ -} - -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()) - { - return QString("INVALID INDEX %1").arg(pos); - } - - Modpack pack = modpacks.at(pos); - if(role == Qt::DisplayRole) - { - return pack.name; - } - else if(role == Qt::DecorationRole) - { - if(m_logoMap.contains(pack.logoName)) - { - return (m_logoMap.value(pack.logoName)); - } - QIcon icon = MMC->getThemedIcon("screenshot-placeholder"); - ((ListModel *)this)->requestLogo(pack.logoName, pack.logoUrl); - return icon; - } - else if(role == Qt::UserRole) - { - QVariant v; - v.setValue(pack); - return v; - } - return QVariant(); -} - -int Technic::ListModel::columnCount(const QModelIndex&) const -{ - return 1; -} - -int Technic::ListModel::rowCount(const QModelIndex&) const -{ - return modpacks.size(); -} - -void Technic::ListModel::searchWithTerm(const QString& term) -{ - if(currentSearchTerm == term && currentSearchTerm.isNull() == term.isNull()) { - return; - } - currentSearchTerm = term; - if(jobPtr) { - jobPtr->abort(); - searchState = ResetRequested; - return; - } - else { - beginResetModel(); - modpacks.clear(); - endResetModel(); - searchState = None; - } - performSearch(); -} - -void Technic::ListModel::performSearch() -{ - NetJob *netJob = new NetJob("Technic::Search"); - QString searchUrl = ""; - if (currentSearchTerm.isEmpty()) { - searchUrl = "https://api.technicpack.net/trending?build=multimc"; - } - else - { - searchUrl = QString( - "https://api.technicpack.net/search?build=multimc&q=%1" - ).arg(currentSearchTerm); - } - netJob->addNetAction(Net::Download::makeByteArray(QUrl(searchUrl), &response)); - jobPtr = netJob; - jobPtr->start(); - QObject::connect(netJob, &NetJob::succeeded, this, &ListModel::searchRequestFinished); - QObject::connect(netJob, &NetJob::failed, this, &ListModel::searchRequestFailed); -} - -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; - return; - } - - QList<Modpack> newList; - try { - auto root = Json::requireObject(doc); - auto objs = Json::requireArray(root, "modpacks"); - for (auto technicPack: objs) { - Modpack pack; - auto technicPackObject = Json::requireObject(technicPack); - pack.name = Json::requireString(technicPackObject, "name"); - pack.slug = Json::requireString(technicPackObject, "slug"); - if (pack.slug == "vanilla") - continue; - - auto rawURL = Json::ensureString(technicPackObject, "iconUrl", "null"); - if(rawURL == "null") { - pack.logoUrl = "null"; - pack.logoName = "null"; - } - else { - pack.logoUrl = rawURL; - pack.logoName = rawURL.section(QLatin1Char('/'), -1).section(QLatin1Char('.'), 0, 0); - } - pack.broken = false; - newList.append(pack); - } - } - catch (const JSONValidationError &err) - { - qCritical() << "Couldn't parse technic search results:" << err.cause() ; - return; - } - searchState = Finished; - beginInsertRows(QModelIndex(), modpacks.size(), modpacks.size() + newList.size() - 1); - modpacks.append(newList); - endInsertRows(); -} - -void Technic::ListModel::getLogo(const QString& logo, const QString& logoUrl, Technic::LogoCallback callback) -{ - if(m_logoMap.contains(logo)) - { - callback(ENV.metacache()->resolveEntry("TechnicPacks", QString("logos/%1").arg(logo))->getFullPath()); - } - else - { - requestLogo(logo, logoUrl); - } -} - -void Technic::ListModel::searchRequestFailed() -{ - jobPtr.reset(); - - if(searchState == ResetRequested) - { - beginResetModel(); - modpacks.clear(); - endResetModel(); - - performSearch(); - } - 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}); - } - } -} - -void Technic::ListModel::logoFailed(QString logo) -{ - m_failedLogos.append(logo); - m_loadingLogos.removeAll(logo); -} - -void Technic::ListModel::requestLogo(QString logo, QString url) -{ - if(m_loadingLogos.contains(logo) || m_failedLogos.contains(logo) || logo == "null") - { - return; - } - - MetaEntryPtr entry = ENV.metacache()->resolveEntry("TechnicPacks", QString("logos/%1").arg(logo)); - NetJob *job = new NetJob(QString("Technic Icon Download %1").arg(logo)); - job->addNetAction(Net::Download::makeCached(QUrl(url), entry)); - - auto fullPath = entry->getFullPath(); - - QObject::connect(job, &NetJob::succeeded, this, [this, logo, fullPath] - { - logoLoaded(logo, fullPath); - }); - - QObject::connect(job, &NetJob::failed, this, [this, logo] - { - logoFailed(logo); - }); - - job->start(); - - m_loadingLogos.append(logo); -} diff --git a/application/pages/modplatform/technic/TechnicModel.h b/application/pages/modplatform/technic/TechnicModel.h deleted file mode 100644 index 82a03842..00000000 --- a/application/pages/modplatform/technic/TechnicModel.h +++ /dev/null @@ -1,70 +0,0 @@ -/* Copyright 2020-2021 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include <QModelIndex> - -#include "TechnicData.h" -#include "net/NetJob.h" - -namespace Technic { - -typedef std::function<void(QString)> LogoCallback; - -class ListModel : public QAbstractListModel -{ - Q_OBJECT - -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); - -private slots: - void searchRequestFinished(); - void searchRequestFailed(); - - void logoFailed(QString logo); - void logoLoaded(QString logo, QString out); - -private: - void performSearch(); - void requestLogo(QString logo, QString url); - -private: - QList<Modpack> modpacks; - QStringList m_failedLogos; - QStringList m_loadingLogos; - QMap<QString, QIcon> m_logoMap; - QMap<QString, LogoCallback> waitingCallbacks; - - QString currentSearchTerm; - enum SearchState { - None, - ResetRequested, - Finished - } searchState = None; - NetJobPtr jobPtr; - QByteArray response; -}; - -} diff --git a/application/pages/modplatform/technic/TechnicPage.cpp b/application/pages/modplatform/technic/TechnicPage.cpp deleted file mode 100644 index e836f767..00000000 --- a/application/pages/modplatform/technic/TechnicPage.cpp +++ /dev/null @@ -1,198 +0,0 @@ -/* 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 "TechnicPage.h" -#include "ui_TechnicPage.h" - -#include "MultiMC.h" -#include "dialogs/NewInstanceDialog.h" -#include "TechnicModel.h" -#include <QKeyEvent> -#include "modplatform/technic/SingleZipPackInstallTask.h" -#include "modplatform/technic/SolderPackInstallTask.h" -#include "Json.h" - -TechnicPage::TechnicPage(NewInstanceDialog* dialog, QWidget *parent) - : QWidget(parent), ui(new Ui::TechnicPage), dialog(dialog) -{ - ui->setupUi(this); - connect(ui->searchButton, &QPushButton::clicked, this, &TechnicPage::triggerSearch); - ui->searchEdit->installEventFilter(this); - model = new Technic::ListModel(this); - ui->packView->setModel(model); - connect(ui->packView->selectionModel(), &QItemSelectionModel::currentChanged, this, &TechnicPage::onSelectionChanged); -} - -bool TechnicPage::eventFilter(QObject* watched, QEvent* event) -{ - if (watched == ui->searchEdit && event->type() == QEvent::KeyPress) { - QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event); - if (keyEvent->key() == Qt::Key_Return) { - triggerSearch(); - keyEvent->accept(); - return true; - } - } - return QWidget::eventFilter(watched, event); -} - -TechnicPage::~TechnicPage() -{ - delete ui; -} - -bool TechnicPage::shouldDisplay() const -{ - return true; -} - -void TechnicPage::openedImpl() -{ - suggestCurrent(); - triggerSearch(); -} - -void TechnicPage::triggerSearch() { - model->searchWithTerm(ui->searchEdit->text()); -} - -void TechnicPage::onSelectionChanged(QModelIndex first, QModelIndex second) -{ - if(!first.isValid()) - { - if(isOpened) - { - dialog->setSuggestedPack(); - } - //ui->frame->clear(); - return; - } - - current = model->data(first, Qt::UserRole).value<Technic::Modpack>(); - suggestCurrent(); -} - -void TechnicPage::suggestCurrent() -{ - if (!isOpened) - { - return; - } - if (current.broken) - { - dialog->setSuggestedPack(); - return; - } - - QString editedLogoName = "technic_" + current.logoName.section(".", 0, 0); - model->getLogo(current.logoName, current.logoUrl, [this, editedLogoName](QString logo) - { - dialog->setSuggestedIconFromFile(logo, editedLogoName); - }); - - if (current.metadataLoaded) - { - metadataLoaded(); - return; - } - - NetJob *netJob = new NetJob(QString("Technic::PackMeta(%1)").arg(current.name)); - std::shared_ptr<QByteArray> response = std::make_shared<QByteArray>(); - QString slug = current.slug; - netJob->addNetAction(Net::Download::makeByteArray(QString("https://api.technicpack.net/modpack/%1?build=multimc").arg(slug), response.get())); - QObject::connect(netJob, &NetJob::succeeded, this, [this, response, slug] - { - if (current.slug != slug) - { - return; - } - QJsonParseError parse_error; - QJsonDocument doc = QJsonDocument::fromJson(*response, &parse_error); - QJsonObject obj = doc.object(); - 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; - } - if (!obj.contains("url")) - { - qWarning() << "Json doesn't contain an url key"; - return; - } - QJsonValueRef url = obj["url"]; - if (url.isString()) - { - current.url = url.toString(); - } - else - { - if (!obj.contains("solder")) - { - qWarning() << "Json doesn't contain a valid url or solder key"; - return; - } - QJsonValueRef solderUrl = obj["solder"]; - if (solderUrl.isString()) - { - current.url = solderUrl.toString(); - current.isSolder = true; - } - else - { - qWarning() << "Json doesn't contain a valid url or solder key"; - return; - } - } - - current.minecraftVersion = Json::ensureString(obj, "minecraft", QString(), "__placeholder__"); - current.websiteUrl = Json::ensureString(obj, "platformUrl", QString(), "__placeholder__"); - current.author = Json::ensureString(obj, "user", QString(), "__placeholder__"); - current.description = Json::ensureString(obj, "description", QString(), "__placeholder__"); - current.metadataLoaded = true; - metadataLoaded(); - }); - netJob->start(); -} - -// expects current.metadataLoaded to be true -void TechnicPage::metadataLoaded() -{ - QString text = ""; - QString name = current.name; - - if (current.websiteUrl.isEmpty()) - // This allows injecting HTML here. - text = name; - else - // URL not properly escaped for inclusion in HTML. The name allows for injecting HTML. - text = "<a href=\"" + current.websiteUrl + "\">" + name + "</a>"; - if (!current.author.isEmpty()) { - // This allows injecting HTML here - text += tr(" by ") + current.author; - } - - ui->frame->setModText(text); - ui->frame->setModDescription(current.description); - if (!current.isSolder) - { - dialog->setSuggestedPack(current.name, new Technic::SingleZipPackInstallTask(current.url, current.minecraftVersion)); - } - else - { - while (current.url.endsWith('/')) current.url.chop(1); - dialog->setSuggestedPack(current.name, new Technic::SolderPackInstallTask(current.url + "/modpack/" + current.slug, current.minecraftVersion)); - } -} diff --git a/application/pages/modplatform/technic/TechnicPage.h b/application/pages/modplatform/technic/TechnicPage.h deleted file mode 100644 index 27e1258a..00000000 --- a/application/pages/modplatform/technic/TechnicPage.h +++ /dev/null @@ -1,78 +0,0 @@ -/* Copyright 2013-2021 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include <QWidget> - -#include "pages/BasePage.h" -#include <MultiMC.h> -#include "tasks/Task.h" -#include "TechnicData.h" - -namespace Ui -{ -class TechnicPage; -} - -class NewInstanceDialog; - -namespace Technic { - class ListModel; -} - -class TechnicPage : public QWidget, public BasePage -{ - Q_OBJECT - -public: - explicit TechnicPage(NewInstanceDialog* dialog, QWidget *parent = 0); - virtual ~TechnicPage(); - virtual QString displayName() const override - { - return tr("Technic"); - } - virtual QIcon icon() const override - { - return MMC->getThemedIcon("technic"); - } - virtual QString id() const override - { - return "technic"; - } - virtual QString helpPage() const override - { - return "Technic-platform"; - } - virtual bool shouldDisplay() const override; - - void openedImpl() override; - - bool eventFilter(QObject* watched, QEvent* event) override; - -private: - void suggestCurrent(); - void metadataLoaded(); - -private slots: - void triggerSearch(); - void onSelectionChanged(QModelIndex first, QModelIndex second); - -private: - Ui::TechnicPage *ui = nullptr; - NewInstanceDialog* dialog = nullptr; - Technic::ListModel* model = nullptr; - Technic::Modpack current; -}; diff --git a/application/pages/modplatform/technic/TechnicPage.ui b/application/pages/modplatform/technic/TechnicPage.ui deleted file mode 100644 index 2ca45dd2..00000000 --- a/application/pages/modplatform/technic/TechnicPage.ui +++ /dev/null @@ -1,95 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<ui version="4.0"> - <class>TechnicPage</class> - <widget class="QWidget" name="TechnicPage"> - <property name="geometry"> - <rect> - <x>0</x> - <y>0</y> - <width>546</width> - <height>405</height> - </rect> - </property> - <layout class="QVBoxLayout" name="verticalLayout"> - <item> - <widget class="QWidget" name="widget" native="true"> - <layout class="QHBoxLayout" name="horizontalLayout"> - <property name="leftMargin"> - <number>0</number> - </property> - <property name="topMargin"> - <number>0</number> - </property> - <property name="rightMargin"> - <number>0</number> - </property> - <property name="bottomMargin"> - <number>0</number> - </property> - <item> - <widget class="QLineEdit" name="searchEdit"> - <property name="placeholderText"> - <string>Search and filter ...</string> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="searchButton"> - <property name="text"> - <string>Search</string> - </property> - </widget> - </item> - </layout> - </widget> - </item> - <item> - <widget class="QListView" name="packView"> - <property name="horizontalScrollBarPolicy"> - <enum>Qt::ScrollBarAlwaysOff</enum> - </property> - <property name="alternatingRowColors"> - <bool>true</bool> - </property> - <property name="iconSize"> - <size> - <width>48</width> - <height>48</height> - </size> - </property> - </widget> - </item> - <item> - <widget class="MCModInfoFrame" name="frame"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Preferred" vsizetype="Minimum"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <property name="frameShape"> - <enum>QFrame::StyledPanel</enum> - </property> - <property name="frameShadow"> - <enum>QFrame::Raised</enum> - </property> - </widget> - </item> - </layout> - </widget> - <customwidgets> - <customwidget> - <class>MCModInfoFrame</class> - <extends>QFrame</extends> - <header>widgets/MCModInfoFrame.h</header> - <container>1</container> - </customwidget> - </customwidgets> - <tabstops> - <tabstop>searchEdit</tabstop> - <tabstop>searchButton</tabstop> - <tabstop>packView</tabstop> - </tabstops> - <resources/> - <connections/> -</ui> |