diff options
23 files changed, 684 insertions, 284 deletions
diff --git a/application/CMakeLists.txt b/application/CMakeLists.txt index b9a671b3..31b0e62c 100644 --- a/application/CMakeLists.txt +++ b/application/CMakeLists.txt @@ -143,6 +143,8 @@ SET(MULTIMC_SOURCES ColumnResizer.cpp InstanceProxyModel.h InstanceProxyModel.cpp + VersionProxyModel.h + VersionProxyModel.cpp # GUI - windows MainWindow.h diff --git a/application/VersionProxyModel.cpp b/application/VersionProxyModel.cpp new file mode 100644 index 00000000..2bfafd47 --- /dev/null +++ b/application/VersionProxyModel.cpp @@ -0,0 +1,382 @@ +#include "VersionProxyModel.h" +#include "MultiMC.h" +#include <QSortFilterProxyModel> +#include <QPixmapCache> +#include <modutils.h> + +class VersionFilterModel : public QSortFilterProxyModel +{ + Q_OBJECT +public: + VersionFilterModel(VersionProxyModel *parent) : QSortFilterProxyModel(parent) + { + m_parent = parent; + } + + bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const + { + const auto &filters = m_parent->filters(); + for (auto it = filters.begin(); it != filters.end(); ++it) + { + auto role = it.key(); + auto idx = sourceModel()->index(source_row, 0, source_parent); + auto data = sourceModel()->data(idx, role); + + switch(role) + { + case BaseVersionList::ParentGameVersionRole: + case BaseVersionList::VersionIdRole: + { + auto versionString = data.toString(); + if(it.value().exact) + { + if (versionString != it.value().string) + { + return false; + } + } + else if (!Util::versionIsInInterval(versionString, it.value().string)) + { + return false; + } + } + default: + { + auto match = data.toString(); + if(it.value().exact) + { + if (match != it.value().string) + { + return false; + } + } + else if (match.contains(it.value().string)) + { + return false; + } + } + } + } + return true; + } +private: + VersionProxyModel *m_parent; +}; + +VersionProxyModel::VersionProxyModel(QObject *parent) : QAbstractProxyModel(parent) +{ + filterModel = new VersionFilterModel(this); + connect(filterModel, &QAbstractItemModel::dataChanged, this, &VersionProxyModel::sourceDataChanged); + // FIXME: implement when needed + /* + connect(replacing, &QAbstractItemModel::rowsAboutToBeInserted, this, &VersionProxyModel::sourceRowsAboutToBeInserted); + connect(replacing, &QAbstractItemModel::rowsInserted, this, &VersionProxyModel::sourceRowsInserted); + connect(replacing, &QAbstractItemModel::rowsAboutToBeRemoved, this, &VersionProxyModel::sourceRowsAboutToBeRemoved); + connect(replacing, &QAbstractItemModel::rowsRemoved, this, &VersionProxyModel::sourceRowsRemoved); + connect(replacing, &QAbstractItemModel::rowsAboutToBeMoved, this, &VersionProxyModel::sourceRowsAboutToBeMoved); + connect(replacing, &QAbstractItemModel::rowsMoved, this, &VersionProxyModel::sourceRowsMoved); + connect(replacing, &QAbstractItemModel::layoutAboutToBeChanged, this, &VersionProxyModel::sourceLayoutAboutToBeChanged); + connect(replacing, &QAbstractItemModel::layoutChanged, this, &VersionProxyModel::sourceLayoutChanged); + */ + connect(filterModel, &QAbstractItemModel::modelAboutToBeReset, this, &VersionProxyModel::sourceAboutToBeReset); + connect(filterModel, &QAbstractItemModel::modelReset, this, &VersionProxyModel::sourceReset); + + QAbstractProxyModel::setSourceModel(filterModel); +} + +QVariant VersionProxyModel::headerData(int section, Qt::Orientation orientation, int role) const +{ + if(section < 0 || section >= m_columns.size()) + return QVariant(); + if(orientation != Qt::Horizontal) + return QVariant(); + auto column = m_columns[section]; + if(role == Qt::DisplayRole) + { + switch(column) + { + case Name: + return tr("Version"); + case ParentVersion: + return tr("Minecraft"); //FIXME: this should come from metadata + case Branch: + return tr("Branch"); + case Type: + return tr("Type"); + case Architecture: + return tr("Architecture"); + case Path: + return tr("Path"); + } + } + else if(role == Qt::ToolTipRole) + { + switch(column) + { + case Name: + return tr("The name of the version."); + case ParentVersion: + return tr("Minecraft version"); //FIXME: this should come from metadata + case Branch: + return tr("The version's branch"); + case Type: + return tr("The version's type"); + case Architecture: + return tr("CPU Architecture"); + case Path: + return tr("Filesystem path to this version"); + } + } + return QVariant(); +} + +QVariant VersionProxyModel::data(const QModelIndex &index, int role) const +{ + if(!index.isValid()) + { + return QVariant(); + } + auto column = m_columns[index.column()]; + auto parentIndex = mapToSource(index); + switch(role) + { + case Qt::DisplayRole: + { + switch(column) + { + case Name: + return sourceModel()->data(parentIndex, BaseVersionList::VersionRole); + case ParentVersion: + return sourceModel()->data(parentIndex, BaseVersionList::ParentGameVersionRole); + case Branch: + return sourceModel()->data(parentIndex, BaseVersionList::BranchRole); + case Type: + return sourceModel()->data(parentIndex, BaseVersionList::TypeRole); + case Architecture: + return sourceModel()->data(parentIndex, BaseVersionList::ArchitectureRole); + case Path: + return sourceModel()->data(parentIndex, BaseVersionList::PathRole); + default: + return QVariant(); + } + } + case Qt::ToolTipRole: + { + switch(column) + { + case Name: + { + auto value = sourceModel()->data(parentIndex, BaseVersionList::RecommendedRole); + if(value.toBool()) + { + return tr("Recommended"); + } + else if(index.row() == 0) + { + return tr("Latest"); + } + } + default: + { + return sourceModel()->data(parentIndex, BaseVersionList::VersionIdRole); + } + } + } + case Qt::DecorationRole: + { + switch(column) + { + case Name: + { + auto value = sourceModel()->data(parentIndex, BaseVersionList::RecommendedRole); + if(value.toBool()) + { + return MMC->getThemedIcon("star"); + } + else if(index.row() == 0) + { + return MMC->getThemedIcon("bug"); + } + auto pixmap = QPixmapCache::find("placeholder"); + if(!pixmap) + { + QPixmap px(16,16); + px.fill(Qt::transparent); + QPixmapCache::insert("placeholder", px); + return px; + } + return *pixmap; + } + default: + { + return QVariant(); + } + } + } + default: + { + if(roles.contains((BaseVersionList::ModelRoles)role)) + { + return sourceModel()->data(parentIndex, role); + } + return QVariant(); + } + } +}; + +QModelIndex VersionProxyModel::parent(const QModelIndex &child) const +{ + return QModelIndex(); +} + +QModelIndex VersionProxyModel::mapFromSource(const QModelIndex &sourceIndex) const +{ + if(sourceIndex.isValid()) + { + return index(sourceIndex.row(), 0); + } + return QModelIndex(); +} + +QModelIndex VersionProxyModel::mapToSource(const QModelIndex &proxyIndex) const +{ + if(proxyIndex.isValid()) + { + return sourceModel()->index(proxyIndex.row(), 0); + } + return QModelIndex(); +} + +QModelIndex VersionProxyModel::index(int row, int column, const QModelIndex &parent) const +{ + // no trees here... shoo + if(parent.isValid()) + { + return QModelIndex(); + } + if(row < 0 || row >= sourceModel()->rowCount()) + return QModelIndex(); + if(column < 0 || column >= columnCount()) + return QModelIndex(); + return QAbstractItemModel::createIndex(row, column); +} + +int VersionProxyModel::columnCount(const QModelIndex &parent) const +{ + return m_columns.size(); +} + +int VersionProxyModel::rowCount(const QModelIndex &parent) const +{ + if(sourceModel()) + { + return sourceModel()->rowCount(); + } + return 0; +} + +void VersionProxyModel::sourceDataChanged(const QModelIndex &source_top_left, + const QModelIndex &source_bottom_right) +{ + if(source_top_left.parent() != source_bottom_right.parent()) + return; + + // whole row is getting changed + auto topLeft = createIndex(source_top_left.row(), 0); + auto bottomRight = createIndex(source_bottom_right.row(), columnCount() - 1); + emit dataChanged(topLeft, bottomRight); +} + +void VersionProxyModel::setSourceModel(BaseVersionList *replacing) +{ + beginResetModel(); + + if(!replacing) + { + m_columns.clear(); + roles.clear(); + filterModel->setSourceModel(replacing); + return; + } + + roles = replacing->providesRoles(); + if(roles.contains(BaseVersionList::VersionRole)) + { + m_columns.push_back(Name); + } + /* + if(roles.contains(BaseVersionList::ParentGameVersionRole)) + { + m_columns.push_back(ParentVersion); + } + */ + if(roles.contains(BaseVersionList::ArchitectureRole)) + { + m_columns.push_back(Architecture); + } + if(roles.contains(BaseVersionList::PathRole)) + { + m_columns.push_back(Path); + } + if(roles.contains(BaseVersionList::BranchRole)) + { + m_columns.push_back(Branch); + } + if(roles.contains(BaseVersionList::TypeRole)) + { + m_columns.push_back(Type); + } + filterModel->setSourceModel(replacing); + + endResetModel(); +} + +QModelIndex VersionProxyModel::getRecommended() const +{ + if(!roles.contains(BaseVersionList::RecommendedRole)) + { + return index(0, 0); + } + int recommended = 0; + for (int i = 0; i < rowCount(); i++) + { + auto value = sourceModel()->data(mapToSource(index(i, 0)), BaseVersionList::RecommendedRole); + if (value.toBool()) + { + recommended = i; + } + } + return index(recommended, 0); +} + +void VersionProxyModel::clearFilters() +{ + m_filters.clear(); + filterModel->invalidate(); +} + +void VersionProxyModel::setFilter(const BaseVersionList::ModelRoles column, const QString &filter, const bool exact) +{ + Filter f; + f.string = filter; + f.exact = exact; + m_filters[column] = f; + filterModel->invalidate(); +} + +const VersionProxyModel::FilterMap &VersionProxyModel::filters() const +{ + return m_filters; +} + +void VersionProxyModel::sourceAboutToBeReset() +{ + beginResetModel(); +} + +void VersionProxyModel::sourceReset() +{ + endResetModel(); +} + +#include "VersionProxyModel.moc" diff --git a/application/VersionProxyModel.h b/application/VersionProxyModel.h new file mode 100644 index 00000000..456268f0 --- /dev/null +++ b/application/VersionProxyModel.h @@ -0,0 +1,56 @@ +#pragma once +#include <QAbstractProxyModel> +#include "BaseVersionList.h" + +class VersionFilterModel; + +class VersionProxyModel: public QAbstractProxyModel +{ + Q_OBJECT +public: + struct Filter + { + QString string; + bool exact = false; + }; + enum Column + { + Name, + ParentVersion, + Branch, + Type, + Architecture, + Path + }; + typedef QHash<BaseVersionList::ModelRoles, Filter> FilterMap; + +public: + VersionProxyModel ( QObject* parent = 0 ); + virtual ~VersionProxyModel() {}; + + virtual int columnCount(const QModelIndex &parent = QModelIndex()) const override; + virtual int rowCount(const QModelIndex &parent = QModelIndex()) const override; + virtual QModelIndex mapFromSource(const QModelIndex &sourceIndex) const override; + virtual QModelIndex mapToSource(const QModelIndex &proxyIndex) const override; + virtual QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override; + virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; + virtual QModelIndex parent(const QModelIndex &child) const override; + void setSourceModel(BaseVersionList *sourceModel); + + const FilterMap &filters() const; + void setFilter(const BaseVersionList::ModelRoles column, const QString &filter, const bool exact); + void clearFilters(); + QModelIndex getRecommended() const; +private slots: + + void sourceDataChanged(const QModelIndex &source_top_left,const QModelIndex &source_bottom_right); + void sourceAboutToBeReset(); + void sourceReset(); + +private: + QList<Column> m_columns; + FilterMap m_filters; + BaseVersionList::RoleList roles; + VersionFilterModel * filterModel; +}; diff --git a/application/dialogs/VersionSelectDialog.cpp b/application/dialogs/VersionSelectDialog.cpp index d1be4ad0..354857e7 100644 --- a/application/dialogs/VersionSelectDialog.cpp +++ b/application/dialogs/VersionSelectDialog.cpp @@ -26,66 +26,8 @@ #include <tasks/Task.h> #include <modutils.h> #include <QDebug> - -class VersionSelectProxyModel : public QSortFilterProxyModel -{ - Q_OBJECT -public: - VersionSelectProxyModel(QObject *parent = 0) : QSortFilterProxyModel(parent) - { - } - - struct Filter - { - QString string; - bool exact = false; - }; - - QHash<int, Filter> filters() const - { - return m_filters; - } - void setFilter(const int column, const QString &filter, const bool exact) - { - Filter f; - f.string = filter; - f.exact = exact; - m_filters[column] = f; - invalidateFilter(); - } - void clearFilters() - { - m_filters.clear(); - invalidateFilter(); - } - -protected: - bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const - { - for (auto it = m_filters.begin(); it != m_filters.end(); ++it) - { - const QString version = - sourceModel()->index(source_row, it.key()).data().toString(); - - if (it.value().exact) - { - if (version != it.value().string) - { - return false; - } - continue; - } - - if (!Util::versionIsInInterval(version, it.value().string)) - { - return false; - } - } - return true; - } - - QHash<int, Filter> m_filters; -}; +#include "MultiMC.h" +#include <VersionProxyModel.h> VersionSelectDialog::VersionSelectDialog(BaseVersionList *vlist, QString title, QWidget *parent, bool cancelable) @@ -98,7 +40,7 @@ VersionSelectDialog::VersionSelectDialog(BaseVersionList *vlist, QString title, m_vlist = vlist; - m_proxyModel = new VersionSelectProxyModel(this); + m_proxyModel = new VersionProxyModel(this); m_proxyModel->setSourceModel(vlist); ui->listView->setModel(m_proxyModel); @@ -135,7 +77,12 @@ int VersionSelectDialog::exec() { loadList(); } - m_proxyModel->invalidate(); + auto idx = m_proxyModel->getRecommended(); + if(idx.isValid()) + { + ui->listView->selectionModel()->setCurrentIndex(idx,QItemSelectionModel::SelectCurrent | QItemSelectionModel::Rows); + ui->listView->scrollTo(idx, QAbstractItemView::PositionAtCenter); + } return QDialog::exec(); } @@ -164,14 +111,14 @@ void VersionSelectDialog::on_refreshButton_clicked() loadList(); } -void VersionSelectDialog::setExactFilter(int column, QString filter) +void VersionSelectDialog::setExactFilter(BaseVersionList::ModelRoles role, QString filter) { - m_proxyModel->setFilter(column, filter, true); + m_proxyModel->setFilter(role, filter, true); } -void VersionSelectDialog::setFuzzyFilter(int column, QString filter) +void VersionSelectDialog::setFuzzyFilter(BaseVersionList::ModelRoles role, QString filter) { - m_proxyModel->setFilter(column, filter, false); + m_proxyModel->setFilter(role, filter, false); } #include "VersionSelectDialog.moc" diff --git a/application/dialogs/VersionSelectDialog.h b/application/dialogs/VersionSelectDialog.h index 69e52fe6..23bd158a 100644 --- a/application/dialogs/VersionSelectDialog.h +++ b/application/dialogs/VersionSelectDialog.h @@ -18,16 +18,14 @@ #include <QDialog> #include <QSortFilterProxyModel> -#include "BaseVersion.h" - -class BaseVersionList; +#include "BaseVersionList.h" namespace Ui { class VersionSelectDialog; } -class VersionSelectProxyModel; +class VersionProxyModel; class VersionSelectDialog : public QDialog { @@ -45,8 +43,8 @@ public: BaseVersionPtr selectedVersion() const; - void setFuzzyFilter(int column, QString filter); - void setExactFilter(int column, QString filter); + void setFuzzyFilter(BaseVersionList::ModelRoles role, QString filter); + void setExactFilter(BaseVersionList::ModelRoles role, QString filter); void setEmptyString(QString emptyString); void setResizeOn(int column); void setUseLatest(const bool useLatest); @@ -60,7 +58,7 @@ private: BaseVersionList *m_vlist; - VersionSelectProxyModel *m_proxyModel; + VersionProxyModel *m_proxyModel; int resizeOnColumn = 0; }; diff --git a/application/pages/VersionPage.cpp b/application/pages/VersionPage.cpp index 6b220017..056bb958 100644 --- a/application/pages/VersionPage.cpp +++ b/application/pages/VersionPage.cpp @@ -269,7 +269,7 @@ void VersionPage::on_changeMCVersionBtn_clicked() void VersionPage::on_forgeBtn_clicked() { VersionSelectDialog vselect(MMC->forgelist().get(), tr("Select Forge version"), this); - vselect.setExactFilter(1, m_inst->currentVersionId()); + vselect.setExactFilter(BaseVersionList::ParentGameVersionRole, m_inst->currentVersionId()); vselect.setEmptyString(tr("No Forge versions are currently available for Minecraft ") + m_inst->currentVersionId()); if (vselect.exec() && vselect.selectedVersion()) @@ -284,7 +284,7 @@ void VersionPage::on_liteloaderBtn_clicked() { VersionSelectDialog vselect(MMC->liteloaderlist().get(), tr("Select LiteLoader version"), this); - vselect.setExactFilter(1, m_inst->currentVersionId()); + vselect.setExactFilter(BaseVersionList::ParentGameVersionRole, m_inst->currentVersionId()); vselect.setEmptyString(tr("No LiteLoader versions are currently available for Minecraft ") + m_inst->currentVersionId()); if (vselect.exec() && vselect.selectedVersion()) diff --git a/application/pages/global/JavaPage.cpp b/application/pages/global/JavaPage.cpp index ab02b3a3..1b480376 100644 --- a/application/pages/global/JavaPage.cpp +++ b/application/pages/global/JavaPage.cpp @@ -97,7 +97,6 @@ void JavaPage::on_javaDetectBtn_clicked() JavaVersionPtr java; VersionSelectDialog vselect(MMC->javalist().get(), tr("Select a Java version"), this, true); - vselect.setResizeOn(2); vselect.exec(); if (vselect.result() == QDialog::Accepted && vselect.selectedVersion()) diff --git a/application/resources/multimc/16x16/star.png b/application/resources/multimc/16x16/star.png Binary files differnew file mode 100644 index 00000000..4963e6ec --- /dev/null +++ b/application/resources/multimc/16x16/star.png diff --git a/application/resources/multimc/24x24/star.png b/application/resources/multimc/24x24/star.png Binary files differnew file mode 100644 index 00000000..7f16618a --- /dev/null +++ b/application/resources/multimc/24x24/star.png diff --git a/application/resources/multimc/32x32/star.png b/application/resources/multimc/32x32/star.png Binary files differnew file mode 100644 index 00000000..b271f0d1 --- /dev/null +++ b/application/resources/multimc/32x32/star.png diff --git a/application/resources/multimc/48x48/star.png b/application/resources/multimc/48x48/star.png Binary files differnew file mode 100644 index 00000000..d9468e7e --- /dev/null +++ b/application/resources/multimc/48x48/star.png diff --git a/application/resources/multimc/64x64/star.png b/application/resources/multimc/64x64/star.png Binary files differnew file mode 100644 index 00000000..4ed5d978 --- /dev/null +++ b/application/resources/multimc/64x64/star.png diff --git a/application/resources/multimc/multimc.qrc b/application/resources/multimc/multimc.qrc index d02d0e0e..4ced586a 100644 --- a/application/resources/multimc/multimc.qrc +++ b/application/resources/multimc/multimc.qrc @@ -17,6 +17,13 @@ <!-- Java icon. From Oracle, fixed because it was derpy. --> <file>scalable/java.svg</file> + <!-- Star, CC-BY-SA 3.0, Oxygen icons.--> + <file>16x16/star.png</file> + <file>24x24/star.png</file> + <file>32x32/star.png</file> + <file>48x48/star.png</file> + <file>64x64/star.png</file> + <!-- Minecraft icon. Source: http://www.minecraftforum.net/forums/show-your-creation/fan-art/1574882-icon-better-minecraft-icon --> <file>16x16/minecraft.png</file> <file>24x24/minecraft.png</file> diff --git a/logic/BaseVersionList.cpp b/logic/BaseVersionList.cpp index 7752b14c..fe17a905 100644 --- a/logic/BaseVersionList.cpp +++ b/logic/BaseVersionList.cpp @@ -50,63 +50,26 @@ QVariant BaseVersionList::data(const QModelIndex &index, int role) const switch (role) { - case Qt::DisplayRole: - switch (index.column()) - { - case NameColumn: - return version->name(); - - case TypeColumn: - return version->typeString(); + case VersionPointerRole: + return qVariantFromValue(version); - default: - return QVariant(); - } + case VersionRole: + return version->name(); - case Qt::ToolTipRole: + case VersionIdRole: return version->descriptor(); - case VersionPointerRole: - return qVariantFromValue(version); + case TypeRole: + return version->typeString(); default: return QVariant(); } } -QVariant BaseVersionList::headerData(int section, Qt::Orientation orientation, int role) const +BaseVersionList::RoleList BaseVersionList::providesRoles() { - switch (role) - { - case Qt::DisplayRole: - switch (section) - { - case NameColumn: - return tr("Name"); - - case TypeColumn: - return tr("Type"); - - default: - return QVariant(); - } - - case Qt::ToolTipRole: - switch (section) - { - case NameColumn: - return tr("The name of the version."); - - case TypeColumn: - return tr("The version's type."); - - default: - return QVariant(); - } - - default: - return QVariant(); - } + return {VersionPointerRole, VersionRole, VersionIdRole, TypeRole}; } int BaseVersionList::rowCount(const QModelIndex &parent) const @@ -117,5 +80,5 @@ int BaseVersionList::rowCount(const QModelIndex &parent) const int BaseVersionList::columnCount(const QModelIndex &parent) const { - return 2; + return 1; } diff --git a/logic/BaseVersionList.h b/logic/BaseVersionList.h index 584d6ca7..6089c31c 100644 --- a/logic/BaseVersionList.h +++ b/logic/BaseVersionList.h @@ -41,20 +41,17 @@ class BaseVersionList : public QAbstractListModel public: enum ModelRoles { - VersionPointerRole = 0x34B1CB48 - }; - - enum VListColumns - { - // First column - Name - NameColumn = 0, - - // Second column - Type - TypeColumn, - - // Third column - Timestamp - TimeColumn + VersionPointerRole = Qt::UserRole, + VersionRole, + VersionIdRole, + ParentGameVersionRole, + RecommendedRole, + TypeRole, + BranchRole, + PathRole, + ArchitectureRole }; + typedef QList<ModelRoles> RoleList; explicit BaseVersionList(QObject *parent = 0); @@ -78,10 +75,12 @@ public: //////// List Model Functions //////// virtual QVariant data(const QModelIndex &index, int role) const; - virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const; virtual int rowCount(const QModelIndex &parent) const; virtual int columnCount(const QModelIndex &parent) const; + //! which roles are provided by this version list? + virtual RoleList providesRoles(); + /*! * \brief Finds a version by its descriptor. * \param The descriptor of the version to find. diff --git a/logic/forge/ForgeVersionList.cpp b/logic/forge/ForgeVersionList.cpp index 56ffad11..b2320a6d 100644 --- a/logic/forge/ForgeVersionList.cpp +++ b/logic/forge/ForgeVersionList.cpp @@ -51,7 +51,7 @@ int ForgeVersionList::count() const int ForgeVersionList::columnCount(const QModelIndex &parent) const { - return 3; + return 1; } QVariant ForgeVersionList::data(const QModelIndex &index, int role) const @@ -65,73 +65,34 @@ QVariant ForgeVersionList::data(const QModelIndex &index, int role) const auto version = std::dynamic_pointer_cast<ForgeVersion>(m_vlist[index.row()]); switch (role) { - case Qt::DisplayRole: - switch (index.column()) - { - case 0: - return version->name(); - - case 1: - return version->mcver_sane; - - case 2: - return version->typeString(); - default: - return QVariant(); - } - - case Qt::ToolTipRole: - return version->descriptor(); - case VersionPointerRole: return qVariantFromValue(m_vlist[index.row()]); - default: - return QVariant(); - } -} - -QVariant ForgeVersionList::headerData(int section, Qt::Orientation orientation, int role) const -{ - switch (role) - { - case Qt::DisplayRole: - switch (section) - { - case 0: - return tr("Version"); - - case 1: - return tr("Minecraft"); - - case 2: - return tr("Type"); + case VersionRole: + return version->name(); - default: - return QVariant(); - } - - case Qt::ToolTipRole: - switch (section) - { - case 0: - return tr("The name of the version."); + case VersionIdRole: + return version->descriptor(); - case 1: - return tr("Minecraft version"); + case ParentGameVersionRole: + return version->mcver_sane; - case 2: - return tr("The version's type."); + case RecommendedRole: + return version->is_recommended; - default: - return QVariant(); - } + case BranchRole: + return version->branch; default: return QVariant(); } } +QList<BaseVersionList::ModelRoles> ForgeVersionList::providesRoles() +{ + return {VersionPointerRole, VersionRole, VersionIdRole, ParentGameVersionRole, RecommendedRole, BranchRole}; +} + BaseVersionPtr ForgeVersionList::getLatestStable() const { return BaseVersionPtr(); @@ -296,6 +257,7 @@ bool ForgeListLoadTask::parseForgeList(QList<BaseVersionPtr> &out) bool ForgeListLoadTask::parseForgeGradleList(QList<BaseVersionPtr> &out) { + QMap<int, std::shared_ptr<ForgeVersion>> lookup; QByteArray data; { auto dlJob = gradleListDownload; @@ -402,6 +364,29 @@ bool ForgeListLoadTask::parseForgeGradleList(QList<BaseVersionPtr> &out) fVersion->installer_filename = installer_filename; fVersion->type = ForgeVersion::Gradle; out.append(fVersion); + lookup[fVersion->m_buildnr] = fVersion; + } + QJsonObject promos = root.value("promos").toObject(); + for (auto it = promos.begin(); it != promos.end(); ++it) + { + QString key = it.key(); + int build = it.value().toInt(); + QRegularExpression regexp("^(?<mcversion>[0-9]+(.[0-9]+)*)-(?<label>[a-z]+)$"); + auto match = regexp.match(key); + if(!match.hasMatch()) + { + qDebug() << key << "doesn't match." << "build" << build; + continue; + } + + QString label = match.captured("label"); + if(label != "recommended") + { + continue; + } + QString mcversion = match.captured("mcversion"); + qDebug() << "Forge build" << build << "is the" << label << "for Minecraft" << mcversion << QString("<%1>").arg(key); + lookup[build]->is_recommended = true; } return true; } diff --git a/logic/forge/ForgeVersionList.h b/logic/forge/ForgeVersionList.h index 75e1dd78..baae570d 100644 --- a/logic/forge/ForgeVersionList.h +++ b/logic/forge/ForgeVersionList.h @@ -44,7 +44,8 @@ public: ForgeVersionPtr findVersionByVersionNr(QString version); virtual QVariant data(const QModelIndex &index, int role) const; - virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const; + virtual QList<ModelRoles> providesRoles() override; + virtual int columnCount(const QModelIndex &parent) const; protected: diff --git a/logic/java/JavaVersionList.cpp b/logic/java/JavaVersionList.cpp index 72fa6dc8..d607ae72 100644 --- a/logic/java/JavaVersionList.cpp +++ b/logic/java/JavaVersionList.cpp @@ -22,6 +22,7 @@ #include "java/JavaVersionList.h" #include "java/JavaCheckerJob.h" #include "java/JavaUtils.h" +#include "MMCStrings.h" JavaVersionList::JavaVersionList(QObject *parent) : BaseVersionList(parent) { @@ -47,11 +48,6 @@ int JavaVersionList::count() const return m_vlist.count(); } -int JavaVersionList::columnCount(const QModelIndex &parent) const -{ - return 3; -} - QVariant JavaVersionList::data(const QModelIndex &index, int role) const { if (!index.isValid()) @@ -63,100 +59,87 @@ QVariant JavaVersionList::data(const QModelIndex &index, int role) const auto version = std::dynamic_pointer_cast<JavaVersion>(m_vlist[index.row()]); switch (role) { - case Qt::DisplayRole: - switch (index.column()) - { - case 0: + case VersionPointerRole: + return qVariantFromValue(m_vlist[index.row()]); + case VersionIdRole: + return version->descriptor(); + case VersionRole: return version->id; - - case 1: - return version->arch; - - case 2: + case RecommendedRole: + return version->recommended; + case PathRole: return version->path; - + case ArchitectureRole: + return version->arch; default: return QVariant(); - } - - case Qt::ToolTipRole: - return version->descriptor(); - - case VersionPointerRole: - return qVariantFromValue(m_vlist[index.row()]); - - default: - return QVariant(); } } -QVariant JavaVersionList::headerData(int section, Qt::Orientation orientation, int role) const +BaseVersionList::RoleList JavaVersionList::providesRoles() { - switch (role) - { - case Qt::DisplayRole: - switch (section) - { - case 0: - return tr("Version"); - - case 1: - return tr("Arch"); - - case 2: - return tr("Path"); - - default: - return QVariant(); - } - - case Qt::ToolTipRole: - switch (section) - { - case 0: - return tr("The name of the version."); - - case 1: - return tr("The architecture this version is for."); - - case 2: - return tr("Path to this Java version."); - - default: - return QVariant(); - } - - default: - return QVariant(); - } + return {VersionPointerRole, VersionIdRole, VersionRole, RecommendedRole, PathRole, ArchitectureRole}; } -BaseVersionPtr JavaVersionList::getTopRecommended() const -{ - auto first = m_vlist.first(); - if(first != nullptr) - { - return first; - } - else - { - return BaseVersionPtr(); - } -} void JavaVersionList::updateListData(QList<BaseVersionPtr> versions) { beginResetModel(); m_vlist = versions; m_loaded = true; + // manual testing fakery + /* + m_vlist.push_back(std::make_shared<JavaVersion>("1.6.0_33", "64", "/foo/bar/baz")); + m_vlist.push_back(std::make_shared<JavaVersion>("1.6.0_44", "64", "/foo/bar/baz")); + m_vlist.push_back(std::make_shared<JavaVersion>("1.6.0_55", "64", "/foo/bar/baz")); + m_vlist.push_back(std::make_shared<JavaVersion>("1.7.0_44", "64", "/foo/bar/baz")); + m_vlist.push_back(std::make_shared<JavaVersion>("1.8.0_44", "64", "/foo/bar/baz")); + m_vlist.push_back(std::make_shared<JavaVersion>("1.6.0_33", "32", "/foo/bar/baz")); + m_vlist.push_back(std::make_shared<JavaVersion>("1.6.0_44", "32", "/foo/bar/baz")); + m_vlist.push_back(std::make_shared<JavaVersion>("1.6.0_55", "32", "/foo/bar/baz")); + m_vlist.push_back(std::make_shared<JavaVersion>("1.7.0_44", "32", "/foo/bar/baz")); + m_vlist.push_back(std::make_shared<JavaVersion>("1.8.0_44", "32", "/foo/bar/baz")); + m_vlist.push_back(std::make_shared<JavaVersion>("1.9.0_1231", "32", "/foo/bar/baz")); + m_vlist.push_back(std::make_shared<JavaVersion>("1.9.0_1", "32", "/foo/bar/baz")); + m_vlist.push_back(std::make_shared<JavaVersion>("1.9.0_1", "64", "/foo/bar/baz")); + */ + sort(); + if(m_vlist.size()) + { + auto best = std::dynamic_pointer_cast<JavaVersion>(m_vlist[0]); + best->recommended = true; + } endResetModel(); - // NOW SORT!! - // sort(); +} + +bool sortJavas(BaseVersionPtr left, BaseVersionPtr right) +{ + auto rleft = std::dynamic_pointer_cast<JavaVersion>(left); + auto rright = std::dynamic_pointer_cast<JavaVersion>(right); + // prefer higher arch + auto archCompare = Strings::naturalCompare(rleft->arch, rright->arch, Qt::CaseInsensitive); + if(archCompare != 0) + return archCompare > 0; + // dirty hack - 1.9 and above is too new + auto labove19 = Strings::naturalCompare(rleft->name(), "1.9.0", Qt::CaseInsensitive) >= 0; + auto rabove19 = Strings::naturalCompare(rright->name(), "1.9.0", Qt::CaseInsensitive) >= 0; + if(labove19 == rabove19) + { + // prefer higher versions in general + auto nameCompare = Strings::naturalCompare(rleft->name(), rright->name(), Qt::CaseInsensitive); + if(nameCompare != 0) + return nameCompare > 0; + // if all else is equal, sort by path + return Strings::naturalCompare(rleft->path, rright->path, Qt::CaseInsensitive) < 0; + } + return labove19 < rabove19; } void JavaVersionList::sort() { - // NO-OP for now + beginResetModel(); + std::sort(m_vlist.begin(), m_vlist.end(), sortJavas); + endResetModel(); } JavaListLoadTask::JavaListLoadTask(JavaVersionList *vlist) : Task() diff --git a/logic/java/JavaVersionList.h b/logic/java/JavaVersionList.h index 0117ea76..f0176673 100644 --- a/logic/java/JavaVersionList.h +++ b/logic/java/JavaVersionList.h @@ -26,6 +26,11 @@ class JavaListLoadTask; struct JavaVersion : public BaseVersion { + JavaVersion(){} + JavaVersion(QString id, QString arch, QString path) + : id(id), arch(arch), path(path) + { + } virtual QString descriptor() { return id; @@ -44,6 +49,7 @@ struct JavaVersion : public BaseVersion QString id; QString arch; QString path; + bool recommended = false; }; typedef std::shared_ptr<JavaVersion> JavaVersionPtr; @@ -54,20 +60,16 @@ class JavaVersionList : public BaseVersionList public: explicit JavaVersionList(QObject *parent = 0); - virtual Task *getLoadTask(); - virtual bool isLoaded(); - virtual const BaseVersionPtr at(int i) const; - virtual int count() const; - virtual void sort(); + virtual Task *getLoadTask() override; + virtual bool isLoaded() override; + virtual const BaseVersionPtr at(int i) const override; + virtual int count() const override; + virtual void sort() override; - virtual BaseVersionPtr getTopRecommended() const; + virtual QVariant data(const QModelIndex &index, int role) const override; + virtual RoleList providesRoles() override; - virtual QVariant data(const QModelIndex &index, int role) const; - virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const; - virtual int columnCount(const QModelIndex &parent) const; - -public -slots: +public slots: virtual void updateListData(QList<BaseVersionPtr> versions); protected: diff --git a/logic/liteloader/LiteLoaderVersionList.cpp b/logic/liteloader/LiteLoaderVersionList.cpp index 2e54afdf..8b3c13e0 100644 --- a/logic/liteloader/LiteLoaderVersionList.cpp +++ b/logic/liteloader/LiteLoaderVersionList.cpp @@ -68,6 +68,42 @@ void LiteLoaderVersionList::sort() endResetModel(); } +QVariant LiteLoaderVersionList::data(const QModelIndex &index, int role) const +{ + if (!index.isValid()) + return QVariant(); + + if (index.row() > count()) + return QVariant(); + + auto version = std::dynamic_pointer_cast<LiteLoaderVersion>(m_vlist[index.row()]); + switch (role) + { + case VersionPointerRole: + return qVariantFromValue(m_vlist[index.row()]); + + case VersionRole: + return version->name(); + + case VersionIdRole: + return version->descriptor(); + + case ParentGameVersionRole: + return version->mcVersion; + + case RecommendedRole: + return version->isLatest; + + default: + return QVariant(); + } +} + +QList<BaseVersionList::ModelRoles> LiteLoaderVersionList::providesRoles() +{ + return {VersionPointerRole, VersionRole, VersionIdRole, ParentGameVersionRole, RecommendedRole}; +} + BaseVersionPtr LiteLoaderVersionList::getLatestStable() const { for (int i = 0; i < m_vlist.length(); i++) diff --git a/logic/liteloader/LiteLoaderVersionList.h b/logic/liteloader/LiteLoaderVersionList.h index fd20fcfa..f3f78349 100644 --- a/logic/liteloader/LiteLoaderVersionList.h +++ b/logic/liteloader/LiteLoaderVersionList.h @@ -78,6 +78,8 @@ public: virtual const BaseVersionPtr at(int i) const; virtual int count() const; virtual void sort(); + virtual QVariant data ( const QModelIndex & index, int role = Qt::DisplayRole ) const; + virtual QList< ModelRoles > providesRoles(); virtual BaseVersionPtr getLatestStable() const; diff --git a/logic/minecraft/MinecraftVersionList.cpp b/logic/minecraft/MinecraftVersionList.cpp index 7b3325e0..f57478e3 100644 --- a/logic/minecraft/MinecraftVersionList.cpp +++ b/logic/minecraft/MinecraftVersionList.cpp @@ -343,6 +343,42 @@ void MinecraftVersionList::sort() endResetModel(); } +QVariant MinecraftVersionList::data(const QModelIndex& index, int role) const +{ + if (!index.isValid()) + return QVariant(); + + if (index.row() > count()) + return QVariant(); + + auto version = std::dynamic_pointer_cast<MinecraftVersion>(m_vlist[index.row()]); + switch (role) + { + case VersionPointerRole: + return qVariantFromValue(m_vlist[index.row()]); + + case VersionRole: + return version->name(); + + case VersionIdRole: + return version->descriptor(); + + case RecommendedRole: + return version->descriptor() == "1.7.10"; + + case TypeRole: + return version->typeString(); + + default: + return QVariant(); + } +} + +BaseVersionList::RoleList MinecraftVersionList::providesRoles() +{ + return {VersionPointerRole, VersionRole, VersionIdRole, RecommendedRole, TypeRole}; +} + BaseVersionPtr MinecraftVersionList::getLatestStable() const { if(m_lookup.contains(m_latestReleaseID)) @@ -622,4 +658,4 @@ void MinecraftVersionList::finalizeUpdate(QString version) saveCachedList(); } -#include "MinecraftVersionList.moc"
\ No newline at end of file +#include "MinecraftVersionList.moc" diff --git a/logic/minecraft/MinecraftVersionList.h b/logic/minecraft/MinecraftVersionList.h index 3266fc2d..7244d453 100644 --- a/logic/minecraft/MinecraftVersionList.h +++ b/logic/minecraft/MinecraftVersionList.h @@ -50,6 +50,8 @@ public: virtual const BaseVersionPtr at(int i) const; virtual int count() const; virtual void sort(); + virtual QVariant data(const QModelIndex & index, int role) const; + virtual RoleList providesRoles(); virtual BaseVersionPtr getLatestStable() const; |