From aea51a08763d81ce82326b2b875ace8a0039fb1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Tue, 28 Apr 2015 09:01:37 +0200 Subject: [PATCH] GH-328 overhaul all relevant version lists --- application/CMakeLists.txt | 2 + application/VersionProxyModel.cpp | 382 +++++++++++++++++++ application/VersionProxyModel.h | 56 +++ application/dialogs/VersionSelectDialog.cpp | 79 +--- application/dialogs/VersionSelectDialog.h | 12 +- application/pages/VersionPage.cpp | 4 +- application/pages/global/JavaPage.cpp | 1 - application/resources/multimc/16x16/star.png | Bin 0 -> 729 bytes application/resources/multimc/24x24/star.png | Bin 0 -> 1217 bytes application/resources/multimc/32x32/star.png | Bin 0 -> 1698 bytes application/resources/multimc/48x48/star.png | Bin 0 -> 3227 bytes application/resources/multimc/64x64/star.png | Bin 0 -> 4554 bytes application/resources/multimc/multimc.qrc | 7 + logic/BaseVersionList.cpp | 61 +-- logic/BaseVersionList.h | 27 +- logic/forge/ForgeVersionList.cpp | 99 ++--- logic/forge/ForgeVersionList.h | 3 +- logic/java/JavaVersionList.cpp | 139 +++---- logic/java/JavaVersionList.h | 26 +- logic/liteloader/LiteLoaderVersionList.cpp | 36 ++ logic/liteloader/LiteLoaderVersionList.h | 2 + logic/minecraft/MinecraftVersionList.cpp | 38 +- logic/minecraft/MinecraftVersionList.h | 2 + 23 files changed, 688 insertions(+), 288 deletions(-) create mode 100644 application/VersionProxyModel.cpp create mode 100644 application/VersionProxyModel.h create mode 100644 application/resources/multimc/16x16/star.png create mode 100644 application/resources/multimc/24x24/star.png create mode 100644 application/resources/multimc/32x32/star.png create mode 100644 application/resources/multimc/48x48/star.png create mode 100644 application/resources/multimc/64x64/star.png diff --git a/application/CMakeLists.txt b/application/CMakeLists.txt index b9a671b3d..31b0e62cd 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 000000000..2bfafd47f --- /dev/null +++ b/application/VersionProxyModel.cpp @@ -0,0 +1,382 @@ +#include "VersionProxyModel.h" +#include "MultiMC.h" +#include +#include +#include + +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 000000000..456268f0a --- /dev/null +++ b/application/VersionProxyModel.h @@ -0,0 +1,56 @@ +#pragma once +#include +#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 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 m_columns; + FilterMap m_filters; + BaseVersionList::RoleList roles; + VersionFilterModel * filterModel; +}; diff --git a/application/dialogs/VersionSelectDialog.cpp b/application/dialogs/VersionSelectDialog.cpp index d1be4ad0d..354857e7d 100644 --- a/application/dialogs/VersionSelectDialog.cpp +++ b/application/dialogs/VersionSelectDialog.cpp @@ -26,66 +26,8 @@ #include #include #include - -class VersionSelectProxyModel : public QSortFilterProxyModel -{ - Q_OBJECT -public: - VersionSelectProxyModel(QObject *parent = 0) : QSortFilterProxyModel(parent) - { - } - - struct Filter - { - QString string; - bool exact = false; - }; - - QHash 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 m_filters; -}; +#include "MultiMC.h" +#include 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 69e52fe66..23bd158a9 100644 --- a/application/dialogs/VersionSelectDialog.h +++ b/application/dialogs/VersionSelectDialog.h @@ -18,16 +18,14 @@ #include #include -#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 6b220017b..056bb9582 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 ab02b3a34..1b480376d 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 new file mode 100644 index 0000000000000000000000000000000000000000..4963e6ec97c21fd1a6f986841e4f2b751f3985ca GIT binary patch literal 729 zcmeAS@N?(olHy`uVBq!ia0y~yU=RRd4mJh`2Kmqb6B!to7I?ZihE&{|Iw{v9I8o&I z`O0^9KKBB9*SG(;KchW*_lajjlb)RH_iGYqKdT|Yxo^iQkTZF zD0*<6OKs%-g7j_RES5A4oc{=aYgyk75+{JiPrN}(Mb z&)5AtdN!+Ivy1;^ugM$rznf|+KJM#RFFup>U_Zm-wKZGsm8?{}(YX2dJk_OF!oQzy z_@{RD+>$eg^l$BL-FR^G?Tc^c7M7%?&OF+=pUFzfV~Jwq^*J>=7R_*R(J0@faVRA` z`1hABtKXamJt@yt5zwh(-YfIKq9{aox30a{{1}0J0U^_ihOaBQHoS>vxc*{!1xEnQjZdVTR%wkIJn3=sZd( z@(;1P<+mo(uCP@+c_MK`vgqZF44b5~8C=iAHFKvvoHKKho86YVq5D2Aa|@lDX%)BL z*Tl4qD_~;B9{#P}Mbr#2`?BuR2TPS!_!`tVq5C0Cww4_%P z6AL*1F4s#V18Xk2m74EPP~-{7WBHdPIn&#FdDd}_3br+0I?prn z&ukQuXMTE9%_KdgA+Lz#>9psY-i7H`9AZ$dW;p-kEv_0W!{T~Jf1_n=8KbLh*2~7ZC{80@6 literal 0 HcmV?d00001 diff --git a/application/resources/multimc/24x24/star.png b/application/resources/multimc/24x24/star.png new file mode 100644 index 0000000000000000000000000000000000000000..7f16618a6d8557c24eae17b40429720c319e1b24 GIT binary patch literal 1217 zcmeAS@N?(olHy`uVBq!ia0y~yV2}V|4mJh`h6m-gKNuKTIy_w*Ln>}<4Xq9cNfohw zzPtLSy1;sm10u3=X_q>bEqV{k=w1{oW@xy~@}+#6VbnK?-_84HNu_OSUz%wZHOqER zQi4~un@56#_K8j&X0Mryg<&mGf@0r}zT3OJ_`P0}ZP}bHyNlmjey_X#{rB9@zt8;? zdsx5kLz+5YoviA~Z9Ap6nmU%hpZMhJzX!RhJBpODx+}|G#yK?3ySFP>Gy6|R z@rh&4t{ht1oznfZZR3LT{C(4GpEn8LJH#s5^?Dh{tW~VXZn=mksVF}B>vX8=$(&26 z8;v&?+{(FR>z9_ZK%BjPouzMAkwf6eYNcI|K2F@9(C%a|FsCxuOPEPM?Sj(Dl*o)u z|M{tX-cys`onl#h)vIBamOy-N=0YG1pPz*rp&mm`bhqj=E^@IH^ZIm)O(ow z@^%%itCKa`uhY}zF`*(nk-jr{!a0ZaSZ{HsLf zKW}`xe%18#$4iRZPfS~TEWc>_dJp4BA!n900mk&E>zijx(a`a>sQPyHg}iLT{HR&% zHH#M?U0t^7ZoT$p;oFAir)8`?uN^6=eKO2troB{!q40~Mhg-BRZ8cNc+3qM?81SJ# ze&gQaJ5QySO)||7e!br;Dpob@oc4(d^S|?A9A>ts=ITeV3nm;ty{mf1=@^H7f_W_L z6U+~oHza#Fq+9R(@xrc3J4wBMpQPBGxvHg4KGZ3j>qm85SfV8LHOJ}e;>`0qo;>%F zm}BE`SDfWr$%RQ<+h4SIu*l~({5jLQ=<7Wn(blQz5s_TnlV>VU;hnCVDQ$J|8utoS zm&Xpzt69pnP5Rrp_=?2D2Opv|&gu$mmE0UEU^Y)+?c|1ey_zArj$9S$i(zIj?dkvG z&9V0Dmcq-17E%)*1W4xSM)dAZR}=2anA>ne>DD2aq6n$JDA{!DWx^NU`yFXJzapzx zH^g1##(#l5n^wuJo|Lphc4ouD&KVE3b93Y_?+npf{Kx6YPfM3WwyqC8DO}s@zk9wN z-+4Ec8^KKL?KjEAcbFRo**M&1I5bmDLh99W{$92pQ^Ym?mPxKRf{=N8YgJZ=6&ht jnp?HbarNqzul+fl8O1pjJH9h8Ffe$!`njxgN@xNA?a@OP literal 0 HcmV?d00001 diff --git a/application/resources/multimc/32x32/star.png b/application/resources/multimc/32x32/star.png new file mode 100644 index 0000000000000000000000000000000000000000..b271f0d1b89c88a7d466066dd653a34c6566a2a4 GIT binary patch literal 1698 zcmeAS@N?(olHy`uVBq!ia0y~yU{C;I4mJh`hT^KKFANN9nVv3=Ar-fdPUp=LaTPiK z-+1@!-LJpy_SF?xuiM2L;=t1)wqXiam_n1GFGmxHOMoDYikh06^OcOArU&d@y$u?5 z?gE02nxQRGj!S1LWGxJ^)6!kK_fpaI-M8m{d|Ug)PNPcbqUXJ{_wK#TXrlYT1z6?>AS_|)8|kB7g_Mr_;f_}xhvaMRlb|#?>%kcQhNV(&3}nU zn;2$oQ?tl;cwdD-_7y|;h021Xnu#5g?%dvce4T~Ep> zT=?+JcIgM1`4KMBA5R^ytcqcjG(Vs}byaiWKK=A3d;hMP8M(LbqlNW_kk3V%MUqM$ z+WdX7pXtM6?^VY_zJy9f&z@wy%I5bkqg~p1A61-RKa{fQ536^LHtbj066o>bu-uL< z=8KkDeqefQ(9GJCKB2#TLa)Mp@yjb7UD>nf%A7++zfQjRn<@D!WQ)wb?r&|ju}?bx zmaGnw`VnUosjeEOu(bMzkh6<#;O?f|q8oya-4r>M;~MkudgP_wk;0chCwjl`Ub2R1 z#VpGp{_bzj8t0X28SsdTNA(}RdXHuMXO=s;$4ehxmd-d+r+L)u(}m~C(>p(}`4*`< zxy3yC^5)}9;%%p>ran15YZ9~DjR|rM>_<;XaL31=V*WSJ=hTO-k_#S$m6V$;UcFXO z*0;T2;nI!g44$ZjeeMZbqjoEc?fxDHj!HF^LxOA%rZXxu-FH1=D!DoJalltCD??r3 z8`u3mim=567bF)ZJ_|j}Jb6Zv4bK53$0Wt1?FyGXLb?nb9?V*}c(?G^tFP;sgZi0S;s^7uzI|A`q>XYYQwf7!jo5g$IEGtImBc4pA7 zJ2#%rU-ZgwR@jH1Q9*}JJLk<>5+SsSv*D-WA_gb9&bw_MA3dhKGfjB8ir4<_t%Q>8 zmg2>FaoW{EQnuMY9tkeF@T3yxIG_`1*ChDG>w>xrv} z{g!X%-t^hz$xdZ~bCXxtA1_=acYDc{%gfhIi=9}tSM5r__y)Tv(pheyJm>v=U-Nq% zZIF7+`Rjoc>!$7)pQGomGv2(*ck`;p>SfjU9Ha^_>b+l^w!BrZ`+bD6|FNvETpu3R z>~D^jG|_tc@88au4Xw?p9zS01Una~F>hw;nwXc9@#&5sQOFEO5ZOBxxc3r*xH(Ne; z$L{5O`2@ueEW5d6;fByw<(tjdQ@FikOfEX-WT<~Ie0N2&@HA5MH#%DYv`f4I;0M<0XNvpwwjF$_~h zH)zRhot(a5;mMdbMkj%792}|@Pn`1l1*YpwP&)j~{E6Xuap!0CE$enLT)WpNqP2g2 z$eGlgv-H^%SOj040c<pBHpB)iOW*J!|RJf`|IIxKq;@4;XB^+0_=!)%82(Zr!21Tfgoo z{^h*;ERP_2!_6??2Vr;BjXb|Fb(ZV>{`JWCPk8Rrh*gy#5-(<`74}+BuT#9UxA(Vj YQqb+0aZdg|3=9kmp00i_>zopr0Br#|9smFU literal 0 HcmV?d00001 diff --git a/application/resources/multimc/48x48/star.png b/application/resources/multimc/48x48/star.png new file mode 100644 index 0000000000000000000000000000000000000000..d9468e7e3a721c480c3b5839ad27e1c51b76e528 GIT binary patch literal 3227 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 U?Cq@>1_lNOPgg&ebxsLQ0G##*ivR!s literal 0 HcmV?d00001 diff --git a/application/resources/multimc/64x64/star.png b/application/resources/multimc/64x64/star.png new file mode 100644 index 0000000000000000000000000000000000000000..4ed5d978f83d9fd90b661555bd243b36fad0cfd3 GIT binary patch literal 4554 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 literal 0 HcmV?d00001 diff --git a/application/resources/multimc/multimc.qrc b/application/resources/multimc/multimc.qrc index d02d0e0e1..4ced586a6 100644 --- a/application/resources/multimc/multimc.qrc +++ b/application/resources/multimc/multimc.qrc @@ -17,6 +17,13 @@ scalable/java.svg + + 16x16/star.png + 24x24/star.png + 32x32/star.png + 48x48/star.png + 64x64/star.png + 16x16/minecraft.png 24x24/minecraft.png diff --git a/logic/BaseVersionList.cpp b/logic/BaseVersionList.cpp index 7752b14ce..fe17a905d 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(); - - default: - return QVariant(); - } - - case Qt::ToolTipRole: - return version->descriptor(); - case VersionPointerRole: return qVariantFromValue(version); + case VersionRole: + return version->name(); + + case VersionIdRole: + return version->descriptor(); + + 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 584d6ca77..6089c31c9 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 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 56ffad11e..b2320a6dc 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,71 +65,32 @@ QVariant ForgeVersionList::data(const QModelIndex &index, int role) const auto version = std::dynamic_pointer_cast(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()]); + case VersionRole: + return version->name(); + + case VersionIdRole: + return version->descriptor(); + + case ParentGameVersionRole: + return version->mcver_sane; + + case RecommendedRole: + return version->is_recommended; + + case BranchRole: + return version->branch; + default: return QVariant(); } } -QVariant ForgeVersionList::headerData(int section, Qt::Orientation orientation, int role) const +QList ForgeVersionList::providesRoles() { - switch (role) - { - case Qt::DisplayRole: - switch (section) - { - case 0: - return tr("Version"); - - case 1: - return tr("Minecraft"); - - case 2: - return tr("Type"); - - default: - return QVariant(); - } - - case Qt::ToolTipRole: - switch (section) - { - case 0: - return tr("The name of the version."); - - case 1: - return tr("Minecraft version"); - - case 2: - return tr("The version's type."); - - default: - return QVariant(); - } - - default: - return QVariant(); - } + return {VersionPointerRole, VersionRole, VersionIdRole, ParentGameVersionRole, RecommendedRole, BranchRole}; } BaseVersionPtr ForgeVersionList::getLatestStable() const @@ -296,6 +257,7 @@ bool ForgeListLoadTask::parseForgeList(QList &out) bool ForgeListLoadTask::parseForgeGradleList(QList &out) { + QMap> lookup; QByteArray data; { auto dlJob = gradleListDownload; @@ -402,6 +364,29 @@ bool ForgeListLoadTask::parseForgeGradleList(QList &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("^(?[0-9]+(.[0-9]+)*)-(?