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