/**************************************************************************** ** ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the QtQml module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL21$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and Digia. For licensing terms and ** conditions see http://qt.digia.com/licensing. For further information ** use the contact form at http://qt.digia.com/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 or version 3 as published by the Free ** Software Foundation and appearing in the file LICENSE.LGPLv21 and ** LICENSE.LGPLv3 included in the packaging of this file. Please review the ** following information to ensure the GNU Lesser General Public License ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Digia gives you certain additional ** rights. These rights are described in the Digia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef QQMLPROPERTYCACHE_P_H #define QQMLPROPERTYCACHE_P_H // // W A R N I N G // ------------- // // This file is not part of the Qt API. It exists purely as an // implementation detail. This header file may change from version to // version without notice, or even be removed. // // We mean it. // #include #include #include "qqmlcleanup_p.h" #include "qqmlnotifier_p.h" #include #include #include #include QT_BEGIN_NAMESPACE class QV8Engine; class QMetaProperty; class QQmlEngine; class QQmlPropertyData; class QQmlAccessors; class QMetaObjectBuilder; class QQmlPropertyCacheMethodArguments; class QQmlVMEMetaObject; class QQmlPropertyCacheCreator; // We have this somewhat awful split between RawData and Data so that RawData can be // used in unions. In normal code, you should always use Data which initializes RawData // to an invalid state on construction. class QQmlPropertyRawData { public: enum Flag { NoFlags = 0x00000000, ValueTypeFlagMask = 0x0000FFFF, // Flags in valueTypeFlags must fit in this mask // Can apply to all properties, except IsFunction IsConstant = 0x00000001, // Has CONST flag IsWritable = 0x00000002, // Has WRITE function IsResettable = 0x00000004, // Has RESET function IsAlias = 0x00000008, // Is a QML alias to another property IsFinal = 0x00000010, // Has FINAL flag IsOverridden = 0x00000020, // Is overridden by a extension property IsDirect = 0x00000040, // Exists on a C++ QMetaObject HasAccessors = 0x00000080, // Has property accessors // These are mutualy exclusive IsFunction = 0x00000100, // Is an invokable IsQObjectDerived = 0x00000200, // Property type is a QObject* derived type IsEnumType = 0x00000400, // Property type is an enum IsQList = 0x00000800, // Property type is a QML list IsQmlBinding = 0x00001000, // Property type is a QQmlBinding* IsQJSValue = 0x00002000, // Property type is a QScriptValue IsV4Handle = 0x00004000, // Property type is a QQmlV4Handle IsVarProperty = 0x00008000, // Property type is a "var" property of VMEMO IsValueTypeVirtual = 0x00010000, // Property is a value type "virtual" property IsQVariant = 0x00020000, // Property is a QVariant // Apply only to IsFunctions IsVMEFunction = 0x00040000, // Function was added by QML HasArguments = 0x00080000, // Function takes arguments IsSignal = 0x00100000, // Function is a signal IsVMESignal = 0x00200000, // Signal was added by QML IsV4Function = 0x00400000, // Function takes QQmlV4Function* args IsSignalHandler = 0x00800000, // Function is a signal handler IsOverload = 0x01000000, // Function is an overload of another function IsCloned = 0x02000000, // The function was marked as cloned // Internal QQmlPropertyCache flags NotFullyResolved = 0x04000000, // True if the type data is to be lazily resolved // Flags that are set based on the propType field PropTypeFlagMask = IsQObjectDerived | IsEnumType | IsQList | IsQmlBinding | IsQJSValue | IsV4Handle | IsQVariant, }; Q_DECLARE_FLAGS(Flags, Flag) Flags getFlags() const { return Flag(flags); } void setFlags(Flags f) { flags = f; } bool isValid() const { return coreIndex != -1; } bool isConstant() const { return flags & IsConstant; } bool isWritable() const { return flags & IsWritable; } bool isResettable() const { return flags & IsResettable; } bool isAlias() const { return flags & IsAlias; } bool isFinal() const { return flags & IsFinal; } bool isOverridden() const { return flags & IsOverridden; } bool isDirect() const { return flags & IsDirect; } bool hasAccessors() const { return flags & HasAccessors; } bool isFunction() const { return flags & IsFunction; } bool isQObject() const { return flags & IsQObjectDerived; } bool isEnum() const { return flags & IsEnumType; } bool isQList() const { return flags & IsQList; } bool isQmlBinding() const { return flags & IsQmlBinding; } bool isQJSValue() const { return flags & IsQJSValue; } bool isV4Handle() const { return flags & IsV4Handle; } bool isVarProperty() const { return flags & IsVarProperty; } bool isValueTypeVirtual() const { return flags & IsValueTypeVirtual; } bool isQVariant() const { return flags & IsQVariant; } bool isVMEFunction() const { return flags & IsVMEFunction; } bool hasArguments() const { return flags & HasArguments; } bool isSignal() const { return flags & IsSignal; } bool isVMESignal() const { return flags & IsVMESignal; } bool isV4Function() const { return flags & IsV4Function; } bool isSignalHandler() const { return flags & IsSignalHandler; } bool isOverload() const { return flags & IsOverload; } bool isCloned() const { return flags & IsCloned; } bool hasOverride() const { return !(flags & IsValueTypeVirtual) && !(flags & HasAccessors) && overrideIndex >= 0; } bool hasRevision() const { return !(flags & HasAccessors) && revision != 0; } // Returns -1 if not a value type virtual property inline int getValueTypeCoreIndex() const; // Returns the "encoded" index for use with bindings. Encoding is: // coreIndex | (valueTypeCoreIndex << 16) inline int encodedIndex() const; union { int propType; // When !NotFullyResolved const char *propTypeName; // When NotFullyResolved }; int coreIndex; union { // The notify index is in the range returned by QObjectPrivate::signalIndex(). // This is different from QMetaMethod::methodIndex(). int notifyIndex; // When !IsFunction void *arguments; // When IsFunction && HasArguments }; union { struct { // When !HasAccessors qint16 revision; qint16 metaObjectOffset; union { struct { // When IsValueTypeVirtual quint16 valueTypeFlags; // flags of the access property on the value type proxy // object quint16 valueTypePropType; // The QVariant::Type of access property on the value // type proxy object quint16 valueTypeCoreIndex; // The prop index of the access property on the value // type proxy object }; struct { // When !IsValueTypeVirtual uint overrideIndexIsProperty : 1; signed int overrideIndex : 31; }; }; }; struct { // When HasAccessors QQmlAccessors *accessors; qintptr accessorData; }; }; private: friend class QQmlPropertyData; friend class QQmlPropertyCache; quint32 flags; }; Q_DECLARE_OPERATORS_FOR_FLAGS(QQmlPropertyRawData::Flags) class QQmlPropertyData : public QQmlPropertyRawData { public: inline QQmlPropertyData(); inline QQmlPropertyData(const QQmlPropertyRawData &); inline bool operator==(const QQmlPropertyRawData &); static Flags flagsForProperty(const QMetaProperty &, QQmlEngine *engine = 0); void load(const QMetaProperty &, QQmlEngine *engine = 0); void load(const QMetaMethod &); QString name(QObject *) const; QString name(const QMetaObject *) const; void markAsOverrideOf(QQmlPropertyData *predecessor); private: friend class QQmlPropertyCache; void lazyLoad(const QMetaProperty &, QQmlEngine *engine = 0); void lazyLoad(const QMetaMethod &); bool notFullyResolved() const { return flags & NotFullyResolved; } }; class QQmlPropertyCacheMethodArguments; class Q_QML_PRIVATE_EXPORT QQmlPropertyCache : public QQmlRefCount, public QQmlCleanup { public: QQmlPropertyCache(QQmlEngine *); QQmlPropertyCache(QQmlEngine *, const QMetaObject *); virtual ~QQmlPropertyCache(); void update(QQmlEngine *, const QMetaObject *); void invalidate(QQmlEngine *, const QMetaObject *); QQmlPropertyCache *copy(); QQmlPropertyCache *copyAndAppend(QQmlEngine *, const QMetaObject *, QQmlPropertyData::Flag propertyFlags = QQmlPropertyData::NoFlags, QQmlPropertyData::Flag methodFlags = QQmlPropertyData::NoFlags, QQmlPropertyData::Flag signalFlags = QQmlPropertyData::NoFlags); QQmlPropertyCache *copyAndAppend(QQmlEngine *, const QMetaObject *, int revision, QQmlPropertyData::Flag propertyFlags = QQmlPropertyData::NoFlags, QQmlPropertyData::Flag methodFlags = QQmlPropertyData::NoFlags, QQmlPropertyData::Flag signalFlags = QQmlPropertyData::NoFlags); QQmlPropertyCache *copyAndReserve(QQmlEngine *, int propertyCount, int methodCount, int signalCount); void appendProperty(const QString &, quint32 flags, int coreIndex, int propType, int notifyIndex); void appendProperty(const QHashedCStringRef &, quint32 flags, int coreIndex, int propType, int notifyIndex); void appendSignal(const QString &, quint32, int coreIndex, const int *types = 0, const QList &names = QList()); void appendSignal(const QHashedCStringRef &, quint32, int coreIndex, const int *types = 0, const QList &names = QList()); void appendMethod(const QString &, quint32 flags, int coreIndex, const QList &names = QList()); void appendMethod(const QHashedCStringRef &, quint32 flags, int coreIndex, const QList &names = QList()); const QMetaObject *metaObject() const; const QMetaObject *createMetaObject(); const QMetaObject *firstCppMetaObject() const; template QQmlPropertyData *property(const K &key, QObject *object, QQmlContextData *context) const { return findProperty(stringCache.find(key), object, context); } QQmlPropertyData *property(int) const; QQmlPropertyData *method(int) const; QQmlPropertyData *signal(int index) const { return signal(index, 0); } int methodIndexToSignalIndex(int) const; QStringList propertyNames() const; QString defaultPropertyName() const; QQmlPropertyData *defaultProperty() const; QQmlPropertyCache *parent() const; // is used by the Qml Designer void setParent(QQmlPropertyCache *newParent); inline QQmlPropertyData *overrideData(QQmlPropertyData *) const; inline bool isAllowedInRevision(QQmlPropertyData *) const; inline QQmlEngine *qmlEngine() const; static QQmlPropertyData *property(QQmlEngine *, QObject *, const QString &, QQmlContextData *, QQmlPropertyData &); static QQmlPropertyData *property(QQmlEngine *, QObject *, const QV4::String *, QQmlContextData *, QQmlPropertyData &); static int *methodParameterTypes(QObject *, int index, QVarLengthArray &dummy, QByteArray *unknownTypeError); static int methodReturnType(QObject *, const QQmlPropertyData &data, QByteArray *unknownTypeError); //see QMetaObjectPrivate::originalClone int originalClone(int index); static int originalClone(QObject *, int index); QList signalParameterNames(int index) const; QString signalParameterStringForJS(int index, QString *errorString = 0); static QString signalParameterStringForJS(QQmlEngine *engine, const QList ¶meterNameList, QString *errorString = 0); const char *className() const; inline int propertyCount() const; inline int propertyOffset() const; inline int methodCount() const; inline int methodOffset() const; inline int signalCount() const; inline int signalOffset() const; static bool isDynamicMetaObject(const QMetaObject *); void toMetaObjectBuilder(QMetaObjectBuilder &); protected: virtual void destroy(); virtual void clear(); private: friend class QQmlEnginePrivate; friend class QQmlCompiler; friend class QQmlPropertyCacheCreator; friend class QQmlComponentAndAliasResolver; inline QQmlPropertyCache *copy(int reserve); void append(QQmlEngine *, const QMetaObject *, int revision, QQmlPropertyData::Flag propertyFlags = QQmlPropertyData::NoFlags, QQmlPropertyData::Flag methodFlags = QQmlPropertyData::NoFlags, QQmlPropertyData::Flag signalFlags = QQmlPropertyData::NoFlags); QQmlPropertyCacheMethodArguments *createArgumentsObject(int count, const QList &names); QQmlPropertyData *signal(int, QQmlPropertyCache **) const; typedef QVector IndexCache; typedef QStringMultiHash > StringCache; typedef QVector AllowedRevisionCache; QQmlPropertyData *findProperty(StringCache::ConstIterator it, QObject *, QQmlContextData *) const; QQmlPropertyData *findProperty(StringCache::ConstIterator it, const QQmlVMEMetaObject *, QQmlContextData *) const; QQmlPropertyData *ensureResolved(QQmlPropertyData*) const; void resolve(QQmlPropertyData *) const; void updateRecur(QQmlEngine *, const QMetaObject *); template QQmlPropertyData *findNamedProperty(const K &key) { StringCache::mapped_type *it = stringCache.value(key); return it ? it->second : 0; } template void setNamedProperty(const K &key, int index, QQmlPropertyData *data, bool isOverride) { stringCache.insert(key, qMakePair(index, data)); _hasPropertyOverrides |= isOverride; } QQmlEngine *engine; QQmlPropertyCache *_parent; int propertyIndexCacheStart; int methodIndexCacheStart; int signalHandlerIndexCacheStart; IndexCache propertyIndexCache; IndexCache methodIndexCache; IndexCache signalHandlerIndexCache; StringCache stringCache; AllowedRevisionCache allowedRevisionCache; bool _hasPropertyOverrides : 1; bool _ownMetaObject : 1; const QMetaObject *_metaObject; QByteArray _dynamicClassName; QByteArray _dynamicStringData; QString _defaultPropertyName; QQmlPropertyCacheMethodArguments *argumentsCache; }; // QQmlMetaObject serves as a wrapper around either QMetaObject or QQmlPropertyCache. // This is necessary as we delay creation of QMetaObject for synthesized QObjects, but // we don't want to needlessly generate QQmlPropertyCaches every time we encounter a // QObject type used in assignment or when we don't have a QQmlEngine etc. // // This class does NOT reference the propertycache. class QQmlEnginePrivate; class Q_QML_EXPORT QQmlMetaObject { public: inline QQmlMetaObject(); inline QQmlMetaObject(QObject *); inline QQmlMetaObject(const QMetaObject *); inline QQmlMetaObject(QQmlPropertyCache *); inline QQmlMetaObject(const QQmlMetaObject &); inline QQmlMetaObject &operator=(const QQmlMetaObject &); inline bool isNull() const; inline const char *className() const; inline int propertyCount() const; inline bool hasMetaObject() const; inline const QMetaObject *metaObject() const; QQmlPropertyCache *propertyCache(QQmlEnginePrivate *) const; static bool canConvert(const QQmlMetaObject &from, const QQmlMetaObject &to); private: QBiPointer _m; }; QQmlPropertyData::QQmlPropertyData() { propType = 0; coreIndex = -1; notifyIndex = -1; overrideIndexIsProperty = false; overrideIndex = -1; revision = 0; metaObjectOffset = -1; flags = 0; } QQmlPropertyData::QQmlPropertyData(const QQmlPropertyRawData &d) { *(static_cast(this)) = d; } bool QQmlPropertyData::operator==(const QQmlPropertyRawData &other) { return flags == other.flags && propType == other.propType && coreIndex == other.coreIndex && notifyIndex == other.notifyIndex && revision == other.revision && (!isValueTypeVirtual() || (valueTypeCoreIndex == other.valueTypeCoreIndex && valueTypePropType == other.valueTypePropType)); } int QQmlPropertyRawData::getValueTypeCoreIndex() const { return isValueTypeVirtual()?valueTypeCoreIndex:-1; } int QQmlPropertyRawData::encodedIndex() const { return isValueTypeVirtual()?(coreIndex | (valueTypeCoreIndex << 16)):coreIndex; } QQmlPropertyData * QQmlPropertyCache::overrideData(QQmlPropertyData *data) const { if (!data->hasOverride()) return 0; if (data->overrideIndexIsProperty) return property(data->overrideIndex); else return method(data->overrideIndex); } bool QQmlPropertyCache::isAllowedInRevision(QQmlPropertyData *data) const { return (data->hasAccessors() || (data->metaObjectOffset == -1 && data->revision == 0)) || (allowedRevisionCache[data->metaObjectOffset] >= data->revision); } QQmlEngine *QQmlPropertyCache::qmlEngine() const { return engine; } int QQmlPropertyCache::propertyCount() const { return propertyIndexCacheStart + propertyIndexCache.count(); } int QQmlPropertyCache::propertyOffset() const { return propertyIndexCacheStart; } int QQmlPropertyCache::methodCount() const { return methodIndexCacheStart + methodIndexCache.count(); } int QQmlPropertyCache::methodOffset() const { return methodIndexCacheStart; } int QQmlPropertyCache::signalCount() const { return signalHandlerIndexCacheStart + signalHandlerIndexCache.count(); } int QQmlPropertyCache::signalOffset() const { return signalHandlerIndexCacheStart; } QQmlMetaObject::QQmlMetaObject() { } QQmlMetaObject::QQmlMetaObject(QObject *o) { if (o) { QQmlData *ddata = QQmlData::get(o, false); if (ddata && ddata->propertyCache) _m = ddata->propertyCache; else _m = o->metaObject(); } } QQmlMetaObject::QQmlMetaObject(const QMetaObject *m) : _m(m) { } QQmlMetaObject::QQmlMetaObject(QQmlPropertyCache *m) : _m(m) { } QQmlMetaObject::QQmlMetaObject(const QQmlMetaObject &o) : _m(o._m) { } QQmlMetaObject &QQmlMetaObject::operator=(const QQmlMetaObject &o) { _m = o._m; return *this; } bool QQmlMetaObject::isNull() const { return _m.isNull(); } const char *QQmlMetaObject::className() const { if (_m.isNull()) { return 0; } else if (_m.isT1()) { return _m.asT1()->className(); } else { return _m.asT2()->className(); } } int QQmlMetaObject::propertyCount() const { if (_m.isNull()) { return 0; } else if (_m.isT1()) { return _m.asT1()->propertyCount(); } else { return _m.asT2()->propertyCount(); } } bool QQmlMetaObject::hasMetaObject() const { return _m.isT2() || (!_m.isNull() && _m.asT1()->metaObject()); } const QMetaObject *QQmlMetaObject::metaObject() const { if (_m.isNull()) return 0; if (_m.isT1()) return _m.asT1()->createMetaObject(); else return _m.asT2(); } QT_END_NAMESPACE #endif // QQMLPROPERTYCACHE_P_H