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