NOISSUE continue reshuffling the codebase
This commit is contained in:
81
launcher/ui/pages/modplatform/atlauncher/AtlFilterModel.cpp
Normal file
81
launcher/ui/pages/modplatform/atlauncher/AtlFilterModel.cpp
Normal file
@ -0,0 +1,81 @@
|
||||
#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;
|
||||
}
|
||||
|
||||
}
|
34
launcher/ui/pages/modplatform/atlauncher/AtlFilterModel.h
Normal file
34
launcher/ui/pages/modplatform/atlauncher/AtlFilterModel.h
Normal file
@ -0,0 +1,34 @@
|
||||
#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;
|
||||
|
||||
};
|
||||
|
||||
}
|
193
launcher/ui/pages/modplatform/atlauncher/AtlListModel.cpp
Normal file
193
launcher/ui/pages/modplatform/atlauncher/AtlListModel.cpp
Normal file
@ -0,0 +1,193 @@
|
||||
#include "AtlListModel.h"
|
||||
|
||||
#include <BuildConfig.h>
|
||||
#include <Application.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 = APPLICATION->getThemedIcon("atlauncher-placeholder");
|
||||
|
||||
auto url = QString(BuildConfig.ATL_DOWNLOAD_SERVER_URL + "launcher/images/%1.png").arg(pack.safeName.toLower());
|
||||
((ListModel *)this)->requestLogo(pack.safeName, url);
|
||||
|
||||
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(APPLICATION->network());
|
||||
|
||||
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(APPLICATION->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 = APPLICATION->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(APPLICATION->network());
|
||||
|
||||
m_loadingLogos.append(file);
|
||||
}
|
||||
|
||||
}
|
52
launcher/ui/pages/modplatform/atlauncher/AtlListModel.h
Normal file
52
launcher/ui/pages/modplatform/atlauncher/AtlListModel.h
Normal file
@ -0,0 +1,52 @@
|
||||
#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;
|
||||
|
||||
NetJob::Ptr jobPtr;
|
||||
QByteArray response;
|
||||
};
|
||||
|
||||
}
|
@ -0,0 +1,209 @@
|
||||
#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;
|
||||
}
|
@ -0,0 +1,66 @@
|
||||
#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;
|
||||
};
|
@ -0,0 +1,65 @@
|
||||
<?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>ui/widgets/ModListView.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
171
launcher/ui/pages/modplatform/atlauncher/AtlPage.cpp
Normal file
171
launcher/ui/pages/modplatform/atlauncher/AtlPage.cpp
Normal file
@ -0,0 +1,171 @@
|
||||
#include "AtlPage.h"
|
||||
#include "ui_AtlPage.h"
|
||||
|
||||
#include "modplatform/atlauncher/ATLPackInstallTask.h"
|
||||
|
||||
#include "AtlOptionalModDialog.h"
|
||||
#include "ui/dialogs/NewInstanceDialog.h"
|
||||
#include "ui/dialogs/VersionSelectDialog.h"
|
||||
|
||||
#include <BuildConfig.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->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 + " " + selectedVersion, 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::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", APPLICATION->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();
|
||||
}
|
86
launcher/ui/pages/modplatform/atlauncher/AtlPage.h
Normal file
86
launcher/ui/pages/modplatform/atlauncher/AtlPage.h
Normal file
@ -0,0 +1,86 @@
|
||||
/* 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 "Application.h"
|
||||
#include "ui/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 APPLICATION->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 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;
|
||||
};
|
92
launcher/ui/pages/modplatform/atlauncher/AtlPage.ui
Normal file
92
launcher/ui/pages/modplatform/atlauncher/AtlPage.ui
Normal file
@ -0,0 +1,92 @@
|
||||
<?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="alternatingRowColors">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
<width>96</width>
|
||||
<height>48</height>
|
||||
</size>
|
||||
</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="0">
|
||||
<widget class="QLineEdit" name="searchEdit">
|
||||
<property name="placeholderText">
|
||||
<string>Search and filter ...</string>
|
||||
</property>
|
||||
<property name="clearButtonEnabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<tabstops>
|
||||
<tabstop>searchEdit</tabstop>
|
||||
<tabstop>packView</tabstop>
|
||||
<tabstop>packDescription</tabstop>
|
||||
<tabstop>sortByBox</tabstop>
|
||||
<tabstop>versionSelectionBox</tabstop>
|
||||
</tabstops>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
Reference in New Issue
Block a user