feat: add QQmlSortFilterProxyModel

pull/31/head
kate 5 years ago
parent 2bcb04a0db
commit 14862617b0

@ -10,6 +10,7 @@ target_sources(${TARGET} PRIVATE
newiconitem.cpp
managedtexturenode.cpp
wheelhandler.cpp
qqmlsortfilterproxymodel.cpp
desktop/menupopupwindow.cpp

@ -25,6 +25,7 @@
#include "windowhelper.h"
#include "newiconitem.h"
#include "wheelhandler.h"
#include "qqmlsortfilterproxymodel.h"
#include "desktop/menupopupwindow.h"
@ -59,6 +60,7 @@ void FishUI::registerTypes(const char *uri)
qmlRegisterType<NewIconItem>(uri, 1, 0, "IconItem");
qmlRegisterType<MenuPopupWindow>(uri, 1, 0, "MenuPopupWindow");
qmlRegisterType<WheelHandler>(uri, 1, 0, "WheelHandler");
qmlRegisterType<QQmlSortFilterProxyModel>(uri, 1, 0, "SortFilterProxyModel");
qmlRegisterSingletonType(componentUrl(QStringLiteral("Theme.qml")), uri, 1, 0, "Theme");
qmlRegisterSingletonType(componentUrl(QStringLiteral("Units.qml")), uri, 1, 0, "Units");

@ -0,0 +1,290 @@
/****************************************************************************
*
* Copyright (C) 2018 Pierre-Yves Siret
*
* $BEGIN_LICENSE:MIT$
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
* $END_LICENSE$
***************************************************************************/
#include "qqmlsortfilterproxymodel.h"
#include <QtQml>
QQmlSortFilterProxyModel::QQmlSortFilterProxyModel(QObject *parent)
: QSortFilterProxyModel(parent)
, m_filterExpression(0)
, m_compareExpression(0)
{
connect(this, &QAbstractProxyModel::sourceModelChanged, this,
&QQmlSortFilterProxyModel::updateRoles);
connect(this, &QAbstractItemModel::modelReset, this, &QQmlSortFilterProxyModel::updateRoles);
connect(this, &QAbstractItemModel::rowsInserted, this, &QQmlSortFilterProxyModel::countChanged);
connect(this, &QAbstractItemModel::rowsRemoved, this, &QQmlSortFilterProxyModel::countChanged);
connect(this, &QAbstractItemModel::modelReset, this, &QQmlSortFilterProxyModel::countChanged);
connect(this, &QAbstractItemModel::layoutChanged, this,
&QQmlSortFilterProxyModel::countChanged);
setDynamicSortFilter(true);
}
int QQmlSortFilterProxyModel::count() const
{
return rowCount();
}
QHash<int, QByteArray> QQmlSortFilterProxyModel::roleNames() const
{
return sourceModel() ? sourceModel()->roleNames() : QHash<int, QByteArray>();
}
const QString &QQmlSortFilterProxyModel::filterRoleName() const
{
return m_filterRoleName;
}
void QQmlSortFilterProxyModel::setFilterRoleName(const QString &filterRoleName)
{
if (m_filterRoleName == filterRoleName)
return;
m_filterRoleName = filterRoleName;
updateFilterRole();
emit filterRoleNameChanged();
}
QString QQmlSortFilterProxyModel::filterPattern() const
{
return filterRegExp().pattern();
}
void QQmlSortFilterProxyModel::setFilterPattern(const QString &filterPattern)
{
QRegExp regExp = filterRegExp();
if (regExp.pattern() == filterPattern)
return;
regExp.setPattern(filterPattern);
QSortFilterProxyModel::setFilterRegExp(regExp);
emit filterPatternChanged();
}
QQmlSortFilterProxyModel::PatternSyntax QQmlSortFilterProxyModel::filterPatternSyntax() const
{
return static_cast<PatternSyntax>(filterRegExp().patternSyntax());
}
void QQmlSortFilterProxyModel::setFilterPatternSyntax(
QQmlSortFilterProxyModel::PatternSyntax patternSyntax)
{
QRegExp regExp = filterRegExp();
QRegExp::PatternSyntax patternSyntaxTmp = static_cast<QRegExp::PatternSyntax>(patternSyntax);
if (regExp.patternSyntax() == patternSyntaxTmp)
return;
regExp.setPatternSyntax(patternSyntaxTmp);
QSortFilterProxyModel::setFilterRegExp(regExp);
emit filterPatternSyntaxChanged();
}
const QVariant &QQmlSortFilterProxyModel::filterValue() const
{
return m_filterValue;
}
void QQmlSortFilterProxyModel::setFilterValue(const QVariant &filterValue)
{
if (m_filterValue == filterValue)
return;
m_filterValue = filterValue;
invalidateFilter();
emit filterValueChanged();
}
const QQmlScriptString &QQmlSortFilterProxyModel::filterExpression() const
{
return m_filterScriptString;
}
void QQmlSortFilterProxyModel::setFilterExpression(const QQmlScriptString &filterScriptString)
{
if (m_filterScriptString == filterScriptString)
return;
m_filterScriptString = filterScriptString;
QQmlContext *context = new QQmlContext(qmlContext(this));
auto roles = roleNames().values();
QVariantMap map;
for (const QByteArray &roleName : roles)
map.insert(QString::fromLatin1(roleName), QVariant());
context->setContextProperty(QStringLiteral("model"), map);
context->setContextProperty(QStringLiteral("index"), -1);
delete (m_filterExpression);
m_filterExpression = new QQmlExpression(m_filterScriptString, context, 0, this);
connect(m_filterExpression, &QQmlExpression::valueChanged, this,
&QQmlSortFilterProxyModel::invalidateFilter);
m_filterExpression->setNotifyOnValueChanged(true);
m_filterExpression->evaluate();
emit filterExpressionChanged();
}
const QString &QQmlSortFilterProxyModel::sortRoleName() const
{
return m_sortRoleName;
}
void QQmlSortFilterProxyModel::setSortRoleName(const QString &sortRoleName)
{
if (m_sortRoleName == sortRoleName)
return;
m_sortRoleName = sortRoleName;
updateSortRole();
emit sortRoleNameChanged();
}
void QQmlSortFilterProxyModel::setSortOrder(Qt::SortOrder sortOrder)
{
if (!m_sortRoleName.isEmpty())
sort(0, sortOrder);
emit sortOrderChanged();
}
const QQmlScriptString &QQmlSortFilterProxyModel::sortExpression() const
{
return m_compareScriptString;
}
void QQmlSortFilterProxyModel::setSortExpression(const QQmlScriptString &compareScriptString)
{
if (m_compareScriptString == compareScriptString)
return;
m_compareScriptString = compareScriptString;
QQmlContext *context = new QQmlContext(qmlContext(this));
auto roles = roleNames().values();
QVariantMap map;
for (const QByteArray &roleName : roles)
map.insert(QString::fromLatin1(roleName), QVariant());
context->setContextProperty(QStringLiteral("modelLeft"), map);
context->setContextProperty(QStringLiteral("indexLeft"), -1);
context->setContextProperty(QStringLiteral("modelRight"), map);
context->setContextProperty(QStringLiteral("indexRight"), -1);
delete (m_compareExpression);
m_compareExpression = new QQmlExpression(m_compareScriptString, context, 0, this);
connect(m_compareExpression, &QQmlExpression::valueChanged, this,
&QQmlSortFilterProxyModel::invalidate);
m_compareExpression->setNotifyOnValueChanged(true);
m_compareExpression->evaluate();
emit sortExpressionChanged();
}
bool QQmlSortFilterProxyModel::filterAcceptsRow(int source_row,
const QModelIndex &source_parent) const
{
QModelIndex modelIndex = sourceModel()->index(source_row, 0, source_parent);
bool valueAccepted = !m_filterValue.isValid()
|| (m_filterValue == sourceModel()->data(modelIndex, filterRole()));
bool baseAcceptsRow =
valueAccepted && QSortFilterProxyModel::filterAcceptsRow(source_row, source_parent);
if (baseAcceptsRow && !m_filterScriptString.isEmpty()) {
QVariantMap map = modelDataMap(modelIndex);
QQmlContext context(qmlContext(this));
context.setContextProperty(QStringLiteral("model"), map);
context.setContextProperty(QStringLiteral("index"), source_row);
QQmlExpression expression(m_filterScriptString, &context, 0);
QVariant result = expression.evaluate();
if (!expression.hasError())
return result.toBool();
else
qWarning() << expression.error();
}
return baseAcceptsRow;
}
bool QQmlSortFilterProxyModel::lessThan(const QModelIndex &source_left,
const QModelIndex &source_right) const
{
if (!m_compareScriptString.isEmpty()) {
QQmlContext context(qmlContext(this));
context.setContextProperty(QStringLiteral("modelLeft"), modelDataMap(source_left));
context.setContextProperty(QStringLiteral("indexLeft"), source_left.row());
context.setContextProperty(QStringLiteral("modelRight"), modelDataMap(source_right));
context.setContextProperty(QStringLiteral("indexRight"), source_right.row());
QQmlExpression expression(m_compareScriptString, &context, 0);
QVariant result = expression.evaluate();
if (!expression.hasError())
return result.toBool();
else
qWarning() << expression.error();
}
return QSortFilterProxyModel::lessThan(source_left, source_right);
}
void QQmlSortFilterProxyModel::invalidateFilter()
{
QSortFilterProxyModel::invalidateFilter();
}
void QQmlSortFilterProxyModel::updateFilterRole()
{
QList<int> filterRoles = roleNames().keys(m_filterRoleName.toUtf8());
if (!filterRoles.empty()) {
setFilterRole(filterRoles.first());
}
}
void QQmlSortFilterProxyModel::updateSortRole()
{
QList<int> sortRoles = roleNames().keys(m_sortRoleName.toUtf8());
if (!sortRoles.empty()) {
setSortRole(sortRoles.first());
sort(0, sortOrder());
}
}
void QQmlSortFilterProxyModel::updateRoles()
{
updateFilterRole();
updateSortRole();
}
QVariantMap QQmlSortFilterProxyModel::modelDataMap(const QModelIndex &modelIndex) const
{
QVariantMap map;
QHash<int, QByteArray> roles = roleNames();
for (QHash<int, QByteArray>::const_iterator it = roles.constBegin(); it != roles.constEnd(); ++it)
map.insert(QString::fromLatin1(it.value()), sourceModel()->data(modelIndex, it.key()));
return map;
}
#include "moc_qqmlsortfilterproxymodel.cpp"

@ -0,0 +1,128 @@
/****************************************************************************
* Copyright (C) 2018 Pierre-Yves Siret
*
* $BEGIN_LICENSE:MIT$
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*
* $END_LICENSE$
***************************************************************************/
#ifndef QQMLSORTFILTERPROXYMODEL_H
#define QQMLSORTFILTERPROXYMODEL_H
#include <QSortFilterProxyModel>
#include <QQmlExpression>
class QQmlSortFilterProxyModel : public QSortFilterProxyModel
{
Q_OBJECT
Q_PROPERTY(int count READ count NOTIFY countChanged)
Q_PROPERTY(QString filterRoleName READ filterRoleName WRITE setFilterRoleName NOTIFY filterRoleNameChanged)
Q_PROPERTY(
QString filterPattern READ filterPattern WRITE setFilterPattern NOTIFY filterPatternChanged)
Q_PROPERTY(PatternSyntax filterPatternSyntax READ filterPatternSyntax WRITE
setFilterPatternSyntax NOTIFY filterPatternSyntaxChanged)
Q_PROPERTY(QVariant filterValue READ filterValue WRITE setFilterValue NOTIFY filterValueChanged)
Q_PROPERTY(QQmlScriptString filterExpression READ filterExpression WRITE setFilterExpression
NOTIFY filterExpressionChanged)
Q_PROPERTY(
QString sortRoleName READ sortRoleName WRITE setSortRoleName NOTIFY sortRoleNameChanged)
Q_PROPERTY(Qt::SortOrder sortOrder READ sortOrder WRITE setSortOrder NOTIFY sortOrderChanged)
Q_PROPERTY(QQmlScriptString sortExpression READ sortExpression WRITE setSortExpression NOTIFY sortExpressionChanged)
public:
enum PatternSyntax {
RegExp = QRegExp::RegExp,
Wildcard = QRegExp::Wildcard,
FixedString = QRegExp::FixedString,
RegExp2 = QRegExp::RegExp2,
WildcardUnix = QRegExp::WildcardUnix,
W3CXmlSchema11 = QRegExp::W3CXmlSchema11
};
Q_ENUM(PatternSyntax)
QQmlSortFilterProxyModel(QObject *parent = 0);
int count() const;
QHash<int, QByteArray> roleNames() const override;
const QString &filterRoleName() const;
void setFilterRoleName(const QString &filterRoleName);
QString filterPattern() const;
void setFilterPattern(const QString &filterPattern);
PatternSyntax filterPatternSyntax() const;
void setFilterPatternSyntax(PatternSyntax patternSyntax);
const QVariant &filterValue() const;
void setFilterValue(const QVariant &filterValue);
const QQmlScriptString &filterExpression() const;
void setFilterExpression(const QQmlScriptString &filterScriptString);
const QString &sortRoleName() const;
void setSortRoleName(const QString &sortRoleName);
void setSortOrder(Qt::SortOrder sortOrder);
const QQmlScriptString &sortExpression() const;
void setSortExpression(const QQmlScriptString &compareScriptString);
signals:
void countChanged();
void filterRoleNameChanged();
void filterPatternSyntaxChanged();
void filterPatternChanged();
void filterValueChanged();
void filterExpressionChanged();
void sortRoleNameChanged();
void sortOrderChanged();
void sortExpressionChanged();
protected:
bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override;
bool lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const override;
private slots:
void invalidateFilter();
void updateFilterRole();
void updateSortRole();
void updateRoles();
private:
QVariantMap modelDataMap(const QModelIndex &modelIndex) const;
QString m_filterRoleName;
QString m_sortRoleName;
QQmlScriptString m_filterScriptString;
QQmlExpression *m_filterExpression;
QQmlScriptString m_compareScriptString;
QQmlExpression *m_compareExpression;
QVariant m_filterValue;
};
#endif // QQMLSORTFILTERPROXYMODEL_H
Loading…
Cancel
Save