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
qqmldelegatecomponent.cpp
Go to the documentation of this file.
1// Copyright (C) 2018 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
4
6#include <QtQmlModels/private/qqmladaptormodel_p.h>
7
9
10/*!
11 \qmltype DelegateChoice
12//! \nativetype QQmlDelegateChoice
13 \inqmlmodule QtQml.Models
14 \since 6.9
15 \brief Encapsulates a delegate and when to use it.
16
17 The DelegateChoice type wraps a delegate and defines the circumstances
18 in which it should be chosen.
19
20 DelegateChoices can be nested inside a DelegateChooser.
21
22 \sa DelegateChooser
23*/
24
25/*!
26 \qmlproperty variant QtQml.Models::DelegateChoice::roleValue
27 This property holds the value used to match the role data for the role provided by \l DelegateChooser::role.
28*/
29QVariant QQmlDelegateChoice::roleValue() const
30{
31 return m_value;
32}
33
34void QQmlDelegateChoice::setRoleValue(const QVariant &value)
35{
36 if (m_value == value)
37 return;
38 m_value = value;
39 emit roleValueChanged();
40 emit changed();
41}
42
43/*!
44 \qmlproperty int QtQml.Models::DelegateChoice::row
45 This property holds the value used to match the row value of model elements.
46 With models that have only the index property (and thus only one column), this property
47 should be intended as an index, and set to the desired index value.
48
49 \note Setting both row and index has undefined behavior. The two are equivalent and only
50 one should be used.
51
52 \sa index
53*/
54
55/*!
56 \qmlproperty int QtQml.Models::DelegateChoice::index
57 This property holds the value used to match the index value of model elements.
58 This is effectively an alias for \l row.
59
60 \sa row
61*/
62int QQmlDelegateChoice::row() const
63{
64 return m_row;
65}
66
67void QQmlDelegateChoice::setRow(int r)
68{
69 if (m_row == r)
70 return;
71 m_row = r;
72 emit rowChanged();
73 emit indexChanged();
74 emit changed();
75}
76
77/*!
78 \qmlproperty int QtQml.Models::DelegateChoice::column
79 This property holds the value used to match the column value of model elements.
80*/
81int QQmlDelegateChoice::column() const
82{
83 return m_column;
84}
85
86void QQmlDelegateChoice::setColumn(int c)
87{
88 if (m_column == c)
89 return;
90 m_column = c;
91 emit columnChanged();
92 emit changed();
93}
94
95QQmlComponent *QQmlDelegateChoice::delegate() const
96{
97 return m_delegate;
98}
99
100/*!
101 \qmlproperty Component QtQml.Models::DelegateChoice::delegate
102 This property holds the delegate to use if this choice matches the model item.
103*/
104void QQmlDelegateChoice::setDelegate(QQmlComponent *delegate)
105{
106 if (m_delegate == delegate)
107 return;
108 QQmlAbstractDelegateComponent *adc = static_cast<QQmlAbstractDelegateComponent *>(m_delegate);
109 if (adc)
110 disconnect(adc, &QQmlAbstractDelegateComponent::delegateChanged, this, &QQmlDelegateChoice::delegateChanged);
111 m_delegate = delegate;
112 adc = static_cast<QQmlAbstractDelegateComponent *>(delegate);
113 if (adc)
114 connect(adc, &QQmlAbstractDelegateComponent::delegateChanged, this, &QQmlDelegateChoice::delegateChanged);
115 emit delegateChanged();
116 emit changed();
117}
118
119bool QQmlDelegateChoice::match(int row, int column, const QVariant &value) const
120{
121 if (!m_value.isValid() && m_row < 0 && m_column < 0)
122 return true;
123
124 bool roleMatched = true;
125 if (m_value.isValid()) {
126 roleMatched = (value == m_value);
127 if (!roleMatched) {
128 bool valueOk = false;
129 bool mValueOk = false;
130 roleMatched = (value.toInt(&valueOk) == m_value.toInt(&mValueOk) && valueOk && mValueOk);
131 }
132 if (!roleMatched)
133 roleMatched = (value.toString() == m_value.toString());
134 }
135 const bool rowMatched = (m_row < 0 ) ? true : m_row == row;
136 const bool columnMatched = (m_column < 0 ) ? true : m_column == column;
137 return roleMatched && rowMatched && columnMatched;
138}
139
140/*!
141 \qmltype DelegateChooser
142//! \nativetype QQmlDelegateChooser
143 \inqmlmodule QtQml.Models
144 \since 6.9
145 \brief Allows a view to use different delegates for different types of items in the model.
146
147 The DelegateChooser is a special \l Component type intended for those scenarios where a
148 Component is required by a view and used as a delegate. DelegateChooser encapsulates a set of \l
149 {DelegateChoice}s. These choices are used to determine the delegate that will be instantiated for
150 each item in the model. The selection of the choice is performed based on the value that a model
151 item has for \l role, and also based on index.
152
153 DelegateChooser is commonly used when a view needs to display a set of delegates that are
154 significantly different from each other. For example, a typical phone settings view might include
155 toggle switches, sliders, radio buttons, and other visualizations based on the type of each
156 setting. In this case, DelegateChooser could provide an easy way to associate a different type of
157 delegate with each setting:
158
159 \qml
160 import QtQml.Models
161 import QtQuick
162 import QtQuick.Controls
163
164 ListView {
165 width: 200; height: 400
166
167 ListModel {
168 id: listModel
169 ListElement { type: "info"; ... }
170 ListElement { type: "switch"; ... }
171 ListElement { type: "swipe"; ... }
172 ListElement { type: "switch"; ... }
173 }
174
175 DelegateChooser {
176 id: chooser
177 role: "type"
178 DelegateChoice { roleValue: "info"; ItemDelegate { ... } }
179 DelegateChoice { roleValue: "switch"; SwitchDelegate { ... } }
180 DelegateChoice { roleValue: "swipe"; SwipeDelegate { ... } }
181 }
182
183 model: listModel
184 delegate: chooser
185 }
186 \endqml
187
188 \note This type is intended to transparently work only with TableView and any
189 DelegateModel-based view. Views (including user-defined views) that aren't internally based on a
190 DelegateModel need to explicitly support this type of component to make it function as described.
191
192 \sa DelegateChoice
193*/
194
195/*!
196 \qmlproperty string QtQml.Models::DelegateChooser::role
197 This property holds the role or the property name used to determine the delegate for a given model item.
198
199 \note For \l{QAbstractItemModel} based models, including \l{ListModel}, the DelegateChooser will
200 reevaluate the choice when the model signals that the role has changed. For any other type of model,
201 this choice will only be done once when the item for a given model index is created.
202
203 \sa DelegateChoice
204*/
205void QQmlDelegateChooser::setRole(const QString &role)
206{
207 if (m_role == role)
208 return;
209 m_role = role;
210 emit roleChanged();
211}
212
213/*!
214 \qmlproperty list<DelegateChoice> QtQml.Models::DelegateChooser::choices
215 \qmldefault
216
217 The list of DelegateChoices for the chooser.
218
219 The list is treated as an ordered list, where the first DelegateChoice to match
220 will be used be a view.
221
222 It should not generally be necessary to refer to the \c choices property,
223 as it is the default property for DelegateChooser and thus all child items are
224 automatically assigned to this property.
225*/
226
227QQmlListProperty<QQmlDelegateChoice> QQmlDelegateChooser::choices()
228{
229 return QQmlListProperty<QQmlDelegateChoice>(this, nullptr,
230 QQmlDelegateChooser::choices_append,
231 QQmlDelegateChooser::choices_count,
232 QQmlDelegateChooser::choices_at,
233 QQmlDelegateChooser::choices_clear,
234 QQmlDelegateChooser::choices_replace,
235 QQmlDelegateChooser::choices_removeLast);
236}
237
238void QQmlDelegateChooser::choices_append(QQmlListProperty<QQmlDelegateChoice> *prop, QQmlDelegateChoice *choice)
239{
240 QQmlDelegateChooser *q = static_cast<QQmlDelegateChooser *>(prop->object);
241 q->m_choices.append(choice);
242 connect(choice, &QQmlDelegateChoice::changed, q, &QQmlAbstractDelegateComponent::delegateChanged);
243 emit q->delegateChanged();
244}
245
246qsizetype QQmlDelegateChooser::choices_count(QQmlListProperty<QQmlDelegateChoice> *prop)
247{
248 QQmlDelegateChooser *q = static_cast<QQmlDelegateChooser*>(prop->object);
249 return q->m_choices.size();
250}
251
252QQmlDelegateChoice *QQmlDelegateChooser::choices_at(QQmlListProperty<QQmlDelegateChoice> *prop, qsizetype index)
253{
254 QQmlDelegateChooser *q = static_cast<QQmlDelegateChooser*>(prop->object);
255 return q->m_choices.at(index);
256}
257
258void QQmlDelegateChooser::choices_clear(QQmlListProperty<QQmlDelegateChoice> *prop)
259{
260 QQmlDelegateChooser *q = static_cast<QQmlDelegateChooser *>(prop->object);
261 for (QQmlDelegateChoice *choice : q->m_choices)
262 disconnect(choice, &QQmlDelegateChoice::changed, q, &QQmlAbstractDelegateComponent::delegateChanged);
263 q->m_choices.clear();
264 emit q->delegateChanged();
265}
266
267void QQmlDelegateChooser::choices_replace(QQmlListProperty<QQmlDelegateChoice> *prop,
268 qsizetype index, QQmlDelegateChoice *choice)
269{
270 QQmlDelegateChooser *q = static_cast<QQmlDelegateChooser *>(prop->object);
271 disconnect(q->m_choices[index], &QQmlDelegateChoice::changed,
272 q, &QQmlAbstractDelegateComponent::delegateChanged);
273 q->m_choices[index] = choice;
274 connect(choice, &QQmlDelegateChoice::changed, q,
275 &QQmlAbstractDelegateComponent::delegateChanged);
276 emit q->delegateChanged();
277}
278
279void QQmlDelegateChooser::choices_removeLast(QQmlListProperty<QQmlDelegateChoice> *prop)
280{
281 QQmlDelegateChooser *q = static_cast<QQmlDelegateChooser *>(prop->object);
282 disconnect(q->m_choices.takeLast(), &QQmlDelegateChoice::changed,
283 q, &QQmlAbstractDelegateComponent::delegateChanged);
284 emit q->delegateChanged();
285}
286
287QQmlComponent *QQmlDelegateChooser::delegate(QQmlAdaptorModel *adaptorModel, int row, int column) const
288{
289 QVariant v;
290 if (!m_role.isNull())
291 v = value(adaptorModel, row, column, m_role);
292 if (!v.isValid()) { // check if the row only has modelData, for example if the row is a QVariantMap
293 v = value(adaptorModel, row, column, QStringLiteral("modelData"));
294
295 if (v.isValid()) {
296 if (v.canConvert(QMetaType(QMetaType::QVariantMap)))
297 v = v.toMap().value(m_role);
298 else if (v.canConvert(QMetaType(QMetaType::QObjectStar)))
299 v = v.value<QObject*>()->property(m_role.toUtf8());
300 }
301 }
302
303 // loop through choices, finding first one that fits
304 for (int i = 0; i < m_choices.size(); ++i) {
305 const QQmlDelegateChoice *choice = m_choices.at(i);
306 if (choice->match(row, column, v))
307 return choice->delegate();
308 }
309
310 return nullptr;
311}
312
313QT_END_NAMESPACE
314
315#include "moc_qqmldelegatecomponent_p.cpp"