Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qqmlfunctionfilter.cpp
Go to the documentation of this file.
1// Copyright (C) 2025 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include <QtQmlModels/private/qqmlfunctionfilter_p.h>
5#include <QtQmlModels/private/qqmlsortfilterproxymodel_p.h>
6#include <QtQml/private/qqmlobjectcreator_p.h>
7#include <QObject>
8#include <QMetaMethod>
9
10QT_BEGIN_NAMESPACE
11
12/*!
13 \qmltype FunctionFilter
14 \inherits Filter
15 \inqmlmodule QtQml.Models
16 \since 6.10
17 \preliminary
18 \brief Filters data in a \l SortFilterProxyModel based on the evaluation
19 of the designated 'filter' method.
20
21 FunctionFilter allows user to define the designated 'filter' method and it
22 will be evaluated to filter the data. The 'filter' method takes one
23 argument and it can be defined as inline component as below:
24
25 \qml
26 SortFilterProxyModel {
27 model: sourceModel
28 filters: [
29 FunctionFilter {
30 id: functionFilter
31 property int ageLimit: 20
32 component RoleData: QtObject {
33 property real age
34 }
35 function filter(data: RoleData) : bool {
36 return (data.age <= ageLimit)
37 }
38 }
39 ]
40 }
41 \endqml
42
43 \note The user needs to explicitly invoke
44 \l{SortFilterProxyModel::invalidate} whenever any external qml property
45 used within the designated 'filter' method changes. This behaviour is
46 subject to change in the future, like implicit invalidation and thus the
47 user doesn't need to explicitly invoke
48 \l{SortFilterProxyModel::invalidate}.
49*/
50
51QQmlFunctionFilter::QQmlFunctionFilter(QObject *parent)
52 : QQmlFilterBase (new QQmlFunctionFilterPrivate, parent)
53{
54}
55
56QQmlFunctionFilter::~QQmlFunctionFilter()
57{
58 Q_D(QQmlFunctionFilter);
59 if (d->m_parameterData.metaType().flags() & QMetaType::PointerToQObject)
60 delete d->m_parameterData.value<QObject *>();
61}
62
63void QQmlFunctionFilter::componentComplete()
64{
65 Q_D(QQmlFunctionFilter);
66 const auto *metaObj = metaObject();
67 for (int idx = metaObj->methodOffset(); idx < metaObj->methodCount(); idx++) {
68 // Once we find the method signature, break the loop
69 QMetaMethod method = metaObj->method(idx);
70 if (method.nameView() == "filter") {
71 d->m_method = method;
72 break;
73 }
74 }
75
76 if (!d->m_method.isValid())
77 return;
78
79 if (d->m_method.parameterCount() != 1) {
80 qWarning("filter method requires a single parameter");
81 return;
82 }
83
84 QQmlData *data = QQmlData::get(this);
85 if (!data || !data->outerContext) {
86 qWarning("filter requires a QML context");
87 return;
88 }
89
90 QQmlRefPointer<QQmlContextData> context = data->outerContext;
91 QQmlEngine *engine = context->engine();
92
93 const QMetaType parameterType = d->m_method.parameterMetaType(0);
94 auto cu = QQmlMetaType::obtainCompilationUnit(parameterType);
95 const QQmlType parameterQmlType = QQmlMetaType::qmlType(parameterType);
96
97 if (!parameterQmlType.isValid()) {
98 qWarning("filter method parameter needs to be a QML-registered type");
99 return;
100 }
101
102 // The code below creates an instance of the inline component, composite,
103 // or specific C++ QObject types. The created instance, along with the
104 // data, is passed as an argument to the 'filter' method, which is invoked
105 // during the call to QQmlFunctionFilter::filterAcceptsRowInternal.
106 // To create an instance of required component types (be it inline or
107 // composite), an executable compilation unit is required, and this can be
108 // obtained by looking up via metatype in the type registry
109 // (QQmlMetaType::obtainCompilationUnit). Pass it through the QML engine to
110 // make it executable. Further, use the executable compilation unit to run
111 // an object creator and produce an instance.
112 if (parameterType.flags() & QMetaType::PointerToQObject) {
113 QObject *created = nullptr;
114 if (parameterQmlType.isInlineComponentType()) {
115 const auto executableCu = engine->handle()->executableCompilationUnit(std::move(cu));
116 const QString icName = parameterQmlType.elementName();
117 created = QQmlObjectCreator(context, executableCu, context, icName).create(
118 executableCu->inlineComponentId(icName), nullptr, nullptr,
119 QQmlObjectCreator::InlineComponent);
120 } else if (parameterQmlType.isComposite()) {
121 const auto executableCu = engine->handle()->executableCompilationUnit(std::move(cu));
122 created = QQmlObjectCreator(context, executableCu, context, QString()).create();
123 } else {
124 created = parameterQmlType.metaObject()->newInstance();
125 }
126
127 const auto names = d->m_method.parameterNames();
128 created->setObjectName(names[0]);
129 d->m_parameterData = QVariant::fromValue(created);
130 } else {
131 d->m_parameterData = QVariant(parameterType);
132 }
133}
134
135/*!
136 \internal
137*/
138bool QQmlFunctionFilter::filterAcceptsRowInternal(int row, const QModelIndex& sourceParent, const QQmlSortFilterProxyModel *proxyModel) const
139{
140 Q_D(const QQmlFunctionFilter);
141 if (!d->m_method.isValid() || !d->m_parameterData.isValid())
142 return true;
143
144 bool retVal = false;
145 if (column() > -1) {
146 QSortFilterProxyModelHelper::setProperties(
147 &d->m_parameterData, proxyModel,
148 proxyModel->sourceModel()->index(row, column(), sourceParent));
149 void *argv[] = {&retVal, d->m_parameterData.data()};
150 QMetaObject::metacall(
151 const_cast<QQmlFunctionFilter *>(this), QMetaObject::InvokeMetaMethod,
152 d->m_method.methodIndex(), argv);
153 } else {
154 const int columnCount = proxyModel->sourceModel()->columnCount(sourceParent);
155 for (int column = 0; column < columnCount; column++) {
156 QSortFilterProxyModelHelper::setProperties(
157 &d->m_parameterData, proxyModel,
158 proxyModel->sourceModel()->index(row, column, sourceParent));
159 void *argv[] = {&retVal, d->m_parameterData.data()};
160 QMetaObject::metacall(
161 const_cast<QQmlFunctionFilter *>(this), QMetaObject::InvokeMetaMethod,
162 d->m_method.methodIndex(), argv);
163 if (retVal)
164 return retVal;
165 }
166 }
167 return retVal;
168}
169
170QT_END_NAMESPACE
171
172#include "moc_qqmlfunctionfilter_p.cpp"