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