sneedmc/launcher/VersionProxyModel.cpp
jdp_ 9cb6200081 Cleanup codebase
for FileSystem.cpp:
Instead of checking if Linux or FreeBSD, check if its not Windows and not OSX. Chances are other operating systems run a DE that adheres to the XDG Desktop standard (.desktop). The check isn't good enough anyways since alternative shells for Windows exist, it will never be an accurate check. In any case this function is unused.

WorldListPage.cpp:
Redo confusing switch statement plagued with fall throughs, now well defined.

LaunchController.cpp:
Remove cringe. Also fix warning and make the unimplemented case(s) more explicit.

VersionProxyModel.cpp:
Add fallthrough for warning suppression.

WorldListPage.cpp:
redo `mceditState`

TranslationsModel.cpp:
Move up definition of `column` variable to when it is needed, clear up switch cases

FlameInstanceCreationTask.cpp:
Fallthrough intentionally

SkinUpload.cpp:
Make `getVariant`

ResourcePack.cpp:
Add new values for 1.19.3+

meta/Index.cpp:
Make clear switch statement behavior

JavaWizardPage.cpp:
Fix case fallthrough

Yggdrasil.cpp:
Fix case fallthrough

AccountList.cpp:
Fix case fallthrough,

WinDarkmode.cpp:
Add an explanation and fix warnings due to FARPROC casts.

Signed-off-by: jdp_ <42700985+jdpatdiscord@users.noreply.github.com>
2023-05-07 06:20:16 -04:00

486 lines
15 KiB
C++

