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
qqmlpropertydata_p.h
Go to the documentation of this file.
1// Copyright (C) 2019 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#ifndef QQMLPROPERTYDATA_P_H
5#define QQMLPROPERTYDATA_P_H
6
7//
8// W A R N I N G
9// -------------
10//
11// This file is not part of the Qt API. It exists purely as an
12// implementation detail. This header file may change from version to
13// version without notice, or even be removed.
14//
15// We mean it.
16//
17
18#include <private/qobject_p.h>
19#include <QtCore/qglobal.h>
20#include <QtCore/qversionnumber.h>
21
22QT_BEGIN_NAMESPACE
23
24class QQmlPropertyCacheMethodArguments;
26{
27public:
34 Q_DECLARE_FLAGS(WriteFlags, WriteFlag)
35
37
38 struct Flags {
39 friend class QQmlPropertyData;
40 enum Type {
42 FunctionType = 1, // Is an invokable
43 QObjectDerivedType = 2, // Property type is a QObject* derived type
44 EnumType = 3, // Property type is an enum
45 QListType = 4, // Property type is a QML list
46 VarPropertyType = 5, // Property type is a "var" property of VMEMO
47 QVariantType = 6, // Property is a QVariant
48 // One spot left for an extra type in the 3 bits used to store this.
49 };
50
51 private:
52 // The _otherBits (which "pad" the Flags struct to align it nicely) are used
53 // to store the relative property index. It will only get used when said index fits. See
54 // trySetStaticMetaCallFunction for details.
55 // (Note: this padding is done here, because certain compilers have surprising behavior
56 // when an enum is declared in-between two bit fields.)
57 enum { BitsLeftInFlags = 14 };
58 unsigned otherBits : BitsLeftInFlags; // align to 32 bits
59
60 // Members of the form aORb can only be a when type is not FunctionType, and only be
61 // b when type equals FunctionType. For that reason, the semantic meaning of the bit is
62 // overloaded, and the accessor functions are used to get the correct value
63 //
64 // Moreover, isSignalHandler, isOverridableSignal and isCloned make only sense
65 // for functions, too (and could at a later point be reused for flags that only make sense
66 // for non-functions)
67 //
68 // Lastly, isDirect and isOverridden apply to both functions and non-functions
69 unsigned isConst : 1; // Property: has CONST flag/Method: is const
70 unsigned isDeepAliasORisVMEFunction : 1; // Alias points into value type OR Function was added by QML
71 unsigned isWritableORhasArguments : 1; // Has WRITE function OR Function takes arguments
72 unsigned isResettableORisSignal : 1; // Has RESET function OR Function is a signal
73 unsigned isAliasORisVMESignal : 1; // Is a QML alias to another property OR Signal was added by QML
74 unsigned isFinalORisV4Function : 1; // Has FINAL flag OR Function takes QQmlV4FunctionPtr args
75 unsigned isSignalHandler : 1; // Function is a signal handler
76
77 // TODO: Remove this once we can. Signals should not be overridable.
78 unsigned isOverridableSignal : 1; // Function is an overridable signal
79
80 unsigned isRequiredORisCloned : 1; // Has REQUIRED flag OR The function was marked as cloned
81 unsigned isConstructorORisBindable : 1; // The function was marked is a constructor OR property is backed by QProperty<T>
82 unsigned isVirtual : 1; // Property: has VIRTUAL specifier
83 // This flag is named doesOverride to avoid potential misspell issues,
84 // that could be caused by naming it isOverriding or isOverride,
85 // since there is alread isOverriden flag
86 unsigned doesOverride : 1; // Property: has OVERRIDE specifier, overrides virtual property
87 unsigned isOverridden : 1; // Is overridden by a extension property
88 unsigned hasMetaObject : 1;
89 unsigned type : 3; // stores an entry of Types
90
91 // Internal QQmlPropertyCache flags
92 unsigned overrideIndexIsProperty : 1;
93
94 public:
95 inline Flags();
96 inline bool operator==(const Flags &other) const;
97 inline void copyPropertyTypeFlags(Flags from);
98
99 void setIsConstant(bool b) {
100 isConst = b;
101 }
102
103 void setIsWritable(bool b) {
104 Q_ASSERT(type != FunctionType);
105 isWritableORhasArguments = b;
106 }
107
108 void setIsResettable(bool b) {
109 Q_ASSERT(type != FunctionType);
110 isResettableORisSignal = b;
111 }
112
113 void setIsAlias(bool b) {
114 Q_ASSERT(type != FunctionType);
115 isAliasORisVMESignal = b;
116 }
117
118 void setIsDeepAlias(bool b) {
119 Q_ASSERT(type != FunctionType);
120 isDeepAliasORisVMEFunction = b;
121 }
122
123 void setIsFinal(bool b) {
124 Q_ASSERT(type != FunctionType);
125 isFinalORisV4Function = b;
126 }
127
128 void setIsVirtual(bool b) {
129 isVirtual = b;
130 }
131
132 void setDoesOverride(bool b) {
133 doesOverride = b;
134 }
135
136 void setIsOverridden(bool b) {
137 isOverridden = b;
138 }
139
140 void setIsBindable(bool b) {
141 Q_ASSERT(type != FunctionType);
142 isConstructorORisBindable = b;
143 }
144
145 void setIsRequired(bool b) {
146 Q_ASSERT(type != FunctionType);
147 isRequiredORisCloned = b;
148 }
149
150 void setIsVMEFunction(bool b) {
151 Q_ASSERT(type == FunctionType);
152 isDeepAliasORisVMEFunction = b;
153 }
154
155 void setHasArguments(bool b) {
156 Q_ASSERT(type == FunctionType);
157 isWritableORhasArguments = b;
158 }
159 void setIsSignal(bool b) {
160 Q_ASSERT(type == FunctionType);
161 isResettableORisSignal = b;
162 }
163 void setIsVMESignal(bool b) {
164 Q_ASSERT(type == FunctionType);
165 isAliasORisVMESignal = b;
166 }
167
168 void setIsV4Function(bool b) {
169 Q_ASSERT(type == FunctionType);
170 isFinalORisV4Function = b;
171 }
172
173 void setIsSignalHandler(bool b) {
174 Q_ASSERT(type == FunctionType);
175 isSignalHandler = b;
176 }
177
178 // TODO: Remove this once we can. Signals should not be overridable.
180 Q_ASSERT(type == FunctionType);
181 Q_ASSERT(isResettableORisSignal);
182 isOverridableSignal = b;
183 }
184
185 void setIsCloned(bool b) {
186 Q_ASSERT(type == FunctionType);
187 isRequiredORisCloned = b;
188 }
189
190 void setIsConstructor(bool b) {
191 Q_ASSERT(type == FunctionType);
192 isConstructorORisBindable = b;
193 }
194
195 void setHasMetaObject(bool b) {
196 hasMetaObject = b;
197 }
198
199 void setType(Type newType) {
200 type = newType;
201 }
202 };
203
204
205 inline bool operator==(const QQmlPropertyData &) const;
206
207 Flags flags() const { return m_flags; }
209 {
210 unsigned otherBits = m_flags.otherBits;
211 m_flags = f;
212 m_flags.otherBits = otherBits;
213 }
214
215 bool isValid() const { return coreIndex() != -1; }
216
217 bool isConstant() const { return m_flags.isConst; }
218 bool isWritable() const { return !isFunction() && m_flags.isWritableORhasArguments; }
219 void setWritable(bool onoff) { Q_ASSERT(!isFunction()); m_flags.isWritableORhasArguments = onoff; }
220 bool isResettable() const { return !isFunction() && m_flags.isResettableORisSignal; }
221 bool isAlias() const { return !isFunction() && m_flags.isAliasORisVMESignal; }
222 bool isFinal() const { return !isFunction() && m_flags.isFinalORisV4Function; }
223 bool isVirtual() const { return m_flags.isVirtual; }
224 bool doesOverride() const { return m_flags.doesOverride; }
225 bool isOverridden() const { return m_flags.isOverridden; }
226 bool isRequired() const { return !isFunction() && m_flags.isRequiredORisCloned; }
227 bool isFunction() const { return m_flags.type == Flags::FunctionType; }
228 bool isQObject() const { return m_flags.type == Flags::QObjectDerivedType; }
229 bool isEnum() const { return m_flags.type == Flags::EnumType; }
230 bool isQList() const { return m_flags.type == Flags::QListType; }
231 bool isVarProperty() const { return m_flags.type == Flags::VarPropertyType; }
232 bool isQVariant() const { return m_flags.type == Flags::QVariantType; }
233 bool isVMEFunction() const { return isFunction() && m_flags.isDeepAliasORisVMEFunction; }
234 bool hasArguments() const { return isFunction() && m_flags.isWritableORhasArguments; }
235 bool isSignal() const { return isFunction() && m_flags.isResettableORisSignal; }
236 bool isVMESignal() const { return isFunction() && m_flags.isAliasORisVMESignal; }
237 bool isV4Function() const { return isFunction() && m_flags.isFinalORisV4Function; }
238 bool isSignalHandler() const { return m_flags.isSignalHandler; }
239 bool hasMetaObject() const { return m_flags.hasMetaObject; }
240
242 {
243 return !isAlias() && staticMetaCallFunction() != nullptr;
244 }
245
246 // TODO: Remove this once we can. Signals should not be overridable.
247 bool isOverridableSignal() const { return m_flags.isOverridableSignal; }
248
249 bool isCloned() const { return isFunction() && m_flags.isRequiredORisCloned; }
250 bool isConstructor() const { return isFunction() && m_flags.isConstructorORisBindable; }
251
252 bool notifiesViaBindable() const { return !isFunction() && m_flags.isConstructorORisBindable; }
253 bool acceptsQBinding() const { return notifiesViaBindable() && !m_flags.isDeepAliasORisVMEFunction; }
254
255 bool hasOverride() const { return overrideIndex() >= 0; }
256 bool hasRevision() const { return revision() != QTypeRevision::zero(); }
257
258 QMetaType propType() const { return m_propType; }
259 void setPropType(QMetaType pt)
260 {
261 m_propType = pt;
262 }
263
264 int notifyIndex() const { return m_notifyIndex; }
265 void setNotifyIndex(int idx)
266 {
267 Q_ASSERT(idx >= std::numeric_limits<qint16>::min());
268 Q_ASSERT(idx <= std::numeric_limits<qint16>::max());
269 m_notifyIndex = qint16(idx);
270 }
271
272 bool overrideIndexIsProperty() const { return m_flags.overrideIndexIsProperty; }
273 void setOverrideIndexIsProperty(bool onoff) { m_flags.overrideIndexIsProperty = onoff; }
274
275 int overrideIndex() const { return m_overrideIndex; }
276 void setOverrideIndex(int idx)
277 {
278 Q_ASSERT(idx >= std::numeric_limits<qint16>::min());
279 Q_ASSERT(idx <= std::numeric_limits<qint16>::max());
280 m_overrideIndex = qint16(idx);
281 }
282
283 int coreIndex() const { return m_coreIndex; }
284 void setCoreIndex(int idx)
285 {
286 Q_ASSERT(idx >= std::numeric_limits<qint16>::min());
287 Q_ASSERT(idx <= std::numeric_limits<qint16>::max());
288 m_coreIndex = qint16(idx);
289 }
290
291 int aliasTarget() const
292 {
293 Q_ASSERT(isAlias());
294 return m_encodedAliasTargetIndex;
295 }
296 void setAliasTarget(int target)
297 {
298 Q_ASSERT(isAlias());
299 m_encodedAliasTargetIndex = target;
300 }
301
302 QTypeRevision revision() const { return m_revision; }
303 void setRevision(QTypeRevision revision) { m_revision = revision; }
304
305 /* If a property is a C++ type, then we store the minor
306 * version of this type.
307 * This is required to resolve property or signal revisions
308 * if this property is used as a grouped property.
309 *
310 * Test.qml
311 * property TextEdit someTextEdit: TextEdit {}
312 *
313 * Test {
314 * someTextEdit.preeditText: "test" //revision 7
315 * someTextEdit.onEditingFinished: console.log("test") //revision 6
316 * }
317 *
318 * To determine if these properties with revisions are available we need
319 * the minor version of TextEdit as imported in Test.qml.
320 *
321 */
322
323 QTypeRevision typeVersion() const { return m_typeVersion; }
324 void setTypeVersion(QTypeRevision typeVersion) { m_typeVersion = typeVersion; }
325
327 {
328 Q_ASSERT(!hasMetaObject());
329 return m_arguments;
330 }
332 {
333 Q_ASSERT(!hasMetaObject());
334 m_arguments = args;
335 }
336
337 const QMetaObject *metaObject() const
338 {
339 Q_ASSERT(hasMetaObject());
340 return m_metaObject;
341 }
342
343 void setMetaObject(const QMetaObject *metaObject)
344 {
345 Q_ASSERT(!hasArguments() || !m_arguments);
346 m_flags.setHasMetaObject(true);
347 m_metaObject = metaObject;
348 }
349
351 {
352 Q_ASSERT(hasMetaObject());
353 Q_ASSERT(isFunction());
354 return m_metaObject->method(m_coreIndex);
355 }
356
357 int metaObjectOffset() const { return m_metaObjectOffset; }
359 {
360 Q_ASSERT(off >= std::numeric_limits<qint16>::min());
361 Q_ASSERT(off <= std::numeric_limits<qint16>::max());
362 m_metaObjectOffset = qint16(off);
363 }
364
366 {
367 Q_ASSERT(!isFunction() && !isAlias());
368 return m_staticMetaCallFunction;
369 }
370
371 void trySetStaticMetaCallFunction(StaticMetaCallFunction f, unsigned relativePropertyIndex)
372 {
373 Q_ASSERT(!isFunction() && !isAlias());
374 if (relativePropertyIndex < (1 << Flags::BitsLeftInFlags) - 1) {
375 m_flags.otherBits = relativePropertyIndex;
376 m_staticMetaCallFunction = f;
377 }
378 }
379 quint16 relativePropertyIndex() const { Q_ASSERT(hasStaticMetaCallFunction()); return m_flags.otherBits; }
380
381 static Flags flagsForProperty(const QMetaProperty &);
382 void load(const QMetaProperty &);
383 void load(const QMetaMethod &);
384
385 QString name(QObject *object) const { return object ? name(object->metaObject()) : QString(); }
386 QString name(const QMetaObject *metaObject) const
387 {
388 if (!metaObject || m_coreIndex == -1)
389 return QString();
390
391 return QString::fromUtf8(isFunction()
392 ? metaObject->method(m_coreIndex).name().constData()
393 : metaObject->property(m_coreIndex).name());
394 }
395
396 void markAsOverrideOf(QQmlPropertyData *predecessor);
397
398 inline void readProperty(QObject *target, void *property) const
399 {
400 void *args[] = { property, nullptr };
401 readPropertyWithArgs(target, args);
402 }
403
404 // This is the same as QMetaObject::metacall(), but inlined here to avoid a function call.
405 // And we ignore the return value.
406 template<QMetaObject::Call call>
407 void doMetacall(QObject *object, int idx, void **argv) const
408 {
409 if (QDynamicMetaObjectData *dynamicMetaObject = QObjectPrivate::get(object)->metaObject)
410 dynamicMetaObject->metaCall(object, call, idx, argv);
411 else
412 object->qt_metacall(call, idx, argv);
413 }
414
415 void readPropertyWithArgs(QObject *target, void *args[]) const
416 {
417 if (hasStaticMetaCallFunction())
418 staticMetaCallFunction()(target, QMetaObject::ReadProperty, relativePropertyIndex(), args);
419 else
420 doMetacall<QMetaObject::ReadProperty>(target, coreIndex(), args);
421 }
422
423 bool writeProperty(QObject *target, void *value, WriteFlags flags) const
424 {
425 int status = -1;
426 void *argv[] = { value, nullptr, &status, &flags };
427 if (flags.testFlag(BypassInterceptor) && hasStaticMetaCallFunction())
428 staticMetaCallFunction()(target, QMetaObject::WriteProperty, relativePropertyIndex(), argv);
429 else
430 doMetacall<QMetaObject::WriteProperty>(target, coreIndex(), argv);
431 return true;
432 }
433
434 bool resetProperty(QObject *target, WriteFlags flags) const
435 {
436 if (flags.testFlag(BypassInterceptor) && hasStaticMetaCallFunction())
437 staticMetaCallFunction()(target, QMetaObject::ResetProperty, relativePropertyIndex(), nullptr);
438 else
439 doMetacall<QMetaObject::ResetProperty>(target, coreIndex(), nullptr);
440 return true;
441 }
442
443 QUntypedBindable propertyBindable(QObject *target) const
444 {
445 QUntypedBindable result;
446 void *argv[] = { &result };
447 if (hasStaticMetaCallFunction())
448 staticMetaCallFunction()(target, QMetaObject::BindableProperty, relativePropertyIndex(), argv);
449 else
450 doMetacall<QMetaObject::BindableProperty>(target, coreIndex(), argv);
451 return result;
452 }
453
455 {
456 Flags f;
458 f.setIsSignal(true);
460 return f;
461 }
462
464 {
465 Flags f;
468 return f;
469 }
470
471private:
472 friend class QQmlPropertyCache;
473
474 Flags m_flags;
475 qint16 m_coreIndex = -1;
476
477 // The notify index is in the range returned by QObjectPrivate::signalIndex().
478 // This is different from QMetaMethod::methodIndex().
479 qint16 m_notifyIndex = -1;
480 qint16 m_overrideIndex = -1;
481
482 qint16 m_metaObjectOffset = -1;
483
484 QTypeRevision m_revision = QTypeRevision::zero();
485 QTypeRevision m_typeVersion = QTypeRevision::zero();
486
487 QMetaType m_propType = {};
488
489 union {
490 // only for methods (if stored in property cache)
492
493 // only for C++-declared properties
495
496 // only for methods (if stored in lookups)
498
499 // only for aliases
501 };
502};
503
504#if QT_POINTER_SIZE == 4
505 Q_STATIC_ASSERT(sizeof(QQmlPropertyData) == 24);
506#else // QT_POINTER_SIZE == 8
508#endif
509
510static_assert(std::is_trivially_copyable<QQmlPropertyData>::value);
511
512bool QQmlPropertyData::operator==(const QQmlPropertyData &other) const
513{
514 return flags() == other.flags() &&
515 propType() == other.propType() &&
516 coreIndex() == other.coreIndex() &&
517 notifyIndex() == other.notifyIndex() &&
518 revision() == other.revision();
519}
520
522 : otherBits(0),
523 isConst(false),
524 isDeepAliasORisVMEFunction(false),
525 isWritableORhasArguments(false),
526 isResettableORisSignal(false),
527 isAliasORisVMESignal(false),
528 isFinalORisV4Function(false),
529 isSignalHandler(false),
530 isOverridableSignal(false),
531 isRequiredORisCloned(false),
532 isConstructorORisBindable(false),
533 isVirtual(false),
534 doesOverride(false),
535 isOverridden(false),
536 hasMetaObject(false),
537 type(OtherType),
538 overrideIndexIsProperty(false)
539{
540}
541
543{
544 return isConst == other.isConst
545 && isDeepAliasORisVMEFunction == other.isDeepAliasORisVMEFunction
546 && isWritableORhasArguments == other.isWritableORhasArguments
547 && isResettableORisSignal == other.isResettableORisSignal
548 && isAliasORisVMESignal == other.isAliasORisVMESignal
549 && isFinalORisV4Function == other.isFinalORisV4Function && isVirtual == other.isVirtual
550 && doesOverride == other.doesOverride && isOverridden == other.isOverridden
551 && isSignalHandler == other.isSignalHandler
552 && isRequiredORisCloned == other.isRequiredORisCloned
553 && hasMetaObject == other.hasMetaObject && type == other.type
554 && isConstructorORisBindable == other.isConstructorORisBindable
555 && overrideIndexIsProperty == other.overrideIndexIsProperty;
556}
557
559{
560 switch (from.type) {
562 case EnumType:
563 case QListType:
564 case QVariantType:
565 type = from.type;
566 }
567}
568
569Q_DECLARE_OPERATORS_FOR_FLAGS(QQmlPropertyData::WriteFlags)
570
571QT_END_NAMESPACE
572
573#endif // QQMLPROPERTYDATA_P_H
bool overrideIndexIsProperty() const
void readProperty(QObject *target, void *property) const
bool isResettable() const
bool isConstructor() const
bool isOverridden() const
int metaObjectOffset() const
bool isVarProperty() const
void readPropertyWithArgs(QObject *target, void *args[]) const
bool notifiesViaBindable() const
QMetaMethod metaMethod() const
QTypeRevision typeVersion() const
void setRevision(QTypeRevision revision)
bool writeProperty(QObject *target, void *value, WriteFlags flags) const
QTypeRevision revision() const
void setAliasTarget(int target)
bool isVMEFunction() const
bool doesOverride() const
void setNotifyIndex(int idx)
StaticMetaCallFunction m_staticMetaCallFunction
StaticMetaCallFunction staticMetaCallFunction() const
bool operator==(const QQmlPropertyData &) const
void setMetaObjectOffset(int off)
void setMetaObject(const QMetaObject *metaObject)
bool hasArguments() const
QMetaType propType() const
bool isV4Function() const
QString name(const QMetaObject *metaObject) const
void doMetacall(QObject *object, int idx, void **argv) const
void setOverrideIndexIsProperty(bool onoff)
void setCoreIndex(int idx)
bool acceptsQBinding() const
void setArguments(QQmlPropertyCacheMethodArguments *args)
void setPropType(QMetaType pt)
bool hasMetaObject() const
const QMetaObject * m_metaObject
void setOverrideIndex(int idx)
QUntypedBindable propertyBindable(QObject *target) const
QQmlPropertyCacheMethodArguments * arguments() const
void markAsOverrideOf(QQmlPropertyData *predecessor)
QQmlPropertyCacheMethodArguments * m_arguments
static Flags defaultSlotFlags()
void setWritable(bool onoff)
bool hasStaticMetaCallFunction() const
void trySetStaticMetaCallFunction(StaticMetaCallFunction f, unsigned relativePropertyIndex)
static Flags defaultSignalFlags()
static Flags flagsForProperty(const QMetaProperty &)
void load(const QMetaProperty &)
bool resetProperty(QObject *target, WriteFlags flags) const
bool isSignalHandler() const
QString name(QObject *object) const
bool isOverridableSignal() const
void setTypeVersion(QTypeRevision typeVersion)
const QMetaObject * metaObject() const
quint16 relativePropertyIndex() const
Q_STATIC_ASSERT(sizeof(SharedImageHeader) % 4==0)
void copyPropertyTypeFlags(Flags from)
bool operator==(const Flags &other) const