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
qqmllist.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 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 "qqmllist.h"
5#include "qqmllist_p.h"
6#include <QtQml/private/qqmlproperty_p.h>
7
9
10static bool isObjectCompatible(QObject *object, QQmlListReferencePrivate *d)
11{
12 if (object) {
13 const QQmlMetaObject elementType = d->elementType();
14 if (elementType.isNull() || !QQmlMetaObject::canConvert(object, elementType))
15 return false;
16 }
17 return true;
18}
19
24
25QQmlListReference QQmlListReferencePrivate::init(
26 const QQmlListProperty<QObject> &prop, QMetaType propType)
27{
29
30 if (!prop.object) return rv;
31
32 rv.d = new QQmlListReferencePrivate;
33 rv.d->object = prop.object;
34 rv.d->property = prop;
35 rv.d->propertyType = propType;
36
37 return rv;
38}
39
41{
42 Q_ASSERT(refCount > 0);
43 ++refCount;
44}
45
47{
48 Q_ASSERT(refCount > 0);
49 --refCount;
50 if (!refCount)
51 delete this;
52}
53
54/*!
55\class QQmlListReference
56\since 5.0
57\inmodule QtQml
58\brief The QQmlListReference class allows the manipulation of \l QQmlListProperty properties.
59
60QQmlListReference allows C++ programs to read from, and assign values to a QML list property in a
61simple and type-safe way. The main advantage over using \l QQmlListProperty itself is its type
62erasure: QQmlListReference is not a template, but can be used for QQmlListProperties of any type.
63Furthermore it watches the owner object for deletion and does not allow the \l QQmlListProperty
64to be accessed anymore if its owner has been deleted.
65
66You can create a QQmlListReference from either an object and a property name or from a QVariant.
67These two are equivalent:
68
69\code
70QQmlListReference ref1(object, "children");
71
72const QVariant var = object->property("children");
73QQmlListReference ref2(var);
74\endcode
75
76Not all QQmlListReferences support all operations. Methods like canAppend(),
77canAt(), canClear(), and canCount() allow programs to query whether an
78operation is supported on a given property. The availability of the methods
79depends on the methods implemented by the underlying \l QQmlListProperty. When
80constructing a \l QQmlListProperty by manually passing the accessor
81functions you can restrict access to the list by passing nullptr to some of them.
82QQmlListReference will recognize those and report them as unavailable.
83
84\l{QQmlListReference}s are type-safe. Only \l{QObject}s that derive of the
85correct base class can be added to the list. The listElementType() method can be
86used to query the \l QMetaObject of the \l QObject type that can be added.
87Attempting to add objects of an incorrect type to a list property will fail.
88
89Like with other lists, when accessing a list element by index, it is the
90callers responsibility to ensure that it does not request an out of range
91element. Use the count() method before calling at() to this effect.
92*/
93
94/*!
95\fn bool QQmlListReference::operator==(const QQmlListReference &other) const
96
97Compares this QQmlListReference to \a other, and returns \c true if they are
98equal. The two are only considered equal if one was created from the other
99via copy assignment or copy construction.
100
101\note Independently created references to the same object are not considered
102to be equal.
103*/
104
105/*!
106Constructs an invalid instance.
107*/
108QQmlListReference::QQmlListReference()
109: d(nullptr)
110{
111}
112
113#if QT_DEPRECATED_SINCE(6, 4)
114/*!
115\since 6.1
116\obsolete [6.4] Use the constructors without QQmlEngine argument instead.
117
118Constructs a QQmlListReference from a QVariant \a variant containing a QQmlListProperty. If
119\a variant does not contain a list property, an invalid QQmlListReference is created. If the object
120owning the list property is destroyed after the reference is constructed, it will automatically
121become invalid. That is, it is safe to hold QQmlListReference instances even after the object is
122deleted.
123
124The \a engine is unused.
125*/
126QQmlListReference::QQmlListReference(const QVariant &variant, [[maybe_unused]] QQmlEngine *engine)
127 : QQmlListReference(variant)
128{}
129
130/*!
131\obsolete [6.4] Use the constructors without QQmlEngine argument instead.
132
133Constructs a QQmlListReference for \a object's \a property. If \a property is not a list
134property, an invalid QQmlListReference is created. If \a object is destroyed after
135the reference is constructed, it will automatically become invalid. That is, it is safe to hold
136QQmlListReference instances even after \a object is deleted.
137
138The \a engine is unused.
139*/
140QQmlListReference::QQmlListReference(QObject *object, const char *property,
141 [[maybe_unused]] QQmlEngine *engine)
142 : QQmlListReference(object, property)
143{}
144#endif
145
146/*!
147\since 6.1
148
149Constructs a QQmlListReference from a QVariant \a variant containing a QQmlListProperty. If
150\a variant does not contain a list property, an invalid QQmlListReference is created. If the object
151owning the list property is destroyed after the reference is constructed, it will automatically
152become invalid. That is, it is safe to hold QQmlListReference instances even after the object is
153deleted.
154*/
155QQmlListReference::QQmlListReference(const QVariant &variant)
156 : d(nullptr)
157{
158 const QMetaType t = variant.metaType();
159 if (!(t.flags() & QMetaType::IsQmlList))
160 return;
161
162 d = new QQmlListReferencePrivate;
163 d->propertyType = t;
164
165 d->property.~QQmlListProperty();
166 t.construct(&d->property, variant.constData());
167
168 d->object = d->property.object;
169}
170
171/*!
172Constructs a QQmlListReference for \a object's \a property. If \a property is not a list
173property, an invalid QQmlListReference is created. If \a object is destroyed after
174the reference is constructed, it will automatically become invalid. That is, it is safe to hold
175QQmlListReference instances even after \a object is deleted.
176*/
177QQmlListReference::QQmlListReference(QObject *object, const char *property)
178 : d(nullptr)
179{
180 if (!object || !property) return;
181
182 QQmlPropertyData local;
183 const QQmlPropertyData *data =
184 QQmlPropertyCache::property(object, QLatin1String(property), nullptr, &local);
185
186 if (!data || !data->isQList()) return;
187
188 d = new QQmlListReferencePrivate;
189 d->object = object;
190 d->propertyType = data->propType();
191
192 void *args[] = { &d->property, nullptr };
193 QMetaObject::metacall(object, QMetaObject::ReadProperty, data->coreIndex(), args);
194}
195
196/*! \internal */
197QQmlListReference::QQmlListReference(const QQmlListReference &o)
198: d(o.d)
199{
200 if (d) d->addref();
201}
202
203/*! \internal */
204QQmlListReference &QQmlListReference::operator=(const QQmlListReference &o)
205{
206 if (o.d) o.d->addref();
207 if (d) d->release();
208 d = o.d;
209 return *this;
210}
211
212/*! \internal */
213QQmlListReference::~QQmlListReference()
214{
215 if (d) d->release();
216}
217
218/*!
219Returns true if the instance refers to a valid list property, otherwise false.
220*/
221bool QQmlListReference::isValid() const
222{
223 return d && d->object;
224}
225
226/*!
227Returns the list property's object. Returns \nullptr if the reference is invalid.
228*/
229QObject *QQmlListReference::object() const
230{
231 if (isValid()) return d->object;
232 else return nullptr;
233}
234
235/*!
236Returns the QMetaObject for the elements stored in the list property,
237or \nullptr if the reference is invalid.
238
239The QMetaObject can be used ahead of time to determine whether a given instance can be added
240to a list. If you didn't pass an engine on construction this may return nullptr.
241*/
242const QMetaObject *QQmlListReference::listElementType() const
243{
244 return isValid() ? d->elementType() : nullptr;
245}
246
247/*!
248Returns true if the list property can be appended to, otherwise false. Returns false if the
249reference is invalid.
250
251\sa append()
252*/
253bool QQmlListReference::canAppend() const
254{
255 return (isValid() && d->property.append);
256}
257
258/*!
259Returns true if the list property can queried by index, otherwise false. Returns false if the
260reference is invalid.
261
262\sa at()
263*/
264bool QQmlListReference::canAt() const
265{
266 return (isValid() && d->property.at);
267}
268
269/*!
270Returns true if the list property can be cleared, otherwise false. Returns false if the
271reference is invalid.
272
273\sa clear()
274*/
275bool QQmlListReference::canClear() const
276{
277 return (isValid() && d->property.clear);
278}
279
280/*!
281Returns true if the list property can be queried for its element count, otherwise false.
282Returns false if the reference is invalid.
283
284\sa count()
285*/
286bool QQmlListReference::canCount() const
287{
288 return (isValid() && d->property.count);
289}
290
291/*!
292Returns true if items in the list property can be replaced, otherwise false.
293Returns false if the reference is invalid.
294
295\sa replace()
296*/
297bool QQmlListReference::canReplace() const
298{
299 return (isValid() && d->property.replace);
300}
301
302/*!
303Returns true if the last item can be removed from the list property, otherwise false.
304Returns false if the reference is invalid.
305
306\sa removeLast()
307*/
308bool QQmlListReference::canRemoveLast() const
309{
310 return (isValid() && d->property.removeLast);
311}
312
313/*!
314 Return true if at(), count(), append(), and either clear() or removeLast()
315 are implemented, so you can manipulate the list.
316
317 Mind that replace() and removeLast() can be emulated by stashing all
318 items and rebuilding the list using clear() and append(). Therefore,
319 they are not required for the list to be manipulable. Furthermore,
320 clear() can be emulated using removeLast().
321
322\sa isReadable(), at(), count(), append(), clear(), replace(), removeLast()
323*/
324bool QQmlListReference::isManipulable() const
325{
326 return (isValid()
327 && d->property.append
328 && d->property.count
329 && d->property.at
330 && d->property.clear);
331}
332
333
334/*!
335 Return true if at() and count() are implemented, so you can access the elements.
336
337\sa isManipulable(), at(), count()
338*/
339bool QQmlListReference::isReadable() const
340{
341 return (isValid() && d->property.count && d->property.at);
342}
343
344/*!
345Appends \a object to the list. Returns true if the operation succeeded, otherwise false.
346
347\sa canAppend()
348*/
349bool QQmlListReference::append(QObject *object) const
350{
351 if (!canAppend()) return false;
352
353 if (!isObjectCompatible(object, d))
354 return false;
355
356 d->property.append(&d->property, object);
357
358 return true;
359}
360
361/*!
362Returns the list element at \a index, or \nullptr if the operation failed.
363
364\sa canAt()
365*/
366QObject *QQmlListReference::at(qsizetype index) const
367{
368 if (!canAt()) return nullptr;
369
370 return d->property.at(&d->property, index);
371}
372
373/*!
374Clears the list. Returns true if the operation succeeded, otherwise false.
375
376\sa canClear()
377*/
378bool QQmlListReference::clear() const
379{
380 if (!canClear()) return false;
381
382 d->property.clear(&d->property);
383
384 return true;
385}
386
387/*!
388Returns the number of items in the list, or 0 if the operation failed.
389*/
390qsizetype QQmlListReference::count() const
391{
392 if (!canCount()) return 0;
393
394 return d->property.count(&d->property);
395}
396
397/*!
398\fn qsizetype QQmlListReference::size() const
399\since 6.2
400Returns the number of items in the list, or 0 if the operation failed.
401*/
402
403/*!
404Replaces the item at \a index in the list with \a object.
405Returns true if the operation succeeded, otherwise false.
406
407\sa canReplace()
408*/
409bool QQmlListReference::replace(qsizetype index, QObject *object) const
410{
411 if (!canReplace())
412 return false;
413
414 if (!isObjectCompatible(object, d))
415 return false;
416
417 d->property.replace(&d->property, index, object);
418 return true;
419}
420
421/*!
422Removes the last item in the list.
423Returns true if the operation succeeded, otherwise false.
424
425\sa canRemoveLast()
426*/
427bool QQmlListReference::removeLast() const
428{
429 if (!canRemoveLast())
430 return false;
431
432 d->property.removeLast(&d->property);
433 return true;
434}
435
436/*!
437\class QQmlListProperty
438\since 5.0
439\inmodule QtQml
440\brief The QQmlListProperty class allows applications to expose list-like
441properties of QObject-derived classes to QML.
442
443QML has many list properties, where more than one object value can be assigned.
444The use of a list property from QML looks like this:
445
446\code
447FruitBasket {
448 fruit: [
449 Apple {},
450 Orange{},
451 Banana{}
452 ]
453}
454\endcode
455
456The QQmlListProperty encapsulates a group of function pointers that represent the
457set of actions QML can perform on the list - adding items, retrieving items and
458clearing the list. In the future, additional operations may be supported. All
459list properties must implement the append operation, but the rest are optional.
460
461To provide a list property, a C++ class must implement the operation callbacks,
462and then return an appropriate QQmlListProperty value from the property getter.
463List properties should have no setter. In the example above, the Q_PROPERTY()
464declarative will look like this:
465
466\code
467Q_PROPERTY(QQmlListProperty<Fruit> fruit READ fruit)
468\endcode
469
470QML list properties are type-safe. The template parameter \a T specifies the
471QObject-derived type that can be stored in the list. In this case \c {Fruit}
472is a QObject type that \c {Apple}, \c {Orange} and \c {Banana} all derive from.
473
474You can use \l{QQmlListReference} to manipulate a QQmlListProperty from C++ using
475a slightly more ergonomic API, at the cost of some overhead.
476
477\sa {Chapter 5: Using List Property Types}, QQmlListReference
478*/
479
480/*!
481 \macro QML_LIST_PROPERTY_ASSIGN_BEHAVIOR_APPEND
482 \relates QQmlListProperty
483
484 This macro defines the behavior of the list properties of this class to Append.
485 When assigning the property in a derived type, the values are appended
486 to those of the base class. This is the default behavior.
487
488 \snippet code/src_qml_qqmllist.cpp 0
489
490 \sa QML_LIST_PROPERTY_ASSIGN_BEHAVIOR_REPLACE_IF_NOT_DEFAULT
491 \sa QML_LIST_PROPERTY_ASSIGN_BEHAVIOR_REPLACE
492 \sa {Defining Object Types through QML Documents}
493*/
494
495/*!
496 \macro QML_LIST_PROPERTY_ASSIGN_BEHAVIOR_REPLACE_IF_NOT_DEFAULT
497 \relates QQmlListProperty
498
499 This macro defines the behavior of the list properties of this class to
500 ReplaceIfNotDefault.
501 When assigning the property in a derived type, the values replace those of
502 the base class unless it's the default property.
503 In the case of the default property, values are appended to those of the base class.
504
505 \snippet code/src_qml_qqmllist.cpp 1
506
507 \sa QML_LIST_PROPERTY_ASSIGN_BEHAVIOR_APPEND
508 \sa QML_LIST_PROPERTY_ASSIGN_BEHAVIOR_REPLACE
509 \sa {Defining Object Types through QML Documents}
510*/
511
512/*!
513 \macro QML_LIST_PROPERTY_ASSIGN_BEHAVIOR_REPLACE
514 \relates QQmlListProperty
515
516 This macro defines the behavior of the list properties of this class to Replace.
517 When assigning the property in a derived type, the values replace those
518 of the base class.
519
520 \snippet code/src_qml_qqmllist.cpp 2
521
522 \sa QML_LIST_PROPERTY_ASSIGN_BEHAVIOR_APPEND
523 \sa QML_LIST_PROPERTY_ASSIGN_BEHAVIOR_REPLACE_IF_NOT_DEFAULT
524 \sa {Defining Object Types through QML Documents}
525*/
526
527/*!
528\fn template<typename T> QQmlListProperty<T>::QQmlListProperty()
529\internal
530*/
531
532/*!
533\fn template<typename T> QQmlListProperty<T>::QQmlListProperty(QObject *object, QList<T *> &list)
534\deprecated
535
536Convenience constructor for making a QQmlListProperty value from an existing
537QList \a list. The \a object owning the list and the \a list itself must be
538provided and kept alive as long as you are holding a QQmlListProperty referring
539to them.
540
541This constructor synthesizes the removeLast() and replace() methods
542introduced in Qt 5.15, using count(), at(), clear(), and append(). This is slow.
543If you intend to manipulate the list beyond clearing it, you should explicitly
544provide these methods.
545*/
546
547/*!
548\fn template<typename T> QQmlListProperty<T>::QQmlListProperty(QObject *object, QList<T *> *list)
549\since 5.15
550
551Convenience constructor for making a QQmlListProperty value from an existing
552QList \a list. The \a object owning the list and the \a list itself must be
553provided and kept alive as long as you are holding a QQmlListProperty referring
554to them.
555
556This is the easiest and safest way to provide a QQmlListProperty backed by a QList
557and should be used in most cases. A typical invocation looks like this:
558
559\snippet tutorials/extending-qml/chapter5-listproperties/piechart.cpp 0
560*/
561
562/*!
563\fn template<typename T> QQmlListProperty<T>::QQmlListProperty(QObject *object, void *data,
564 CountFunction count, AtFunction at)
565
566Construct a readonly QQmlListProperty from a set of operation functions
567\a count and \a at. An opaque \a data handle may be passed which can be
568accessed from within the operation functions. The list property
569remains valid while the \a object owning the list property exists.
570*/
571
572/*!
573\fn template<typename T> QQmlListProperty<T>::QQmlListProperty(QObject *object, void *data, AppendFunction append,
574 CountFunction count, AtFunction at,
575 ClearFunction clear)
576
577Construct a QQmlListProperty from a set of operation functions \a append,
578\a count, \a at, and \a clear. An opaque \a data handle may be passed which
579can be accessed from within the operation functions. The list property
580remains valid while the \a object owning the list property exists.
581
582Null pointers can be passed for any function. If any null pointers are passed in, the list
583will be neither designable nor alterable by the debugger. It is recommended to provide valid
584pointers for all functions.
585
586\note The resulting QQmlListProperty will synthesize the removeLast() and
587replace() methods using \a count, \a at, \a clear, and \a append if all of those
588are given. This is slow. If you intend to manipulate the list beyond clearing it,
589you should explicitly provide these methods.
590*/
591
592/*!
593\fn template<typename T> QQmlListProperty<T>::QQmlListProperty(
594 QObject *object, void *data, AppendFunction append, CountFunction count,
595 AtFunction at, ClearFunction clear, ReplaceFunction replace,
596 RemoveLastFunction removeLast)
597
598Construct a QQmlListProperty from a set of operation functions \a append,
599\a count, \a at, \a clear, \a replace, and \removeLast. An opaque \a data handle
600may be passed which can be accessed from within the operation functions. The
601list property remains valid while the \a object owning the list property
602exists.
603
604Null pointers can be passed for any function, causing the respective function to
605be synthesized using the others, if possible. QQmlListProperty can synthesize
606\list
607 \li \a clear using \a count and \a removeLast
608 \li \a replace using \a count, \a at, \a clear, and \a append
609 \li \a replace using \a count, \a at, \a removeLast, and \a append
610 \li \a removeLast using \a count, \a at, \a clear, and \a append
611\endlist
612if those are given. This is slow, but if your list does not natively provide
613faster options for these primitives, you may want to use the synthesized ones.
614
615Furthermore, if either of \a count, \a at, \a append, and \a clear are neither
616given explicitly nor synthesized, the list will be neither designable nor
617alterable by the debugger. It is recommended to provide enough valid pointers
618to avoid this situation.
619*/
620
621/*!
622\typedef QQmlListProperty::AppendFunction
623
624Synonym for \c {void (*)(QQmlListProperty<T> *property, T *value)}.
625
626Append the \a value to the list \a property.
627*/
628
629/*!
630\typedef QQmlListProperty::CountFunction
631
632Synonym for \c {qsizetype (*)(QQmlListProperty<T> *property)}.
633
634Return the number of elements in the list \a property.
635*/
636
637/*!
638\fn template<typename T> bool QQmlListProperty<T>::operator==(const QQmlListProperty &other) const
639
640Returns true if this QQmlListProperty is equal to \a other, otherwise false.
641*/
642
643/*!
644\typedef QQmlListProperty::AtFunction
645
646Synonym for \c {T *(*)(QQmlListProperty<T> *property, qsizetype index)}.
647
648Return the element at position \a index in the list \a property.
649*/
650
651/*!
652\typedef QQmlListProperty::ClearFunction
653
654Synonym for \c {void (*)(QQmlListProperty<T> *property)}.
655
656Clear the list \a property.
657*/
658
659/*!
660\typedef QQmlListProperty::ReplaceFunction
661
662Synonym for \c {void (*)(QQmlListProperty<T> *property, qsizetype index, T *value)}.
663
664Replace the element at position \a index in the list \a property with \a value.
665*/
666
667/*!
668\typedef QQmlListProperty::RemoveLastFunction
669
670Synonym for \c {void (*)(QQmlListProperty<T> *property)}.
671
672Remove the last element from the list \a property.
673*/
674
675/*!
676\variable QQmlListProperty::object
677\brief This field holds the \e owner of the QQmlListProperty
678
679When manually implementing the accessor methods, you may need to use this field
680for retrieving the content of the manipulated list.
681*/
682
683/*!
684\variable QQmlListProperty::data
685\brief This field can hold an arbitrary data pointer
686
687If you manually implement the accessor methods and need to store custom data,
688you can pass an arbitrary pointer to the QQmlListProperty constructor and
689retrieve it from the \e data field when accessing the same QQmlListProperty
690later.
691
692A \l{QQmlListProperty(QObject *object, QList<T *> *list)}{QQmlListProperty constructed from a QList pointer}
693uses this field to store the pointer to the list itself, as it cannot directly
694access the list contents from the owner.
695
696*/
697
698QT_END_NAMESPACE
The QQmlListProperty class allows applications to expose list-like properties of QObject-derived clas...
Definition qqmllist.h:24
const QMetaObject * elementType()
Definition qqmllist_p.h:46
The QQmlListReference class allows the manipulation of \l QQmlListProperty properties.
Definition qqmllist.h:189
Combined button and popup list for selecting options.
static QT_BEGIN_NAMESPACE bool isObjectCompatible(QObject *object, QQmlListReferencePrivate *d)
Definition qqmllist.cpp:10