// SPDX-License-Identifier: GPL-3.0-only
/*
* PolyMC - Minecraft Launcher
* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*
* This file incorporates work covered by the following copyright and
* permission notice:
*
* Copyright 2013-2021 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.
*/
#include "VersionProxyModel.h"
#include "Application.h"
#include <QSortFilterProxyModel>
#include <QPixmapCache>
#include <Version.h>
#include <meta/VersionList.h>
class VersionFilterModel : public QSortFilterProxyModel
{
Q_OBJECT
public:
VersionFilterModel(VersionProxyModel *parent) : QSortFilterProxyModel(parent)
{
m_parent = parent;
setSortRole(BaseVersionList::SortRole);
sort(0, Qt::DescendingOrder);
}
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 idx = sourceModel()->index(source_row, 0, source_parent);
auto data = sourceModel()->data(idx, it.key());
auto match = data.toString();
if(!it.value()->accepts(match))
{
return false;
}
}
return true;
}
void filterChanged()
{
invalidateFilter();
}
private:
VersionProxyModel *m_parent;
};
VersionProxyModel::VersionProxyModel(QObject *parent) : QAbstractProxyModel(parent)
{
filterModel = new VersionFilterModel(this);
connect(filterModel, &QAbstractItemModel::dataChanged, this, &VersionProxyModel::sourceDataChanged);
connect(filterModel, &QAbstractItemModel::rowsAboutToBeInserted, this, &VersionProxyModel::sourceRowsAboutToBeInserted);
connect(filterModel, &QAbstractItemModel::rowsInserted, this, &VersionProxyModel::sourceRowsInserted);
connect(filterModel, &QAbstractItemModel::rowsAboutToBeRemoved, this, &VersionProxyModel::sourceRowsAboutToBeRemoved);
connect(filterModel, &QAbstractItemModel::rowsRemoved, this, &VersionProxyModel::sourceRowsRemoved);
// FIXME: implement when needed
/*
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");
case Time:
return tr("Released");
}
}
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");
case Time:
return tr("Release date of 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:
{
QString version = sourceModel()->data(parentIndex, BaseVersionList::VersionRole).toString();
if(version == m_currentVersion)
{
return tr("%1 (installed)").arg(version);
}
return version;
}
case ParentVersion:
return sourceModel()->data(parentIndex, BaseVersionList::ParentVersionRole);
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);
case Time:
return sourceModel()->data(parentIndex, Meta::VersionList::TimeRole).toDate();
default:
return QVariant();
}
}
case Qt::ToolTipRole:
{
switch(column)
{
case Name:
{
if(hasRecommended)
{
auto value = sourceModel()->data(parentIndex, BaseVersionList::RecommendedRole);
if(value.toBool())
{
return tr("Recommended");
}
else if(hasLatest)
{
auto value = sourceModel()->data(parentIndex, BaseVersionList::LatestRole);
if(value.toBool())
{
return tr("Latest");
}
}
else if(index.row() == 0)
{
return tr("Latest");
}
}
[[fallthrough]];
}
default:
{
return sourceModel()->data(parentIndex, BaseVersionList::VersionIdRole);
}
}
}
case Qt::DecorationRole:
{
switch(column)
{
case Name:
{
if(hasRecommended)
{
auto value = sourceModel()->data(parentIndex, BaseVersionList::RecommendedRole);
if(value.toBool())
{
return APPLICATION->getThemedIcon("star");
}
else if(hasLatest)
{
auto value = sourceModel()->data(parentIndex, BaseVersionList::LatestRole);
if(value.toBool())
{
return APPLICATION->getThemedIcon("bug");
}
}
else if(index.row() == 0)
{
return APPLICATION->getThemedIcon("bug");
}
QPixmap pixmap;
QPixmapCache::find("placeholder", &pixmap);
if(!pixmap)
{
QPixmap px(16,16);
px.fill(Qt::transparent);
QPixmapCache::insert("placeholder", px);
return px;
}
return pixmap;
}
[[fallthrough]];
}
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(QAbstractItemModel *replacingRaw)
{
auto replacing = dynamic_cast<BaseVersionList *>(replacingRaw);
beginResetModel();
m_columns.clear();
if(!replacing)
{
roles.clear();
filterModel->setSourceModel(replacing);
return;
}
roles = replacing->providesRoles();
if(roles.contains(BaseVersionList::VersionRole))
{
m_columns.push_back(Name);
}
/*
if(roles.contains(BaseVersionList::ParentVersionRole))
{
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(Meta::VersionList::TimeRole))
{
m_columns.push_back(Time);
}
if(roles.contains(BaseVersionList::BranchRole))
{
m_columns.push_back(Branch);
}
if(roles.contains(BaseVersionList::TypeRole))
{
m_columns.push_back(Type);
}
if(roles.contains(BaseVersionList::RecommendedRole))
{
hasRecommended = true;
}
if(roles.contains(BaseVersionList::LatestRole))
{
hasLatest = true;
}
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);
}
QModelIndex VersionProxyModel::getVersion(const QString& version) const
{
int found = -1;
for (int i = 0; i < rowCount(); i++)
{
auto value = sourceModel()->data(mapToSource(index(i, 0)), BaseVersionList::VersionRole);
if (value.toString() == version)
{
found = i;
}
}
if(found == -1)
{
return QModelIndex();
}
return index(found, 0);
}
void VersionProxyModel::clearFilters()
{
m_filters.clear();
filterModel->filterChanged();
}
void VersionProxyModel::setFilter(const BaseVersionList::ModelRoles column, Filter * f)
{
m_filters[column].reset(f);
filterModel->filterChanged();
}
const VersionProxyModel::FilterMap &VersionProxyModel::filters() const
{
return m_filters;
}
void VersionProxyModel::sourceAboutToBeReset()
{
beginResetModel();
}
void VersionProxyModel::sourceReset()
{
endResetModel();
}
void VersionProxyModel::sourceRowsAboutToBeInserted(const QModelIndex& parent, int first, int last)
{
beginInsertRows(parent, first, last);
}
void VersionProxyModel::sourceRowsInserted(const QModelIndex& parent, int first, int last)
{
endInsertRows();
}
void VersionProxyModel::sourceRowsAboutToBeRemoved(const QModelIndex& parent, int first, int last)
{
beginRemoveRows(parent, first, last);
}
void VersionProxyModel::sourceRowsRemoved(const QModelIndex& parent, int first, int last)
{
endRemoveRows();
}
void VersionProxyModel::setCurrentVersion(const QString &version)
{
m_currentVersion = version;
}
#include "VersionProxyModel.moc"