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;
25class QQmlPropertyData
26{
27public:
28 enum WriteFlag {
29 BypassInterceptor = 0x01,
30 DontRemoveBinding = 0x02,
31 RemoveBindingOnAliasWrite = 0x04,
32 HasInternalIndex = 0x8,
33 };
34 Q_DECLARE_FLAGS(WriteFlags, WriteFlag)
35
36 typedef QObjectPrivate::StaticMetaCallFunction StaticMetaCallFunction;
37
38 struct Flags {
39 friend class QQmlPropertyData;
40 enum Type {
41 OtherType = 0,
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 isVMEFunction : 1; // 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 setIsFinal(bool b) {
114 Q_ASSERT(type != FunctionType);
115 isFinalORisV4Function = b;
116 }
117
118 void setIsOverridden(bool b) {
119 isOverridden = b;
120 }
121
122 void setIsBindable(bool b) {
123 Q_ASSERT(type != FunctionType);
124 isConstructorORisBindable = b;
125 }
126
127 void setIsRequired(bool b) {
128 Q_ASSERT(type != FunctionType);
129 isRequiredORisCloned = b;
130 }
131
132 void setIsVMEFunction(bool b) {
133 Q_ASSERT(type == FunctionType);
134 isVMEFunction = b;
135 }
136 void setHasArguments(bool b) {
137 Q_ASSERT(type == FunctionType);
138 isWritableORhasArguments = b;
139 }
140 void setIsSignal(bool b) {
141 Q_ASSERT(type == FunctionType);
142 isResettableORisSignal = b;
143 }
144 void setIsVMESignal(bool b) {
145 Q_ASSERT(type == FunctionType);
146 isAliasORisVMESignal = b;
147 }
148
149 void setIsV4Function(bool b) {
150 Q_ASSERT(type == FunctionType);
151 isFinalORisV4Function = b;
152 }
153
154 void setIsSignalHandler(bool b) {
155 Q_ASSERT(type == FunctionType);
156 isSignalHandler = b;
157 }
158
159 // TODO: Remove this once we can. Signals should not be overridable.
160 void setIsOverridableSignal(bool b) {
161 Q_ASSERT(type == FunctionType);
162 Q_ASSERT(isResettableORisSignal);
163 isOverridableSignal = b;
164 }
165
166 void setIsCloned(bool b) {
167 Q_ASSERT(type == FunctionType);
168 isRequiredORisCloned = b;
169 }
170
171 void setIsConstructor(bool b) {
172 Q_ASSERT(type == FunctionType);
173 isConstructorORisBindable = b;
174 }
175
176 void setHasMetaObject(bool b) {
177 hasMetaObject = b;
178 }
179
180 void setType(Type newType) {
181 type = newType;
182 }
183 };
184
185
186 inline bool operator==(const QQmlPropertyData &) const;
187
188 Flags flags() const { return m_flags; }
189 void setFlags(Flags f)
190 {
191 unsigned otherBits = m_flags.otherBits;
192 m_flags = f;
193 m_flags.otherBits = otherBits;
194 }
195
196 bool isValid() const { return coreIndex() != -1; }
197
198 bool isConstant() const { return m_flags.isConst; }
199 bool isWritable() const { return !isFunction() && m_flags.isWritableORhasArguments; }
200 void setWritable(bool onoff) { Q_ASSERT(!isFunction()); m_flags.isWritableORhasArguments = onoff; }
201 bool isResettable() const { return !isFunction() && m_flags.isResettableORisSignal; }
202 bool isAlias() const { return !isFunction() && m_flags.isAliasORisVMESignal; }
203 bool isFinal() const { return !isFunction() && m_flags.isFinalORisV4Function; }
204 bool isOverridden() const { return m_flags.isOverridden; }
205 bool isRequired() const { return !isFunction() && m_flags.isRequiredORisCloned; }
206 bool hasStaticMetaCallFunction() const { return staticMetaCallFunction() != nullptr; }
207 bool isFunction() const { return m_flags.type == Flags::FunctionType; }
208 bool isQObject() const { return m_flags.type == Flags::QObjectDerivedType; }
209 bool isEnum() const { return m_flags.type == Flags::EnumType; }
210 bool isQList() const { return m_flags.type == Flags::QListType; }
211 bool isVarProperty() const { return m_flags.type == Flags::VarPropertyType; }
212 bool isQVariant() const { return m_flags.type == Flags::QVariantType; }
213 bool isVMEFunction() const { return isFunction() && m_flags.isVMEFunction; }
214 bool hasArguments() const { return isFunction() && m_flags.isWritableORhasArguments; }
215 bool isSignal() const { return isFunction() && m_flags.isResettableORisSignal; }
216 bool isVMESignal() const { return isFunction() && m_flags.isAliasORisVMESignal; }
217 bool isV4Function() const { return isFunction() && m_flags.isFinalORisV4Function; }
218 bool isSignalHandler() const { return m_flags.isSignalHandler; }
219 bool hasMetaObject() const { return m_flags.hasMetaObject; }
220
221 // TODO: Remove this once we can. Signals should not be overridable.
222 bool isOverridableSignal() const { return m_flags.isOverridableSignal; }
223
224 bool isCloned() const { return isFunction() && m_flags.isRequiredORisCloned; }
225 bool isConstructor() const { return isFunction() && m_flags.isConstructorORisBindable; }
226 bool isBindable() const { return !isFunction() && m_flags.isConstructorORisBindable; }
227
228 bool hasOverride() const { return overrideIndex() >= 0; }
229 bool hasRevision() const { return revision() != QTypeRevision::zero(); }
230
231 QMetaType propType() const { return m_propType; }
232 void setPropType(QMetaType pt)
233 {
234 m_propType = pt;
235 }
236
237 int notifyIndex() const { return m_notifyIndex; }
238 void setNotifyIndex(int idx)
239 {
240 Q_ASSERT(idx >= std::numeric_limits<qint16>::min());
241 Q_ASSERT(idx <= std::numeric_limits<qint16>::max());
242 m_notifyIndex = qint16(idx);
243 }
244
245 bool overrideIndexIsProperty() const { return m_flags.overrideIndexIsProperty; }
246 void setOverrideIndexIsProperty(bool onoff) { m_flags.overrideIndexIsProperty = onoff; }
247
248 int overrideIndex() const { return m_overrideIndex; }
249 void setOverrideIndex(int idx)
250 {
251 Q_ASSERT(idx >= std::numeric_limits<qint16>::min());
252 Q_ASSERT(idx <= std::numeric_limits<qint16>::max());
253 m_overrideIndex = qint16(idx);
254 }
255
256 int coreIndex() const { return m_coreIndex; }
257 void setCoreIndex(int idx)
258 {
259 Q_ASSERT(idx >= std::numeric_limits<qint16>::min());
260 Q_ASSERT(idx <= std::numeric_limits<qint16>::max());
261 m_coreIndex = qint16(idx);
262 }
263
264 QTypeRevision revision() const { return m_revision; }
265 void setRevision(QTypeRevision revision) { m_revision = revision; }
266
267 /* If a property is a C++ type, then we store the minor
268 * version of this type.
269 * This is required to resolve property or signal revisions
270 * if this property is used as a grouped property.
271 *
272 * Test.qml
273 * property TextEdit someTextEdit: TextEdit {}
274 *
275 * Test {
276 * someTextEdit.preeditText: "test" //revision 7
277 * someTextEdit.onEditingFinished: console.log("test") //revision 6
278 * }
279 *
280 * To determine if these properties with revisions are available we need
281 * the minor version of TextEdit as imported in Test.qml.
282 *
283 */
284
285 QTypeRevision typeVersion() const { return m_typeVersion; }
286 void setTypeVersion(QTypeRevision typeVersion) { m_typeVersion = typeVersion; }
287
288 QQmlPropertyCacheMethodArguments *arguments() const
289 {
290 Q_ASSERT(!hasMetaObject());
291 return m_arguments;
292 }
293 void setArguments(QQmlPropertyCacheMethodArguments *args)
294 {
295 Q_ASSERT(!hasMetaObject());
296 m_arguments = args;
297 }
298
299 const QMetaObject *metaObject() const
300 {
301 Q_ASSERT(hasMetaObject());
302 return m_metaObject;
303 }
304
305 void setMetaObject(const QMetaObject *metaObject)
306 {
307 Q_ASSERT(!hasArguments() || !m_arguments);
308 m_flags.setHasMetaObject(true);
309 m_metaObject = metaObject;
310 }
311
312 QMetaMethod metaMethod() const
313 {
314 Q_ASSERT(hasMetaObject());
315 Q_ASSERT(isFunction());
316 return m_metaObject->method(index: m_coreIndex);
317 }
318
319 int metaObjectOffset() const { return m_metaObjectOffset; }
320 void setMetaObjectOffset(int off)
321 {
322 Q_ASSERT(off >= std::numeric_limits<qint16>::min());
323 Q_ASSERT(off <= std::numeric_limits<qint16>::max());
324 m_metaObjectOffset = qint16(off);
325 }
326
327 StaticMetaCallFunction staticMetaCallFunction() const { Q_ASSERT(!isFunction()); return m_staticMetaCallFunction; }
328 void trySetStaticMetaCallFunction(StaticMetaCallFunction f, unsigned relativePropertyIndex)
329 {
330 Q_ASSERT(!isFunction());
331 if (relativePropertyIndex < (1 << Flags::BitsLeftInFlags) - 1) {
332 m_flags.otherBits = relativePropertyIndex;
333 m_staticMetaCallFunction = f;
334 }
335 }
336 quint16 relativePropertyIndex() const { Q_ASSERT(hasStaticMetaCallFunction()); return m_flags.otherBits; }
337
338 static Flags flagsForProperty(const QMetaProperty &);
339 void load(const QMetaProperty &);
340 void load(const QMetaMethod &);
341
342 QString name(QObject *object) const { return object ? name(metaObject: object->metaObject()) : QString(); }
343 QString name(const QMetaObject *metaObject) const
344 {
345 if (!metaObject || m_coreIndex == -1)
346 return QString();
347
348 return QString::fromUtf8(utf8: isFunction()
349 ? metaObject->method(index: m_coreIndex).name().constData()
350 : metaObject->property(index: m_coreIndex).name());
351 }
352
353 bool markAsOverrideOf(QQmlPropertyData *predecessor);
354
355 inline void readProperty(QObject *target, void *property) const
356 {
357 void *args[] = { property, nullptr };
358 readPropertyWithArgs(target, args);
359 }
360
361 // This is the same as QMetaObject::metacall(), but inlined here to avoid a function call.
362 // And we ignore the return value.
363 template<QMetaObject::Call call>
364 void doMetacall(QObject *object, int idx, void **argv) const
365 {
366 if (QDynamicMetaObjectData *dynamicMetaObject = QObjectPrivate::get(o: object)->metaObject)
367 dynamicMetaObject->metaCall(object, call, id: idx, argv);
368 else
369 object->qt_metacall(call, idx, argv);
370 }
371
372 void readPropertyWithArgs(QObject *target, void *args[]) const
373 {
374 if (hasStaticMetaCallFunction())
375 staticMetaCallFunction()(target, QMetaObject::ReadProperty, relativePropertyIndex(), args);
376 else
377 doMetacall<QMetaObject::ReadProperty>(object: target, idx: coreIndex(), argv: args);
378 }
379
380 bool writeProperty(QObject *target, void *value, WriteFlags flags) const
381 {
382 int status = -1;
383 void *argv[] = { value, nullptr, &status, &flags };
384 if (flags.testFlag(flag: BypassInterceptor) && hasStaticMetaCallFunction())
385 staticMetaCallFunction()(target, QMetaObject::WriteProperty, relativePropertyIndex(), argv);
386 else
387 doMetacall<QMetaObject::WriteProperty>(object: target, idx: coreIndex(), argv);
388 return true;
389 }
390
391 bool resetProperty(QObject *target, WriteFlags flags) const
392 {
393 if (flags.testFlag(flag: BypassInterceptor) && hasStaticMetaCallFunction())
394 staticMetaCallFunction()(target, QMetaObject::ResetProperty, relativePropertyIndex(), nullptr);
395 else
396 doMetacall<QMetaObject::ResetProperty>(object: target, idx: coreIndex(), argv: nullptr);
397 return true;
398 }
399
400 static Flags defaultSignalFlags()
401 {
402 Flags f;
403 f.setType(Flags::FunctionType);
404 f.setIsSignal(true);
405 f.setIsVMESignal(true);
406 return f;
407 }
408
409 static Flags defaultSlotFlags()
410 {
411 Flags f;
412 f.setType(Flags::FunctionType);
413 f.setIsVMEFunction(true);
414 return f;
415 }
416
417private:
418 friend class QQmlPropertyCache;
419
420 Flags m_flags;
421 qint16 m_coreIndex = -1;
422
423 // The notify index is in the range returned by QObjectPrivate::signalIndex().
424 // This is different from QMetaMethod::methodIndex().
425 qint16 m_notifyIndex = -1;
426 qint16 m_overrideIndex = -1;
427
428 qint16 m_metaObjectOffset = -1;
429
430 QTypeRevision m_revision = QTypeRevision::zero();
431 QTypeRevision m_typeVersion = QTypeRevision::zero();
432
433 QMetaType m_propType = {};
434
435 union {
436 QQmlPropertyCacheMethodArguments *m_arguments = nullptr;
437 StaticMetaCallFunction m_staticMetaCallFunction;
438 const QMetaObject *m_metaObject;
439 };
440};
441
442#if QT_POINTER_SIZE == 4
443 Q_STATIC_ASSERT(sizeof(QQmlPropertyData) == 24);
444#else // QT_POINTER_SIZE == 8
445 Q_STATIC_ASSERT(sizeof(QQmlPropertyData) == 32);
446#endif
447
448static_assert(std::is_trivially_copyable<QQmlPropertyData>::value);
449
450bool QQmlPropertyData::operator==(const QQmlPropertyData &other) const
451{
452 return flags() == other.flags() &&
453 propType() == other.propType() &&
454 coreIndex() == other.coreIndex() &&
455 notifyIndex() == other.notifyIndex() &&
456 revision() == other.revision();
457}
458
459QQmlPropertyData::Flags::Flags()
460 : otherBits(0)
461 , isConst(false)
462 , isVMEFunction(false)
463 , isWritableORhasArguments(false)
464 , isResettableORisSignal(false)
465 , isAliasORisVMESignal(false)
466 , isFinalORisV4Function(false)
467 , isSignalHandler(false)
468 , isOverridableSignal(false)
469 , isRequiredORisCloned(false)
470 , isConstructorORisBindable(false)
471 , isOverridden(false)
472 , hasMetaObject(false)
473 , type(OtherType)
474 , overrideIndexIsProperty(false)
475{
476}
477
478bool QQmlPropertyData::Flags::operator==(const QQmlPropertyData::Flags &other) const
479{
480 return isConst == other.isConst &&
481 isVMEFunction == other.isVMEFunction &&
482 isWritableORhasArguments == other.isWritableORhasArguments &&
483 isResettableORisSignal == other.isResettableORisSignal &&
484 isAliasORisVMESignal == other.isAliasORisVMESignal &&
485 isFinalORisV4Function == other.isFinalORisV4Function &&
486 isOverridden == other.isOverridden &&
487 isSignalHandler == other.isSignalHandler &&
488 isRequiredORisCloned == other.isRequiredORisCloned &&
489 hasMetaObject == other.hasMetaObject &&
490 type == other.type &&
491 isConstructorORisBindable == other.isConstructorORisBindable &&
492 overrideIndexIsProperty == other.overrideIndexIsProperty;
493}
494
495void QQmlPropertyData::Flags::copyPropertyTypeFlags(QQmlPropertyData::Flags from)
496{
497 switch (from.type) {
498 case QObjectDerivedType:
499 case EnumType:
500 case QListType:
501 case QVariantType:
502 type = from.type;
503 }
504}
505
506Q_DECLARE_OPERATORS_FOR_FLAGS(QQmlPropertyData::WriteFlags)
507
508QT_END_NAMESPACE
509
510#endif // QQMLPROPERTYDATA_P_H
511

Provided by KDAB

Privacy Policy
Learn to use CMake with our Intro Training
Find out more

source code of qtdeclarative/src/qml/qml/qqmlpropertydata_p.h