diff options
Diffstat (limited to 'application')
-rw-r--r-- | application/CMakeLists.txt | 2 | ||||
-rw-r--r-- | application/VersionProxyModel.cpp | 382 | ||||
-rw-r--r-- | application/VersionProxyModel.h | 56 | ||||
-rw-r--r-- | application/dialogs/VersionSelectDialog.cpp | 79 | ||||
-rw-r--r-- | application/dialogs/VersionSelectDialog.h | 12 | ||||
-rw-r--r-- | application/pages/VersionPage.cpp | 4 | ||||
-rw-r--r-- | application/pages/global/JavaPage.cpp | 1 | ||||
-rw-r--r-- | application/resources/multimc/16x16/star.png | bin | 0 -> 729 bytes | |||
-rw-r--r-- | application/resources/multimc/24x24/star.png | bin | 0 -> 1217 bytes | |||
-rw-r--r-- | application/resources/multimc/32x32/star.png | bin | 0 -> 1698 bytes | |||
-rw-r--r-- | application/resources/multimc/48x48/star.png | bin | 0 -> 3227 bytes | |||
-rw-r--r-- | application/resources/multimc/64x64/star.png | bin | 0 -> 4554 bytes | |||
-rw-r--r-- | application/resources/multimc/multimc.qrc | 7 |
13 files changed, 467 insertions, 76 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> |