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 - in this case \c {Fruit} is a QObject type that
471\c {Apple}, \c {Orange} and \c {Banana} all derive from.
472
473You can use \l{QQmlListReference} to manipulate a QQmlListProperty from C++ using
474a slightly more ergonomic API, at the cost of some overhead.
475
476\sa {Chapter 5: Using List Property Types}, QQmlListReference
477*/
478
479/*!
480 \macro QML_LIST_PROPERTY_ASSIGN_BEHAVIOR_APPEND
481 \relates QQmlListProperty
482
483 This macro defines the behavior of the list properties of this class to Append.
484 When assigning the property in a derived type, the values are appended
485 to those of the base class. This is the default behavior.
486
487 \snippet code/src_qml_qqmllist.cpp 0
488
489 \sa QML_LIST_PROPERTY_ASSIGN_BEHAVIOR_REPLACE_IF_NOT_DEFAULT
490 \sa QML_LIST_PROPERTY_ASSIGN_BEHAVIOR_REPLACE
491 \sa {Defining Object Types through QML Documents}
492*/
493
494/*!
495 \macro QML_LIST_PROPERTY_ASSIGN_BEHAVIOR_REPLACE_IF_NOT_DEFAULT
496 \relates QQmlListProperty
497
498 This macro defines the behavior of the list properties of this class to
499 ReplaceIfNotDefault.
500 When assigning the property in a derived type, the values replace those of
501 the base class unless it's the default property.
502 In the case of the default property, values are appended to those of the base class.
503
504 \snippet code/src_qml_qqmllist.cpp 1
505
506 \sa QML_LIST_PROPERTY_ASSIGN_BEHAVIOR_APPEND
507 \sa QML_LIST_PROPERTY_ASSIGN_BEHAVIOR_REPLACE
508 \sa {Defining Object Types through QML Documents}
509*/
510
511/*!
512 \macro QML_LIST_PROPERTY_ASSIGN_BEHAVIOR_REPLACE
513 \relates QQmlListProperty
514
515 This macro defines the behavior of the list properties of this class to Replace.
516 When assigning the property in a derived type, the values replace those
517 of the base class.
518
519 \snippet code/src_qml_qqmllist.cpp 2
520
521 \sa QML_LIST_PROPERTY_ASSIGN_BEHAVIOR_APPEND
522 \sa QML_LIST_PROPERTY_ASSIGN_BEHAVIOR_REPLACE_IF_NOT_DEFAULT
523 \sa {Defining Object Types through QML Documents}
524*/
525
526/*!
527\fn template<typename T> QQmlListProperty<T>::QQmlListProperty()
528\internal
529*/
530
531/*!
532\fn template<typename T> QQmlListProperty<T>::QQmlListProperty(QObject *object, QList<T *> &list)
533\deprecated
534
535Convenience constructor for making a QQmlListProperty value from an existing
536QList \a list. The \a object owning the list and the \a list itself must be
537provided and kept alive as long as you are holding a QQmlListProperty referring
538to them.
539
540This constructor synthesizes the removeLast() and replace() methods
541introduced in Qt 5.15, using count(), at(), clear(), and append(). This is slow.
542If you intend to manipulate the list beyond clearing it, you should explicitly
543provide these methods.
544*/
545
546/*!
547\fn template<typename T> QQmlListProperty<T>::QQmlListProperty(QObject *object, QList<T *> *list)
548\since 5.15
549
550Convenience constructor for making a QQmlListProperty value from an existing
551QList \a list. The \a object owning the list and the \a list itself must be
552provided and kept alive as long as you are holding a QQmlListProperty referring
553to them.
554
555This is the easiest and safest way to provide a QQmlListProperty backed by a QList
556and should be used in most cases. A typical invocation looks like this:
557
558\snippet tutorials/extending-qml/chapter5-listproperties/piechart.cpp 0
559*/
560
561/*!
562\fn template<typename T> QQmlListProperty<T>::QQmlListProperty(QObject *object, void *data,
563 CountFunction count, AtFunction at)
564
565Construct a readonly QQmlListProperty from a set of operation functions
566\a count and \a at. An opaque \a data handle may be passed which can be
567accessed from within the operation functions. The list property
568remains valid while the \a object owning the list property exists.
569*/
570
571/*!
572\fn template<typename T> QQmlListProperty<T>::QQmlListProperty(QObject *object, void *data, AppendFunction append,
573 CountFunction count, AtFunction at,
574 ClearFunction clear)
575
576Construct a QQmlListProperty from a set of operation functions \a append,
577\a count, \a at, and \a clear. An opaque \a data handle may be passed which
578can be accessed from within the operation functions. The list property
579remains valid while the \a object owning the list property exists.
580
581Null pointers can be passed for any function. If any null pointers are passed in, the list
582will be neither designable nor alterable by the debugger. It is recommended to provide valid
583pointers for all functions.
584
585\note The resulting QQmlListProperty will synthesize the removeLast() and
586replace() methods using \a count, \a at, \a clear, and \a append if all of those
587are given. This is slow. If you intend to manipulate the list beyond clearing it,
588you should explicitly provide these methods.
589*/
590
591/*!
592\fn template<typename T> QQmlListProperty<T>::QQmlListProperty(
593 QObject *object, void *data, AppendFunction append, CountFunction count,
594 AtFunction at, ClearFunction clear, ReplaceFunction replace,
595 RemoveLastFunction removeLast)
596
597Construct a QQmlListProperty from a set of operation functions \a append,
598\a count, \a at, \a clear, \a replace, and \removeLast. An opaque \a data handle
599may be passed which can be accessed from within the operation functions. The
600list property remains valid while the \a object owning the list property
601exists.
602
603Null pointers can be passed for any function, causing the respective function to
604be synthesized using the others, if possible. QQmlListProperty can synthesize
605\list
606 \li \a clear using \a count and \a removeLast
607 \li \a replace using \a count, \a at, \a clear, and \a append
608 \li \a replace using \a count, \a at, \a removeLast, and \a append
609 \li \a removeLast using \a count, \a at, \a clear, and \a append
610\endlist
611if those are given. This is slow, but if your list does not natively provide
612faster options for these primitives, you may want to use the synthesized ones.
613
614Furthermore, if either of \a count, \a at, \a append, and \a clear are neither
615given explicitly nor synthesized, the list will be neither designable nor
616alterable by the debugger. It is recommended to provide enough valid pointers
617to avoid this situation.
618*/
619
620/*!
621\typedef QQmlListProperty::AppendFunction
622
623Synonym for \c {void (*)(QQmlListProperty<T> *property, T *value)}.
624
625Append the \a value to the list \a property.
626*/
627
628/*!
629\typedef QQmlListProperty::CountFunction
630
631Synonym for \c {qsizetype (*)(QQmlListProperty<T> *property)}.
632
633Return the number of elements in the list \a property.
634*/
635
636/*!
637\fn template<typename T> bool QQmlListProperty<T>::operator==(const QQmlListProperty &other) const
638
639Returns true if this QQmlListProperty is equal to \a other, otherwise false.
640*/
641
642/*!
643\typedef QQmlListProperty::AtFunction
644
645Synonym for \c {T *(*)(QQmlListProperty<T> *property, qsizetype index)}.
646
647Return the element at position \a index in the list \a property.
648*/
649
650/*!
651\typedef QQmlListProperty::ClearFunction
652
653Synonym for \c {void (*)(QQmlListProperty<T> *property)}.
654
655Clear the list \a property.
656*/
657
658/*!
659\typedef QQmlListProperty::ReplaceFunction
660
661Synonym for \c {void (*)(QQmlListProperty<T> *property, qsizetype index, T *value)}.
662
663Replace the element at position \a index in the list \a property with \a value.
664*/
665
666/*!
667\typedef QQmlListProperty::RemoveLastFunction
668
669Synonym for \c {void (*)(QQmlListProperty<T> *property)}.
670
671Remove the last element from the list \a property.
672*/
673
674/*!
675\variable QQmlListProperty::object
676\brief This field holds the \e owner of the QQmlListProperty
677
678When manually implementing the accessor methods, you may need to use this field
679for retrieving the content of the manipulated list.
680*/
681
682/*!
683\variable QQmlListProperty::data
684\brief This field can hold an arbitrary data pointer
685
686If you manually implement the accessor methods and need to store custom data,
687you can pass an arbitrary pointer to the QQmlListProperty constructor and
688retrieve it from the \e data field when accessing the same QQmlListProperty
689later.
690
691A \l{QQmlListProperty(QObject *object, QList<T *> *list)}{QQmlListProperty constructed from a QList pointer}
692uses this field to store the pointer to the list itself, as it cannot directly
693access the list contents from the owner.
694
695*/
696
697QT_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:183
Combined button and popup list for selecting options.
static QT_BEGIN_NAMESPACE bool isObjectCompatible(QObject *object, QQmlListReferencePrivate *d)
Definition qqmllist.cpp:10