1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the QtQml module of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
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;
76 // We have this somewhat awful split between RawData and Data so that RawData can be
77 // used in unions. In normal code, you should always use Data which initializes RawData
78 // to an invalid state on construction.
79 class QQmlPropertyRawData
84 ValueTypeFlagMask = 0x0000FFFF, // Flags in valueTypeFlags must fit in this mask
86 // Can apply to all properties, except IsFunction
87 IsConstant = 0x00000001, // Has CONST flag
88 IsWritable = 0x00000002, // Has WRITE function
89 IsResettable = 0x00000004, // Has RESET function
90 IsAlias = 0x00000008, // Is a QML alias to another property
91 IsFinal = 0x00000010, // Has FINAL flag
92 IsOverridden = 0x00000020, // Is overridden by a extension property
93 IsDirect = 0x00000040, // Exists on a C++ QMetaObject
94 HasAccessors = 0x00000080, // Has property accessors
96 // These are mutualy exclusive
97 IsFunction = 0x00000100, // Is an invokable
98 IsQObjectDerived = 0x00000200, // Property type is a QObject* derived type
99 IsEnumType = 0x00000400, // Property type is an enum
100 IsQList = 0x00000800, // Property type is a QML list
101 IsQmlBinding = 0x00001000, // Property type is a QQmlBinding*
102 IsQJSValue = 0x00002000, // Property type is a QScriptValue
103 IsV8Handle = 0x00004000, // Property type is a QQmlV8Handle
104 IsVarProperty = 0x00008000, // Property type is a "var" property of VMEMO
105 IsValueTypeVirtual = 0x00010000, // Property is a value type "virtual" property
106 IsQVariant = 0x00020000, // Property is a QVariant
108 // Apply only to IsFunctions
109 IsVMEFunction = 0x00040000, // Function was added by QML
110 HasArguments = 0x00080000, // Function takes arguments
111 IsSignal = 0x00100000, // Function is a signal
112 IsVMESignal = 0x00200000, // Signal was added by QML
113 IsV8Function = 0x00400000, // Function takes QQmlV8Function* args
114 IsSignalHandler = 0x00800000, // Function is a signal handler
115 IsOverload = 0x01000000, // Function is an overload of another function
116 IsCloned = 0x02000000, // The function was marked as cloned
118 // Internal QQmlPropertyCache flags
119 NotFullyResolved = 0x04000000, // True if the type data is to be lazily resolved
121 // Flags that are set based on the propType field
122 PropTypeFlagMask = IsQObjectDerived | IsEnumType | IsQList | IsQmlBinding | IsQJSValue |
123 IsV8Handle | IsQVariant,
125 Q_DECLARE_FLAGS(Flags, Flag)
127 Flags getFlags() const { return Flag(flags); }
128 void setFlags(Flags f) { flags = f; }
130 bool isValid() const { return coreIndex != -1; }
132 bool isConstant() const { return flags & IsConstant; }
133 bool isWritable() const { return flags & IsWritable; }
134 bool isResettable() const { return flags & IsResettable; }
135 bool isAlias() const { return flags & IsAlias; }
136 bool isFinal() const { return flags & IsFinal; }
137 bool isOverridden() const { return flags & IsOverridden; }
138 bool isDirect() const { return flags & IsDirect; }
139 bool hasAccessors() const { return flags & HasAccessors; }
140 bool isFunction() const { return flags & IsFunction; }
141 bool isQObject() const { return flags & IsQObjectDerived; }
142 bool isEnum() const { return flags & IsEnumType; }
143 bool isQList() const { return flags & IsQList; }
144 bool isQmlBinding() const { return flags & IsQmlBinding; }
145 bool isQJSValue() const { return flags & IsQJSValue; }
146 bool isV8Handle() const { return flags & IsV8Handle; }
147 bool isVarProperty() const { return flags & IsVarProperty; }
148 bool isValueTypeVirtual() const { return flags & IsValueTypeVirtual; }
149 bool isQVariant() const { return flags & IsQVariant; }
150 bool isVMEFunction() const { return flags & IsVMEFunction; }
151 bool hasArguments() const { return flags & HasArguments; }
152 bool isSignal() const { return flags & IsSignal; }
153 bool isVMESignal() const { return flags & IsVMESignal; }
154 bool isV8Function() const { return flags & IsV8Function; }
155 bool isSignalHandler() const { return flags & IsSignalHandler; }
156 bool isOverload() const { return flags & IsOverload; }
157 bool isCloned() const { return flags & IsCloned; }
159 bool hasOverride() const { return !(flags & IsValueTypeVirtual) &&
160 !(flags & HasAccessors) &&
161 overrideIndex >= 0; }
162 bool hasRevision() const { return !(flags & HasAccessors) && revision != 0; }
164 // Returns -1 if not a value type virtual property
165 inline int getValueTypeCoreIndex() const;
167 // Returns the "encoded" index for use with bindings. Encoding is:
168 // coreIndex | (valueTypeCoreIndex << 16)
169 inline int encodedIndex() const;
172 int propType; // When !NotFullyResolved
173 const char *propTypeName; // When NotFullyResolved
177 // The notify index is in the range returned by QObjectPrivate::signalIndex().
178 // This is different from QMetaMethod::methodIndex().
179 int notifyIndex; // When !IsFunction
180 void *arguments; // When IsFunction && HasArguments
184 struct { // When !HasAccessors
186 qint16 metaObjectOffset;
189 struct { // When IsValueTypeVirtual
190 quint16 valueTypeFlags; // flags of the access property on the value type proxy
192 quint16 valueTypePropType; // The QVariant::Type of access property on the value
194 quint16 valueTypeCoreIndex; // The prop index of the access property on the value
198 struct { // When !IsValueTypeVirtual
199 uint overrideIndexIsProperty : 1;
200 signed int overrideIndex : 31;
204 struct { // When HasAccessors
205 QQmlAccessors *accessors;
206 intptr_t accessorData;
211 friend class QQmlPropertyData;
212 friend class QQmlPropertyCache;
215 Q_DECLARE_OPERATORS_FOR_FLAGS(QQmlPropertyRawData::Flags);
217 class QQmlPropertyData : public QQmlPropertyRawData
220 inline QQmlPropertyData();
221 inline QQmlPropertyData(const QQmlPropertyRawData &);
223 inline bool operator==(const QQmlPropertyRawData &);
225 static Flags flagsForProperty(const QMetaProperty &, QQmlEngine *engine = 0);
226 void load(const QMetaProperty &, QQmlEngine *engine = 0);
227 void load(const QMetaMethod &);
228 QString name(QObject *);
229 QString name(const QMetaObject *);
232 friend class QQmlPropertyCache;
233 void lazyLoad(const QMetaProperty &, QQmlEngine *engine = 0);
234 void lazyLoad(const QMetaMethod &);
235 bool notFullyResolved() const { return flags & NotFullyResolved; }
238 class Q_QML_PRIVATE_EXPORT QQmlPropertyCache : public QQmlRefCount, public QQmlCleanup
241 QQmlPropertyCache(QQmlEngine *);
242 QQmlPropertyCache(QQmlEngine *, const QMetaObject *);
243 virtual ~QQmlPropertyCache();
245 void update(QQmlEngine *, const QMetaObject *);
247 QQmlPropertyCache *copy();
249 QQmlPropertyCache *copyAndAppend(QQmlEngine *, const QMetaObject *,
250 QQmlPropertyData::Flag propertyFlags = QQmlPropertyData::NoFlags,
251 QQmlPropertyData::Flag methodFlags = QQmlPropertyData::NoFlags,
252 QQmlPropertyData::Flag signalFlags = QQmlPropertyData::NoFlags);
253 QQmlPropertyCache *copyAndAppend(QQmlEngine *, const QMetaObject *, int revision,
254 QQmlPropertyData::Flag propertyFlags = QQmlPropertyData::NoFlags,
255 QQmlPropertyData::Flag methodFlags = QQmlPropertyData::NoFlags,
256 QQmlPropertyData::Flag signalFlags = QQmlPropertyData::NoFlags);
258 QQmlPropertyCache *copyAndReserve(QQmlEngine *, int propertyCount,
259 int methodCount, int signalCount);
260 void appendProperty(const QString &,
261 quint32 flags, int coreIndex, int propType, int notifyIndex);
262 void appendProperty(const QHashedCStringRef &,
263 quint32 flags, int coreIndex, int propType, int notifyIndex);
264 void appendSignal(const QString &, quint32, int coreIndex, const int *types = 0,
265 const QList<QByteArray> &names = QList<QByteArray>());
266 void appendSignal(const QHashedCStringRef &, quint32, int coreIndex, const int *types = 0,
267 const QList<QByteArray> &names = QList<QByteArray>());
268 void appendMethod(const QString &, quint32 flags, int coreIndex,
269 const QList<QByteArray> &names = QList<QByteArray>());
270 void appendMethod(const QHashedCStringRef &, quint32 flags, int coreIndex,
271 const QList<QByteArray> &names = QList<QByteArray>());
273 const QMetaObject *metaObject() const;
274 const QMetaObject *createMetaObject();
275 const QMetaObject *firstCppMetaObject() const;
277 inline QQmlPropertyData *property(const QHashedV8String &) const;
278 QQmlPropertyData *property(const QHashedStringRef &) const;
279 QQmlPropertyData *property(const QHashedCStringRef &) const;
280 QQmlPropertyData *property(const QString &) const;
281 QQmlPropertyData *property(int) const;
282 QQmlPropertyData *method(int) const;
283 QQmlPropertyData *signal(int) const;
284 int methodIndexToSignalIndex(int) const;
285 QStringList propertyNames() const;
287 QString defaultPropertyName() const;
288 QQmlPropertyData *defaultProperty() const;
289 QQmlPropertyCache *parent() const;
291 inline QQmlPropertyData *overrideData(QQmlPropertyData *) const;
292 inline bool isAllowedInRevision(QQmlPropertyData *) const;
294 inline QQmlEngine *qmlEngine() const;
295 static QQmlPropertyData *property(QQmlEngine *, QObject *, const QString &,
297 static QQmlPropertyData *property(QQmlEngine *, QObject *, const QHashedV8String &,
299 static int *methodParameterTypes(QObject *, int index, QVarLengthArray<int, 9> &dummy,
300 QByteArray *unknownTypeError);
301 static int methodReturnType(QObject *, const QQmlPropertyData &data,
302 QByteArray *unknownTypeError);
303 static QList<QByteArray> signalParameterNames(QObject *, int index);
305 const char *className() const;
307 inline int propertyCount() const;
308 inline int propertyOffset() const;
309 inline int methodCount() const;
310 inline int methodOffset() const;
311 inline int signalCount() const;
312 inline int signalOffset() const;
314 static bool isDynamicMetaObject(const QMetaObject *);
316 void toMetaObjectBuilder(QMetaObjectBuilder &);
319 virtual void destroy();
320 virtual void clear();
323 friend class QQmlEnginePrivate;
324 friend class QV8QObjectWrapper;
325 friend class QQmlCompiler;
327 inline QQmlPropertyCache *copy(int reserve);
329 void append(QQmlEngine *, const QMetaObject *, int revision,
330 QQmlPropertyData::Flag propertyFlags = QQmlPropertyData::NoFlags,
331 QQmlPropertyData::Flag methodFlags = QQmlPropertyData::NoFlags,
332 QQmlPropertyData::Flag signalFlags = QQmlPropertyData::NoFlags);
334 // Implemented in v8/qv8qobjectwrapper.cpp
335 v8::Local<v8::Object> newQObject(QObject *, QV8Engine *);
337 typedef QVector<QQmlPropertyData> IndexCache;
338 typedef QStringHash<QQmlPropertyData *> StringCache;
339 typedef QVector<int> AllowedRevisionCache;
341 void resolve(QQmlPropertyData *) const;
342 void updateRecur(QQmlEngine *, const QMetaObject *);
346 QQmlPropertyCache *_parent;
347 int propertyIndexCacheStart;
348 int methodIndexCacheStart;
349 int signalHandlerIndexCacheStart;
351 IndexCache propertyIndexCache;
352 IndexCache methodIndexCache;
353 IndexCache signalHandlerIndexCache;
354 StringCache stringCache;
355 AllowedRevisionCache allowedRevisionCache;
356 v8::Persistent<v8::Function> constructor;
359 const QMetaObject *_metaObject;
360 QByteArray _dynamicClassName;
361 QByteArray _dynamicStringData;
362 QString _defaultPropertyName;
363 QQmlPropertyCacheMethodArguments *argumentsCache;
366 // QQmlMetaObject serves as a wrapper around either QMetaObject or QQmlPropertyCache.
367 // This is necessary as we delay creation of QMetaObject for synthesized QObjects, but
368 // we don't want to needlessly generate QQmlPropertyCaches every time we encounter a
369 // QObject type used in assignment or when we don't have a QQmlEngine etc.
371 // This class does NOT reference the propertycache.
372 class QQmlEnginePrivate;
373 class Q_QML_EXPORT QQmlMetaObject
376 inline QQmlMetaObject();
377 inline QQmlMetaObject(QObject *);
378 inline QQmlMetaObject(const QMetaObject *);
379 inline QQmlMetaObject(QQmlPropertyCache *);
380 inline QQmlMetaObject(const QQmlMetaObject &);
382 inline QQmlMetaObject &operator=(const QQmlMetaObject &);
384 inline bool isNull() const;
386 inline const char *className() const;
387 inline int propertyCount() const;
389 inline bool hasMetaObject() const;
390 inline const QMetaObject *metaObject() const;
392 QQmlPropertyCache *propertyCache(QQmlEnginePrivate *) const;
394 static bool canConvert(const QQmlMetaObject &from, const QQmlMetaObject &to);
397 QBiPointer<QQmlPropertyCache, const QMetaObject> _m;
400 QQmlPropertyData::QQmlPropertyData()
405 overrideIndexIsProperty = false;
408 metaObjectOffset = -1;
412 QQmlPropertyData::QQmlPropertyData(const QQmlPropertyRawData &d)
414 *(static_cast<QQmlPropertyRawData *>(this)) = d;
417 bool QQmlPropertyData::operator==(const QQmlPropertyRawData &other)
419 return flags == other.flags &&
420 propType == other.propType &&
421 coreIndex == other.coreIndex &&
422 notifyIndex == other.notifyIndex &&
423 revision == other.revision &&
424 (!isValueTypeVirtual() ||
425 (valueTypeCoreIndex == other.valueTypeCoreIndex &&
426 valueTypePropType == other.valueTypePropType));
429 int QQmlPropertyRawData::getValueTypeCoreIndex() const
431 return isValueTypeVirtual()?valueTypeCoreIndex:-1;
434 int QQmlPropertyRawData::encodedIndex() const
436 return isValueTypeVirtual()?(coreIndex | (valueTypeCoreIndex << 16)):coreIndex;
440 QQmlPropertyCache::overrideData(QQmlPropertyData *data) const
442 if (!data->hasOverride())
445 if (data->overrideIndexIsProperty)
446 return property(data->overrideIndex);
448 return method(data->overrideIndex);
451 bool QQmlPropertyCache::isAllowedInRevision(QQmlPropertyData *data) const
453 return (data->hasAccessors() || (data->metaObjectOffset == -1 && data->revision == 0)) ||
454 (allowedRevisionCache[data->metaObjectOffset] >= data->revision);
457 QQmlEngine *QQmlPropertyCache::qmlEngine() const
462 QQmlPropertyData *QQmlPropertyCache::property(const QHashedV8String &str) const
464 QQmlPropertyData **rv = stringCache.value(str);
465 if (rv && (*rv)->notFullyResolved()) resolve(*rv);
469 int QQmlPropertyCache::propertyCount() const
471 return propertyIndexCacheStart + propertyIndexCache.count();
474 int QQmlPropertyCache::propertyOffset() const
476 return propertyIndexCacheStart;
479 int QQmlPropertyCache::methodCount() const
481 return methodIndexCacheStart + methodIndexCache.count();
484 int QQmlPropertyCache::methodOffset() const
486 return methodIndexCacheStart;
489 int QQmlPropertyCache::signalCount() const
491 return signalHandlerIndexCacheStart + signalHandlerIndexCache.count();
494 int QQmlPropertyCache::signalOffset() const
496 return signalHandlerIndexCacheStart;
499 QQmlMetaObject::QQmlMetaObject()
503 QQmlMetaObject::QQmlMetaObject(QObject *o)
506 QQmlData *ddata = QQmlData::get(o, false);
507 if (ddata && ddata->propertyCache) _m = ddata->propertyCache;
508 else _m = o->metaObject();
512 QQmlMetaObject::QQmlMetaObject(const QMetaObject *m)
517 QQmlMetaObject::QQmlMetaObject(QQmlPropertyCache *m)
522 QQmlMetaObject::QQmlMetaObject(const QQmlMetaObject &o)
527 QQmlMetaObject &QQmlMetaObject::operator=(const QQmlMetaObject &o)
533 bool QQmlMetaObject::isNull() const
538 const char *QQmlMetaObject::className() const
542 } else if (_m.isT1()) {
543 return _m.asT1()->className();
545 return _m.asT2()->className();
549 int QQmlMetaObject::propertyCount() const
553 } else if (_m.isT1()) {
554 return _m.asT1()->propertyCount();
556 return _m.asT2()->propertyCount();
560 bool QQmlMetaObject::hasMetaObject() const
562 return _m.isT2() || (!_m.isNull() && _m.asT1()->metaObject());
565 const QMetaObject *QQmlMetaObject::metaObject() const
567 if (_m.isNull()) return 0;
568 if (_m.isT1()) return _m.asT1()->createMetaObject();
569 else return _m.asT2();
574 #endif // QQMLPROPERTYCACHE_P_H