1 /****************************************************************************
3 ** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
6 ** This file is part of the QtQml module of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia. For licensing terms and
14 ** conditions see http://qt.digia.com/licensing. For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights. These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file. Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
40 ****************************************************************************/
42 #ifndef QQMLPROPERTYCACHE_P_H
43 #define QQMLPROPERTYCACHE_P_H
49 // This file is not part of the Qt API. It exists purely as an
50 // implementation detail. This header file may change from version to
51 // version without notice, or even be removed.
56 #include <private/qqmlrefcount_p.h>
57 #include <private/qflagpointer_p.h>
58 #include "qqmlcleanup_p.h"
59 #include "qqmlnotifier_p.h"
61 #include <private/qhashedstring_p.h>
62 #include <QtCore/qvarlengtharray.h>
63 #include <QtCore/qvector.h>
69 class QV8QObjectWrapper;
71 class QQmlPropertyData;
73 class QMetaObjectBuilder;
74 class QQmlPropertyCacheMethodArguments;
75 class QQmlVMEMetaObject;
77 // We have this somewhat awful split between RawData and Data so that RawData can be
78 // used in unions. In normal code, you should always use Data which initializes RawData
79 // to an invalid state on construction.
80 class QQmlPropertyRawData
85 ValueTypeFlagMask = 0x0000FFFF, // Flags in valueTypeFlags must fit in this mask
87 // Can apply to all properties, except IsFunction
88 IsConstant = 0x00000001, // Has CONST flag
89 IsWritable = 0x00000002, // Has WRITE function
90 IsResettable = 0x00000004, // Has RESET function
91 IsAlias = 0x00000008, // Is a QML alias to another property
92 IsFinal = 0x00000010, // Has FINAL flag
93 IsOverridden = 0x00000020, // Is overridden by a extension property
94 IsDirect = 0x00000040, // Exists on a C++ QMetaObject
95 HasAccessors = 0x00000080, // Has property accessors
97 // These are mutualy exclusive
98 IsFunction = 0x00000100, // Is an invokable
99 IsQObjectDerived = 0x00000200, // Property type is a QObject* derived type
100 IsEnumType = 0x00000400, // Property type is an enum
101 IsQList = 0x00000800, // Property type is a QML list
102 IsQmlBinding = 0x00001000, // Property type is a QQmlBinding*
103 IsQJSValue = 0x00002000, // Property type is a QScriptValue
104 IsV8Handle = 0x00004000, // Property type is a QQmlV8Handle
105 IsVarProperty = 0x00008000, // Property type is a "var" property of VMEMO
106 IsValueTypeVirtual = 0x00010000, // Property is a value type "virtual" property
107 IsQVariant = 0x00020000, // Property is a QVariant
109 // Apply only to IsFunctions
110 IsVMEFunction = 0x00040000, // Function was added by QML
111 HasArguments = 0x00080000, // Function takes arguments
112 IsSignal = 0x00100000, // Function is a signal
113 IsVMESignal = 0x00200000, // Signal was added by QML
114 IsV8Function = 0x00400000, // Function takes QQmlV8Function* args
115 IsSignalHandler = 0x00800000, // Function is a signal handler
116 IsOverload = 0x01000000, // Function is an overload of another function
117 IsCloned = 0x02000000, // The function was marked as cloned
119 // Internal QQmlPropertyCache flags
120 NotFullyResolved = 0x04000000, // True if the type data is to be lazily resolved
122 // Flags that are set based on the propType field
123 PropTypeFlagMask = IsQObjectDerived | IsEnumType | IsQList | IsQmlBinding | IsQJSValue |
124 IsV8Handle | IsQVariant,
126 Q_DECLARE_FLAGS(Flags, Flag)
128 Flags getFlags() const { return Flag(flags); }
129 void setFlags(Flags f) { flags = f; }
131 bool isValid() const { return coreIndex != -1; }
133 bool isConstant() const { return flags & IsConstant; }
134 bool isWritable() const { return flags & IsWritable; }
135 bool isResettable() const { return flags & IsResettable; }
136 bool isAlias() const { return flags & IsAlias; }
137 bool isFinal() const { return flags & IsFinal; }
138 bool isOverridden() const { return flags & IsOverridden; }
139 bool isDirect() const { return flags & IsDirect; }
140 bool hasAccessors() const { return flags & HasAccessors; }
141 bool isFunction() const { return flags & IsFunction; }
142 bool isQObject() const { return flags & IsQObjectDerived; }
143 bool isEnum() const { return flags & IsEnumType; }
144 bool isQList() const { return flags & IsQList; }
145 bool isQmlBinding() const { return flags & IsQmlBinding; }
146 bool isQJSValue() const { return flags & IsQJSValue; }
147 bool isV8Handle() const { return flags & IsV8Handle; }
148 bool isVarProperty() const { return flags & IsVarProperty; }
149 bool isValueTypeVirtual() const { return flags & IsValueTypeVirtual; }
150 bool isQVariant() const { return flags & IsQVariant; }
151 bool isVMEFunction() const { return flags & IsVMEFunction; }
152 bool hasArguments() const { return flags & HasArguments; }
153 bool isSignal() const { return flags & IsSignal; }
154 bool isVMESignal() const { return flags & IsVMESignal; }
155 bool isV8Function() const { return flags & IsV8Function; }
156 bool isSignalHandler() const { return flags & IsSignalHandler; }
157 bool isOverload() const { return flags & IsOverload; }
158 bool isCloned() const { return flags & IsCloned; }
160 bool hasOverride() const { return !(flags & IsValueTypeVirtual) &&
161 !(flags & HasAccessors) &&
162 overrideIndex >= 0; }
163 bool hasRevision() const { return !(flags & HasAccessors) && revision != 0; }
165 // Returns -1 if not a value type virtual property
166 inline int getValueTypeCoreIndex() const;
168 // Returns the "encoded" index for use with bindings. Encoding is:
169 // coreIndex | (valueTypeCoreIndex << 16)
170 inline int encodedIndex() const;
173 int propType; // When !NotFullyResolved
174 const char *propTypeName; // When NotFullyResolved
178 // The notify index is in the range returned by QObjectPrivate::signalIndex().
179 // This is different from QMetaMethod::methodIndex().
180 int notifyIndex; // When !IsFunction
181 void *arguments; // When IsFunction && HasArguments
185 struct { // When !HasAccessors
187 qint16 metaObjectOffset;
190 struct { // When IsValueTypeVirtual
191 quint16 valueTypeFlags; // flags of the access property on the value type proxy
193 quint16 valueTypePropType; // The QVariant::Type of access property on the value
195 quint16 valueTypeCoreIndex; // The prop index of the access property on the value
199 struct { // When !IsValueTypeVirtual
200 uint overrideIndexIsProperty : 1;
201 signed int overrideIndex : 31;
205 struct { // When HasAccessors
206 QQmlAccessors *accessors;
207 intptr_t accessorData;
212 friend class QQmlPropertyData;
213 friend class QQmlPropertyCache;
216 Q_DECLARE_OPERATORS_FOR_FLAGS(QQmlPropertyRawData::Flags);
218 class QQmlPropertyData : public QQmlPropertyRawData
221 inline QQmlPropertyData();
222 inline QQmlPropertyData(const QQmlPropertyRawData &);
224 inline bool operator==(const QQmlPropertyRawData &);
226 static Flags flagsForProperty(const QMetaProperty &, QQmlEngine *engine = 0);
227 void load(const QMetaProperty &, QQmlEngine *engine = 0);
228 void load(const QMetaMethod &);
229 QString name(QObject *);
230 QString name(const QMetaObject *);
232 void markAsOverrideOf(QQmlPropertyData *predecessor);
235 friend class QQmlPropertyCache;
236 void lazyLoad(const QMetaProperty &, QQmlEngine *engine = 0);
237 void lazyLoad(const QMetaMethod &);
238 bool notFullyResolved() const { return flags & NotFullyResolved; }
241 class QQmlPropertyCacheMethodArguments;
242 class Q_QML_PRIVATE_EXPORT QQmlPropertyCache : public QQmlRefCount, public QQmlCleanup
245 QQmlPropertyCache(QQmlEngine *);
246 QQmlPropertyCache(QQmlEngine *, const QMetaObject *);
247 virtual ~QQmlPropertyCache();
249 void update(QQmlEngine *, const QMetaObject *);
250 void invalidate(QQmlEngine *, const QMetaObject *);
252 QQmlPropertyCache *copy();
254 QQmlPropertyCache *copyAndAppend(QQmlEngine *, const QMetaObject *,
255 QQmlPropertyData::Flag propertyFlags = QQmlPropertyData::NoFlags,
256 QQmlPropertyData::Flag methodFlags = QQmlPropertyData::NoFlags,
257 QQmlPropertyData::Flag signalFlags = QQmlPropertyData::NoFlags);
258 QQmlPropertyCache *copyAndAppend(QQmlEngine *, const QMetaObject *, int revision,
259 QQmlPropertyData::Flag propertyFlags = QQmlPropertyData::NoFlags,
260 QQmlPropertyData::Flag methodFlags = QQmlPropertyData::NoFlags,
261 QQmlPropertyData::Flag signalFlags = QQmlPropertyData::NoFlags);
263 QQmlPropertyCache *copyAndReserve(QQmlEngine *, int propertyCount,
264 int methodCount, int signalCount);
265 void appendProperty(const QString &,
266 quint32 flags, int coreIndex, int propType, int notifyIndex);
267 void appendProperty(const QHashedCStringRef &,
268 quint32 flags, int coreIndex, int propType, int notifyIndex);
269 void appendSignal(const QString &, quint32, int coreIndex, const int *types = 0,
270 const QList<QByteArray> &names = QList<QByteArray>());
271 void appendSignal(const QHashedCStringRef &, quint32, int coreIndex, const int *types = 0,
272 const QList<QByteArray> &names = QList<QByteArray>());
273 void appendMethod(const QString &, quint32 flags, int coreIndex,
274 const QList<QByteArray> &names = QList<QByteArray>());
275 void appendMethod(const QHashedCStringRef &, quint32 flags, int coreIndex,
276 const QList<QByteArray> &names = QList<QByteArray>());
278 const QMetaObject *metaObject() const;
279 const QMetaObject *createMetaObject();
280 const QMetaObject *firstCppMetaObject() const;
283 QQmlPropertyData *property(const K &key, QObject *object, QQmlContextData *context) const
285 return findProperty(stringCache.find(key), object, context);
288 QQmlPropertyData *property(int) const;
289 QQmlPropertyData *method(int) const;
290 QQmlPropertyData *signal(int index) const { return signal(index, 0); }
291 int methodIndexToSignalIndex(int) const;
292 QStringList propertyNames() const;
294 QString defaultPropertyName() const;
295 QQmlPropertyData *defaultProperty() const;
296 QQmlPropertyCache *parent() const;
297 void setParent(QQmlPropertyCache *newParent);
299 inline QQmlPropertyData *overrideData(QQmlPropertyData *) const;
300 inline bool isAllowedInRevision(QQmlPropertyData *) const;
302 inline QQmlEngine *qmlEngine() const;
303 static QQmlPropertyData *property(QQmlEngine *, QObject *, const QString &,
304 QQmlContextData *, QQmlPropertyData &);
305 static QQmlPropertyData *property(QQmlEngine *, QObject *, const QHashedV8String &,
306 QQmlContextData *, QQmlPropertyData &);
307 static int *methodParameterTypes(QObject *, int index, QVarLengthArray<int, 9> &dummy,
308 QByteArray *unknownTypeError);
309 static int methodReturnType(QObject *, const QQmlPropertyData &data,
310 QByteArray *unknownTypeError);
312 //see QMetaObjectPrivate::originalClone
313 int originalClone(int index);
314 static int originalClone(QObject *, int index);
316 QList<QByteArray> signalParameterNames(int index) const;
317 QString signalParameterStringForJS(int index, int *count = 0, QString *errorString = 0);
319 const char *className() const;
321 inline int propertyCount() const;
322 inline int propertyOffset() const;
323 inline int methodCount() const;
324 inline int methodOffset() const;
325 inline int signalCount() const;
326 inline int signalOffset() const;
328 static bool isDynamicMetaObject(const QMetaObject *);
330 void toMetaObjectBuilder(QMetaObjectBuilder &);
333 virtual void destroy();
334 virtual void clear();
337 friend class QQmlEnginePrivate;
338 friend class QV8QObjectWrapper;
339 friend class QQmlCompiler;
341 inline QQmlPropertyCache *copy(int reserve);
343 void append(QQmlEngine *, const QMetaObject *, int revision,
344 QQmlPropertyData::Flag propertyFlags = QQmlPropertyData::NoFlags,
345 QQmlPropertyData::Flag methodFlags = QQmlPropertyData::NoFlags,
346 QQmlPropertyData::Flag signalFlags = QQmlPropertyData::NoFlags);
348 // Implemented in v8/qv8qobjectwrapper.cpp
349 v8::Local<v8::Object> newQObject(QObject *, QV8Engine *);
351 QQmlPropertyCacheMethodArguments *createArgumentsObject(int count,
352 const QList<QByteArray> &names = QList<QByteArray>());
353 QQmlPropertyData *signal(int, QQmlPropertyCache **) const;
355 typedef QVector<QQmlPropertyData> IndexCache;
356 typedef QStringMultiHash<QPair<int, QQmlPropertyData *> > StringCache;
357 typedef QVector<int> AllowedRevisionCache;
359 QQmlPropertyData *findProperty(StringCache::ConstIterator it, QObject *, QQmlContextData *) const;
360 QQmlPropertyData *findProperty(StringCache::ConstIterator it, const QQmlVMEMetaObject *, QQmlContextData *) const;
362 QQmlPropertyData *ensureResolved(QQmlPropertyData*) const;
364 void resolve(QQmlPropertyData *) const;
365 void updateRecur(QQmlEngine *, const QMetaObject *);
368 QQmlPropertyData *findNamedProperty(const K &key)
370 StringCache::mapped_type *it = stringCache.value(key);
371 return it ? it->second : 0;
375 void setNamedProperty(const K &key, int index, QQmlPropertyData *data, bool isOverride)
377 stringCache.insert(key, qMakePair(index, data));
378 _hasPropertyOverrides |= isOverride;
383 QQmlPropertyCache *_parent;
384 int propertyIndexCacheStart;
385 int methodIndexCacheStart;
386 int signalHandlerIndexCacheStart;
388 IndexCache propertyIndexCache;
389 IndexCache methodIndexCache;
390 IndexCache signalHandlerIndexCache;
391 StringCache stringCache;
392 AllowedRevisionCache allowedRevisionCache;
393 v8::Persistent<v8::Function> constructor;
395 bool _hasPropertyOverrides : 1;
396 bool _ownMetaObject : 1;
397 const QMetaObject *_metaObject;
398 QByteArray _dynamicClassName;
399 QByteArray _dynamicStringData;
400 QString _defaultPropertyName;
401 QQmlPropertyCacheMethodArguments *argumentsCache;
404 // QQmlMetaObject serves as a wrapper around either QMetaObject or QQmlPropertyCache.
405 // This is necessary as we delay creation of QMetaObject for synthesized QObjects, but
406 // we don't want to needlessly generate QQmlPropertyCaches every time we encounter a
407 // QObject type used in assignment or when we don't have a QQmlEngine etc.
409 // This class does NOT reference the propertycache.
410 class QQmlEnginePrivate;
411 class Q_QML_EXPORT QQmlMetaObject
414 inline QQmlMetaObject();
415 inline QQmlMetaObject(QObject *);
416 inline QQmlMetaObject(const QMetaObject *);
417 inline QQmlMetaObject(QQmlPropertyCache *);
418 inline QQmlMetaObject(const QQmlMetaObject &);
420 inline QQmlMetaObject &operator=(const QQmlMetaObject &);
422 inline bool isNull() const;
424 inline const char *className() const;
425 inline int propertyCount() const;
427 inline bool hasMetaObject() const;
428 inline const QMetaObject *metaObject() const;
430 QQmlPropertyCache *propertyCache(QQmlEnginePrivate *) const;
432 static bool canConvert(const QQmlMetaObject &from, const QQmlMetaObject &to);
435 QBiPointer<QQmlPropertyCache, const QMetaObject> _m;
438 QQmlPropertyData::QQmlPropertyData()
443 overrideIndexIsProperty = false;
446 metaObjectOffset = -1;
450 QQmlPropertyData::QQmlPropertyData(const QQmlPropertyRawData &d)
452 *(static_cast<QQmlPropertyRawData *>(this)) = d;
455 bool QQmlPropertyData::operator==(const QQmlPropertyRawData &other)
457 return flags == other.flags &&
458 propType == other.propType &&
459 coreIndex == other.coreIndex &&
460 notifyIndex == other.notifyIndex &&
461 revision == other.revision &&
462 (!isValueTypeVirtual() ||
463 (valueTypeCoreIndex == other.valueTypeCoreIndex &&
464 valueTypePropType == other.valueTypePropType));
467 int QQmlPropertyRawData::getValueTypeCoreIndex() const
469 return isValueTypeVirtual()?valueTypeCoreIndex:-1;
472 int QQmlPropertyRawData::encodedIndex() const
474 return isValueTypeVirtual()?(coreIndex | (valueTypeCoreIndex << 16)):coreIndex;
478 QQmlPropertyCache::overrideData(QQmlPropertyData *data) const
480 if (!data->hasOverride())
483 if (data->overrideIndexIsProperty)
484 return property(data->overrideIndex);
486 return method(data->overrideIndex);
489 bool QQmlPropertyCache::isAllowedInRevision(QQmlPropertyData *data) const
491 return (data->hasAccessors() || (data->metaObjectOffset == -1 && data->revision == 0)) ||
492 (allowedRevisionCache[data->metaObjectOffset] >= data->revision);
495 QQmlEngine *QQmlPropertyCache::qmlEngine() const
500 int QQmlPropertyCache::propertyCount() const
502 return propertyIndexCacheStart + propertyIndexCache.count();
505 int QQmlPropertyCache::propertyOffset() const
507 return propertyIndexCacheStart;
510 int QQmlPropertyCache::methodCount() const
512 return methodIndexCacheStart + methodIndexCache.count();
515 int QQmlPropertyCache::methodOffset() const
517 return methodIndexCacheStart;
520 int QQmlPropertyCache::signalCount() const
522 return signalHandlerIndexCacheStart + signalHandlerIndexCache.count();
525 int QQmlPropertyCache::signalOffset() const
527 return signalHandlerIndexCacheStart;
530 QQmlMetaObject::QQmlMetaObject()
534 QQmlMetaObject::QQmlMetaObject(QObject *o)
537 QQmlData *ddata = QQmlData::get(o, false);
538 if (ddata && ddata->propertyCache) _m = ddata->propertyCache;
539 else _m = o->metaObject();
543 QQmlMetaObject::QQmlMetaObject(const QMetaObject *m)
548 QQmlMetaObject::QQmlMetaObject(QQmlPropertyCache *m)
553 QQmlMetaObject::QQmlMetaObject(const QQmlMetaObject &o)
558 QQmlMetaObject &QQmlMetaObject::operator=(const QQmlMetaObject &o)
564 bool QQmlMetaObject::isNull() const
569 const char *QQmlMetaObject::className() const
573 } else if (_m.isT1()) {
574 return _m.asT1()->className();
576 return _m.asT2()->className();
580 int QQmlMetaObject::propertyCount() const
584 } else if (_m.isT1()) {
585 return _m.asT1()->propertyCount();
587 return _m.asT2()->propertyCount();
591 bool QQmlMetaObject::hasMetaObject() const
593 return _m.isT2() || (!_m.isNull() && _m.asT1()->metaObject());
596 const QMetaObject *QQmlMetaObject::metaObject() const
598 if (_m.isNull()) return 0;
599 if (_m.isT1()) return _m.asT1()->createMetaObject();
600 else return _m.asT2();
605 #endif // QQMLPROPERTYCACHE_P_H