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 = 16 };
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 isOverridden : 1; // Is overridden by a extension property
83 unsigned hasMetaObject : 1;
84 unsigned type : 3; // stores an entry of Types
85
86 // Internal QQmlPropertyCache flags
87 unsigned overrideIndexIsProperty : 1;
88
89 public:
90 inline Flags();
91 inline bool operator==(const Flags &other) const;
92 inline void copyPropertyTypeFlags(Flags from);
93
94 void setIsConstant(bool b) {
95 isConst = b;
96 }
97
98 void setIsWritable(bool b) {
99 Q_ASSERT(type != FunctionType);
100 isWritableORhasArguments = b;
101 }
102
103 void setIsResettable(bool b) {
104 Q_ASSERT(type != FunctionType);
105 isResettableORisSignal = b;
106 }
107
108 void setIsAlias(bool b) {
109 Q_ASSERT(type != FunctionType);
110 isAliasORisVMESignal = b;
111 }
112
113 void setIsDeepAlias(bool b) {
114 Q_ASSERT(type != FunctionType);
115 isDeepAliasORisVMEFunction = b;
116 }
117
118 void setIsFinal(bool b) {
119 Q_ASSERT(type != FunctionType);
120 isFinalORisV4Function = b;
121 }
122
123 void setIsOverridden(bool b) {
124 isOverridden = b;
125 }
126
127 void setIsBindable(bool b) {
128 Q_ASSERT(type != FunctionType);
129 isConstructorORisBindable = b;
130 }
131
132 void setIsRequired(bool b) {
133 Q_ASSERT(type != FunctionType);
134 isRequiredORisCloned = b;
135 }
136
137 void setIsVMEFunction(bool b) {
138 Q_ASSERT(type == FunctionType);
139 isDeepAliasORisVMEFunction = b;
140 }
141
142 void setHasArguments(bool b) {
143 Q_ASSERT(type == FunctionType);
144 isWritableORhasArguments = b;
145 }
146 void setIsSignal(bool b) {
147 Q_ASSERT(type == FunctionType);
148 isResettableORisSignal = b;
149 }
150 void setIsVMESignal(bool b) {
151 Q_ASSERT(type == FunctionType);
152 isAliasORisVMESignal = b;
153 }
154
155 void setIsV4Function(bool b) {
156 Q_ASSERT(type == FunctionType);
157 isFinalORisV4Function = b;
158 }
159
160 void setIsSignalHandler(bool b) {
161 Q_ASSERT(type == FunctionType);
162 isSignalHandler = b;
163 }
164
165 // TODO: Remove this once we can. Signals should not be overridable.
167 Q_ASSERT(type == FunctionType);
168 Q_ASSERT(isResettableORisSignal);
169 isOverridableSignal = b;
170 }
171
172 void setIsCloned(bool b) {
173 Q_ASSERT(type == FunctionType);
174 isRequiredORisCloned = b;
175 }
176
177 void setIsConstructor(bool b) {
178 Q_ASSERT(type == FunctionType);
179 isConstructorORisBindable = b;
180 }
181
182 void setHasMetaObject(bool b) {
183 hasMetaObject = b;
184 }
185
186 void setType(Type newType) {
187 type = newType;
188 }
189 };
190
191
192 inline bool operator==(const QQmlPropertyData &) const;
193
194 Flags flags() const { return m_flags; }
196 {
197 unsigned otherBits = m_flags.otherBits;
198 m_flags = f;
199 m_flags.otherBits = otherBits;
200 }
201
202 bool isValid() const { return coreIndex() != -1; }
203
204 bool isConstant() const { return m_flags.isConst; }
205 bool isWritable() const { return !isFunction() && m_flags.isWritableORhasArguments; }
206 void setWritable(bool onoff) { Q_ASSERT(!isFunction()); m_flags.isWritableORhasArguments = onoff; }
207 bool isResettable() const { return !isFunction() && m_flags.isResettableORisSignal; }
208 bool isAlias() const { return !isFunction() && m_flags.isAliasORisVMESignal; }
209 bool isFinal() const { return !isFunction() && m_flags.isFinalORisV4Function; }
210 bool isOverridden() const { return m_flags.isOverridden; }
211 bool isRequired() const { return !isFunction() && m_flags.isRequiredORisCloned; }
212 bool isFunction() const { return m_flags.type == Flags::FunctionType; }
213 bool isQObject() const { return m_flags.type == Flags::QObjectDerivedType; }
214 bool isEnum() const { return m_flags.type == Flags::EnumType; }
215 bool isQList() const { return m_flags.type == Flags::QListType; }
216 bool isVarProperty() const { return m_flags.type == Flags::VarPropertyType; }
217 bool isQVariant() const { return m_flags.type == Flags::QVariantType; }
218 bool isVMEFunction() const { return isFunction() && m_flags.isDeepAliasORisVMEFunction; }
219 bool hasArguments() const { return isFunction() && m_flags.isWritableORhasArguments; }
220 bool isSignal() const { return isFunction() && m_flags.isResettableORisSignal; }
221 bool isVMESignal() const { return isFunction() && m_flags.isAliasORisVMESignal; }
222 bool isV4Function() const { return isFunction() && m_flags.isFinalORisV4Function; }
223 bool isSignalHandler() const { return m_flags.isSignalHandler; }
224 bool hasMetaObject() const { return m_flags.hasMetaObject; }
225
227 {
228 return !isAlias() && staticMetaCallFunction() != nullptr;
229 }
230
231 // TODO: Remove this once we can. Signals should not be overridable.
232 bool isOverridableSignal() const { return m_flags.isOverridableSignal; }
233
234 bool isCloned() const { return isFunction() && m_flags.isRequiredORisCloned; }
235 bool isConstructor() const { return isFunction() && m_flags.isConstructorORisBindable; }
236
237 bool notifiesViaBindable() const { return !isFunction() && m_flags.isConstructorORisBindable; }
238 bool acceptsQBinding() const { return notifiesViaBindable() && !m_flags.isDeepAliasORisVMEFunction; }
239
240 bool hasOverride() const { return overrideIndex() >= 0; }
241 bool hasRevision() const { return revision() != QTypeRevision::zero(); }
242
243 QMetaType propType() const { return m_propType; }
244 void setPropType(QMetaType pt)
245 {
246 m_propType = pt;
247 }
248
249 int notifyIndex() const { return m_notifyIndex; }
250 void setNotifyIndex(int idx)
251 {
252 Q_ASSERT(idx >= std::numeric_limits<qint16>::min());
253 Q_ASSERT(idx <= std::numeric_limits<qint16>::max());
254 m_notifyIndex = qint16(idx);
255 }
256
257 bool overrideIndexIsProperty() const { return m_flags.overrideIndexIsProperty; }
258 void setOverrideIndexIsProperty(bool onoff) { m_flags.overrideIndexIsProperty = onoff; }
259
260 int overrideIndex() const { return m_overrideIndex; }
261 void setOverrideIndex(int idx)
262 {
263 Q_ASSERT(idx >= std::numeric_limits<qint16>::min());
264 Q_ASSERT(idx <= std::numeric_limits<qint16>::max());
265 m_overrideIndex = qint16(idx);
266 }
267
268 int coreIndex() const { return m_coreIndex; }
269 void setCoreIndex(int idx)
270 {
271 Q_ASSERT(idx >= std::numeric_limits<qint16>::min());
272 Q_ASSERT(idx <= std::numeric_limits<qint16>::max());
273 m_coreIndex = qint16(idx);
274 }
275
276 int aliasTarget() const
277 {
278 Q_ASSERT(isAlias());
279 return m_encodedAliasTargetIndex;
280 }
281 void setAliasTarget(int target)
282 {
283 Q_ASSERT(isAlias());
284 m_encodedAliasTargetIndex = target;
285 }
286
287 QTypeRevision revision() const { return m_revision; }
288 void setRevision(QTypeRevision revision) { m_revision = revision; }
289
290 /* If a property is a C++ type, then we store the minor
291 * version of this type.
292 * This is required to resolve property or signal revisions
293 * if this property is used as a grouped property.
294 *
295 * Test.qml
296 * property TextEdit someTextEdit: TextEdit {}
297 *
298 * Test {
299 * someTextEdit.preeditText: "test" //revision 7
300 * someTextEdit.onEditingFinished: console.log("test") //revision 6
301 * }
302 *
303 * To determine if these properties with revisions are available we need
304 * the minor version of TextEdit as imported in Test.qml.
305 *
306 */
307
308 QTypeRevision typeVersion() const { return m_typeVersion; }
309 void setTypeVersion(QTypeRevision typeVersion) { m_typeVersion = typeVersion; }
310
312 {
313 Q_ASSERT(!hasMetaObject());
314 return m_arguments;
315 }
317 {
318 Q_ASSERT(!hasMetaObject());
319 m_arguments = args;
320 }
321
322 const QMetaObject *metaObject() const
323 {
324 Q_ASSERT(hasMetaObject());
325 return m_metaObject;
326 }
327
328 void setMetaObject(const QMetaObject *metaObject)
329 {
330 Q_ASSERT(!hasArguments() || !m_arguments);
331 m_flags.setHasMetaObject(true);
332 m_metaObject = metaObject;
333 }
334
336 {
337 Q_ASSERT(hasMetaObject());
338 Q_ASSERT(isFunction());
339 return m_metaObject->method(m_coreIndex);
340 }
341
342 int metaObjectOffset() const { return m_metaObjectOffset; }
344 {
345 Q_ASSERT(off >= std::numeric_limits<qint16>::min());
346 Q_ASSERT(off <= std::numeric_limits<qint16>::max());
347 m_metaObjectOffset = qint16(off);
348 }
349
351 {
352 Q_ASSERT(!isFunction() && !isAlias());
353 return m_staticMetaCallFunction;
354 }
355
356 void trySetStaticMetaCallFunction(StaticMetaCallFunction f, unsigned relativePropertyIndex)
357 {
358 Q_ASSERT(!isFunction() && !isAlias());
359 if (relativePropertyIndex < (1 << Flags::BitsLeftInFlags) - 1) {
360 m_flags.otherBits = relativePropertyIndex;
361 m_staticMetaCallFunction = f;
362 }
363 }
364 quint16 relativePropertyIndex() const { Q_ASSERT(hasStaticMetaCallFunction()); return m_flags.otherBits; }
365
366 static Flags flagsForProperty(const QMetaProperty &);
367 void load(const QMetaProperty &);
368 void load(const QMetaMethod &);
369
370 QString name(QObject *object) const { return object ? name(object->metaObject()) : QString(); }
371 QString name(const QMetaObject *metaObject) const
372 {
373 if (!metaObject || m_coreIndex == -1)
374 return QString();
375
376 return QString::fromUtf8(isFunction()
377 ? metaObject->method(m_coreIndex).name().constData()
378 : metaObject->property(m_coreIndex).name());
379 }
380
381 void markAsOverrideOf(QQmlPropertyData *predecessor);
382
383 inline void readProperty(QObject *target, void *property) const
384 {
385 void *args[] = { property, nullptr };
386 readPropertyWithArgs(target, args);
387 }
388
389 // This is the same as QMetaObject::metacall(), but inlined here to avoid a function call.
390 // And we ignore the return value.
391 template<QMetaObject::Call call>
392 void doMetacall(QObject *object, int idx, void **argv) const
393 {
394 if (QDynamicMetaObjectData *dynamicMetaObject = QObjectPrivate::get(object)->metaObject)
395 dynamicMetaObject->metaCall(object, call, idx, argv);
396 else
397 object->qt_metacall(call, idx, argv);
398 }
399
400 void readPropertyWithArgs(QObject *target, void *args[]) const
401 {
402 if (hasStaticMetaCallFunction())
403 staticMetaCallFunction()(target, QMetaObject::ReadProperty, relativePropertyIndex(), args);
404 else
405 doMetacall<QMetaObject::ReadProperty>(target, coreIndex(), args);
406 }
407
408 bool writeProperty(QObject *target, void *value, WriteFlags flags) const
409 {
410 int status = -1;
411 void *argv[] = { value, nullptr, &status, &flags };
412 if (flags.testFlag(BypassInterceptor) && hasStaticMetaCallFunction())
413 staticMetaCallFunction()(target, QMetaObject::WriteProperty, relativePropertyIndex(), argv);
414 else
415 doMetacall<QMetaObject::WriteProperty>(target, coreIndex(), argv);
416 return true;
417 }
418
419 bool resetProperty(QObject *target, WriteFlags flags) const
420 {
421 if (flags.testFlag(BypassInterceptor) && hasStaticMetaCallFunction())
422 staticMetaCallFunction()(target, QMetaObject::ResetProperty, relativePropertyIndex(), nullptr);
423 else
424 doMetacall<QMetaObject::ResetProperty>(target, coreIndex(), nullptr);
425 return true;
426 }
427
428 QUntypedBindable propertyBindable(QObject *target) const
429 {
430 QUntypedBindable result;
431 void *argv[] = { &result };
432 if (hasStaticMetaCallFunction())
433 staticMetaCallFunction()(target, QMetaObject::BindableProperty, relativePropertyIndex(), argv);
434 else
435 doMetacall<QMetaObject::BindableProperty>(target, coreIndex(), argv);
436 return result;
437 }
438
440 {
441 Flags f;
443 f.setIsSignal(true);
445 return f;
446 }
447
449 {
450 Flags f;
453 return f;
454 }
455
456private:
457 friend class QQmlPropertyCache;
458
459 Flags m_flags;
460 qint16 m_coreIndex = -1;
461
462 // The notify index is in the range returned by QObjectPrivate::signalIndex().
463 // This is different from QMetaMethod::methodIndex().
464 qint16 m_notifyIndex = -1;
465 qint16 m_overrideIndex = -1;
466
467 qint16 m_metaObjectOffset = -1;
468
469 QTypeRevision m_revision = QTypeRevision::zero();
470 QTypeRevision m_typeVersion = QTypeRevision::zero();
471
472 QMetaType m_propType = {};
473
474 union {
475 // only for methods (if stored in property cache)
477
478 // only for C++-declared properties
480
481 // only for methods (if stored in lookups)
483
484 // only for aliases
486 };
487};
488
489#if QT_POINTER_SIZE == 4
490 Q_STATIC_ASSERT(sizeof(QQmlPropertyData) == 24);
491#else // QT_POINTER_SIZE == 8
493#endif
494
495static_assert(std::is_trivially_copyable<QQmlPropertyData>::value);
496
497bool QQmlPropertyData::operator==(const QQmlPropertyData &other) const
498{
499 return flags() == other.flags() &&
500 propType() == other.propType() &&
501 coreIndex() == other.coreIndex() &&
502 notifyIndex() == other.notifyIndex() &&
503 revision() == other.revision();
504}
505
507 : otherBits(0)
508 , isConst(false)
509 , isDeepAliasORisVMEFunction(false)
510 , isWritableORhasArguments(false)
511 , isResettableORisSignal(false)
512 , isAliasORisVMESignal(false)
513 , isFinalORisV4Function(false)
514 , isSignalHandler(false)
515 , isOverridableSignal(false)
516 , isRequiredORisCloned(false)
517 , isConstructorORisBindable(false)
518 , isOverridden(false)
519 , hasMetaObject(false)
520 , type(OtherType)
521 , overrideIndexIsProperty(false)
522{
523}
524
526{
527 return isConst == other.isConst &&
528 isDeepAliasORisVMEFunction == other.isDeepAliasORisVMEFunction &&
529 isWritableORhasArguments == other.isWritableORhasArguments &&
530 isResettableORisSignal == other.isResettableORisSignal &&
531 isAliasORisVMESignal == other.isAliasORisVMESignal &&
532 isFinalORisV4Function == other.isFinalORisV4Function &&
533 isOverridden == other.isOverridden &&
534 isSignalHandler == other.isSignalHandler &&
535 isRequiredORisCloned == other.isRequiredORisCloned &&
536 hasMetaObject == other.hasMetaObject &&
537 type == other.type &&
538 isConstructorORisBindable == other.isConstructorORisBindable &&
539 overrideIndexIsProperty == other.overrideIndexIsProperty;
540}
541
543{
544 switch (from.type) {
546 case EnumType:
547 case QListType:
548 case QVariantType:
549 type = from.type;
550 }
551}
552
553Q_DECLARE_OPERATORS_FOR_FLAGS(QQmlPropertyData::WriteFlags)
554
555QT_END_NAMESPACE
556
557#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
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