summaryrefslogtreecommitdiffstats
path: root/application/pages/modplatform/legacy_ftb
diff options
context:
space:
mode:
authorPetr Mrázek <peterix@gmail.com>2019-11-03 23:48:12 +0100
committerPetr Mrázek <peterix@gmail.com>2019-11-03 23:48:12 +0100
commit47ed2f48d4a118876263f37b9fe2ab8911c2a8fe (patch)
tree3caa2000d3fe9f57a82757dec2ae138e7474c499 /application/pages/modplatform/legacy_ftb
parent0c9340a3d2e32223a9097f95b92b11045aaec845 (diff)
downloadMultiMC-47ed2f48d4a118876263f37b9fe2ab8911c2a8fe.tar
MultiMC-47ed2f48d4a118876263f37b9fe2ab8911c2a8fe.tar.gz
MultiMC-47ed2f48d4a118876263f37b9fe2ab8911c2a8fe.tar.lz
MultiMC-47ed2f48d4a118876263f37b9fe2ab8911c2a8fe.tar.xz
MultiMC-47ed2f48d4a118876263f37b9fe2ab8911c2a8fe.zip
NOISSUE put legacy FTB support in a namespace, fix its base URL
Diffstat (limited to 'application/pages/modplatform/legacy_ftb')
-rw-r--r--application/pages/modplatform/legacy_ftb/ListModel.cpp260
-rw-r--r--application/pages/modplatform/legacy_ftb/ListModel.h78
-rw-r--r--application/pages/modplatform/legacy_ftb/Page.cpp368
-rw-r--r--application/pages/modplatform/legacy_ftb/Page.h119
-rw-r--r--application/pages/modplatform/legacy_ftb/Page.ui126
5 files changed, 951 insertions, 0 deletions
diff --git a/application/pages/modplatform/legacy_ftb/ListModel.cpp b/application/pages/modplatform/legacy_ftb/ListModel.cpp
new file mode 100644
index 00000000..105db25a
--- /dev/null
+++ b/application/pages/modplatform/legacy_ftb/ListModel.cpp
@@ -0,0 +1,260 @@
+#include "ListModel.h"
+#include "MultiMC.h"
+
+#include <MMCStrings.h>
+#include <Version.h>
+
+#include <QtMath>
+#include <QLabel>
+
+#include <RWStorage.h>
+#include <Env.h>
+
+#include "net/URLConstants.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(URLConstants::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
new file mode 100644
index 00000000..c55df000
--- /dev/null
+++ b/application/pages/modplatform/legacy_ftb/ListModel.h
@@ -0,0 +1,78 @@
+#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
new file mode 100644
index 00000000..8e40ba9e
--- /dev/null
+++ b/application/pages/modplatform/legacy_ftb/Page.cpp
@@ -0,0 +1,368 @@
+#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)
+ {
+ if(!selected.broken)
+ {
+ 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);
+ });
+ }
+ }
+ else
+ {
+ dialog->setSuggestedPack();
+ }
+ }
+}
+
+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
new file mode 100644
index 00000000..ed6d1657
--- /dev/null
+++ b/application/pages/modplatform/legacy_ftb/Page.h
@@ -0,0 +1,119 @@
+/* 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 <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
new file mode 100644
index 00000000..36fb2359
--- /dev/null
+++ b/application/pages/modplatform/legacy_ftb/Page.ui
@@ -0,0 +1,126 @@
+<?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>
+ </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>
+ </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>
+ </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>