diff options
author | Michael Brasser <michael.brasser@nokia.com> | 2009-04-22 04:47:24 (GMT) |
---|---|---|
committer | Michael Brasser <michael.brasser@nokia.com> | 2009-04-22 04:47:24 (GMT) |
commit | 2366667fc97eb6a56203b2dd7dac776ff4164abd (patch) | |
tree | b2acb6cc6bfe475d7e619e4788973b61fff775e0 /src/declarative/qml | |
parent | 2c762f3b8b284a7c6dc0c499b7052013bad5b707 (diff) | |
download | Qt-2366667fc97eb6a56203b2dd7dac776ff4164abd.zip Qt-2366667fc97eb6a56203b2dd7dac776ff4164abd.tar.gz Qt-2366667fc97eb6a56203b2dd7dac776ff4164abd.tar.bz2 |
Initial import of kinetic-dui branch from the old kinetic
Diffstat (limited to 'src/declarative/qml')
71 files changed, 16974 insertions, 0 deletions
diff --git a/src/declarative/qml/qml.h b/src/declarative/qml/qml.h new file mode 100644 index 0000000..bf7b6bc --- /dev/null +++ b/src/declarative/qml/qml.h @@ -0,0 +1,98 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QML_H +#define QML_H + +#include <QtCore/qbytearray.h> +#include <QtCore/qstringlist.h> +#include <QtCore/qurl.h> +#include <QtCore/qmetaobject.h> +#include <QtDeclarative/qfxglobal.h> +#include <QtDeclarative/qmlmetatype.h> +#include <QtDeclarative/qmlmetaproperty.h> +#include <QtDeclarative/qmlparserstatus.h> +#include <QtDeclarative/qmllist.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +#define QML_DECLARE_TYPE(TYPE) \ + Q_DECLARE_METATYPE(TYPE *); \ + Q_DECLARE_METATYPE(QList<TYPE *> *); \ + Q_DECLARE_METATYPE(QmlList<TYPE *> *); + +#define QML_DECLARE_TYPE_HASMETATYPE(TYPE) \ + Q_DECLARE_METATYPE(QList<TYPE *> *); \ + Q_DECLARE_METATYPE(QmlList<TYPE *> *); + +#define QML_DECLARE_INTERFACE(INTERFACE) \ + QML_DECLARE_TYPE(INTERFACE) + +#define QML_DECLARE_INTERFACE_HASMETATYPE(INTERFACE) \ + QML_DECLARE_TYPE_HASMETATYPE(INTERFACE) + +#define QML_DEFINE_INTERFACE(INTERFACE) \ + template<> QmlPrivate::InstanceType QmlPrivate::Define<INTERFACE *>::instance(qmlRegisterInterface<INTERFACE>(#INTERFACE)); + +#define QML_DEFINE_EXTENDED_TYPE(TYPE, NAME, EXTENSION) \ + template<> QmlPrivate::InstanceType QmlPrivate::Define<TYPE *>::instance(qmlRegisterExtendedType<TYPE,EXTENSION>(#NAME, #TYPE)); + +#define QML_DEFINE_TYPE(TYPE, NAME) \ + template<> QmlPrivate::InstanceType QmlPrivate::Define<TYPE *>::instance(qmlRegisterType<TYPE>(#NAME, #TYPE)); + +#define QML_DEFINE_EXTENDED_NOCREATE_TYPE(TYPE, EXTENSION) \ + template<> QmlPrivate::InstanceType QmlPrivate::Define<TYPE *>::instance(qmlRegisterExtendedType<TYPE,EXTENSION>(#TYPE)); + +#define QML_DEFINE_NOCREATE_TYPE(TYPE) \ + template<> QmlPrivate::InstanceType QmlPrivate::Define<TYPE *>::instance(qmlRegisterType<TYPE>(#TYPE)); + +QML_DECLARE_TYPE(QObject); +Q_DECLARE_METATYPE(QVariant); + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QML_H diff --git a/src/declarative/qml/qml.pri b/src/declarative/qml/qml.pri new file mode 100644 index 0000000..65e6763 --- /dev/null +++ b/src/declarative/qml/qml.pri @@ -0,0 +1,63 @@ +SOURCES += qml/qmlparser.cpp \ + qml/qmlinstruction.cpp \ + qml/qmlvmemetaobject.cpp \ + qml/qmlengine.cpp \ + qml/qmlbindablevalue.cpp \ + qml/qmlmetaproperty.cpp \ + qml/qmlcomponent.cpp \ + qml/qmlcontext.cpp \ + qml/qmlcustomparser.cpp \ + qml/qmlpropertyvaluesource.cpp \ + qml/qmlxmlparser.cpp \ + qml/qmlproxymetaobject.cpp \ + qml/qmlvme.cpp \ + qml/qmlcompiler.cpp \ + qml/qmlcompiledcomponent.cpp \ + qml/qmlboundsignal.cpp \ + qml/qmldom.cpp \ + qml/qmlrefcount.cpp \ + qml/qmlprivate.cpp \ + qml/qmlmetatype.cpp \ + qml/qmlstringconverters.cpp \ + qml/qmlclassfactory.cpp \ + qml/qmlparserstatus.cpp \ + qml/qmlcompositetypemanager.cpp \ + qml/qmlinfo.cpp + +HEADERS += qml/qmlparser_p.h \ + qml/qmlinstruction_p.h \ + qml/qmlvmemetaobject_p.h \ + qml/qml.h \ + qml/qmlbindablevalue.h \ + qml/qmlmetaproperty.h \ + qml/qmlcomponent.h \ + qml/qmlcomponent_p.h \ + qml/qmlcustomparser.h \ + qml/qmlpropertyvaluesource.h \ + qml/qmlboundsignal_p.h \ + qml/qmlxmlparser_p.h \ + qml/qmlparserstatus.h \ + qml/qmlproxymetaobject_p.h \ + qml/qmlcompiledcomponent_p.h \ + qml/qmlvme_p.h \ + qml/qmlcompiler_p.h \ + qml/qmlengine_p.h \ + qml/qmlprivate.h \ + qml/qmldom.h \ + qml/qmldom_p.h \ + qml/qmlrefcount_p.h \ + qml/qmlmetatype.h \ + qml/qmlengine.h \ + qml/qmlcontext.h \ + qml/qmlexpression.h \ + qml/qmlstringconverters_p.h \ + qml/qmlclassfactory_p.h \ + qml/qmlinfo.h \ + qml/qmlmetaproperty_p.h \ + qml/qmlcontext_p.h \ + qml/qmlcompositetypemanager_p.h \ + qml/qmllist.h + +# for qtscript debugger +QT += scripttools +include(script/script.pri) diff --git a/src/declarative/qml/qmlbindablevalue.cpp b/src/declarative/qml/qmlbindablevalue.cpp new file mode 100644 index 0000000..423fda8 --- /dev/null +++ b/src/declarative/qml/qmlbindablevalue.cpp @@ -0,0 +1,210 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <qml.h> +#include "qmlbindablevalue.h" +#include <gfxeasing.h> +#include <qmlcontext.h> +#include <gfxtimeline.h> +#include <QVariant> +#include <qfxperf.h> +#include <QtCore/qdebug.h> + + +QT_BEGIN_NAMESPACE +DEFINE_BOOL_CONFIG_OPTION(scriptWarnings, QML_SCRIPT_WARNINGS); + +QML_DEFINE_NOCREATE_TYPE(QmlBindableValue); +QmlBindableValue::QmlBindableValue(QObject *parent) +: QmlPropertyValueSource(parent), _inited(false) +{ + qFatal("QmlBindableValue: Default constructor not supported"); +} + +QmlBindableValue::QmlBindableValue(void *data, QmlRefCount *rc, QObject *obj, QObject *parent) +: QmlPropertyValueSource(parent), QmlExpression(QmlContext::activeContext(), data, rc, obj), _inited(false) +{ +} + +QmlBindableValue::QmlBindableValue(const QString &str, QObject *obj, bool sse, QObject *parent) +: QmlPropertyValueSource(parent), QmlExpression(QmlContext::activeContext(), str, obj, sse), _inited(false) +{ +} + +QmlBindableValue::~QmlBindableValue() +{ +} + +void QmlBindableValue::setTarget(const QmlMetaProperty &prop) +{ + _property = prop; + + update(); +} + +void QmlBindableValue::init() +{ + if(_inited) + return; + _inited = true; + update(); +} + +void QmlBindableValue::setExpression(const QString &expr) +{ + QmlExpression::setExpression(expr); + update(); +} + +Q_DECLARE_METATYPE(QList<QObject *>); +void QmlBindableValue::update() +{ +#ifdef Q_ENABLE_PERFORMANCE_LOG + QFxPerfTimer<QFxPerf::BindableValueUpdate> bu; +#endif + if(!_inited) + return; + + if(_property.propertyCategory() == QmlMetaProperty::List) { + QVariant value = this->value(); + int listType = QmlMetaType::listType(_property.propertyType()); + + if(value.userType() == qMetaTypeId<QList<QObject *> >()) { + const QList<QObject *> &list = + qvariant_cast<QList<QObject *> >(value); + QVariant listVar = _property.read(); + QmlMetaType::clear(listVar); + for(int ii = 0; ii < list.count(); ++ii) { + QVariant v = QmlMetaType::fromObject(list.at(ii), listType); + QmlMetaType::append(listVar, v); + } + + } else if(value.type() == uint(listType) || + value.userType() == listType) { + QVariant listVar = _property.read(); + QmlMetaType::clear(listVar); + QmlMetaType::append(listVar, value); + } + } else if(_property.propertyCategory() == QmlMetaProperty::QmlList) { + // XXX - optimize! + QVariant value = this->value(); + QVariant list = _property.read(); + QmlPrivate::ListInterface *li = + *(QmlPrivate::ListInterface **)list.constData(); + + int type = li->type(); + + if (QObject *obj = QmlMetaType::toQObject(value)) { + const QMetaObject *mo = + QmlMetaType::rawMetaObjectForType(type); + + const QMetaObject *objMo = obj->metaObject(); + bool found = false; + while(!found && objMo) { + if(objMo == mo) + found = true; + else + objMo = objMo->superClass(); + } + + if(!found) { + qWarning() << "Unable to assign object to list"; + return; + } + + // NOTE: This assumes a cast to QObject does not alter + // the object pointer + void *d = (void *)&obj; + li->append(d); + } + } else if(_property.propertyCategory() == QmlMetaProperty::Bindable) { + + // NOTE: We assume that only core properties can have + // propertyType == Bindable + int idx = _property.coreIndex(); + Q_ASSERT(idx != -1); + + void *a[1]; + QmlBindableValue *t = this; + a[0] = (void *)&t; + _property.object()->qt_metacall(QMetaObject::WriteProperty, + idx, a); + + } else if(_property.propertyCategory() == QmlMetaProperty::Object) { + + QVariant value = this->value(); + if((int)value.type() != qMetaTypeId<QObject *>()) { + if(scriptWarnings()) { + if(!value.isValid()) { + qWarning() << "QmlBindableValue: Unable to assign invalid value to object property"; + } else { + qWarning() << "QmlBindableValue: Unable to assign non-object to object property"; + } + } + return; + } + + // NOTE: This assumes a cast to QObject does not alter the + // object pointer + QObject *obj = *(QObject **)value.data(); + + // NOTE: We assume that only core properties can have + // propertyType == Object + int idx = _property.coreIndex(); + Q_ASSERT(idx != -1); + + void *a[1]; + a[0] = (void *)&obj; + _property.object()->qt_metacall(QMetaObject::WriteProperty, + idx, a); + + } else if(_property.propertyCategory() == QmlMetaProperty::Normal) { + QVariant value = this->value(); + _property.write(value); + } +} + +void QmlBindableValue::valueChanged() +{ + update(); +} + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlbindablevalue.h b/src/declarative/qml/qmlbindablevalue.h new file mode 100644 index 0000000..578fc12 --- /dev/null +++ b/src/declarative/qml/qmlbindablevalue.h @@ -0,0 +1,94 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLBINDABLEVALUE_H +#define QMLBINDABLEVALUE_H + +#include <QObject> +#include <qfxglobal.h> +#include <qml.h> +#include <qmlpropertyvaluesource.h> +#include <QtDeclarative/qmlexpression.h> + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) +class QmlExpression; +class QmlContext; +class Q_DECLARATIVE_EXPORT QmlBindableValue : public QmlPropertyValueSource, + public QmlExpression +{ +Q_OBJECT +public: + QmlBindableValue(QObject *parent); + QmlBindableValue(const QString &, QObject *, bool = true, QObject *parent=0); + QmlBindableValue(void *, QmlRefCount *, QObject *, QObject *parent); + ~QmlBindableValue(); + + virtual void setTarget(const QmlMetaProperty &); + QmlMetaProperty property() const { return _property; } + + Q_CLASSINFO("DefaultProperty", "expression"); + Q_PROPERTY(QString expression READ expression WRITE setExpression); + virtual void setExpression(const QString &); + + void init(); + +private Q_SLOTS: + void update(); + +protected: + virtual void valueChanged(); + +private: + bool _inited; + QmlMetaProperty _property; +}; +QML_DECLARE_TYPE(QmlBindableValue); + + +QT_END_NAMESPACE + +QT_END_HEADER +#endif // QMLBINDABLEVALUE_H diff --git a/src/declarative/qml/qmlboundsignal.cpp b/src/declarative/qml/qmlboundsignal.cpp new file mode 100644 index 0000000..5359753 --- /dev/null +++ b/src/declarative/qml/qmlboundsignal.cpp @@ -0,0 +1,158 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmlboundsignal_p.h" +#include "private/qmetaobjectbuilder_p.h" +#include "private/qmlengine_p.h" +#include "private/qmlcontext_p.h" +#include <qfxglobal.h> +#include <qmlmetatype.h> +#include <qml.h> +#include <qmlcontext.h> + +QT_BEGIN_NAMESPACE + +int QmlBoundSignal::evaluateIdx = -1; +QmlBoundSignal::QmlBoundSignal(QmlContext *ctxt, const QString &val, QObject *me, int idx, QObject *parent) +: QmlExpressionObject(ctxt, val, me, false), _idx(idx) +{ + // A cached evaluation of the QmlExpressionObject::value() slot index. + // + // This is thread safe. Although it may be updated by two threads, they + // will both set it to the same value - so the worst thing that can happen + // is that they both do the work to figure it out. Boo hoo. + if(evaluateIdx == -1) evaluateIdx = QmlExpressionObject::staticMetaObject.indexOfMethod("value()"); + + setTrackChange(false); + QFx_setParent_noEvent(this, parent); + QMetaObject::connect(me, _idx, this, evaluateIdx); +} + +QmlBoundSignalProxy::QmlBoundSignalProxy(QmlContext *ctxt, const QString &val, QObject *me, int idx, QObject *parent) +: QmlBoundSignal(ctxt, val, me, idx, parent) +{ + QMetaMethod signal = me->metaObject()->method(idx); + + params = new QmlBoundSignalParameters(signal, this); + + ctxt->d_func()->addDefaultObject(params, QmlContextPrivate::HighPriority); +} + +int QmlBoundSignalProxy::qt_metacall(QMetaObject::Call c, int id, void **a) +{ + if(c == QMetaObject::InvokeMetaMethod && id == evaluateIdx) { + params->setValues(a); + value(); + params->clearValues(); + return -1; + } else { + return QmlBoundSignal::qt_metacall(c, id, a); + } +} + +#include <QDebug> +QmlBoundSignalParameters::QmlBoundSignalParameters(const QMetaMethod &method, + QObject *parent) +: QObject(parent), types(0), values(0) +{ + MetaObject *mo = new MetaObject(this); + + // ### Optimize! + // ### Ensure only supported types are allowed, otherwise it might crash + QMetaObjectBuilder mob; + mob.setSuperClass(&QmlBoundSignalParameters::staticMetaObject); + + QList<QByteArray> paramTypes = method.parameterTypes(); + QList<QByteArray> paramNames = method.parameterNames(); + types = new int[paramTypes.count()]; + for(int ii = 0; ii < paramTypes.count(); ++ii) { + const QByteArray &type = paramTypes.at(ii); + const QByteArray &name = paramNames.at(ii); + + if(name.isEmpty() || type.isEmpty()) { + types[ii] = 0; + continue; + } + + QVariant::Type t = (QVariant::Type)QMetaType::type(type.constData()); + if(QmlMetaType::isObject(t)) { + types[ii] = QMetaType::QObjectStar; + QMetaPropertyBuilder prop = mob.addProperty(name, "QObject*"); + prop.setWritable(false); + } else { + types[ii] = t; + QMetaPropertyBuilder prop = mob.addProperty(name, type); + prop.setWritable(false); + } + } + myMetaObject = mob.toMetaObject(); + *static_cast<QMetaObject *>(mo) = *myMetaObject; + + d_ptr->metaObject = mo; +} + +QmlBoundSignalParameters::~QmlBoundSignalParameters() +{ + delete [] types; + qFree(myMetaObject); +} + +void QmlBoundSignalParameters::setValues(void **v) +{ + values = v; +} + +void QmlBoundSignalParameters::clearValues() +{ + values = 0; +} + +int QmlBoundSignalParameters::metaCall(QMetaObject::Call c, int id, void **a) +{ + if(c == QMetaObject::ReadProperty && id >= 1) { + QmlMetaType::copy(types[id - 1], a[0], values[id]); + return -1; + } else { + return qt_metacall(c, id, a); + } +} + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlboundsignal_p.h b/src/declarative/qml/qmlboundsignal_p.h new file mode 100644 index 0000000..e84f0c1 --- /dev/null +++ b/src/declarative/qml/qmlboundsignal_p.h @@ -0,0 +1,104 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLBOUNDSIGNAL_P_H +#define QMLBOUNDSIGNAL_P_H + +#include <qmlexpression.h> +#include <private/qobject_p.h> + +QT_BEGIN_NAMESPACE +class QmlBoundSignal : public QmlExpressionObject +{ +Q_OBJECT +public: + QmlBoundSignal(QmlContext *, const QString &, QObject *me, int idx, QObject *parent); + + int index() const { return _idx; } +protected: + static int evaluateIdx; +private: + int _idx; +}; + +class QmlBoundSignalParameters : public QObject +{ +Q_OBJECT +public: + QmlBoundSignalParameters(const QMetaMethod &, QObject * = 0); + ~QmlBoundSignalParameters(); + + void setValues(void **); + void clearValues(); + +private: + friend class MetaObject; + int metaCall(QMetaObject::Call, int _id, void **); + struct MetaObject : public QAbstractDynamicMetaObject { + MetaObject(QmlBoundSignalParameters *b) + : parent(b) {} + + int metaCall(QMetaObject::Call c, int id, void **a) { + return parent->metaCall(c, id, a); + } + QmlBoundSignalParameters *parent; + }; + + int *types; + void **values; + QMetaObject *myMetaObject; +}; + +class QmlBoundSignalProxy : public QmlBoundSignal +{ +public: + QmlBoundSignalProxy(QmlContext *, const QString &, QObject *me, int idx, QObject *parent); + +protected: + virtual int qt_metacall(QMetaObject::Call c, int id, void **a); +private: + QmlBoundSignalParameters *params; +}; + + +#endif // QMLBOUNDSIGNAL_P_H + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlclassfactory.cpp b/src/declarative/qml/qmlclassfactory.cpp new file mode 100644 index 0000000..7e5b929 --- /dev/null +++ b/src/declarative/qml/qmlclassfactory.cpp @@ -0,0 +1,47 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmlclassfactory_p.h" + +QmlClassFactory::~QmlClassFactory() +{ +} + diff --git a/src/declarative/qml/qmlclassfactory_p.h b/src/declarative/qml/qmlclassfactory_p.h new file mode 100644 index 0000000..e3e71c9 --- /dev/null +++ b/src/declarative/qml/qmlclassfactory_p.h @@ -0,0 +1,63 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLCLASSFACTORY_P_H +#define QMLCLASSFACTORY_P_H + +#include <QtCore/qglobal.h> + +QT_BEGIN_NAMESPACE + +class QmlEngine; +class QByteArray; +class QUrl; +class QmlComponent; + +class QmlClassFactory +{ +public: + virtual ~QmlClassFactory(); + virtual QmlComponent *create(const QByteArray &, const QUrl& baseUrl, QmlEngine*) = 0; +}; + +QT_END_NAMESPACE + +#endif // QMLCLASSFACTORY_P_H diff --git a/src/declarative/qml/qmlcompiledcomponent.cpp b/src/declarative/qml/qmlcompiledcomponent.cpp new file mode 100644 index 0000000..a8b2be0 --- /dev/null +++ b/src/declarative/qml/qmlcompiledcomponent.cpp @@ -0,0 +1,170 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmlcompiledcomponent_p.h" +#include "qmlparser_p.h" +#include <QtCore/qdebug.h> +#include <QmlComponent> +using namespace QmlParser; + +QT_BEGIN_NAMESPACE + +DEFINE_BOOL_CONFIG_OPTION(compilerDump, QML_COMPILER_DUMP); + +QmlCompiledComponent::QmlCompiledComponent() +: dumpStatus(NoDump) +{ +} + +QmlCompiledComponent::~QmlCompiledComponent() +{ + for(int ii = 0; ii < mos.count(); ++ii) + qFree(mos.at(ii)); +} + + +void QmlCompiledComponent::dumpInstructions() +{ + if(!compilerDump()) + return; + + if(!name.isEmpty()) + qWarning() << name; + qWarning() << "Index\tLine\tOperation\t\tData1\tData2\t\tComments"; + qWarning() << "-------------------------------------------------------------------------------"; + for(int ii = 0; ii < bytecode.count(); ++ii) { + dump(&bytecode[ii], ii); + } + qWarning() << "-------------------------------------------------------------------------------"; +} + +void QmlCompiledComponent::dump(int indent, Property *p) +{ + QByteArray ba(indent * 4, ' '); + for(int ii = 0; ii < p->values.count(); ++ii) + dump(indent, p->values.at(ii)); + if(p->value) + dump(indent, p->value); +} + +void QmlCompiledComponent::dump(int indent, Object *o) +{ + QByteArray ba(indent * 4, ' '); + if(o->type != -1) { + qWarning() << ba.constData() << "Object:" << types.at(o->type).className; + } else { + qWarning() << ba.constData() << "Object: fetched"; + } + + for(QHash<QByteArray, Property *>::ConstIterator iter = o->properties.begin(); + iter != o->properties.end(); + ++iter) { + qWarning() << ba.constData() << " Property" << iter.key(); + dump(indent + 1, *iter); + } + + if(o->defaultProperty) { + qWarning() << ba.constData() << " Default property"; + dump(indent + 1, o->defaultProperty); + } +} + +void QmlCompiledComponent::dump(int indent, Value *v) +{ + QByteArray type; + switch(v->type) { + default: + case Value::Unknown: + type = "Unknown"; + break; + case Value::Literal: + type = "Literal"; + break; + case Value::PropertyBinding: + type = "PropertyBinding"; + break; + case Value::ValueSource: + type = "ValueSource"; + break; + case Value::CreatedObject: + type = "CreatedObject"; + break; + case Value::SignalObject: + type = "SignalObject"; + break; + case Value::SignalExpression: + type = "SignalExpression"; + break; + case Value::Component: + type = "Component"; + break; + case Value::Id: + type = "Id"; + break; + }; + + QByteArray ba(indent * 4, ' '); + if(v->object) { + qWarning() << ba.constData() << "Value (" << type << "):"; + dump(indent + 1, v->object); + } else { + qWarning() << ba.constData() << "Value (" << type << "):" << v->primitive; + } +} + +void QmlCompiledComponent::dumpPre() +{ + if(!(dumpStatus & DumpPre)) { + dumpInstructions(); + dumpStatus = (DumpStatus)(dumpStatus | DumpPre); + } +} + +void QmlCompiledComponent::dumpPost() +{ + if(!(dumpStatus & DumpPost)) { + dumpInstructions(); + dumpStatus = (DumpStatus)(dumpStatus | DumpPost); + } + +} + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlcompiledcomponent_p.h b/src/declarative/qml/qmlcompiledcomponent_p.h new file mode 100644 index 0000000..fa68eab --- /dev/null +++ b/src/declarative/qml/qmlcompiledcomponent_p.h @@ -0,0 +1,80 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLCOMPILEDCOMPONENT_P_H +#define QMLCOMPILEDCOMPONENT_P_H + +#include <qml.h> +#include <private/qmlinstruction_p.h> +#include <private/qmlcompiler_p.h> +#include <private/qmlrefcount_p.h> +class QmlXmlParser; + +QT_BEGIN_NAMESPACE +namespace QmlParser { + class Property; + class Object; + class Value; +}; + +class QmlCompiledComponent : public QmlRefCount, public QmlCompiledData +{ +public: + QmlCompiledComponent(); + ~QmlCompiledComponent(); + + void dumpPre(); + void dumpPost(); + +private: + enum DumpStatus { NoDump = 0x00, DumpPre = 0x01, DumpPost = 0x02 } dumpStatus; + void dumpInstructions(); + void dump(int indent, QmlParser::Property *p); + void dump(int indent, QmlParser::Object *o); + void dump(int indent, QmlParser::Value *v); + void dump(QmlInstruction *, int idx = -1); + friend class QmlCompiler; + friend class QmlDomDocument; +}; + + +QT_END_NAMESPACE +#endif // QMLCOMPILEDCOMPONENT_P_H diff --git a/src/declarative/qml/qmlcompiler.cpp b/src/declarative/qml/qmlcompiler.cpp new file mode 100644 index 0000000..9af0a06 --- /dev/null +++ b/src/declarative/qml/qmlcompiler.cpp @@ -0,0 +1,1662 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "private/qmlcompiler_p.h" +#include <qfxperf.h> +#include "qmlparser_p.h" +#include "private/qmlxmlparser_p.h" +#include <qmlpropertyvaluesource.h> +#include <qmlcomponent.h> +#include "private/qmetaobjectbuilder_p.h" +#include <qmlbasicscript.h> +#include <QColor> +#include <QDebug> +#include <QPointF> +#include <QSizeF> +#include <QRectF> +#include <private/qmlcompiledcomponent_p.h> +#include <private/qmlstringconverters_p.h> +#include <private/qmlengine_p.h> +#include <qmlengine.h> +#include <qmlcontext.h> +#include <qmlmetatype.h> +#include <QtCore/qdebug.h> + +QT_BEGIN_NAMESPACE +/* + New properties and signals can be added to any QObject type from QML. + <QObject> + <properties><Property name="myProperty" /></properties> + <signals><Signal name="mySignal" /></signals> + </QObject + The special names used as magical properties (in the above case "properties" + and "signals") are defined here. +*/ +#define PROPERTIES_NAME "properties" +#define SIGNALS_NAME "signals" + +using namespace QmlParser; + +int QmlCompiledData::indexForString(const QString &data) +{ + int idx = primitives.indexOf(data); + if(idx == -1) { + idx = primitives.count(); + primitives << data; + } + return idx; +} + +int QmlCompiledData::indexForByteArray(const QByteArray &data) +{ + int idx = datas.indexOf(data); + if(idx == -1) { + idx = datas.count(); + datas << data; + } + return idx; +} + +int QmlCompiledData::indexForFloat(float *data, int count) +{ + Q_ASSERT(count > 0); + + for(int ii = 0; ii < floatData.count() - count; ++ii) { + bool found = true; + for(int jj = 0; jj < count; ++jj) { + if(floatData.at(ii + jj) != data[jj]) { + found = false; + break; + } + } + + if(found) + return ii; + } + + int idx = floatData.count(); + for(int ii = 0; ii < count; ++ii) + floatData << data[ii]; + + return idx; +} + +int QmlCompiledData::indexForInt(int *data, int count) +{ + Q_ASSERT(count > 0); + + for(int ii = 0; ii < floatData.count() - count; ++ii) { + bool found = true; + for(int jj = 0; jj < count; ++jj) { + if(intData.at(ii + jj) != data[jj]) { + found = false; + break; + } + } + + if(found) + return ii; + } + + int idx = intData.count(); + for(int ii = 0; ii < count; ++ii) + intData << data[ii]; + + return idx; +} + +QmlCompiler::QmlCompiler() +: exceptionLine(-1), output(0) +{ +} + +bool QmlCompiler::isError() const +{ + return exceptionLine != -1; +} + +qint64 QmlCompiler::errorLine() const +{ + return exceptionLine; +} + +QString QmlCompiler::errorDescription() const +{ + return exceptionDescription; +} + +bool QmlCompiler::isValidId(const QString &val) +{ + if(val.isEmpty()) + return false; + + QChar u(QLatin1Char('_')); + for(int ii = 0; ii < val.count(); ++ii) + if(val.at(ii) != u && + ((ii == 0 && !val.at(ii).isLetter()) || + (ii != 0 && !val.at(ii).isLetterOrNumber())) ) + return false; + + return true; +} + +/*! + Returns true if \a str is a valid binding string, false otherwise. + + Valid binding strings are those enclosed in braces ({}). +*/ +bool QmlCompiler::isBinding(const QString &str) +{ + return str.startsWith(QLatin1Char('{')) && str.endsWith(QLatin1Char('}')); +} + +/*! + Returns true if property name \a name refers to an attached property, false + otherwise. + + Attached property names are those that start with a capital letter. +*/ +bool QmlCompiler::isAttachedProperty(const QByteArray &name) +{ + return !name.isEmpty() && name.at(0) >= 'A' && name.at(0) <= 'Z'; +} + +QmlCompiler::StoreInstructionResult +QmlCompiler::generateStoreInstruction(QmlCompiledData &cdata, + QmlInstruction &instr, + const QMetaProperty &prop, + int coreIdx, int primitive, + const QString *string) +{ + if(!prop.isWritable()) + return ReadOnly; + if(prop.isEnumType()) { + int value; + if (prop.isFlagType()) { + value = prop.enumerator().keysToValue(string->toLatin1().constData()); + } else + value = prop.enumerator().keyToValue(string->toLatin1().constData()); + if(value == -1) + return InvalidData; + instr.type = QmlInstruction::StoreInteger; + instr.storeInteger.propertyIndex = coreIdx; + instr.storeInteger.value = value; + return Ok; + } + int type = prop.type(); + switch(type) { + case -1: + instr.type = QmlInstruction::StoreVariant; + instr.storeString.propertyIndex = coreIdx; + if(primitive == -1) + primitive = cdata.indexForString(*string); + instr.storeString.value = primitive; + break; + break; + case QVariant::String: + { + instr.type = QmlInstruction::StoreString; + instr.storeString.propertyIndex = coreIdx; + if(string->startsWith(QLatin1Char('\'')) && string->endsWith(QLatin1Char('\''))) { + QString unquotedString = string->mid(1, string->length() - 2); + primitive = cdata.indexForString(unquotedString); + } else { + if(primitive == -1) + primitive = cdata.indexForString(*string); + } + instr.storeString.value = primitive; + } + break; + case QVariant::UInt: + { + instr.type = QmlInstruction::StoreInteger; + instr.storeInteger.propertyIndex = coreIdx; + bool ok; + int value = string->toUInt(&ok); + if (!ok) + return InvalidData; + instr.storeInteger.value = value; + } + break; + case QVariant::Int: + { + instr.type = QmlInstruction::StoreInteger; + instr.storeInteger.propertyIndex = coreIdx; + bool ok; + int value = string->toInt(&ok); + if (!ok) + return InvalidData; + instr.storeInteger.value = value; + } + break; + case 135: + case QVariant::Double: + { + instr.type = QmlInstruction::StoreReal; + instr.storeReal.propertyIndex = coreIdx; + bool ok; + float value = string->toFloat(&ok); + if (!ok) + return InvalidData; + instr.storeReal.value = value; + } + break; + case QVariant::Color: + { + QColor c = QmlStringConverters::colorFromString(*string); + if (!c.isValid()) + return InvalidData; + instr.type = QmlInstruction::StoreColor; + instr.storeColor.propertyIndex = coreIdx; + instr.storeColor.value = c.rgba(); + } + break; + case QVariant::Date: + { + QDate d = QDate::fromString(*string, Qt::ISODate); + if (!d.isValid()) + return InvalidData; + instr.type = QmlInstruction::StoreDate; + instr.storeDate.propertyIndex = coreIdx; + instr.storeDate.value = d.toJulianDay(); + } + break; + case QVariant::Time: + { + QTime time = QTime::fromString(*string, Qt::ISODate); + if (!time.isValid()) + return InvalidData; + int data[] = { time.hour(), time.minute(), time.second(), time.msec() }; + int index = cdata.indexForInt(data, 4); + instr.type = QmlInstruction::StoreTime; + instr.storeTime.propertyIndex = coreIdx; + instr.storeTime.valueIndex = index; + } + break; + case QVariant::DateTime: + { + QDateTime dateTime = QDateTime::fromString(*string, Qt::ISODate); + if (!dateTime.isValid()) + return InvalidData; + int data[] = { dateTime.date().toJulianDay(), + dateTime.time().hour(), + dateTime.time().minute(), + dateTime.time().second(), + dateTime.time().msec() }; + int index = cdata.indexForInt(data, 5); + instr.type = QmlInstruction::StoreDateTime; + instr.storeDateTime.propertyIndex = coreIdx; + instr.storeDateTime.valueIndex = index; + } + break; + case QVariant::Point: + case QVariant::PointF: + { + bool ok; + QPointF point = QmlStringConverters::pointFFromString(*string, &ok); + if (!ok) + return InvalidData; + float data[] = { point.x(), point.y() }; + int index = cdata.indexForFloat(data, 2); + if (type == QVariant::PointF) + instr.type = QmlInstruction::StorePointF; + else + instr.type = QmlInstruction::StorePoint; + instr.storeRealPair.propertyIndex = coreIdx; + instr.storeRealPair.valueIndex = index; + } + break; + case QVariant::Size: + case QVariant::SizeF: + { + bool ok; + QSizeF size = QmlStringConverters::sizeFFromString(*string, &ok); + if (!ok) + return InvalidData; + float data[] = { size.width(), size.height() }; + int index = cdata.indexForFloat(data, 2); + if (type == QVariant::SizeF) + instr.type = QmlInstruction::StoreSizeF; + else + instr.type = QmlInstruction::StoreSize; + instr.storeRealPair.propertyIndex = coreIdx; + instr.storeRealPair.valueIndex = index; + } + break; + case QVariant::Rect: + case QVariant::RectF: + { + bool ok; + QRectF rect = QmlStringConverters::rectFFromString(*string, &ok); + if (!ok) + return InvalidData; + float data[] = { rect.x(), rect.y(), + rect.width(), rect.height() }; + int index = cdata.indexForFloat(data, 4); + if (type == QVariant::RectF) + instr.type = QmlInstruction::StoreRectF; + else + instr.type = QmlInstruction::StoreRect; + instr.storeRect.propertyIndex = coreIdx; + instr.storeRect.valueIndex = index; + } + break; + case QVariant::Bool: + { + bool ok; + bool b = QmlStringConverters::boolFromString(*string, &ok); + if (!ok) + return InvalidData; + instr.type = QmlInstruction::StoreBool; + instr.storeBool.propertyIndex = coreIdx; + instr.storeBool.value = b; + } + break; + default: + { + int t = prop.type(); + if(t == QVariant::UserType) + t = prop.userType(); + QmlMetaType::StringConverter converter = + QmlMetaType::customStringConverter(t); + if (converter) { + int index = cdata.customTypeData.count(); + instr.type = QmlInstruction::AssignCustomType; + instr.assignCustomType.propertyIndex = coreIdx; + instr.assignCustomType.valueIndex = index; + + QmlCompiledData::CustomTypeData data; + if(primitive == -1) + primitive = cdata.indexForString(*string); + data.index = primitive; + data.type = t; + cdata.customTypeData << data; + break; + } + } + return UnknownType; + break; + } + return Ok; +} + +void QmlCompiler::reset(QmlCompiledComponent *cc, bool deleteMemory) +{ + cc->types.clear(); + cc->primitives.clear(); + cc->floatData.clear(); + cc->intData.clear(); + cc->customTypeData.clear(); + cc->datas.clear(); + if(deleteMemory) { + for(int ii = 0; ii < cc->mos.count(); ++ii) + qFree(cc->mos.at(ii)); + } + cc->mos.clear(); + cc->bytecode.clear(); +} + +#define COMPILE_EXCEPTION(desc) \ + { \ + exceptionLine = obj->line; \ + QDebug d(&exceptionDescription); \ + d << desc; \ + return false; \ + } + +#define COMPILE_CHECK(a) \ + { \ + if (!a) return false; \ + } + +bool QmlCompiler::compile(QmlEngine *engine, + QmlCompositeTypeManager::TypeData *unit, + QmlCompiledComponent *out) +{ +#ifdef Q_ENABLE_PERFORMANCE_LOG + QFxPerfTimer<QFxPerf::Compile> pc; +#endif + exceptionLine = -1; + + Q_ASSERT(out); + reset(out, true); + + output = out; + + // Compile types + for(int ii = 0; ii < unit->types.count(); ++ii) { + QmlCompositeTypeManager::TypeData::TypeReference &tref = unit->types[ii]; + QmlCompiledComponent::TypeReference ref; + if(tref.type) + ref.type = tref.type; + else if(tref.unit) { + ref.component = tref.unit->toComponent(engine); + ref.ref = tref.unit; + ref.ref->addref(); + } else if(tref.parser) + ref.parser = tref.parser; + ref.className = unit->data.types().at(ii).toLatin1(); + out->types << ref; + } + + Object *root = unit->data.tree(); + if(!root) { + exceptionDescription = QLatin1String("Can't compile because of earlier errors"); + output = 0; + return false; + } + + compileTree(root); + + if(!isError()) { + out->dumpPre(); + } else { + reset(out, true); + } + + output = 0; + return !isError(); +} + +void QmlCompiler::compileTree(Object *tree) +{ + QmlInstruction init; + init.type = QmlInstruction::Init; + init.line = 0; + init.init.dataSize = 0; + output->bytecode << init; + + if(!compileObject(tree, 0)) // Compile failed + return; + + QmlInstruction def; + init.line = 0; + def.type = QmlInstruction::SetDefault; + output->bytecode << def; + + optimizeExpressions(0, output->bytecode.count() - 1, 0); +} + +bool QmlCompiler::compileObject(Object *obj, int ctxt) +{ + if(obj->type != -1) { + obj->metatype = + QmlMetaType::metaObjectForType(output->types.at(obj->type).className); + } + + if(output->types.at(obj->type).className == "Component") { + COMPILE_CHECK(compileComponent(obj, ctxt)); + return true; + } + + ctxt = 0; + + // Only use magical "properties" and "signals" properties if the type + // doesn't have already have them + bool ignoreProperties = false; + bool ignoreSignals = false; + if(obj->metatype && obj->metatype->indexOfProperty(PROPERTIES_NAME) != -1) + ignoreProperties = true; + if(obj->metatype && obj->metatype->indexOfProperty(SIGNALS_NAME) != -1) + ignoreSignals = true; + + Property *propertiesProperty = ignoreProperties?0:obj->getProperty(PROPERTIES_NAME, false); + Property *signalsProperty = ignoreSignals?0:obj->getProperty(SIGNALS_NAME, false); + + if(propertiesProperty) { + obj->dynamicPropertiesProperty = propertiesProperty; + obj->properties.remove(PROPERTIES_NAME); + } + if(signalsProperty) { + obj->dynamicSignalsProperty = signalsProperty; + obj->properties.remove(SIGNALS_NAME); + } + + if(obj->type != -1 && output->types.at(obj->type).parser) { + QByteArray data = obj->custom; + int ref = output->indexForByteArray(data); + + QmlInstruction create; + create.type = QmlInstruction::CreateCustomObject; + create.line = obj->line; + create.createCustom.type = obj->type; + create.createCustom.data = ref; + output->bytecode << create; + } else { + // Create the object + QmlInstruction create; + create.type = QmlInstruction::CreateObject; + create.line = obj->line; + create.create.type = obj->type; + output->bytecode << create; + } + + COMPILE_CHECK(compileDynamicPropertiesAndSignals(obj)); + + if(obj->type != -1) { + if(output->types.at(obj->type).component) { + QmlInstruction begin; + begin.type = QmlInstruction::TryBeginObject; + begin.line = obj->line; + output->bytecode << begin; + } else { + int cast = QmlMetaType::qmlParserStatusCast(QmlMetaType::type(output->types.at(obj->type).className)); + if(cast != -1) { + QmlInstruction begin; + begin.type = QmlInstruction::BeginObject; + begin.begin.castValue = cast; + begin.line = obj->line; + output->bytecode << begin; + } + } + } + + foreach(Property *prop, obj->properties) { + if(!ignoreProperties && prop->name == PROPERTIES_NAME) { + } else if(!ignoreSignals && prop->name == SIGNALS_NAME) { + } else if(prop->name.length() >= 3 && prop->name.startsWith("on") && + ('A' <= prop->name.at(2) && 'Z' >= prop->name.at(2))) { + COMPILE_CHECK(compileSignal(prop, obj)); + } else { + COMPILE_CHECK(compileProperty(prop, obj, ctxt)); + } + } + + if(obj->defaultProperty) + COMPILE_CHECK(compileProperty(obj->defaultProperty, obj, ctxt)); + + if(obj->type != -1) { + if(output->types.at(obj->type).component) { + QmlInstruction complete; + complete.type = QmlInstruction::TryCompleteObject; + complete.line = obj->line; + output->bytecode << complete; + } else { + int cast = QmlMetaType::qmlParserStatusCast(QmlMetaType::type(output->types.at(obj->type).className)); + if(cast != -1) { + QmlInstruction complete; + complete.type = QmlInstruction::CompleteObject; + complete.complete.castValue = cast; + complete.line = obj->line; + output->bytecode << complete; + } + } + } + + return true; +} + +bool QmlCompiler::compileComponent(Object *obj, int ctxt) +{ + Property *idProp = 0; + if(obj->properties.count() > 1 || + (obj->properties.count() == 1 && obj->properties.begin().key() != "id")) + COMPILE_EXCEPTION("Invalid component specification"); + if(obj->defaultProperty && + (obj->defaultProperty->value || obj->defaultProperty->values.count() > 1 || + (obj->defaultProperty->values.count() == 1 && !obj->defaultProperty->values.first()->object))) + COMPILE_EXCEPTION("Invalid component body specification"); + if(obj->properties.count()) + idProp = *obj->properties.begin(); + if(idProp && (idProp->value || idProp->values.count() > 1)) + COMPILE_EXCEPTION("Invalid component id specification"); + + Object *root = 0; + if(obj->defaultProperty && obj->defaultProperty->values.count()) + root = obj->defaultProperty->values.first()->object; + + COMPILE_CHECK(compileComponentFromRoot(root, ctxt)); + + if(idProp && idProp->values.count()) { + QString val = idProp->values.at(0)->primitive; + if(!isValidId(val)) + COMPILE_EXCEPTION("Invalid id property value"); + + if(ids.contains(val)) + COMPILE_EXCEPTION("id is not unique"); + ids.insert(val); + + int pref = output->indexForString(val); + QmlInstruction id; + id.type = QmlInstruction::SetId; + id.line = idProp->line; + id.setId.value = pref; + id.setId.save = -1; + output->bytecode << id; + } + + return true; +} + +bool QmlCompiler::compileComponentFromRoot(Object *obj, int ctxt) +{ + output->bytecode.push_back(QmlInstruction()); + QmlInstruction &create = output->bytecode.last(); + create.type = QmlInstruction::CreateComponent; + create.line = obj->line; + int count = output->bytecode.count(); + + QmlInstruction init; + init.type = QmlInstruction::Init; + init.init.dataSize = 0; + init.line = obj->line; + output->bytecode << init; + + QSet<QString> oldIds = ids; + ids.clear(); + if(obj) + COMPILE_CHECK(compileObject(obj, ctxt)); + ids = oldIds; + + create.createComponent.count = output->bytecode.count() - count; + + int inc = optimizeExpressions(count, count - 1 + create.createComponent.count, count); + create.createComponent.count += inc; + return true; +} + + +bool QmlCompiler::compileFetchedObject(Object *obj, int ctxt) +{ + if(obj->defaultProperty) + COMPILE_CHECK(compileProperty(obj->defaultProperty, obj, ctxt)); + + foreach(Property *prop, obj->properties) { + if(prop->name.length() >= 3 && prop->name.startsWith("on") && + ('A' <= prop->name.at(2) && 'Z' >= prop->name.at(2))) { + COMPILE_CHECK(compileSignal(prop, obj)); + } else { + COMPILE_CHECK(compileProperty(prop, obj, ctxt)); + } + } + + return true; +} + +bool QmlCompiler::compileSignal(Property *prop, Object *obj) +{ + if(prop->values.isEmpty() && !prop->value) + return true; + + if(prop->value || prop->values.count() > 1) + COMPILE_EXCEPTION("Incorrectly specified signal"); + + if(prop->values.at(0)->object) { + int pr = output->indexForByteArray(prop->name); + + bool rv = compileObject(prop->values.at(0)->object, 0); + + if(rv) { + QmlInstruction assign; + assign.type = QmlInstruction::AssignSignalObject; + assign.line = prop->values.at(0)->line; + assign.assignSignalObject.signal = pr; + + output->bytecode << assign; + + prop->values.at(0)->type = Value::SignalObject; + } + + return rv; + + } else { + QString script = prop->values.at(0)->primitive.trimmed(); + if(script.isEmpty()) + return true; + + if(isBinding(script)) + COMPILE_EXCEPTION("Cannot assign binding to signal property"); + + int idx = output->indexForString(script); + int pr = output->indexForByteArray(prop->name); + + QmlInstruction assign; + assign.type = QmlInstruction::AssignSignal; + assign.line = prop->values.at(0)->line; + assign.assignSignal.signal = pr; + assign.assignSignal.value = idx; + + output->bytecode << assign; + + prop->values.at(0)->type = Value::SignalExpression; + } + + return true; +} + +bool QmlCompiler::compileProperty(Property *prop, Object *obj, int ctxt) +{ + if(prop->values.isEmpty() && !prop->value) + return true; + + // First we're going to need a reference to this property + if(obj->type != -1) { + + const QMetaObject *mo = obj->metaObject(); + if(mo) { + if(prop->isDefault) { + QMetaProperty p = QmlMetaType::defaultProperty(mo); + // XXX + // Currently we don't handle enums in the static analysis + // so we let them drop through to generateStoreInstruction() + if(p.name() && !p.isEnumType()) { + prop->index = mo->indexOfProperty(p.name()); + prop->name = p.name(); + + int t = p.type(); + if(t == QVariant::UserType) + t = p.userType(); + + prop->type = t; + } + } else { + prop->index = mo->indexOfProperty(prop->name.constData()); + QMetaProperty p = mo->property(prop->index); + // XXX + // Currently we don't handle enums in the static analysis + // so we let them drop through to generateStoreInstruction() + if(p.name() && !p.isEnumType()) { + int t = p.type(); + if(t == QVariant::UserType) + t = p.userType(); + + prop->type = t; + } + } + } + } else { + const QMetaObject *mo = obj->metaObject(); + if(mo) { + if(prop->isDefault) { + QMetaProperty p = QmlMetaType::defaultProperty(mo); + if(p.name()) { + prop->index = mo->indexOfProperty(p.name()); + prop->name = p.name(); + } + int t = p.type(); + if(t == QVariant::UserType) + t = p.userType(); + prop->type = t; + } else { + prop->index = mo->indexOfProperty(prop->name.constData()); + QMetaProperty p = mo->property(prop->index); + int t = p.type(); + if(t == QVariant::UserType) + t = p.userType(); + prop->type = t; + } + } + } + + if(prop->name == "id") { + + COMPILE_CHECK(compileIdProperty(prop, obj)); + + } else if(isAttachedProperty(prop->name)) { + + COMPILE_CHECK(compileAttachedProperty(prop, obj, ctxt)); + + } else if(prop->value) { + + COMPILE_CHECK(compileNestedProperty(prop, ctxt)); + + } else if(QmlMetaType::isQmlList(prop->type) || + QmlMetaType::isList(prop->type)) { + + COMPILE_CHECK(compileListProperty(prop, obj, ctxt)); + + } else { + + COMPILE_CHECK(compilePropertyAssignment(prop, obj, ctxt)); + + } + + return true; +} + +bool QmlCompiler::compileIdProperty(QmlParser::Property *prop, + QmlParser::Object *obj) +{ + if(prop->value) + COMPILE_EXCEPTION("The 'id' property cannot be fetched"); + if(prop->values.count() > 1) + COMPILE_EXCEPTION("The 'id' property cannot be multiset"); + + if(prop->values.count() == 1) { + if(prop->values.at(0)->object) + COMPILE_EXCEPTION("Cannot assign an object as an id"); + QString val = prop->values.at(0)->primitive; + if(!isValidId(val)) + COMPILE_EXCEPTION(val << "is not a valid id"); + if(ids.contains(val)) + COMPILE_EXCEPTION("id is not unique"); + ids.insert(val); + + int pref = output->indexForString(val); + + if(prop->type == QVariant::String) { + QmlInstruction assign; + assign.type = QmlInstruction::StoreString; + assign.storeString.propertyIndex = prop->index; + assign.storeString.value = pref; + assign.line = prop->values.at(0)->line; + output->bytecode << assign; + + prop->values.at(0)->type = Value::Id; + } else { + prop->values.at(0)->type = Value::Literal; + } + + QmlInstruction id; + id.type = QmlInstruction::SetId; + id.line = prop->values.at(0)->line; + id.setId.value = pref; + id.setId.save = -1; + id.line = prop->values.at(0)->line; + output->bytecode << id; + + obj->id = val.toLatin1(); + } + + return true; +} + +bool QmlCompiler::compileAttachedProperty(QmlParser::Property *prop, + QmlParser::Object *obj, + int ctxt) +{ + if(!prop->value) + COMPILE_EXCEPTION("Incorrect usage of an attached property"); + + QmlInstruction fetch; + fetch.type = QmlInstruction::FetchAttached; + fetch.line = prop->line; + int ref = output->indexForByteArray(prop->name); + fetch.fetchAttached.idx = ref; + output->bytecode << fetch; + + COMPILE_CHECK(compileFetchedObject(prop->value, ctxt + 1)); + + QmlInstruction pop; + pop.type = QmlInstruction::PopFetchedObject; + pop.line = prop->line; + output->bytecode << pop; + + return true; +} + +bool QmlCompiler::compileNestedProperty(QmlParser::Property *prop, + int ctxt) +{ + if(prop->type != 0) + prop->value->metatype = QmlMetaType::metaObjectForType(prop->type); + + QmlInstruction fetch; + if(prop->index != -1 && + QmlMetaType::isObject(prop->value->metatype)) { + fetch.type = QmlInstruction::FetchObject; + fetch.fetch.property = prop->index; + fetch.fetch.isObject = true; + } else { + fetch.type = QmlInstruction::ResolveFetchObject; + fetch.fetch.property = output->indexForByteArray(prop->name); + } + fetch.line = prop->line; + output->bytecode << fetch; + + COMPILE_CHECK(compileFetchedObject(prop->value, ctxt + 1)); + + QmlInstruction pop; + pop.type = QmlInstruction::PopFetchedObject; + pop.line = prop->line; + output->bytecode << pop; + + return true; +} + +bool QmlCompiler::compileListProperty(QmlParser::Property *prop, + QmlParser::Object *obj, + int ctxt) +{ + int t = prop->type; + if(QmlMetaType::isQmlList(t)) { + QmlInstruction fetch; + fetch.line = prop->line; + fetch.type = QmlInstruction::FetchQmlList; + fetch.fetchQmlList.property = prop->index; + fetch.fetchQmlList.type = QmlMetaType::qmlListType(t); + output->bytecode << fetch; + + for(int ii = 0; ii < prop->values.count(); ++ii) { + Value *v = prop->values.at(ii); + if(v->object) { + v->type = Value::CreatedObject; + COMPILE_CHECK(compileObject(v->object, ctxt)); + QmlInstruction assign; + assign.type = QmlInstruction::AssignObjectList; + assign.line = prop->line; + assign.assignObject.property = output->indexForByteArray(prop->name); + assign.assignObject.castValue = 0; + output->bytecode << assign; + } else { + COMPILE_EXCEPTION("Cannot assign primitives to lists"); + } + } + + QmlInstruction pop; + pop.type = QmlInstruction::PopQList; + pop.line = prop->line; + output->bytecode << pop; + } else { + Q_ASSERT(QmlMetaType::isList(t)); + + QmlInstruction fetch; + fetch.type = QmlInstruction::FetchQList; + fetch.line = prop->line; + fetch.fetch.property = prop->index; + output->bytecode << fetch; + + bool assignedBinding = false; + for(int ii = 0; ii < prop->values.count(); ++ii) { + Value *v = prop->values.at(ii); + if(v->object) { + v->type = Value::CreatedObject; + COMPILE_CHECK(compileObject(v->object, ctxt)); + QmlInstruction assign; + assign.type = QmlInstruction::AssignObjectList; + assign.line = v->line; + assign.assignObject.property = output->indexForByteArray(prop->name); + assign.assignObject.castValue = 0; + output->bytecode << assign; + } else if(isBinding(v->primitive)) { + if(assignedBinding) + COMPILE_EXCEPTION("Can only assign one binding to lists"); + + compileBinding(v->primitive, prop, ctxt, obj->metaObject(), v->line); + v->type = Value::PropertyBinding; + } else { + COMPILE_EXCEPTION("Cannot assign primitives to lists"); + } + } + + QmlInstruction pop; + pop.line = prop->line; + pop.type = QmlInstruction::PopQList; + output->bytecode << pop; + } + return true; +} + +bool QmlCompiler::compilePropertyAssignment(QmlParser::Property *prop, + QmlParser::Object *obj, + int ctxt) +{ + for(int ii = 0; ii < prop->values.count(); ++ii) { + Value *v = prop->values.at(ii); + if(v->object) { + + COMPILE_CHECK(compilePropertyObjectAssignment(prop, obj, v, ctxt)); + + } else { + + COMPILE_CHECK(compilePropertyLiteralAssignment(prop, obj, v, ctxt)); + + } + } + + return true; +} + +bool QmlCompiler::compilePropertyObjectAssignment(QmlParser::Property *prop, + QmlParser::Object *obj, + QmlParser::Value *v, + int ctxt) +{ + if(v->object->type != -1) + v->object->metatype = QmlMetaType::metaObjectForType(output->types.at(v->object->type).className); + + if(v->object->metaObject()) { + + const QMetaObject *propmo = + QmlMetaType::rawMetaObjectForType(prop->type); + + bool isPropertyValue = false; + bool isAssignable = false; + + if(propmo) { + // We want to raw metaObject here as the raw metaobject is the + // actual property type before we applied any extensions + const QMetaObject *c = v->object->metatype; + while(propmo && c) { + isPropertyValue = isPropertyValue || (c == &QmlPropertyValueSource::staticMetaObject); + isAssignable = isAssignable || (c == propmo); + c = c->superClass(); + } + } else { + const QMetaObject *c = v->object->metatype; + while(!isPropertyValue && c) { + isPropertyValue = c == &QmlPropertyValueSource::staticMetaObject; + c = c->superClass(); + } + } + + if(!propmo && !isPropertyValue) { + COMPILE_CHECK(compileObject(v->object, ctxt)); + + QmlInstruction assign; + assign.type = QmlInstruction::AssignObject; + assign.line = v->object->line; + assign.assignObject.castValue = 0; + if(prop->isDefault) + assign.assignObject.property = -1; + else + assign.assignObject.property = + output->indexForByteArray(prop->name); + output->bytecode << assign; + + v->type = Value::CreatedObject; + } else if(isAssignable) { + COMPILE_CHECK(compileObject(v->object, ctxt)); + + QmlInstruction assign; + assign.type = QmlInstruction::StoreObject; + assign.line = v->object->line; + assign.storeObject.propertyIndex = prop->index; + // XXX - this cast may not be 0 + assign.storeObject.cast = 0; + output->bytecode << assign; + + v->type = Value::CreatedObject; + } else if(propmo == &QmlComponent::staticMetaObject) { + + COMPILE_CHECK(compileComponentFromRoot(v->object, ctxt)); + + QmlInstruction assign; + assign.type = QmlInstruction::StoreObject; + assign.line = v->object->line; + assign.storeObject.propertyIndex = prop->index; + // XXX - this cast may not be 0 + assign.storeObject.cast = 0; + output->bytecode << assign; + + v->type = Value::Component; + } else if(isPropertyValue) { + COMPILE_CHECK(compileObject(v->object, ctxt)); + + if (prop->index != -1) { + QmlInstruction assign; + assign.type = QmlInstruction::StoreValueSource; + assign.line = v->object->line; + assign.assignValueSource.property = prop->index; + output->bytecode << assign; + } else { + QmlInstruction assign; + assign.type = QmlInstruction::AssignValueSource; + assign.line = v->object->line; + assign.assignValueSource.property = output->indexForByteArray(prop->name);; + output->bytecode << assign; + } + + v->type = Value::ValueSource; + } else { + COMPILE_EXCEPTION("Unassignable object"); + } + + } else { + COMPILE_CHECK(compileObject(v->object, ctxt)); + + QmlInstruction assign; + assign.type = QmlInstruction::AssignObject; + assign.line = v->object->line; + assign.assignObject.property = output->indexForByteArray(prop->name); + assign.assignObject.castValue = 0; + output->bytecode << assign; + + v->type = Value::CreatedObject; + } + + return true; +} + +bool QmlCompiler::compilePropertyLiteralAssignment(QmlParser::Property *prop, + QmlParser::Object *obj, + QmlParser::Value *v, + int ctxt) +{ + if(isBinding(v->primitive)) { + + compileBinding(v->primitive, prop, ctxt, obj->metaObject(), v->line); + + v->type = Value::PropertyBinding; + + } else { + + QmlInstruction assign; + assign.line = v->line; + + bool doassign = true; + if(prop->index != -1) { + StoreInstructionResult r = + generateStoreInstruction(*output, assign, obj->metaObject()->property(prop->index), prop->index, -1, &v->primitive); + + if(r == Ok) { + doassign = false; + } else if(r == InvalidData) { + //### we are restricted to a rather generic message here. If we can find a way to move + // the exception into generateStoreInstruction we could potentially have better messages. + // (the problem is that both compile and run exceptions can be generated, though) + COMPILE_EXCEPTION("Cannot assign value" << v->primitive << "to property" << obj->metaObject()->property(prop->index).name()); + doassign = false; + } else if(r == ReadOnly) { + COMPILE_EXCEPTION("Cannot assign value" << v->primitive << "to the read-only property" << obj->metaObject()->property(prop->index).name()); + } else { + doassign = true; + } + } + + if(doassign) { + assign.type = QmlInstruction::AssignConstant; + if(prop->isDefault) { + assign.assignConstant.property = -1; + } else { + assign.assignConstant.property = + output->indexForByteArray(prop->name); + } + assign.assignConstant.constant = + output->indexForString(v->primitive); + } + + output->bytecode << assign; + + v->type = Value::Literal; + } + return true; +} + +bool QmlCompiler::findDynamicProperties(QmlParser::Property *prop, + QmlParser::Object *obj) +{ + QList<Object::DynamicProperty> definedProperties; + + struct TypeNameToType { + const char *name; + Object::DynamicProperty::Type type; + } propTypeNameToTypes[] = { + { "", Object::DynamicProperty::Variant }, + { "int", Object::DynamicProperty::Int }, + { "bool", Object::DynamicProperty::Bool }, + { "double", Object::DynamicProperty::Real }, + { "real", Object::DynamicProperty::Real }, + { "string", Object::DynamicProperty::String }, + { "color", Object::DynamicProperty::Color }, + { "date", Object::DynamicProperty::Date }, + { "variant", Object::DynamicProperty::Variant } + }; + const int propTypeNameToTypesCount = sizeof(propTypeNameToTypes) / + sizeof(propTypeNameToTypes[0]); + + + if(prop->value) + COMPILE_EXCEPTION("Invalid property specification"); + + bool seenDefault = false; + for(int ii = 0; ii < prop->values.count(); ++ii) { + QmlParser::Value *val = prop->values.at(ii); + if(!val->object) + COMPILE_EXCEPTION("Invalid property specification"); + + QmlParser::Object *obj = val->object; + if(obj->type == -1 || output->types.at(obj->type).className != "Property") + COMPILE_EXCEPTION("Use Property tag to specify properties"); + + + enum Seen { None = 0, Name = 0x01, + Type = 0x02, Value = 0x04, + ValueChanged = 0x08, + Default = 0x10 } seen = None; + + Object::DynamicProperty propDef; + + for(QHash<QByteArray, QmlParser::Property *>::ConstIterator iter = + obj->properties.begin(); + iter != obj->properties.end(); + ++iter) { + + QmlParser::Property *property = *iter; + if(property->name == "name") { + if (seen & Name) + COMPILE_EXCEPTION("May only specify Property name once"); + seen = (Seen)(seen | Name); + + if(property->value || property->values.count() != 1 || + property->values.at(0)->object) + COMPILE_EXCEPTION("Invalid Property name"); + + propDef.name = property->values.at(0)->primitive.toLatin1(); + + } else if(property->name == "type") { + if (seen & Type) + COMPILE_EXCEPTION("May only specify Property type once"); + seen = (Seen)(seen | Type); + + if(property->value || property->values.count() != 1 || + property->values.at(0)->object) + COMPILE_EXCEPTION("Invalid Property type"); + + QString type = property->values.at(0)->primitive.toLower(); + bool found = false; + for(int ii = 0; !found && ii < propTypeNameToTypesCount; ++ii) { + if(type == QLatin1String(propTypeNameToTypes[ii].name)){ + found = true; + propDef.type = propTypeNameToTypes[ii].type; + } + + } + + if(!found) + COMPILE_EXCEPTION("Invalid Property type"); + + } else if(property->name == "value") { + if (seen & Value) + COMPILE_EXCEPTION("May only specify Property value once"); + seen = (Seen)(seen | Value); + + propDef.defaultValue = property; + } else if(property->name == "onValueChanged") { + if (seen & ValueChanged) + COMPILE_EXCEPTION("May only specify Property onValueChanged once"); + seen = (Seen)(seen | ValueChanged); + + if(property->value || property->values.count() != 1 || + property->values.at(0)->object) + COMPILE_EXCEPTION("Invalid Property onValueChanged"); + + propDef.onValueChanged = property->values.at(0)->primitive; + + } else if(property->name == "default") { + if(seen & Default) + COMPILE_EXCEPTION("May only specify Property default once"); + seen = (Seen)(seen | Default); + if(property->value || property->values.count() != 1 || + property->values.at(0)->object) + COMPILE_EXCEPTION("Invalid Property default"); + + bool defaultValue = + QmlStringConverters::boolFromString(property->values.at(0)->primitive); + propDef.isDefaultProperty = defaultValue; + if(defaultValue) { + if(seenDefault) + COMPILE_EXCEPTION("Only one property may be the default"); + seenDefault = true; + } + + } else { + COMPILE_EXCEPTION("Invalid Property property"); + } + + } + if(obj->defaultProperty) { + if(seen & Value) + COMPILE_EXCEPTION("May only specify Property value once"); + + seen = (Seen)(seen | Value); + propDef.defaultValue = obj->defaultProperty; + } + + if(!(seen & Name)) + COMPILE_EXCEPTION("Must specify Property name"); + + definedProperties << propDef; + } + + obj->dynamicProperties = definedProperties; + return true; +} + +bool QmlCompiler::findDynamicSignals(QmlParser::Property *sigs, + QmlParser::Object *obj) +{ + QList<Object::DynamicSignal> definedSignals; + + if(sigs->value) + COMPILE_EXCEPTION("Invalid signal specification"); + + for(int ii = 0; ii < sigs->values.count(); ++ii) { + QmlParser::Value *val = sigs->values.at(ii); + if(!val->object) + COMPILE_EXCEPTION("Invalid signal specification"); + + QmlParser::Object *obj = val->object; + if(obj->type == -1 || output->types.at(obj->type).className != "Signal") + COMPILE_EXCEPTION("Use Signal tag to specify signals"); + + enum Seen { None = 0, Name = 0x01 } seen = None; + Object::DynamicSignal sigDef; + + for(QHash<QByteArray, QmlParser::Property *>::ConstIterator iter = + obj->properties.begin(); + iter != obj->properties.end(); + ++iter) { + + QmlParser::Property *property = *iter; + if(property->name == "name") { + if (seen & Name) + COMPILE_EXCEPTION("May only specify Signal name once"); + seen = (Seen)(seen | Name); + + if(property->value || property->values.count() != 1 || + property->values.at(0)->object) + COMPILE_EXCEPTION("Invalid Signal name"); + + sigDef.name = property->values.at(0)->primitive.toLatin1(); + + } else { + COMPILE_EXCEPTION("Invalid Signal property"); + } + + } + + if(obj->defaultProperty) + COMPILE_EXCEPTION("Invalid Signal property"); + + if(!(seen & Name)) + COMPILE_EXCEPTION("Must specify Signal name"); + + definedSignals << sigDef; + } + + obj->dynamicSignals = definedSignals; + return true; +} + +bool QmlCompiler::compileDynamicPropertiesAndSignals(QmlParser::Object *obj) +{ + if(obj->dynamicPropertiesProperty) + findDynamicProperties(obj->dynamicPropertiesProperty, obj); + if(obj->dynamicSignalsProperty) + findDynamicSignals(obj->dynamicSignalsProperty, obj); + + if(obj->dynamicProperties.isEmpty() && obj->dynamicSignals.isEmpty()) + return true; + + QMetaObjectBuilder builder; + if(obj->metatype) + builder.setClassName(QByteArray(obj->metatype->className()) + "QML"); + + builder.setFlags(QMetaObjectBuilder::DynamicMetaObject); + for(int ii = 0; ii < obj->dynamicProperties.count(); ++ii) { + const Object::DynamicProperty &p = obj->dynamicProperties.at(ii); + + if(p.isDefaultProperty) + builder.addClassInfo("DefaultProperty", p.name); + + QByteArray type; + switch(p.type) { + case Object::DynamicProperty::Variant: + type = "QVariant"; + break; + case Object::DynamicProperty::Int: + type = "int"; + break; + case Object::DynamicProperty::Bool: + type = "bool"; + break; + case Object::DynamicProperty::Real: + type = "double"; + break; + case Object::DynamicProperty::String: + type = "QString"; + break; + case Object::DynamicProperty::Color: + type = "QColor"; + break; + case Object::DynamicProperty::Date: + type = "QDate"; + break; + } + + builder.addSignal("qml__" + QByteArray::number(ii) + "()"); + builder.addProperty(p.name, type, ii); + } + + for(int ii = 0; ii < obj->dynamicSignals.count(); ++ii) { + const Object::DynamicSignal &s = obj->dynamicSignals.at(ii); + builder.addSignal(s.name + "()"); + } + + if(obj->metatype) + builder.setSuperClass(obj->metatype); + + obj->extObject = builder.toMetaObject(); + + output->mos << obj->extObject; + QmlInstruction store; + store.type = QmlInstruction::StoreMetaObject; + store.storeMeta.data = output->mos.count() - 1; + store.line = obj->line; + output->bytecode << store; + + for(int ii = 0; ii < obj->dynamicProperties.count(); ++ii) { + const Object::DynamicProperty &p = obj->dynamicProperties.at(ii); + + if(p.defaultValue) { + p.defaultValue->name = p.name; + p.defaultValue->isDefault = false; + COMPILE_CHECK(compileProperty(p.defaultValue, obj, 0)); + } + + if(!p.onValueChanged.isEmpty()) { + QmlInstruction assign; + assign.type = QmlInstruction::AssignSignal; + assign.line = obj->line; + assign.assignSignal.signal = + output->indexForByteArray("onQml__" + QByteArray::number(ii)); + assign.assignSignal.value = + output->indexForString(p.onValueChanged); + output->bytecode << assign; + } + } + + return true; +} + +void QmlCompiler::compileBinding(const QString &str, QmlParser::Property *prop, + int ctxt, const QMetaObject *mo, qint64 line) +{ + Q_ASSERT(isBinding(str)); + + QString bind = str.mid(1, str.length() - 2).trimmed(); + QmlBasicScript bs; + bs.compile(bind.toLatin1()); + + int bref; + if(bs.isValid()) { + bref = output->indexForByteArray(QByteArray(bs.compileData(), bs.compileDataSize())); + } else { + bref = output->indexForString(bind); + } + + QmlInstruction assign; + assign.assignBinding.context = ctxt; + assign.line = line; + if(prop->index != -1) { + if(bs.isValid()) + assign.type = QmlInstruction::StoreCompiledBinding; + else + assign.type = QmlInstruction::StoreBinding; + + assign.assignBinding.property = prop->index; + assign.assignBinding.value = bref; + assign.assignBinding.category = QmlMetaProperty::Unknown; + if(mo) { + //XXX we should generate an exception if the property is read-only + QMetaProperty mp = mo->property(assign.assignBinding.property); + assign.assignBinding.category = QmlMetaProperty::propertyCategory(mp); + } + } else { + if(bs.isValid()) + assign.type = QmlInstruction::AssignCompiledBinding; + else + assign.type = QmlInstruction::AssignBinding; + assign.assignBinding.property = output->indexForByteArray(prop->name); + assign.assignBinding.value = bref; + assign.assignBinding.category = QmlMetaProperty::Unknown; + } + output->bytecode << assign; +} + +int QmlCompiler::optimizeExpressions(int start, int end, int patch) +{ + QHash<QString, int> ids; + int saveCount = 0; + int newInstrs = 0; + + for(int ii = start; ii <= end; ++ii) { + const QmlInstruction &instr = output->bytecode.at(ii); + + if(instr.type == QmlInstruction::CreateComponent) { + ii += instr.createComponent.count - 1; + continue; + } + + if(instr.type == QmlInstruction::SetId) { + QString id = output->primitives.at(instr.setId.value); + ids.insert(id, ii); + } + } + + for(int ii = start; ii <= end; ++ii) { + const QmlInstruction &instr = output->bytecode.at(ii); + + if(instr.type == QmlInstruction::CreateComponent) { + ii += instr.createComponent.count - 1; + continue; + } + + if(instr.type == QmlInstruction::StoreCompiledBinding) { + QmlBasicScript s(output->datas.at(instr.assignBinding.value).constData()); + + if(s.isSingleLoad()) { + QString slt = QLatin1String(s.singleLoadTarget()); + if(!slt.at(0).isUpper()) + continue; + + if(ids.contains(slt) && + instr.assignBinding.category == QmlMetaProperty::Object) { + int id = ids[slt]; + int saveId = -1; + + if(output->bytecode.at(id).setId.save != -1) { + saveId = output->bytecode.at(id).setId.save; + } else { + output->bytecode[id].setId.save = saveCount; + saveId = saveCount; + ++saveCount; + } + + int prop = instr.assignBinding.property; + + QmlInstruction &rwinstr = output->bytecode[ii]; + rwinstr.type = QmlInstruction::PushProperty; + rwinstr.pushProperty.property = prop; + + QmlInstruction instr; + instr.type = QmlInstruction::AssignStackObject; + instr.line = 0; + instr.assignStackObject.property = newInstrs; + instr.assignStackObject.object = saveId; + output->bytecode << instr; + ++newInstrs; + } + } + } + + } + + if(saveCount) + output->bytecode[patch].init.dataSize = saveCount; + + return newInstrs; +} + +QmlCompiledData::QmlCompiledData() +{ +} + +QmlCompiledData::QmlCompiledData(const QmlCompiledData &other) +{ + *this = other; +} + +QmlCompiledData::~QmlCompiledData() +{ + for(int ii = 0; ii < types.count(); ++ii) { + if(types.at(ii).ref) + types.at(ii).ref->release(); + } +} + +QmlCompiledData &QmlCompiledData::operator=(const QmlCompiledData &other) +{ + types = other.types; + primitives = other.primitives; + floatData = other.floatData; + intData = other.intData; + customTypeData = other.customTypeData; + datas = other.datas; + mos = other.mos; + bytecode = other.bytecode; + return *this; +} + +QObject *QmlCompiledData::TypeReference::createInstance() const +{ + if(type) { + return type->create(); + } else if(component) { + return component->create(QmlContext::activeContext()); + } else { + return 0; + } +} + + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlcompiler_p.h b/src/declarative/qml/qmlcompiler_p.h new file mode 100644 index 0000000..732d9ea --- /dev/null +++ b/src/declarative/qml/qmlcompiler_p.h @@ -0,0 +1,183 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLCOMPILER_P_H +#define QMLCOMPILER_P_H + +#include <QtCore/qbytearray.h> +#include <QtCore/qset.h> +#include <qml.h> +#include <private/qmlinstruction_p.h> +#include <private/qmlcompositetypemanager_p.h> +class QStringList; + +QT_BEGIN_NAMESPACE +class QmlXmlParser; +class QmlEngine; +class QmlComponent; +class QmlCompiledComponent; + +namespace QmlParser { + class Object; + class Property; + class Value; +}; + +class QmlCompiledData +{ +public: + QmlCompiledData(); + QmlCompiledData(const QmlCompiledData &other); + QmlCompiledData &operator=(const QmlCompiledData &other); + virtual ~QmlCompiledData(); + + QByteArray name; + QUrl url; + + struct TypeReference + { + TypeReference() + : type(0), component(0), parser(0), ref(0) {} + + QByteArray className; + QmlType *type; + QmlComponent *component; + QmlCustomParser *parser; + + QmlRefCount *ref; + QObject *createInstance() const; + }; + QList<TypeReference> types; + struct CustomTypeData + { + int index; + int type; + }; + QList<QString> primitives; + QList<float> floatData; + QList<int> intData; + QList<CustomTypeData> customTypeData; + QList<QByteArray> datas; + QList<QMetaObject *> mos; + QList<QmlInstruction> bytecode; + +private: + friend class QmlCompiler; + int indexForString(const QString &); + int indexForByteArray(const QByteArray &); + int indexForFloat(float *, int); + int indexForInt(int *, int); +}; + +class Q_DECLARATIVE_EXPORT QmlCompiler +{ +public: + QmlCompiler(); + + bool compile(QmlEngine *, QmlCompositeTypeManager::TypeData *, QmlCompiledComponent *); + + bool isError() const; + qint64 errorLine() const; + QString errorDescription() const; + + static bool isValidId(const QString &); + static bool isBinding(const QString &); + static bool isAttachedProperty(const QByteArray &); + + enum StoreInstructionResult { Ok, UnknownType, InvalidData, ReadOnly }; + static StoreInstructionResult + generateStoreInstruction(QmlCompiledData &data, + QmlInstruction &instr, + const QMetaProperty &prop, + int index, + int primitive, + const QString *string); +private: + void reset(QmlCompiledComponent *, bool); + + void compileTree(QmlParser::Object *tree); + bool compileObject(QmlParser::Object *obj, int); + bool compileComponent(QmlParser::Object *obj, int); + bool compileComponentFromRoot(QmlParser::Object *obj, int); + bool compileFetchedObject(QmlParser::Object *obj, int); + bool compileSignal(QmlParser::Property *prop, QmlParser::Object *obj); + bool compileProperty(QmlParser::Property *prop, QmlParser::Object *obj, int); + bool compileIdProperty(QmlParser::Property *prop, + QmlParser::Object *obj); + bool compileAttachedProperty(QmlParser::Property *prop, + QmlParser::Object *obj, + int ctxt); + bool compileNestedProperty(QmlParser::Property *prop, + int ctxt); + bool compileListProperty(QmlParser::Property *prop, + QmlParser::Object *obj, + int ctxt); + bool compilePropertyAssignment(QmlParser::Property *prop, + QmlParser::Object *obj, + int ctxt); + bool compilePropertyObjectAssignment(QmlParser::Property *prop, + QmlParser::Object *obj, + QmlParser::Value *value, + int ctxt); + bool compilePropertyLiteralAssignment(QmlParser::Property *prop, + QmlParser::Object *obj, + QmlParser::Value *value, + int ctxt); + + bool findDynamicProperties(QmlParser::Property *prop, + QmlParser::Object *obj); + bool findDynamicSignals(QmlParser::Property *sigs, + QmlParser::Object *obj); + + bool compileDynamicPropertiesAndSignals(QmlParser::Object *obj); + void compileBinding(const QString &, QmlParser::Property *prop, + int ctxt, const QMetaObject *, qint64); + + int optimizeExpressions(int start, int end, int patch = -1); + + QSet<QString> ids; + qint64 exceptionLine; + QString exceptionDescription; + QmlCompiledData *output; +}; + +QT_END_NAMESPACE +#endif // QMLCOMPILER_P_H diff --git a/src/declarative/qml/qmlcomponent.cpp b/src/declarative/qml/qmlcomponent.cpp new file mode 100644 index 0000000..c863a00 --- /dev/null +++ b/src/declarative/qml/qmlcomponent.cpp @@ -0,0 +1,405 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmlcomponent.h" +#include "qmlcomponent_p.h" +#include "private/qmlcontext_p.h" +#include "private/qmlengine_p.h" +#include "qmlvme_p.h" +#include "qml.h" +#include <QStack> +#include <qfxperf.h> +#include <QStringList> +#include <qmlengine.h> +#include <QFileInfo> +#include <qmlbindablevalue.h> +#include "private/qmlxmlparser_p.h" +#include "qmlcompiledcomponent_p.h" +#include <QtCore/qdebug.h> +#include <QApplication> + + +QT_BEGIN_NAMESPACE +class QByteArray; + +/*! + \class QmlComponent + \brief The QmlComponent class encapsulates a QML component description. + \mainclass +*/ +QML_DEFINE_TYPE(QmlComponent,Component); + +void QmlComponentPrivate::typeDataReady() +{ + Q_Q(QmlComponent); + + Q_ASSERT(typeData); + + fromTypeData(typeData); + typeData = 0; + + emit q->readyChanged(); +} + +void QmlComponentPrivate::fromTypeData(QmlCompositeTypeManager::TypeData *data) +{ + name = data->url; + QmlCompiledComponent *c = data->toCompiledComponent(engine); + + if(!c) { + Q_ASSERT(data->status == QmlCompositeTypeManager::TypeData::Error); + + qWarning().nospace() << "QmlComponent: " + << data->errorDescription.toLatin1().constData(); + } else { + + cc = c; + + } + + data->release(); +} + +/*! + Construct a null QmlComponent. +*/ +QmlComponent::QmlComponent(QObject *parent) + : QObject(*(new QmlComponentPrivate), parent) +{ + Q_D(QmlComponent); + d->name = QLatin1String("<unspecified file>"); +} + +/*! + Destruct the QmlComponent. +*/ +QmlComponent::~QmlComponent() +{ + Q_D(QmlComponent); + if (d->typeData) { + d->typeData->remWaiter(d); + d->typeData->release(); + } + if (d->cc) + d->cc->release(); +} + +/*! + \property QmlComponent::name + \brief the component's name. + + The component's name is used in error and warning messages. If available, + the XML source file name is used as the component's name, otherwise it is + set to "<unspecified file>". +*/ +QString QmlComponent::name() const +{ + Q_D(const QmlComponent); + return d->name; +} + +void QmlComponent::setName(const QString &name) +{ + Q_D(QmlComponent); + d->name = name; +} + +/*! + \internal +*/ +QmlComponent::QmlComponent(QmlEngine *engine, QmlCompiledComponent *cc, int start, int count, QObject *parent) + : QObject(*(new QmlComponentPrivate), parent) +{ + Q_D(QmlComponent); + d->engine = engine; + d->name = QLatin1String("<unspecified file>"); + d->cc = cc; + cc->addref(); + d->start = start; + d->count = count; +} + +QmlComponent::QmlComponent(QmlEngine *engine, const QUrl &url, QObject *parent) +: QObject(*(new QmlComponentPrivate), parent) +{ + Q_D(QmlComponent); + d->engine = engine; + d->name = url.toString(); + + QmlCompositeTypeManager::TypeData *data = + engine->d_func()->typeManager.get(url); + + if(data->status == QmlCompositeTypeManager::TypeData::Waiting) { + + d->typeData = data; + d->typeData->addWaiter(d); + + } else { + + d->fromTypeData(data); + + } +} + +/*! + Create a QmlComponent with no data. Set setData(). +*/ +QmlComponent::QmlComponent(QmlEngine *engine, QObject *parent) + : QObject(*(new QmlComponentPrivate), parent) +{ + Q_D(QmlComponent); + d->engine = engine; +} + +/*! + Create a QmlComponent from the given XML \a data. If provided, \a filename + is used to set the component name, and to provide a base path for items + resolved by this component. +*/ +QmlComponent::QmlComponent(QmlEngine *engine, const QByteArray &data, const QUrl &url, QObject *parent) + : QObject(*(new QmlComponentPrivate), parent) +{ + Q_D(QmlComponent); + d->engine = engine; + setData(data,url); +} + +/*! + Sets the QmlComponent to use the given XML \a data. If provided, \a filename + is used to set the component name, and to provide a base path for items + resolved by this component. + + Currently only supported to call once per component. +*/ +void QmlComponent::setData(const QByteArray &data, const QUrl &url) +{ + Q_D(QmlComponent); + + if(d->cc) d->cc->release(); + if(d->typeData) d->typeData->release(); + d->cc = 0; + d->typeData = 0; + + d->name = url.toString(); + + QmlCompositeTypeManager::TypeData *typeData = + d->engine->d_func()->typeManager.getImmediate(data, url); + + if(typeData->status == QmlCompositeTypeManager::TypeData::Waiting) { + + d->typeData = typeData; + d->typeData->addWaiter(d); + + } else { + + d->fromTypeData(typeData); + + } + +} + +bool QmlComponent::isReady() const +{ + Q_D(const QmlComponent); + + return d->engine && !d->typeData; +} + +/*! + \internal +*/ +QmlComponent::QmlComponent(QmlComponentPrivate &dd, QObject *parent) + : QObject(dd, parent) +{ + Q_D(QmlComponent); + d->name = QLatin1String("<unspecified file>"); + d->cc = new QmlCompiledComponent; +} + +/*! + Create an object instance from this component. Returns 0 if creation + failed. \a context specifies the context within which to create the object + instance. + + If \a context is 0 (the default), it will create the instance in the + engine' s \l {QmlEngine::rootContext()}{root context}. +*/ +QObject *QmlComponent::create(QmlContext *context) +{ + Q_D(QmlComponent); + + if(!context) + context = d->engine->rootContext(); + + if(context->engine() != d->engine) { + qWarning("QmlComponent::create(): Must create component in context from the same QmlEngine"); + return 0; + } + + QObject *rv = beginCreate(context); + completeCreate(); + return rv; +} + +/*! + This method provides more advanced control over component instance creation. + In general, programmers should use QmlComponent::create() to create a + component. + + Create an object instance from this component. Returns 0 if creation + failed. \a context specifies the context within which to create the object + instance. + + When QmlComponent constructs an instance, it occurs in three steps: + \list 1 + \i The object hierarchy is created, and constant values are assigned. + \i Property bindings are evaluated for the the first time. + \i If applicable, QmlParserStatus::componentComplete() is called on objects. + \endlist + QmlComponent::beginCreate() differs from QmlComponent::create() in that it + only performs step 1. QmlComponent::completeCreate() must be called to + complete steps 2 and 3. + + This breaking point is sometimes useful when using attached properties to + communicate information to an instantiated component, as it allows their + initial values to be configured before property bindings take effect. +*/ +QObject *QmlComponent::beginCreate(QmlContext *context) +{ + Q_D(QmlComponent); + + if(!context) { + qWarning("QmlComponent::beginCreate(): Cannot create a component in a null context"); + return 0; + } + + if(context->engine() != d->engine) { + qWarning("QmlComponent::beginCreate(): Must create component in context from the same QmlEngine"); + return 0; + } + + if (d->completePending) { + qWarning("QmlComponent: Cannot create new component instance before completing the previous"); + return 0; + } + if (!d->cc) { + qWarning("QmlComponent: Cannot load component data"); + return 0; + } + +#ifdef Q_ENABLE_PERFORMANCE_LOG + QFxPerfTimer<QFxPerf::CreateComponent> perf; +#endif + if(!d->engine->d_func()->rootComponent) + d->engine->d_func()->rootComponent = this; + + QmlContext *ctxt = + new QmlContext(context, 0); + static_cast<QmlContextPrivate*>(ctxt->d_ptr)->component = d->cc; + static_cast<QmlContextPrivate*>(ctxt->d_ptr)->component->addref(); + ctxt->activate(); + + QmlVME vme; + QObject *rv = vme.run(ctxt, d->cc, d->start, d->count); + if(vme.isError()) { + qWarning().nospace() +#ifdef QML_VERBOSEERRORS_ENABLED + << "QmlComponent: " +#endif + << vme.errorDescription().toLatin1().constData() << " @" + << d->name.toLatin1().constData() << ":" << vme.errorLine(); + } + + + ctxt->deactivate(); + + if(rv) { + QFx_setParent_noEvent(ctxt, rv); + QmlEnginePrivate *ep = d->engine->d_func(); + if(ep->rootComponent == this) { + ep->rootComponent = 0; + + d->bindValues = ep->currentBindValues; + d->parserStatus = ep->currentParserStatus; + ep->currentBindValues.clear(); + ep->currentParserStatus.clear(); + d->completePending = true; + } + } else { + delete ctxt; + } + + return rv; +} + +/*! + This method provides more advanced control over component instance creation. + In general, programmers should use QmlComponent::create() to create a + component. + + Complete a component creation begin with QmlComponent::beginCreate(). +*/ +void QmlComponent::completeCreate() +{ + Q_D(QmlComponent); + if (d->completePending) { + { +#ifdef Q_ENABLE_PERFORMANCE_LOG + QFxPerfTimer<QFxPerf::BindInit> bi; +#endif + for(int ii = 0; ii < d->bindValues.count(); ++ii) + d->bindValues.at(ii)->init(); + } + QSet<QmlParserStatus *> done; + for(int ii = 0; ii < d->parserStatus.count(); ++ii) { + QmlParserStatus *ps = d->parserStatus.at(ii); + if(!done.contains(ps)) { + done.insert(ps); + ps->componentComplete(); + } + } + + d->bindValues.clear(); + d->parserStatus.clear(); + d->completePending = false; + } +} +QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlcomponent.h b/src/declarative/qml/qmlcomponent.h new file mode 100644 index 0000000..1a74fe9 --- /dev/null +++ b/src/declarative/qml/qmlcomponent.h @@ -0,0 +1,102 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLCOMPONENT_H +#define QMLCOMPONENT_H + +#include <QtCore/qobject.h> +#include <QtCore/qstring.h> +#include <QtDeclarative/qfxglobal.h> +#include <QtDeclarative/qml.h> + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) +class QmlCompiledComponent; +class QByteArray; +class QmlComponentPrivate; +class QmlEngine; +class Q_DECLARATIVE_EXPORT QmlComponent : public QObject +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QmlComponent); + + Q_PROPERTY(QString name READ name WRITE setName); + +public: + QmlComponent(QObject *parent=0); + QmlComponent(QmlEngine *, QObject *parent=0); + QmlComponent(QmlEngine *, const QUrl &url, QObject *parent = 0); + QmlComponent(QmlEngine *, const QByteArray &, const QUrl &url=QUrl(), QObject *parent=0); + ~QmlComponent(); + + virtual QObject *create(QmlContext *context = 0); + virtual QObject *beginCreate(QmlContext *); + virtual void completeCreate(); + + QString name() const; + void setName(const QString &name); + + void setData(const QByteArray &, const QUrl &url); + + bool isReady() const; + + QmlComponent(QmlEngine *, QmlCompiledComponent *, int, int, QObject *parent); + +Q_SIGNALS: + void readyChanged(); + +protected: + QmlComponent(QmlComponentPrivate &dd, QObject* parent); + +private: + friend class QmlVME; +}; +QML_DECLARE_TYPE(QmlComponent); + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QMLCOMPONENT_H diff --git a/src/declarative/qml/qmlcomponent_p.h b/src/declarative/qml/qmlcomponent_p.h new file mode 100644 index 0000000..e97ec67 --- /dev/null +++ b/src/declarative/qml/qmlcomponent_p.h @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLCOMPONENT_P_H +#define QMLCOMPONENT_P_H + +#include <QString> +#include <QStringList> +#include <QList> +#include "private/qobject_p.h" +#include "private/qmlcompositetypemanager_p.h" +#include "qmlcomponent.h" +class QmlComponent; +class QmlEngine; +class QmlCompiledComponent; +#include "qml.h" + + +QT_BEGIN_NAMESPACE + +class QmlComponentPrivate : public QObjectPrivate +{ + Q_DECLARE_PUBLIC(QmlComponent) + +public: + QmlComponentPrivate() : typeData(0), start(-1), count(-1), cc(0), completePending(false), engine(0) {} + + QmlCompositeTypeManager::TypeData *typeData; + void typeDataReady(); + + void fromTypeData(QmlCompositeTypeManager::TypeData *data); + + QString name; + + int start; + int count; + QmlCompiledComponent *cc; + QList<QmlBindableValue *> bindValues; + QList<QmlParserStatus *> parserStatus; + bool completePending; + + QmlEngine *engine; +}; + +#endif // QMLCOMPONENT_P_H + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlcompositetypemanager.cpp b/src/declarative/qml/qmlcompositetypemanager.cpp new file mode 100644 index 0000000..65596ae --- /dev/null +++ b/src/declarative/qml/qmlcompositetypemanager.cpp @@ -0,0 +1,359 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <private/qmlcompositetypemanager_p.h> +#include <private/qmlxmlparser_p.h> +#include <private/qmlcompiledcomponent_p.h> +#include <QtDeclarative/qmlengine.h> +#include <QtNetwork/qnetworkreply.h> +#include <private/qmlengine_p.h> +#include <QtCore/qdebug.h> +#include <QtCore/qfile.h> +#include <QtDeclarative/qmlcomponent.h> +#include <private/qmlcomponent_p.h> + +QmlCompositeTypeManager::TypeData::TypeData() +: status(Invalid), component(0), compiledComponent(0) +{ +} + +QmlCompositeTypeManager::TypeData::~TypeData() +{ + for(int ii = 0; ii < dependants.count(); ++ii) + dependants.at(ii)->release(); + + if(compiledComponent) + compiledComponent->release(); + + if(component) + delete component; +} + +void QmlCompositeTypeManager::TypeData::addWaiter(QmlComponentPrivate *p) +{ + waiters << p; +} + +void QmlCompositeTypeManager::TypeData::remWaiter(QmlComponentPrivate *p) +{ + waiters.removeAll(p); +} + +QmlComponent *QmlCompositeTypeManager::TypeData::toComponent(QmlEngine *engine) +{ + if(!component) { + + QmlCompiledComponent *cc = toCompiledComponent(engine); + if(cc) { + component = new QmlComponent(engine, cc, -1, -1, 0); + } else { + component = new QmlComponent(engine, 0); + } + + } + + return component; +} + +QmlCompiledComponent * +QmlCompositeTypeManager::TypeData::toCompiledComponent(QmlEngine *engine) +{ + if(status == Complete && !compiledComponent) { + + compiledComponent = new QmlCompiledComponent; + compiledComponent->url = QUrl(url); + compiledComponent->name = url.toLatin1(); // ### + + QmlCompiler compiler; + if(!compiler.compile(engine, this, compiledComponent)) { + status = Error; + errorDescription = compiler.errorDescription() + + QLatin1String("@") + + url + QLatin1String(":") + + QString::number(compiler.errorLine()); + compiledComponent->release(); + compiledComponent = 0; + } + + // Data is no longer needed once we have a compiled component + data.clear(); + } + + if(compiledComponent) + compiledComponent->addref(); + + return compiledComponent; +} + +QmlCompositeTypeManager::TypeData::TypeReference::TypeReference() +: type(0), unit(0), parser(0) +{ +} + +QmlCompositeTypeManager::QmlCompositeTypeManager(QmlEngine *e) +: engine(e) +{ +} + +QmlCompositeTypeManager::TypeData *QmlCompositeTypeManager::get(const QUrl &url) +{ + TypeData *unit = components.value(url.toString()); + + if(!unit) { + unit = new TypeData; + unit->status = TypeData::Waiting; + unit->url = url.toString(); + components.insert(url.toString(), unit); + + loadSource(unit); + } + + unit->addref(); + return unit; +} + +QmlCompositeTypeManager::TypeData * +QmlCompositeTypeManager::getImmediate(const QByteArray &data, const QUrl &url) +{ + TypeData *unit = new TypeData; + unit->status = TypeData::Waiting; + unit->url = url.toString(); + setData(unit, data, url); + return unit; +} + +void QmlCompositeTypeManager::clearCache() +{ + for(Components::Iterator iter = components.begin(); iter != components.end();) { + if((*iter)->status != TypeData::Waiting) { + (*iter)->release(); + iter = components.erase(iter); + } else { + ++iter; + } + } +} + + +void QmlCompositeTypeManager::replyFinished() +{ + QNetworkReply *reply = static_cast<QNetworkReply *>(sender()); + + TypeData *unit = components.value(reply->url().toString()); + Q_ASSERT(unit); + + if(reply->error() != QNetworkReply::NoError) { + + QString errorDescription; + // ### - Fill in error + errorDescription = QLatin1String("Network error for URL ") + + reply->url().toString(); + + unit->status = TypeData::Error; + unit->errorDescription = errorDescription; + doComplete(unit); + + } else { + QByteArray data = reply->readAll(); + + setData(unit, data, reply->url()); + } + + reply->deleteLater(); +} + +void QmlCompositeTypeManager::loadSource(TypeData *unit) +{ + QUrl url(unit->url); + + if(url.scheme() == QLatin1String("file")) { + + QFile file(url.toLocalFile()); + if(file.open(QFile::ReadOnly)) { + QByteArray data = file.readAll(); + setData(unit, data, url); + } else { + QString errorDescription; + // ### - Fill in error + errorDescription = QLatin1String("File error for URL ") + url.toString(); + unit->status = TypeData::Error; + unit->errorDescription = errorDescription; + doComplete(unit); + } + + } else { + QNetworkReply *reply = + engine->networkAccessManager()->get(QNetworkRequest(url)); + QObject::connect(reply, SIGNAL(finished()), + this, SLOT(replyFinished())); + } +} + +void QmlCompositeTypeManager::setData(TypeData *unit, const QByteArray &data, + const QUrl &url) +{ + if(!unit->data.parse(data, url)) { + + unit->status = TypeData::Error; + unit->errorDescription = unit->data.errorDescription(); + doComplete(unit); + + } else { + + engine->addNameSpacePaths(unit->data.nameSpacePaths()); + compile(unit); + + } +} + +void QmlCompositeTypeManager::doComplete(TypeData *unit) +{ + for(int ii = 0; ii < unit->dependants.count(); ++ii) { + checkComplete(unit->dependants.at(ii)); + unit->dependants.at(ii)->release(); + } + unit->dependants.clear(); + + while(!unit->waiters.isEmpty()) { + QmlComponentPrivate *p = unit->waiters.takeFirst(); + p->typeDataReady(); + } +} + +void QmlCompositeTypeManager::checkComplete(TypeData *unit) +{ + if(unit->status != TypeData::Waiting) + return; + + int waiting = 0; + for(int ii = 0; ii < unit->types.count(); ++ii) { + TypeData *u = unit->types.at(ii).unit; + + if(!u) + continue; + + if(u->status == TypeData::Error) { + unit->status = TypeData::Error; + unit->errorDescription = u->errorDescription; + doComplete(unit); + return; + } else if(u->status == TypeData::Waiting) { + waiting++; + } + } + if(!waiting) { + unit->status = TypeData::Complete; + doComplete(unit); + } +} + +void QmlCompositeTypeManager::compile(TypeData *unit) +{ + QStringList typeNames = unit->data.types(); + + int waiting = 0; + for(int ii = 0; ii < typeNames.count(); ++ii) { + QByteArray type = typeNames.at(ii).toLatin1(); + + TypeData::TypeReference ref; + if (type == QByteArray("Property") || + type == QByteArray("Signal")) { + unit->types << ref; + continue; + } + + QmlCustomParser *parser = + QmlMetaType::customParser(type); + + if(parser) { + ref.parser = parser; + unit->types << ref; + continue; + } + + ref.type = QmlMetaType::qmlType(type); + if(ref.type) { + ref.parser = parser; + unit->types << ref; + continue; + } + + QUrl url = engine->componentUrl(QUrl(type + ".qml"), QUrl(unit->url)); + TypeData *urlUnit = components.value(url.toString()); + + if(!urlUnit) { + urlUnit = new TypeData; + urlUnit->status = TypeData::Waiting; + urlUnit->url = url.toString(); + components.insert(url.toString(), urlUnit); + + loadSource(urlUnit); + } + + ref.unit = urlUnit; + switch(urlUnit->status) { + case TypeData::Invalid: + case TypeData::Error: + unit->status = TypeData::Error; + unit->errorDescription = urlUnit->errorDescription; + doComplete(unit); + return; + + case TypeData::Complete: + break; + + case TypeData::Waiting: + unit->addref(); + ref.unit->dependants << unit; + waiting++; + break; + } + + unit->types << ref; + } + + if(waiting) { + unit->status = TypeData::Waiting; + } else { + unit->status = TypeData::Complete; + doComplete(unit); + } +} diff --git a/src/declarative/qml/qmlcompositetypemanager_p.h b/src/declarative/qml/qmlcompositetypemanager_p.h new file mode 100644 index 0000000..6982844 --- /dev/null +++ b/src/declarative/qml/qmlcompositetypemanager_p.h @@ -0,0 +1,144 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLCOMPOSITETYPEMANAGER_P_H +#define QMLCOMPOSITETYPEMANAGER_P_H + +#include <qglobal.h> +#include <private/qmlxmlparser_p.h> +#include <private/qmlrefcount_p.h> + +QT_BEGIN_NAMESPACE + +class QmlXmlParser; +class QmlEngine; +class QmlCompiledComponent; +class QmlComponentPrivate; +class QmlComponent; +class QmlCompositeTypeManager : public QObject +{ + Q_OBJECT +public: + QmlCompositeTypeManager(QmlEngine *); + + struct TypeData : public QmlRefCount + { + TypeData(); + virtual ~TypeData(); + + enum Status { + Invalid, + Complete, + Error, + Waiting + }; + Status status; + QString errorDescription; + + QString url; + QList<TypeData *> dependants; + + // Return a QmlComponent if the TypeData is not in the Waiting state. + // The QmlComponent is owned by the TypeData, so a reference should be + // kept to keep the QmlComponent alive. + QmlComponent *toComponent(QmlEngine *); + // Return a QmlCompiledComponent if possible, or 0 if an error + // occurs + QmlCompiledComponent *toCompiledComponent(QmlEngine *); + + struct TypeReference + { + TypeReference(); + + QmlType *type; + TypeData *unit; + QmlCustomParser *parser; + }; + + QList<TypeReference> types; + + // Add or remove p as a waiter. When the TypeData becomes ready, the + // QmlComponentPrivate::typeDataReady() method will be invoked on p. + // The waiter is automatically removed when the typeDataReady() method + // is invoked, so there is no need to call remWaiter() in this case. + void addWaiter(QmlComponentPrivate *p); + void remWaiter(QmlComponentPrivate *p); + + private: + friend class QmlCompositeTypeManager; + friend class QmlCompiler; + + QmlXmlParser data; + QList<QmlComponentPrivate *> waiters; + QmlComponent *component; + QmlCompiledComponent *compiledComponent; + }; + + // Return a TypeData for url. The TypeData may be cached. + TypeData *get(const QUrl &url); + // Return a TypeData for data, with the provided base url. The TypeData + // will not be cached. + TypeData *getImmediate(const QByteArray &data, const QUrl &url); + + // Clear cached types. Only types that aren't in the Waiting state will + // be cleared. + void clearCache(); + +private Q_SLOTS: + void replyFinished(); + +private: + void loadSource(TypeData *); + void compile(TypeData *); + void setData(TypeData *, const QByteArray &, const QUrl &); + + void doComplete(TypeData *); + void checkComplete(TypeData *); + + QmlEngine *engine; + typedef QHash<QString, TypeData *> Components; + Components components; +}; + +QT_END_NAMESPACE + +#endif // QMLCOMPOSITETYPEMANAGER_P_H + diff --git a/src/declarative/qml/qmlcontext.cpp b/src/declarative/qml/qmlcontext.cpp new file mode 100644 index 0000000..104f460 --- /dev/null +++ b/src/declarative/qml/qmlcontext.cpp @@ -0,0 +1,405 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <qmlcontext.h> +#include <private/qmlcontext_p.h> +#include <private/qmlengine_p.h> +#include <private/qmlcompiledcomponent_p.h> +#include <qmlengine.h> +#include <qscriptengine.h> + +#include <qdebug.h> + +// 6-bits +#define MAXIMUM_DEFAULT_OBJECTS 63 + +QT_BEGIN_NAMESPACE + +QmlContextPrivate::QmlContextPrivate() + : parent(0), engine(0), highPriorityCount(0), component(0) +{ +} + +void QmlContextPrivate::dump() +{ + dump(0); +} + +void QmlContextPrivate::dump(int depth) +{ + QByteArray ba(depth * 4, ' '); + qWarning() << ba << properties.keys(); + qWarning() << ba << variantProperties.keys(); + if(parent) + parent->d_func()->dump(depth + 1); +} + +void QmlContextPrivate::destroyed(QObject *obj) +{ + defaultObjects.removeAll(obj); + for(QHash<QString, QObject *>::Iterator iter = properties.begin(); + iter != properties.end(); ) { + if(*iter == obj) + iter = properties.erase(iter); + else + ++iter; + } +} + +void QmlContextPrivate::init() +{ + Q_Q(QmlContext); + //set scope chain + QScriptEngine *scriptEngine = engine->scriptEngine(); + QScriptValue scopeObj = + scriptEngine->newObject(engine->d_func()->contextClass, scriptEngine->newVariant(QVariant::fromValue((QObject*)q))); + if (!parent) + scopeChain.append(scriptEngine->globalObject()); + else + scopeChain = parent->d_func()->scopeChain; + scopeChain.prepend(scopeObj); +} + +void QmlContextPrivate::addDefaultObject(QObject *object, Priority priority) +{ + if(defaultObjects.count() >= (MAXIMUM_DEFAULT_OBJECTS - 1)) { + qWarning("QmlContext: Cannot have more than %d default objects on " + "one bind context.", MAXIMUM_DEFAULT_OBJECTS - 1); + return; + } + + if(priority == HighPriority) { + defaultObjects.insert(highPriorityCount++, object); + } else { + defaultObjects.append(object); + } + QObject::connect(object, SIGNAL(destroyed(QObject*)), + q_ptr, SLOT(objectDestroyed(QObject*))); +} + + +/*! + \class QmlContext + \brief The QmlContext class defines a context within a QML engine. + \mainclass + + Contexts allow data to be exposed to the QML components instantiated by the + QML engine. + + Each QmlContext contains a set of properties, distinct from + its QObject properties, that allow data to be + explicitly bound to a context by name. The context properties are defined or + updated by calling QmlContext::setContextProperty(). The following example shows + a Qt model being bound to a context and then accessed from a QML file. + + \code + QmlEngine engine; + QmlContext context(engine.rootContext()); + context.setContextProperty("myModel", modelData); + + QmlComponent component("<ListView model=\"{myModel}\" />"); + component.create(&context); + \endcode + + To simplify binding and maintaining larger data sets, QObject's can be + added to a QmlContext. These objects are known as the context's default + objects. In this case all the properties of the QObject are + made available by name in the context, as though they were all individually + added by calling QmlContext::setContextProperty(). Changes to the property's + values are detected through the property's notify signal. This method is + also slightly more faster than manually adding property values. + + The following example has the same effect as the one above, but it is + achieved using a default object. + + \code + class MyDataSet : ... { + ... + Q_PROPERTY(QAbstractItemModel *myModel READ model NOTIFY modelChanged); + ... + }; + + MyDataSet myDataSet; + QmlEngine engine; + QmlContext context(engine.rootContext()); + context.addDefaultObject(&myDataSet); + + QmlComponent component("<ListView model=\"{myModel}\" />"); + component.create(&context); + \endcode + + Each context may have up to 32 default objects, and objects added first take + precedence over those added later. All properties added explicitly by + QmlContext::setContextProperty() take precedence over default object properties. + + Contexts are hierarchal, with the \l {QmlEngine::rootContext()}{root context} + being created by the QmlEngine. A component instantiated in a given context + has access to that context's data, as well as the data defined by its + ancestor contexts. Data values (including those added implicitly by the + default objects) in a context override those in ancestor contexts. Data + that should be available to all components instantiated by the QmlEngine + should be added to the \l {QmlEngine::rootContext()}{root context}. + + In the following example, + + \code + QmlEngine engine; + QmlContext context1(engine.rootContext()); + QmlContext context2(&context1); + QmlContext context3(&context2); + + context1.setContextProperty("a", 12); + context2.setContextProperty("b", 13); + context3.setContextProperty("a", 14); + context3.setContextProperty("c", 14); + \endcode + + a QML component instantiated in context1 would have access to the "a" data, + a QML component instantiated in context2 would have access to the "a" and + "b" data, and a QML component instantiated in context3 would have access to + the "a", "b" and "c" data - although its "a" data would return 14, unlike + that in context1 or context2. +*/ + +/*! \internal */ +QmlContext::QmlContext(QmlEngine *e) +: QObject(*(new QmlContextPrivate)) +{ + Q_D(QmlContext); + d->engine = e; + d->init(); +} + +/*! + Create a new QmlContext with the given \a parentContext, and the + QObject \a parent. +*/ +QmlContext::QmlContext(QmlContext *parentContext, QObject *parent) +: QObject(*(new QmlContextPrivate), parent) +{ + Q_D(QmlContext); + d->parent = parentContext; + d->engine = parentContext->engine(); + d->init(); +} + +/*! + Destroys the QmlContext. + + Any expressions, or sub-contexts dependent on this context will be + invalidated, but not destroyed (unless they are parented to the QmlContext + object). + */ +QmlContext::~QmlContext() +{ + Q_D(QmlContext); + if(d->component) d->component->release(); +} + + +/*! + Return the context's QmlEngine, or 0 if the context has no QmlEngine or the + QmlEngine was destroyed. +*/ +QmlEngine *QmlContext::engine() const +{ + Q_D(const QmlContext); + return d->engine; +} + +/*! + Return the context's parent QmlContext, or 0 if this context has no + parent or if the parent has been destroyed. +*/ +QmlContext *QmlContext::parentContext() const +{ + Q_D(const QmlContext); + return d->parent; +} + +/*! + Add a default \a object to this context. The object will be added after + any existing default objects. +*/ +void QmlContext::addDefaultObject(QObject *defaultObject) +{ + Q_D(QmlContext); + d->addDefaultObject(defaultObject, QmlContextPrivate::NormalPriority); +} + +/*! + Set a the \a value of the \a name property on this context. +*/ +void QmlContext::setContextProperty(const QString &name, const QVariant &value) +{ + Q_D(QmlContext); + d->variantProperties.insert(name, value); +} + +/*! + Set a the \a value of the \a name property on this context. + + QmlContext does \b not take ownership of \a value. +*/ +void QmlContext::setContextProperty(const QString &name, QObject *value) +{ + Q_D(QmlContext); + d->properties.insert(name, value); + QObject::connect(value, SIGNAL(destroyed(QObject*)), this, SLOT(objectDestroyed(QObject*))); +} + +/*! + Activate this bind context. + + \sa QmlEngine::activeContext() QmlContext::activeContext() +*/ +void QmlContext::activate() +{ + QmlEnginePrivate *ep = engine()->d_func(); + ep->activeContexts.push(this); + ep->setCurrentBindContext(this); + ep->contextActivated(this); +} + +/*! + Deactivate this bind context. The previously active bind context will + become active, or, if there was no previously active bind context, no + context will be active. + + \sa QmlEngine::activeContext() QmlContext::activeContext() +*/ +void QmlContext::deactivate() +{ + QmlEnginePrivate *ep = engine()->d_func(); + Q_ASSERT(ep->activeContexts.top() == this); + ep->activeContexts.pop(); + if(ep->activeContexts.isEmpty()) + ep->setCurrentBindContext(0); + else + ep->setCurrentBindContext(ep->activeContexts.top()); + ep->contextDeactivated(this); +} + +/*! + Returns the currently active context, or 0 if no context is active. + + This method is thread-safe. The active context is maintained individually + for each thread. This method is equivalent to + \code + QmlEngine::activeEngine()->activeContext() + \endcode +*/ +QmlContext *QmlContext::activeContext() +{ + QmlEngine *engine = QmlEngine::activeEngine(); + if(engine) + return engine->activeContext(); + else + return 0; +} + +/*! + Resolves the URL \a src relative to the URL of the + containing component. + + If \a src is absolute, it is simply returned. + + If there is no containing component, an empty URL is returned. + + \sa componentUrl +*/ +QUrl QmlContext::resolvedUrl(const QUrl &src) +{ + QmlContext *ctxt = this; + if(src.isRelative()) { + if(ctxt) { + while(ctxt) { + if(ctxt->d_func()->component) + break; + else + ctxt = ctxt->parentContext(); + } + + if(ctxt) + return ctxt->d_func()->component->url.resolved(src); + } + return QUrl(); + } else { + return src; + } +} + +/*! + Resolves the component URI \a src relative to the URL of the + containing component, and according to the + \link QmlEngine::nameSpacePaths() namespace paths\endlink of the + context's engine, returning the resolved URL. + + \sa componentUrl +*/ +QUrl QmlContext::resolvedUri(const QUrl &src) +{ + QmlContext *ctxt = this; + if(src.isRelative()) { + if(ctxt) { + while(ctxt) { + if(ctxt->d_func()->component) + break; + else + ctxt = ctxt->parentContext(); + } + + if(ctxt) + return ctxt->d_func()->engine->componentUrl(src, ctxt->d_func()->component->url); + } + return QUrl(); + } else { + return ctxt->d_func()->engine->componentUrl(src, QUrl()); + } +} + +void QmlContext::objectDestroyed(QObject *object) +{ + Q_D(QmlContext); + d->destroyed(object); +} + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlcontext.h b/src/declarative/qml/qmlcontext.h new file mode 100644 index 0000000..9e3b6d8 --- /dev/null +++ b/src/declarative/qml/qmlcontext.h @@ -0,0 +1,104 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLCONTEXT_H +#define QMLCONTEXT_H + +#include <QtCore/qurl.h> +#include <QtCore/qobject.h> +#include <QtScript/qscriptvalue.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +class QString; +class QmlEngine; +class QmlRefCount; +class QmlContextPrivate; +class Q_DECLARATIVE_EXPORT QmlContext : public QObject +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QmlContext) + +public: + QmlContext(QmlContext *parent, QObject *objParent=0); + virtual ~QmlContext(); + + QmlEngine *engine() const; + QmlContext *parentContext() const; + + void addDefaultObject(QObject *); + void setContextProperty(const QString &, QObject *); + void setContextProperty(const QString &, const QVariant &); + + void activate(); + void deactivate(); + + static QmlContext *activeContext(); + + QUrl resolvedUri(const QUrl &); + QUrl resolvedUrl(const QUrl &); + +private Q_SLOTS: + void objectDestroyed(QObject *); + +private: + friend class QmlEngine; + friend class QmlEnginePrivate; + friend class QmlExpression; + friend class QmlBasicScript; + friend class QmlContextScriptClass; + friend class QmlObjectScriptClass; + friend class QmlComponent; + friend class QmlScriptPrivate; + friend class QmlBoundSignalProxy; + QmlContext(QmlEngine *); +}; + + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QMLCONTEXT_H diff --git a/src/declarative/qml/qmlcontext_p.h b/src/declarative/qml/qmlcontext_p.h new file mode 100644 index 0000000..8c51a6b --- /dev/null +++ b/src/declarative/qml/qmlcontext_p.h @@ -0,0 +1,87 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLCONTEXT_P_H +#define QMLCONTEXT_P_H + +#include <qmlcontext.h> +#include <private/qobject_p.h> +#include <qhash.h> +#include <qscriptvalue.h> + +QT_BEGIN_NAMESPACE +class QmlContext; +class QmlEngine; +class QmlCompiledComponent; + +class QmlContextPrivate : public QObjectPrivate +{ + Q_DECLARE_PUBLIC(QmlContext) +public: + QmlContextPrivate(); + + QmlContext *parent; + QmlEngine *engine; + QHash<QString, QObject *> properties; + QHash<QString, QVariant> variantProperties; + + QObjectList defaultObjects; + int highPriorityCount; + + QScriptValueList scopeChain; + + QmlCompiledComponent *component; + void init(); + + void dump(); + void dump(int depth); + + void destroyed(QObject *); + + enum Priority { + HighPriority, + NormalPriority + }; + void addDefaultObject(QObject *, Priority); +}; +QT_END_NAMESPACE + +#endif // QMLCONTEXT_P_H diff --git a/src/declarative/qml/qmlcustomparser.cpp b/src/declarative/qml/qmlcustomparser.cpp new file mode 100644 index 0000000..a342ca8 --- /dev/null +++ b/src/declarative/qml/qmlcustomparser.cpp @@ -0,0 +1,96 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmlcustomparser.h" + + +QT_BEGIN_NAMESPACE + +/*! + \class QmlCustomParser + \brief The QmlCustomParser class allows you to add new arbitrary types to QML. + + By subclassing QmlCustomParser, you can add an XML parser for building a + particular type. + + The subclass must implement compile() and create(), and define itself in + the meta type system with one of the macros: + + \code + QML_DEFINE_CUSTOM_PARSER(Name, parserClass) + \endcode + + \code + QML_DEFINE_CUSTOM_PARSER_NS("XmlNamespaceUri", Name, parserClass) + \endcode +*/ + +/*! + \fn QByteArray QmlCustomParser::compile(QXmlStreamReader& reader, bool *ok) + + Upon entry to this function, \a reader is positioned on a QXmlStreamReader::StartElement + with the name specified when the class was defined with the QML_DEFINE_CUSTOM_PARSER macro. + + The custom parser must consume tokens from \a reader until the EndElement matching the + initial start element is reached, or until error. + + On return, \c *ok indicates success. + + The returned QByteArray contains data meaningful only to the custom parser; the + type engine will pass this same data to create() when making an instance of the data. + + The QByteArray may be cached between executions of the system, so it must contain + correctly-serialized data (not, for example, pointers to stack objects). +*/ + +/*! + \fn QVariant QmlCustomParser::create(const QByteArray &data) + + This function returns a QVariant containing the value represented by \a data, which + is a block of data previously returned by a call to compile(). + + If the compile is for a type, the variant should be a pointer to the + correctly-named QObject subclass (i.e. the one defined by QML_DEFINE_TYPE for + the same-named type as this custom parser is defined for). +*/ + + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlcustomparser.h b/src/declarative/qml/qmlcustomparser.h new file mode 100644 index 0000000..9de1be4 --- /dev/null +++ b/src/declarative/qml/qmlcustomparser.h @@ -0,0 +1,82 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLCUSTOMPARSER_H +#define QMLCUSTOMPARSER_H + +#include <QtCore/qbytearray.h> +#include <QtCore/qxmlstream.h> +#include <QtDeclarative/qfxglobal.h> +#include <QtDeclarative/qmlmetatype.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +class Q_DECLARATIVE_EXPORT QmlCustomParser +{ +public: + virtual ~QmlCustomParser() {} + + virtual QByteArray compile(QXmlStreamReader&, bool *ok)=0; + virtual QVariant create(const QByteArray &)=0; + + struct Register { + Register(const char *name, QmlCustomParser *parser) { + qmlRegisterCustomParser(name, parser); + } + }; + template<typename T> + struct Define { + static Register instance; + }; +}; +#define QML_DEFINE_CUSTOM_PARSER(name, parserClass) \ + template<> QmlCustomParser::Register QmlCustomParser::Define<parserClass>::instance(# name, new parserClass); +#define QML_DEFINE_CUSTOM_PARSER_NS(namespacestring, name, parserClass) \ + template<> QmlCustomParser::Register QmlCustomParser::Define<parserClass>::instance(namespacestring "/" # name, new parserClass); + +QT_END_NAMESPACE + +QT_END_HEADER +#endif diff --git a/src/declarative/qml/qmldom.cpp b/src/declarative/qml/qmldom.cpp new file mode 100644 index 0000000..274b542 --- /dev/null +++ b/src/declarative/qml/qmldom.cpp @@ -0,0 +1,1372 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmldom.h" +#include "qmldom_p.h" +#include "private/qmlxmlparser_p.h" +#include "private/qmlcompiler_p.h" +#include "qmlcompiledcomponent_p.h" +#include <QtCore/qbytearray.h> +#include <QtCore/qstring.h> + +QT_BEGIN_NAMESPACE + +QmlDomDocumentPrivate::QmlDomDocumentPrivate() +: root(0) +{ +} + +QmlDomDocumentPrivate::QmlDomDocumentPrivate(const QmlDomDocumentPrivate &other) +: QSharedData(other), root(0) +{ + root = other.root; + if(root) root->addref(); +} + +QmlDomDocumentPrivate::~QmlDomDocumentPrivate() +{ + if(root) root->release(); +} + +/*! + \class QmlDomDocument + \brief The QmlDomDocument class represents the root of a QML document + + A QML document is a self-contained snippet of QML, usually contained in a + single file. Each document has a version number, accessible through + QmlDomDocument::version(), and a root object, accessible through + QmlDomDocument::rootObject(). + + The QmlDomDocument class allows the programmer to load a QML document, by + calling QmlDomDocument::load(), manipulate it and save it to textual form + by calling QmlDomDocument::save(). By using the QML DOM API, editors can + non-destructively modify a QML document even if they only understand a + subset of the total QML functionality. + + The following example loads a QML file from disk, and prints out its root + object type and the properties assigned in the root object. + \code + QFile file(inputFileName); + file.open(QIODevice::ReadOnly); + QByteArray xmlData = file.readAll(); + + QDomDocument document; + document.load(xmlData); + + QDomObject rootObject = document.rootObject(); + qDebug() << rootObject.objectType(); + foreach(QmlDomProperty property, rootObject.properties()) + qDebug() << property.propertyName(); + \endcode +*/ + +/*! + Construct an empty QmlDomDocument. +*/ +QmlDomDocument::QmlDomDocument() +: d(new QmlDomDocumentPrivate) +{ +} + +/*! + Create a copy of \a other QmlDomDocument. +*/ +QmlDomDocument::QmlDomDocument(const QmlDomDocument &other) +: d(other.d) +{ +} + +/*! + Destroy the QmlDomDocument +*/ +QmlDomDocument::~QmlDomDocument() +{ +} + +/*! + Assign \a other to this QmlDomDocument. +*/ +QmlDomDocument &QmlDomDocument::operator=(const QmlDomDocument &other) +{ + d = other.d; + return *this; +} + +/*! + Return the version number of the Qml document. Currently only version + 1 exists. +*/ +int QmlDomDocument::version() const +{ + return 1; +} + +/*! + Loads a QmlDomDocument from \a data. \a data should be valid QML XML + data. On success, true is returned. If the \a data is malformed, false + is returned and QmlDomDocument::loadError() contains an error description. + + \sa QmlDomDocument::save() QmlDomDocument::loadError() +*/ +bool QmlDomDocument::load(QmlEngine *engine, const QByteArray &data) +{ + d->error = QString(); + + QmlXmlParser parser; + if(!parser.parse(data)) { + d->error = parser.errorDescription(); + return false; + } + + QmlCompiledComponent component; + QmlCompiler compiler; + // ### +// compiler.compile(engine, parser, &component); + + if(compiler.isError()) { + d->error = compiler.errorDescription(); + return false; + } + + if(parser.tree()) { + component.dump(0, parser.tree()); + d->root = parser.tree(); + d->root->addref(); + } + + return true; +} + +/*! + Returns the last load error. The load error will be reset after a + successful call to load(). + + \sa load() +*/ +QString QmlDomDocument::loadError() const +{ + return d->error; +} + +/*! + Return a saved copy of the QmlDomDocument. The returned data will be valid + QML XML data. + + \sa load() +*/ +QByteArray QmlDomDocument::save() const +{ + return QByteArray(); +} + +/*! + Returns the document's root object, or an invalid QmlDomObject if the + document has no root. + + In the sample QML below, the root object will be the QFxItem type. + \code + <Item> + <Text text="Hello World" /> + </Item> + \endcode +*/ +QmlDomObject QmlDomDocument::rootObject() const +{ + QmlDomObject rv; + rv.d->object = d->root; + if(rv.d->object) rv.d->object->addref(); + return rv; +} + +QmlDomPropertyPrivate::QmlDomPropertyPrivate() +: property(0) +{ +} + +QmlDomPropertyPrivate::QmlDomPropertyPrivate(const QmlDomPropertyPrivate &other) +: QSharedData(other), property(0) +{ + property = other.property; + if(property) property->addref(); +} + +QmlDomPropertyPrivate::~QmlDomPropertyPrivate() +{ + if(property) property->release(); +} + +/*! + \class QmlDomProperty + \brief The QmlDomProperty class represents one property assignment in the + QML DOM tree + + Properties in QML can be assigned QML \l {QmlDomValue}{values}. + + \sa QmlDomObject +*/ + +/*! + Construct an invalid QmlDomProperty. +*/ +QmlDomProperty::QmlDomProperty() +: d(new QmlDomPropertyPrivate) +{ +} + +/*! + Create a copy of \a other QmlDomProperty. +*/ +QmlDomProperty::QmlDomProperty(const QmlDomProperty &other) +: d(other.d) +{ +} + +/*! + Destroy the QmlDomProperty. +*/ +QmlDomProperty::~QmlDomProperty() +{ +} + +/*! + Assign \a other to this QmlDomProperty. +*/ +QmlDomProperty &QmlDomProperty::operator=(const QmlDomProperty &other) +{ + d = other.d; + return *this; +} + +/*! + Return the name of this property. + + \code + <Text x="10" y="10" font.bold="true" /> + \endcode + + As illustrated above, a property name can be a simple string, such as "x" or + "y", or a more complex "dot property", such as "font.bold". In both cases + the full name is returned ("x", "y" and "font.bold") by this method. + + For dot properties, a split version of the name can be accessed by calling + QmlDomProperty::propertyNameParts(). + + \sa QmlDomProperty::propertyNameParts() +*/ +QByteArray QmlDomProperty::propertyName() const +{ + return d->propertyName; +} + +/*! + Return the name of this property, split into multiple parts in the case + of dot properties. + + \code + <Text x="10" y="10" font.bold="true" /> + \endcode + + For each of the properties shown above, this method would return ("x"), + ("y") and ("font", "bold"). + + \sa QmlDomProperty::propertyName() +*/ +QList<QByteArray> QmlDomProperty::propertyNameParts() const +{ + if(d->propertyName.isEmpty()) return QList<QByteArray>(); + else return d->propertyName.split('.'); +} + +/*! + Return true if this property is used as a default property in the QML + document. + + \code + <Text text="hello" /> + <Text>hello</Text> + \endcode + + The above two examples return the same DOM tree, except that the second has + the default property flag set on the text property. Observe that whether + or not a property has isDefaultProperty set is determined by how the + property is used, and not only by whether the property is the types default + property. +*/ +bool QmlDomProperty::isDefaultProperty() const +{ + return d->property && d->property->isDefault; +} + +/*! + Returns the QmlDomValue that is assigned to this property, or an invalid + QmlDomValue if no value is assigned. +*/ +QmlDomValue QmlDomProperty::value() const +{ + QmlDomValue rv; + if(d->property) { + rv.d->property = d->property; + rv.d->value = d->property->values.at(0); + rv.d->property->addref(); + rv.d->value->addref(); + } + return rv; +} + +/*! + Sets the QmlDomValue that is assigned to this property to \a value. +*/ +void QmlDomProperty::setValue(const QmlDomValue &value) +{ + Q_UNUSED(value); + qWarning("QmlDomProperty::setValue(const QmlDomValue &): Not Implemented"); +} + +QmlDomObjectPrivate::QmlDomObjectPrivate() +: object(0), isVirtualComponent(false) +{ +} + +QmlDomObjectPrivate::QmlDomObjectPrivate(const QmlDomObjectPrivate &other) +: QSharedData(other), object(0), isVirtualComponent(false) +{ + object = other.object; + if(object) object->addref(); + isVirtualComponent = other.isVirtualComponent; +} + +QmlDomObjectPrivate::~QmlDomObjectPrivate() +{ + if(object) object->release(); +} + +QmlDomObjectPrivate::Properties +QmlDomObjectPrivate::properties() const +{ + Properties rv; + + for(QHash<QByteArray, QmlParser::Property *>::ConstIterator iter = + object->properties.begin(); + iter != object->properties.end(); + ++iter) { + + rv << properties(*iter); + + } + return rv; +} + +QmlDomObjectPrivate::Properties +QmlDomObjectPrivate::properties(QmlParser::Property *property) const +{ + Properties rv; + + if(property->value) { + + for(QHash<QByteArray, QmlParser::Property *>::ConstIterator iter = + property->value->properties.begin(); + iter != property->value->properties.end(); + ++iter) { + + rv << properties(*iter); + + } + + QByteArray name(property->name + "."); + for(Properties::Iterator iter = rv.begin(); iter != rv.end(); ++iter) + iter->second.prepend(name); + + } else { + + // We don't display "id" sets as a property in the dom + if(property->values.count() != 1 || + property->values.at(0)->type != QmlParser::Value::Id) + rv << qMakePair(property, property->name); + + } + + return rv; +} + +/*! + \class QmlDomObject + \brief The QmlDomObject class represents an object instantiation. + + Each object instantiated in a QML file has a corresponding QmlDomObject + node in the QML DOM. + + In addition to the type information that determines the object to + instantiate, QmlDomObject's also have a set of associated QmlDomProperty's. + Each QmlDomProperty represents a QML property assignment on the instantiated + object. For example, + + \code + <QGraphicsWidget opacity="0.5" size="100x100" /> + \endcode + + describes a single QmlDomObject - "QGraphicsWidget" - with two properties, + "opacity" and "size". Obviously QGraphicsWidget has many more properties than just + these two, but the QML DOM representation only contains those assigned + values (or bindings) in the QML file. + + The DOM tree can be modified to include new property assignments by calling + QmlDomObject::addProperty(). Existing property assignments can be modified + through the QmlDomProperty::setValue() method, or removed entirely by + calling QmlDomObject::removeProperty(). +*/ + +/*! + Construct an invalid QmlDomObject. +*/ +QmlDomObject::QmlDomObject() +: d(new QmlDomObjectPrivate) +{ +} + +/*! + Construct a new QmlDomObject with the specified \a objectType. +*/ +QmlDomObject::QmlDomObject(const QByteArray &objectType) +: d(new QmlDomObjectPrivate) +{ + Q_UNUSED(objectType); + qWarning("QmlDomObject::QmlDomObject(const QByteArray &): Not implemented"); +} + +/*! + Create a copy of \a other QmlDomObject. +*/ +QmlDomObject::QmlDomObject(const QmlDomObject &other) +: d(other.d) +{ +} + +/*! + Destroy the QmlDomObject. +*/ +QmlDomObject::~QmlDomObject() +{ +} + +/*! + Assign \a other to this QmlDomObject. +*/ +QmlDomObject &QmlDomObject::operator=(const QmlDomObject &other) +{ + d = other.d; + return *this; +} + +/*! + Returns true if this is a valid QmlDomObject, false otherwise. +*/ +bool QmlDomObject::isValid() const +{ + return d->object != 0; +} + +/*! + Returns the type name of this object. + + For example, the type of this object would be "QGraphicsWidget". + \code + <QGraphicsWidget /> + \endcode +*/ +QByteArray QmlDomObject::objectType() const +{ + if(d->object) return d->object->typeName; + else return QByteArray(); +} + +/*! + Returns the QML id assigned to this object, or an empty QByteArray if no id + has been assigned. + + For example, the object id of this object would be "MyText". + \code + <Text id="MyText" /> + \endcode +*/ +QByteArray QmlDomObject::objectId() const +{ + if(d->object) return d->object->id; + else return QByteArray(); +} + +/*! + Set the object \a id. If any other object within the DOM tree has the same + id, the other object's id will be cleared. +*/ +void QmlDomObject::setObjectId(const QByteArray &id) +{ + Q_UNUSED(id); + qWarning("QmlDomObject::setObjectId(const QByteArray &): Not implemented"); +} + + +/*! + Returns the list of assigned properties on this object. + + In the following example, "text" and "x" properties would be returned. + \code + <Text text="Hello world!" x="100" /> + \endcode +*/ +QList<QmlDomProperty> QmlDomObject::properties() const +{ + QList<QmlDomProperty> rv; + + if(!d->object) + return rv; + + QmlDomObjectPrivate::Properties properties = d->properties(); + for(int ii = 0; ii < properties.count(); ++ii) { + + QmlDomProperty domProperty; + domProperty.d->property = properties.at(ii).first; + domProperty.d->property->addref(); + domProperty.d->propertyName = properties.at(ii).second; + rv << domProperty; + + } + + if(d->object->defaultProperty) { + QmlDomProperty domProperty; + domProperty.d->property = d->object->defaultProperty; + domProperty.d->property->addref(); + domProperty.d->propertyName = d->object->defaultProperty->name; + rv << domProperty; + } + + return rv; +} + +/*! + Returns the object's \a name property if a value has been assigned to + it, or an invalid QmlDomProperty otherwise. + + In the example below, \c {object.property("src")} would return a valid + QmlDomProperty, and \c {object.property("tile")} an invalid QmlDomProperty. + + \code + <Image src="sample.jpg" /> + \endcode +*/ +QmlDomProperty QmlDomObject::property(const QByteArray &name) const +{ + QList<QmlDomProperty> props = properties(); + for(int ii = 0; ii < props.count(); ++ii) + if(props.at(ii).propertyName() == name) + return props.at(ii); + return QmlDomProperty(); +} + +/*! + Remove the property \a name from this object, if it exists. Otherwise does + nothing. +*/ +void QmlDomObject::removeProperty(const QByteArray &name) +{ + Q_UNUSED(name); + qWarning("QmlDomObject::removeProperty(const QByteArray &): Not implemented"); +} + +/*! + Adds the property \a name with the specified \a value to this object. If + a property by \a name already exists, it will be removed. +*/ +void QmlDomObject::addProperty(const QByteArray &name, const QmlDomValue &value) +{ + Q_UNUSED(name); + Q_UNUSED(value); + qWarning("QmlDomObject::addProperty(const QByteArray &, const QmlDomValue &): Not implemented"); +} + +/*! + Returns true if this object is a custom type. Custom types are special + types that allow embeddeding non-QML data, such as SVG or HTML data, + directly into QML files. + + \note Currently this method will always return false, and is a placekeeper + for future functionality. + + \sa QmlDomObject::customTypeData() +*/ +bool QmlDomObject::isCustomType() const +{ + return false; +} + +/*! + Sets the custom type \a data. If this type is not a custom type, this + method does nothing. + + \sa QmlDomObject::isCustomType() QmlDomObject::customTypeData() +*/ +void QmlDomObject::setCustomTypeData(const QByteArray &data) +{ + Q_UNUSED(data); + qWarning("QmlDomObject::setCustomTypeData(const QByteArray &): Not implemented"); +} + +/*! + If this object represents a custom type, returns the data associated with + the custom type, otherwise returns an empty QByteArray(). + QmlDomObject::isCustomType() can be used to check if this object represents + a custom type. +*/ +QByteArray QmlDomObject::customTypeData() const +{ + return QByteArray(); +} + +/*! + Returns true if this object is a sub-component object. Sub-component + objects can be converted into QmlDomComponent instances by calling + QmlDomObject::toComponent(). + + \sa QmlDomObject::toComponent() +*/ +bool QmlDomObject::isComponent() const +{ + return d->isVirtualComponent || + (d->object && d->object->typeName == "Component"); +} + +/*! + Returns a QmlDomComponent for this object if it is a sub-component, or + an invalid QmlDomComponent if not. QmlDomObject::isComponent() can be used + to check if this object represents a sub-component. + + \sa QmlDomObject::isComponent() +*/ +QmlDomComponent QmlDomObject::toComponent() const +{ + QmlDomComponent rv; + if(isComponent()) + rv.d = d; + return rv; +} + +QmlDomBasicValuePrivate::QmlDomBasicValuePrivate() +: value(0) +{ +} + +QmlDomBasicValuePrivate::QmlDomBasicValuePrivate(const QmlDomBasicValuePrivate &other) +: QSharedData(other), value(0) +{ + value = other.value; + if(value) value->addref(); +} + +QmlDomBasicValuePrivate::~QmlDomBasicValuePrivate() +{ + if(value) value->release(); +} + +/*! + \class QmlDomValueLiteral + \brief The QmlDomValueLiteral class represents a literal value. + + A literal value is a simple value, written inline with the QML. In the + example below, the "x", "y" and "color" properties are being assigned + literal values. + + \code + <Rect x="10" y="10" color="red" /> + \endcode +*/ + +/*! + Construct an empty QmlDomValueLiteral. +*/ +QmlDomValueLiteral::QmlDomValueLiteral(): + d(new QmlDomBasicValuePrivate) +{ +} + +/*! + Create a copy of \a other QmlDomValueLiteral. +*/ +QmlDomValueLiteral::QmlDomValueLiteral(const QmlDomValueLiteral &other) +: d(other.d) +{ +} + +/*! + Destroy the QmlDomValueLiteral. +*/ +QmlDomValueLiteral::~QmlDomValueLiteral() +{ +} + +/*! + Assign \a other to this QmlDomValueLiteral. +*/ +QmlDomValueLiteral &QmlDomValueLiteral::operator=(const QmlDomValueLiteral &other) +{ + d = other.d; + return *this; +} + +/*! + Return the literal value. + + In the example below, the literal value will be the string "10". + \code + <Rect x="10" /> + \endcode +*/ +QString QmlDomValueLiteral::literal() const +{ + if(d->value) return d->value->primitive; + else return QString(); +} + +/*! + Sets the literal \a value. +*/ +void QmlDomValueLiteral::setLiteral(const QString &value) +{ + Q_UNUSED(value); + qWarning("QmlDomValueLiteral::setLiteral(const QString &): Not implemented"); +} + +/*! + \class QmlDomValueBinding + \brief The QmlDomValueBinding class represents a property binding. + + A property binding is an ECMAScript expression assigned to a property. In + the example below, the "x" property is being assigned a property binding. + + \code + <Rect x="{Other.x}" /> + \endcode +*/ + +/*! + Construct an empty QmlDomValueBinding. +*/ +QmlDomValueBinding::QmlDomValueBinding() +{ +} + +/*! + Create a copy of \a other QmlDomValueBinding. +*/ +QmlDomValueBinding::QmlDomValueBinding(const QmlDomValueBinding &other) +: d(other.d) +{ +} + +/*! + Destroy the QmlDomValueBinding. +*/ +QmlDomValueBinding::~QmlDomValueBinding() +{ +} + +/*! + Assign \a other to this QmlDomValueBinding. +*/ +QmlDomValueBinding &QmlDomValueBinding::operator=(const QmlDomValueBinding &other) +{ + d = other.d; + return *this; +} + +/*! + Return the binding expression. + + In the example below, the string "Other.x" will be returned. + \code + <Rect x="{Other.x}" /> + \endcode +*/ +QString QmlDomValueBinding::binding() const +{ + if(d->value) + return d->value->primitive.mid(1, d->value->primitive.length() - 2); + else + return QString(); +} + +/*! + Sets the binding \a expression. +*/ +void QmlDomValueBinding::setBinding(const QString &expression) +{ + Q_UNUSED(expression); + qWarning("QmlDomValueBinding::setBinding(const QString &): Not implemented"); +} + +/*! + \class QmlDomValueValueSource + \brief The QmlDomValueValueSource class represents a value source assignment value. + + In QML, value sources are special value generating types that may be + assigned to properties. Value sources inherit the QmlPropertyValueSource + class. In the example below, the "x" property is being assigned the + NumericAnimation value source. + + \code + <Rect> + <x> + <NumericAnimation from="0" to="100" repeat="true" running="true" /> + </x> + </Rect> + \endcode +*/ + +/*! + Construct an empty QmlDomValueValueSource. +*/ +QmlDomValueValueSource::QmlDomValueValueSource() +{ +} + +/*! + Create a copy of \a other QmlDomValueValueSource. +*/ +QmlDomValueValueSource::QmlDomValueValueSource(const QmlDomValueValueSource &other) +: d(other.d) +{ +} + +/*! + Destroy the QmlDomValueValueSource. +*/ +QmlDomValueValueSource::~QmlDomValueValueSource() +{ +} + +/*! + Assign \a other to this QmlDomValueValueSource. +*/ +QmlDomValueValueSource &QmlDomValueValueSource::operator=(const QmlDomValueValueSource &other) +{ + d = other.d; + return *this; +} + +/*! + Return the value source object. + + In the example below, an object representing the NumericAnimation will be + returned. + \code + <Rect> + <x> + <NumericAnimation from="0" to="100" repeat="true" running="true" /> + </x> + </Rect> + \endcode +*/ +QmlDomObject QmlDomValueValueSource::object() const +{ + QmlDomObject rv; + if(d->value) { + rv.d->object = d->value->object; + rv.d->object->addref(); + } + return QmlDomObject(); +} + +/*! + Sets the value source \a object. +*/ +void QmlDomValueValueSource::setObject(const QmlDomObject &object) +{ + Q_UNUSED(object); + qWarning("QmlDomValueValueSource::setObject(const QmlDomObject &): Not implemented"); +} + +QmlDomValuePrivate::QmlDomValuePrivate() +: property(0), value(0) +{ +} + +QmlDomValuePrivate::QmlDomValuePrivate(const QmlDomValuePrivate &other) +: QSharedData(other), property(0), value(0) +{ + property = other.property; + value = other.value; + if(property) property->addref(); + if(value) value->addref(); +} + +QmlDomValuePrivate::~QmlDomValuePrivate() +{ + if(property) property->release(); + if(value) value->release(); +} + +/*! + \class QmlDomValue + \brief The QmlDomValue class represents a generic Qml value. + + QmlDomValue's can be assigned to QML \l {QmlDomProperty}{properties}. In + QML, properties can be assigned various different values, including basic + literals, property bindings, property value sources, objects and lists of + values. The QmlDomValue class allows a programmer to determine the specific + value type being assigned and access more detailed information through a + corresponding value type class. + + For example, in the following example, + + \code + <Text text="Hello World!" y="{Other.y}" /> + \endcode + + The text property is being assigned a literal, and the y property a property + binding. To output the values assigned to the text and y properties in the + above example from C++, + + \code + QmlDomDocument document; + QmlDomObject root = document.rootObject(); + + QmlDomProperty text = root.property("text"); + if(text.value().isLiteral()) { + QmlDomValueLiteral literal = text.value().toLiteral(); + qDebug() << literal.literal(); + } + + QmlDomProperty y = root.property("y"); + if(y.value().isBinding()) { + QmlDomValueBinding binding = y.value().toBinding(); + qDebug() << binding.binding(); + } + \endcode +*/ + +/*! + Construct an invalid QmlDomValue. +*/ +QmlDomValue::QmlDomValue() +: d(new QmlDomValuePrivate) +{ +} + +/*! + Create a copy of \a other QmlDomValue. +*/ +QmlDomValue::QmlDomValue(const QmlDomValue &other) +: d(other.d) +{ +} + +/*! + Destroy the QmlDomValue +*/ +QmlDomValue::~QmlDomValue() +{ +} + +/*! + Assign \a other to this QmlDomValue. +*/ +QmlDomValue &QmlDomValue::operator=(const QmlDomValue &other) +{ + d = other.d; + return *this; +} + +/*! + \enum QmlDomValue::Type + + The type of the QmlDomValue node. + + \value Invalid The QmlDomValue is invalid. + \value Literal The QmlDomValue is a literal value assignment. Use QmlDomValue::toLiteral() to access the type instance. + \value PropertyBinding The QmlDomValue is a property binding. Use QmlDomValue::toBinding() to access the type instance. + \value ValueSource The QmlDomValue is a property value source. Use QmlDomValue::toValueSource() to access the type instance. + \value Object The QmlDomValue is an object assignment. Use QmlDomValue::toObject() to access the type instnace. + \value List The QmlDomValue is a list of other values. Use QmlDomValue::toList() to access the type instance. +*/ + +/*! + Returns the type of this QmlDomValue. +*/ +QmlDomValue::Type QmlDomValue::type() const +{ + if(d->property) + if(QmlMetaType::isList(d->property->type) || + QmlMetaType::isQmlList(d->property->type) || + (d->property && d->property->values.count() > 1)) + return List; + + QmlParser::Value *value = d->value; + if (!value && !d->property) + return Invalid; + + switch(value->type) { + case QmlParser::Value::Unknown: + return Invalid; + case QmlParser::Value::Literal: + return Literal; + case QmlParser::Value::PropertyBinding: + return PropertyBinding; + case QmlParser::Value::ValueSource: + return ValueSource; + case QmlParser::Value::Component: + case QmlParser::Value::CreatedObject: + return Object; + case QmlParser::Value::SignalObject: + return Invalid; + case QmlParser::Value::SignalExpression: + return Literal; + case QmlParser::Value::Id: + return Invalid; + } + return Invalid; +} + +/*! + Returns true if this is an invalid value, otherwise false. +*/ +bool QmlDomValue::isInvalid() const +{ + return type() == Invalid; +} + +/*! + Returns true if this is a literal value, otherwise false. +*/ +bool QmlDomValue::isLiteral() const +{ + return type() == Literal; +} + +/*! + Returns true if this is a property binding value, otherwise false. +*/ +bool QmlDomValue::isBinding() const +{ + return type() == PropertyBinding; +} + +/*! + Returns true if this is a value source value, otherwise false. +*/ +bool QmlDomValue::isValueSource() const +{ + return type() == ValueSource; +} + +/*! + Returns true if this is an object value, otherwise false. +*/ +bool QmlDomValue::isObject() const +{ + return type() == Object; +} + +/*! + Returns true if this is a list value, otherwise false. +*/ +bool QmlDomValue::isList() const +{ + return type() == List; +} + +/*! + Returns a QmlDomValueLiteral if this value is a literal type, otherwise + returns an invalid QmlDomValueLiteral. + + \sa QmlDomValue::type() +*/ +QmlDomValueLiteral QmlDomValue::toLiteral() const +{ + QmlDomValueLiteral rv; + if(type() == Literal) { + rv.d->value = d->value; + rv.d->value->addref(); + } + return rv; +} + +/*! + Returns a QmlDomValueBinding if this value is a property binding type, + otherwise returns an invalid QmlDomValueBinding. + + \sa QmlDomValue::type() +*/ +QmlDomValueBinding QmlDomValue::toBinding() const +{ + QmlDomValueBinding rv; + if(type() == PropertyBinding) { + rv.d->value = d->value; + rv.d->value->addref(); + } + return rv; +} + +/*! + Returns a QmlDomValueValueSource if this value is a property value source + type, otherwise returns an invalid QmlDomValueValueSource. + + \sa QmlDomValue::type() +*/ +QmlDomValueValueSource QmlDomValue::toValueSource() const +{ + QmlDomValueValueSource rv; + if(type() == ValueSource) { + rv.d->value = d->value; + rv.d->value->addref(); + } + return rv; +} + +/*! + Returns a QmlDomObject if this value is an object assignment type, otherwise + returns an invalid QmlDomObject. + + \sa QmlDomValue::type() +*/ +QmlDomObject QmlDomValue::toObject() const +{ + QmlDomObject rv; + if(type() == Object) { + rv.d->object = d->value->object; + rv.d->object->addref(); + } + return rv; +} + +/*! + Returns a QmlDomList if this value is a list type, otherwise returns an + invalid QmlDomList. + + \sa QmlDomValue::type() +*/ +QmlDomList QmlDomValue::toList() const +{ + QmlDomList rv; + if(type() == List) { + rv.d = d; + } + return rv; +} + +/*! + \class QmlDomList + \brief The QmlDomList class represents a list of values assigned to a QML property. + + Lists of values can be assigned to properties. For example, the following + example assigns multiple objects to Item's "children" property + \code + <Item> + <children> + <Text /> + <Rect /> + </children> + </Item> + \endcode + + Lists can also be implicitly created by assigning multiple + \l {QmlDomValueValueSource}{value sources} or constants to a property. + \code + <Item x="10"> + <x> + <NumericAnimation running="false" from="0" to="100" /> + </x> + </Item> + \endcode +*/ + +/*! + Construct an empty QmlDomList. +*/ +QmlDomList::QmlDomList() +{ +} + +/*! + Create a copy of \a other QmlDomList. +*/ +QmlDomList::QmlDomList(const QmlDomList &other) +: d(other.d) +{ +} + +/*! + Destroy the QmlDomList. +*/ +QmlDomList::~QmlDomList() +{ +} + +/*! + Assign \a other to this QmlDomList. +*/ +QmlDomList &QmlDomList::operator=(const QmlDomList &other) +{ + d = other.d; + return *this; +} + +/*! + Returns the list of QmlDomValue's. +*/ +QList<QmlDomValue> QmlDomList::values() const +{ + QList<QmlDomValue> rv; + if(!d->property) + return rv; + + for(int ii = 0; ii < d->property->values.count(); ++ii) { + QmlDomValue v; + v.d->value = d->property->values.at(ii); + v.d->value->addref(); + rv << v; + } + + return rv; +} + +/*! + Set the list of QmlDomValue's to \a values. +*/ +void QmlDomList::setValues(const QList<QmlDomValue> &values) +{ + Q_UNUSED(values); + qWarning("QmlDomList::setValues(const QList<QmlDomValue> &): Not implemented"); +} + + +/*! + \class QmlDomComponent + \brief The QmlDomComponent class represents sub-component within a QML document. + + Sub-components are QmlComponents defined within a QML document. The + following example shows the definition of a sub-component with the id + "ListDelegate". + + \code + <Item> + <Component id="ListDelegate"> + <Text text="{modelData.text}" /> + </Component> + </Item> + \endcode + + Like QmlDomDocument's, components contain a single root object. +*/ + +/*! + Construct an empty QmlDomComponent. +*/ +QmlDomComponent::QmlDomComponent() +{ +} + +/*! + Create a copy of \a other QmlDomComponent. +*/ +QmlDomComponent::QmlDomComponent(const QmlDomComponent &other) +: QmlDomObject(other) +{ +} + +/*! + Destroy the QmlDomComponent. +*/ +QmlDomComponent::~QmlDomComponent() +{ +} + +/*! + Assign \a other to this QmlDomComponent. +*/ +QmlDomComponent &QmlDomComponent::operator=(const QmlDomComponent &other) +{ + static_cast<QmlDomObject &>(*this) = other; + return *this; +} + +/*! + Returns the component's root object. + + In the example below, the root object is the "Text" object. + \code + <Item> + <Component id="ListDelegate"> + <Text text="{modelData.text}" /> + </Component> + </Item> + \endcode +*/ +QmlDomObject QmlDomComponent::componentRoot() const +{ + QmlDomObject rv; + if(d->isVirtualComponent) { + rv.d->object = d->object; + rv.d->object->addref(); + } else if(d->object) { + QmlParser::Object *obj = 0; + if(d->object->defaultProperty && + d->object->defaultProperty->values.count() == 1 && + d->object->defaultProperty->values.at(0)->object) + obj = d->object->defaultProperty->values.at(0)->object; + + if(obj) { + rv.d->object = obj; + rv.d->object->addref(); + } + } + + return rv; +} + +/*! + Set the component's \a root object. +*/ +void QmlDomComponent::setComponentRoot(const QmlDomObject &root) +{ + Q_UNUSED(root); + qWarning("QmlDomComponent::setComponentRoot(const QmlDomObject &): Not implemented"); +} + +QT_END_NAMESPACE + diff --git a/src/declarative/qml/qmldom.h b/src/declarative/qml/qmldom.h new file mode 100644 index 0000000..47a89d9 --- /dev/null +++ b/src/declarative/qml/qmldom.h @@ -0,0 +1,263 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLDOM_H +#define QMLDOM_H + +#include <QtCore/qlist.h> +#include <QtCore/qshareddata.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +class QString; +class QByteArray; +class QmlDomObject; +class QmlDomList; +class QmlDomValue; +class QmlEngine; +class QmlDomComponent; +class QIODevice; + +class QmlDomDocumentPrivate; +class Q_DECLARATIVE_EXPORT QmlDomDocument +{ +public: + QmlDomDocument(); + QmlDomDocument(const QmlDomDocument &); + ~QmlDomDocument(); + QmlDomDocument &operator=(const QmlDomDocument &); + + int version() const; + + QString loadError() const; + bool load(QmlEngine *, const QByteArray &); + QByteArray save() const; + + QmlDomObject rootObject() const; +private: + QSharedDataPointer<QmlDomDocumentPrivate> d; +}; + +class QmlDomPropertyPrivate; +class Q_DECLARATIVE_EXPORT QmlDomProperty +{ +public: + QmlDomProperty(); + QmlDomProperty(const QmlDomProperty &); + ~QmlDomProperty(); + QmlDomProperty &operator=(const QmlDomProperty &); + + QByteArray propertyName() const; + QList<QByteArray> propertyNameParts() const; + + bool isDefaultProperty() const; + + QmlDomValue value() const; + void setValue(const QmlDomValue &); + +private: + friend class QmlDomObject; + QSharedDataPointer<QmlDomPropertyPrivate> d; +}; + +class QmlDomObjectPrivate; +class Q_DECLARATIVE_EXPORT QmlDomObject +{ +public: + QmlDomObject(); + QmlDomObject(const QByteArray &); + QmlDomObject(const QmlDomObject &); + ~QmlDomObject(); + QmlDomObject &operator=(const QmlDomObject &); + + bool isValid() const; + + QByteArray objectType() const; + QByteArray objectId() const; + + void setObjectId(const QByteArray &); + + QList<QmlDomProperty> properties() const; + QmlDomProperty property(const QByteArray &) const; + + void removeProperty(const QByteArray &); + void addProperty(const QByteArray &, const QmlDomValue &); + + bool isCustomType() const; + QByteArray customTypeData() const; + void setCustomTypeData(const QByteArray &); + + bool isComponent() const; + QmlDomComponent toComponent() const; + +private: + friend class QmlDomDocument; + friend class QmlDomComponent; + friend class QmlDomValue; + friend class QmlDomValueValueSource; + QSharedDataPointer<QmlDomObjectPrivate> d; +}; + +class QmlDomValuePrivate; +class QmlDomBasicValuePrivate; +class Q_DECLARATIVE_EXPORT QmlDomValueLiteral +{ +public: + QmlDomValueLiteral(); + QmlDomValueLiteral(const QmlDomValueLiteral &); + ~QmlDomValueLiteral(); + QmlDomValueLiteral &operator=(const QmlDomValueLiteral &); + + QString literal() const; + void setLiteral(const QString &); + +private: + friend class QmlDomValue; + QSharedDataPointer<QmlDomBasicValuePrivate> d; +}; + +class Q_DECLARATIVE_EXPORT QmlDomValueBinding +{ +public: + QmlDomValueBinding(); + QmlDomValueBinding(const QmlDomValueBinding &); + ~QmlDomValueBinding(); + QmlDomValueBinding &operator=(const QmlDomValueBinding &); + + QString binding() const; + void setBinding(const QString &); + +private: + friend class QmlDomValue; + QSharedDataPointer<QmlDomBasicValuePrivate> d; +}; + +class Q_DECLARATIVE_EXPORT QmlDomValueValueSource +{ +public: + QmlDomValueValueSource(); + QmlDomValueValueSource(const QmlDomValueValueSource &); + ~QmlDomValueValueSource(); + QmlDomValueValueSource &operator=(const QmlDomValueValueSource &); + + QmlDomObject object() const; + void setObject(const QmlDomObject &); + +private: + friend class QmlDomValue; + QSharedDataPointer<QmlDomBasicValuePrivate> d; +}; + +class Q_DECLARATIVE_EXPORT QmlDomComponent : public QmlDomObject +{ +public: + QmlDomComponent(); + QmlDomComponent(const QmlDomComponent &); + ~QmlDomComponent(); + QmlDomComponent &operator=(const QmlDomComponent &); + + QmlDomObject componentRoot() const; + void setComponentRoot(const QmlDomObject &); +}; + +class Q_DECLARATIVE_EXPORT QmlDomValue +{ +public: + enum Type { + Invalid, + Literal, + PropertyBinding, + ValueSource, + Object, + List + }; + + QmlDomValue(); + QmlDomValue(const QmlDomValue &); + ~QmlDomValue(); + QmlDomValue &operator=(const QmlDomValue &); + + Type type() const; + + bool isInvalid() const; + bool isLiteral() const; + bool isBinding() const; + bool isValueSource() const; + bool isObject() const; + bool isList() const; + + QmlDomValueLiteral toLiteral() const; + QmlDomValueBinding toBinding() const; + QmlDomValueValueSource toValueSource() const; + QmlDomObject toObject() const; + QmlDomList toList() const; + +private: + friend class QmlDomProperty; + friend class QmlDomList; + QSharedDataPointer<QmlDomValuePrivate> d; +}; + +class Q_DECLARATIVE_EXPORT QmlDomList +{ +public: + QmlDomList(); + QmlDomList(const QmlDomList &); + ~QmlDomList(); + QmlDomList &operator=(const QmlDomList &); + + QList<QmlDomValue> values() const; + void setValues(const QList<QmlDomValue> &); + +private: + friend class QmlDomValue; + QSharedDataPointer<QmlDomValuePrivate> d; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QMLDOM_H diff --git a/src/declarative/qml/qmldom_p.h b/src/declarative/qml/qmldom_p.h new file mode 100644 index 0000000..8ea56bf --- /dev/null +++ b/src/declarative/qml/qmldom_p.h @@ -0,0 +1,116 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLDOM_P_H +#define QMLDOM_P_H + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +#include "qmlparser_p.h" + +class QmlDomDocumentPrivate : public QSharedData +{ +public: + QmlDomDocumentPrivate(); + QmlDomDocumentPrivate(const QmlDomDocumentPrivate &); + ~QmlDomDocumentPrivate(); + + QString error; + QmlParser::Object *root; +}; + +class QmlDomObjectPrivate : public QSharedData +{ +public: + QmlDomObjectPrivate(); + QmlDomObjectPrivate(const QmlDomObjectPrivate &); + ~QmlDomObjectPrivate(); + + typedef QList<QPair<QmlParser::Property *, QByteArray> > Properties; + Properties properties() const; + Properties properties(QmlParser::Property *) const; + + QmlParser::Object *object; + bool isVirtualComponent; +}; + +class QmlDomPropertyPrivate : public QSharedData +{ +public: + QmlDomPropertyPrivate(); + QmlDomPropertyPrivate(const QmlDomPropertyPrivate &); + ~QmlDomPropertyPrivate(); + + QByteArray propertyName; + QmlParser::Property *property; +}; + +class QmlDomValuePrivate : public QSharedData +{ +public: + QmlDomValuePrivate(); + QmlDomValuePrivate(const QmlDomValuePrivate &); + ~QmlDomValuePrivate(); + + QmlParser::Property *property; + QmlParser::Value *value; +}; + +class QmlDomBasicValuePrivate : public QSharedData +{ +public: + QmlDomBasicValuePrivate(); + QmlDomBasicValuePrivate(const QmlDomBasicValuePrivate &); + ~QmlDomBasicValuePrivate(); + + QmlParser::Value *value; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QMLDOM_P_H + diff --git a/src/declarative/qml/qmlengine.cpp b/src/declarative/qml/qmlengine.cpp new file mode 100644 index 0000000..63f45b4 --- /dev/null +++ b/src/declarative/qml/qmlengine.cpp @@ -0,0 +1,1295 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +// XXX ;) +#define private public +#include <QMetaProperty> +#undef private + +#include <private/qmlengine_p.h> +#include <private/qmlcontext_p.h> + +#ifdef QT_SCRIPTTOOLS_LIB +#include <QScriptEngineDebugger> +#endif + +#include <QScriptClass> +#include <QNetworkReply> +#include <QNetworkRequest> +#include <QNetworkAccessManager> +#include <QList> +#include <QPair> +#include <QDebug> +#include <QMetaObject> +#include "qml.h" +#include <qfxperf.h> +#include <QStack> +#include "private/qmlbasicscript_p.h" +#include "private/qmlcompiledcomponent_p.h" +#include "qmlengine.h" +#include "qmlcontext.h" +#include "qmlexpression.h" +#include <QtCore/qthreadstorage.h> +#include <QtCore/qthread.h> +#include <QtCore/qcoreapplication.h> +#include <QtCore/qdir.h> +#include <qmlcomponent.h> +#include "private/qmlmetaproperty_p.h" + + +QT_BEGIN_NAMESPACE + +DEFINE_BOOL_CONFIG_OPTION(bindValueDebug, QML_BINDVALUE_DEBUG); +#ifdef QT_SCRIPTTOOLS_LIB +DEFINE_BOOL_CONFIG_OPTION(debuggerEnabled, QML_DEBUGGER); +#endif + +Q_DECLARE_METATYPE(QmlMetaProperty); + +QML_DEFINE_TYPE(QObject,Object); + +static QScriptValue qmlMetaProperty_emit(QScriptContext *ctx, QScriptEngine *engine) +{ + QmlMetaProperty mp = qscriptvalue_cast<QmlMetaProperty>(ctx->thisObject()); + if(mp.type() & QmlMetaProperty::Signal) + mp.emitSignal(); + return engine->nullValue(); +} + +struct StaticQtMetaObject : public QObject +{ + static const QMetaObject *get() + { return &static_cast<StaticQtMetaObject*> (0)->staticQtMetaObject; } +}; + + +struct QmlEngineStack { + QmlEngineStack(); + + QStack<QmlEngine *> mainThreadEngines; + QThread *mainThread; + + QThreadStorage<QStack<QmlEngine *> *> storage; + + QStack<QmlEngine *> *engines(); +}; + +Q_GLOBAL_STATIC(QmlEngineStack, engineStack); + +QmlEngineStack::QmlEngineStack() +: mainThread(0) +{ +} + +QStack<QmlEngine *> *QmlEngineStack::engines() +{ + if(mainThread== 0) { + if(!QCoreApplication::instance()) + return 0; + mainThread = QCoreApplication::instance()->thread(); + } + + // Note: This is very slightly faster than just using the thread storage + // for everything. + QStack<QmlEngine *> *engines = 0; + if(QThread::currentThread() == mainThread) { + engines = &mainThreadEngines; + } else { + engines = storage.localData(); + if(!engines) { + engines = new QStack<QmlEngine *>; + storage.setLocalData(engines); + } + } + return engines; +} + + +QmlEnginePrivate::QmlEnginePrivate(QmlEngine *e) +: rootContext(0), currentBindContext(0), currentExpression(0), q(e), + rootComponent(0), networkAccessManager(0), typeManager(e) +{ + QScriptValue proto = scriptEngine.newObject(); + proto.setProperty(QLatin1String("emit"), + scriptEngine.newFunction(qmlMetaProperty_emit)); + scriptEngine.setDefaultPrototype(qMetaTypeId<QmlMetaProperty>(), proto); + + QScriptValue qtObject = scriptEngine.newQMetaObject(StaticQtMetaObject::get()); + scriptEngine.globalObject().setProperty(QLatin1String("Qt"), qtObject); +} + +QmlEnginePrivate::~QmlEnginePrivate() +{ + delete rootContext; + rootContext = 0; + delete contextClass; + contextClass = 0; + delete objectClass; + objectClass = 0; + delete networkAccessManager; + networkAccessManager = 0; +} + +void QmlEnginePrivate::init() +{ + contextClass = new QmlContextScriptClass(q); + objectClass = new QmlObjectScriptClass(q); + rootContext = new QmlContext(q); +#ifdef QT_SCRIPTTOOLS_LIB + if(debuggerEnabled()){ + debugger = new QScriptEngineDebugger(q); + debugger->attachTo(&scriptEngine); + } +#endif +} + +QmlContext *QmlEnginePrivate::setCurrentBindContext(QmlContext *c) +{ + QmlContext *old = currentBindContext; + currentBindContext = c; + return old; +} + +//////////////////////////////////////////////////////////////////// +typedef QHash<QPair<const QMetaObject *, QString>, bool> FunctionCache; +Q_GLOBAL_STATIC(FunctionCache, functionCache); + +QScriptClass::QueryFlags +QmlEnginePrivate::queryObject(const QString &propName, + uint *id, QObject *obj) +{ + QScriptClass::QueryFlags rv = 0; + + QmlMetaProperty prop(obj, propName); + if(prop.type() == QmlMetaProperty::Invalid) { + QPair<const QMetaObject *, QString> key = + qMakePair(obj->metaObject(), propName); + bool isFunction = false; + if (functionCache()->contains(key)) { + isFunction = functionCache()->value(key); + } else { + QScriptValue sobj = scriptEngine.newQObject(obj); + QScriptValue func = sobj.property(propName); + isFunction = func.isFunction(); + functionCache()->insert(key, isFunction); + } + + if(isFunction) { + *id = QmlScriptClass::FunctionId; + rv |= QScriptClass::HandlesReadAccess; + } + } else { + *id = QmlScriptClass::PropertyId; + *id |= prop.save(); + + rv |= QScriptClass::HandlesReadAccess; + if(prop.isWritable()) + rv |= QScriptClass::HandlesWriteAccess; + } + + return rv; +} + +QScriptValue QmlEnginePrivate::propertyObject(const QScriptString &propName, + QObject *obj, uint id) +{ + if(id == QmlScriptClass::FunctionId) { + QScriptValue sobj = scriptEngine.newQObject(obj); + QScriptValue func = sobj.property(propName); + return func; + } else { + QmlMetaProperty prop; + prop.restore(id, obj); + if(!prop.isValid()) + return QScriptValue(); + + if(prop.type() & QmlMetaProperty::Signal) { + return scriptEngine.newVariant(qVariantFromValue(prop)); + } else { + QVariant var = prop.read(); + capturedProperties << prop; + QObject *varobj = QmlMetaType::toQObject(var); + if(!varobj) + varobj = qvariant_cast<QObject *>(var); + if(varobj) { + return scriptEngine.newObject(objectClass, scriptEngine.newVariant(QVariant::fromValue(varobj))); + } else { + if (var.type() == QVariant::Bool) + return QScriptValue(&scriptEngine, var.toBool()); + return scriptEngine.newVariant(var); + } + } + } + + return QScriptValue(); +} + +void QmlEnginePrivate::contextActivated(QmlContext *) +{ + Q_Q(QmlEngine); + QmlEngineStack *stack = engineStack(); + if(!stack) + return; + QStack<QmlEngine *> *engines = stack->engines(); + if(engines) + engines->push(q); +} + +void QmlEnginePrivate::contextDeactivated(QmlContext *) +{ + QmlEngineStack *stack = engineStack(); + if(!stack) + return; + QStack<QmlEngine *> *engines = stack->engines(); + if(engines) { + Q_ASSERT(engines->top() == q_func()); + engines->pop(); + } +} + + +//////////////////////////////////////////////////////////////////// + +bool QmlEnginePrivate::fetchCache(QmlBasicScriptNodeCache &cache, const QString &propName, QObject *obj) +{ + QmlMetaProperty prop(obj, propName); + + if(!prop.isValid()) + return false; + + capturedProperties << prop; + + if(prop.type() & QmlMetaProperty::Attached) { + + cache.object = obj; + cache.type = QmlBasicScriptNodeCache::Attached; + cache.attached = prop.d->attachedObject(); + return true; + + } else if(prop.type() & QmlMetaProperty::Property) { + + cache.object = obj; + cache.type = QmlBasicScriptNodeCache::Core; + cache.core = prop.property().idx + prop.property().mobj->propertyOffset(); + cache.coreType = prop.propertyType(); + return true; + + } else if(prop.type() & QmlMetaProperty::SignalProperty) { + + cache.object = obj; + cache.type = QmlBasicScriptNodeCache::SignalProperty; + cache.core = prop.coreIndex(); + return true; + + } else if(prop.type() & QmlMetaProperty::Signal) { + + cache.object = obj; + cache.type = QmlBasicScriptNodeCache::Signal; + cache.core = prop.coreIndex(); + return true; + + } + + return false; +} + +bool QmlEnginePrivate::loadCache(QmlBasicScriptNodeCache &cache, const QString &propName, QmlContextPrivate *context) +{ + while(context) { + if(context->variantProperties.contains(propName)) { + cache.object = 0; + cache.type = QmlBasicScriptNodeCache::Variant; + cache.context = context; + return true; + } + + if(context->properties.contains(propName)) { + cache.object = context->properties[propName]; + cache.type = QmlBasicScriptNodeCache::Explicit; + return true; + } + + foreach(QObject *obj, context->defaultObjects) { + if(fetchCache(cache, propName, obj)) + return true; + } + + if(context->parent) + context = context->parent->d_func(); + else + context = 0; + } + return false; +} + + +/*! + \class QmlEngine + \brief The QmlEngine class provides an environment for instantiating QML components. + \mainclass + + Each QML component is instantiated in a QmlContext. QmlContext's are + essential for passing data to QML components. In QML, contexts are arranged + hierarchically and this hierarchy is managed by the QmlEngine. + + Prior to creating any QML components, an application must have created a + QmlEngine to gain access to a QML context. The following example shows how + to create a simple Text item. + + \code + QmlEngine engine; + QmlComponent component("<Text text=\"Hello world!\"/>"); + QFxItem *item = qobject_cast<QFxItem *>(component.create(&engine)); + + //add item to view, etc + ... + \endcode + + In this case, the Text item will be created in the engine's + \l {QmlEngine::rootContext()}{root context}. + + \sa QmlComponent QmlContext +*/ + +/*! + Create a new QmlEngine with the given \a parent. +*/ +QmlEngine::QmlEngine(QObject *parent) +: QObject(*new QmlEnginePrivate(this), parent) +{ + Q_D(QmlEngine); + d->init(); + + qRegisterMetaType<QVariant>("QVariant"); +} + +/*! + Destroys the QmlEngine. + + Any QmlContext's created on this engine will be invalidated, but not + destroyed (unless they are parented to the QmlEngine object). +*/ +QmlEngine::~QmlEngine() +{ +} + +void QmlEngine::clearComponentCache() +{ + Q_D(QmlEngine); + d->typeManager.clearCache(); +} + +/*! + Returns the engine's root context. + + The root context is automatically created by the QmlEngine. Data that + should be available to all QML component instances instantiated by the + engine should be put in the root context. + + Additional data that should only be available to a subset of component + instances should be added to sub-contexts parented to the root context. +*/ +QmlContext *QmlEngine::rootContext() +{ + Q_D(QmlEngine); + return d->rootContext; +} + +/*! + Returns this engine's active context, or 0 if no context is active on this + engine. + + Contexts are activated and deactivated by calling QmlContext::activate() and + QmlContext::deactivate() respectively. + + Context activation holds no special semantic, other than it allows types + instantiated by QML to access "their" context without having it passed as + a parameter in their constructor, as shown below. + \code + class MyClass : ... { + ... + MyClass() { + qWarning() << "I was instantiated in this context:" + << QmlContext::activeContext(); + } + }; + \endcode +*/ +QmlContext *QmlEngine::activeContext() +{ + Q_D(QmlEngine); + if(d->currentBindContext) + return d->currentBindContext; + else + return 0; +} + +/*! + Sets the mappings from namespace URIs to URL to \a map. + + \sa nameSpacePaths +*/ +void QmlEngine::setNameSpacePaths(const QMap<QString,QString>& map) +{ + Q_D(QmlEngine); + d->nameSpacePaths = map; +} + +/*! + Adds mappings (given by \a map) from namespace URIs to URL. + + \sa nameSpacePaths +*/ +void QmlEngine::addNameSpacePaths(const QMap<QString,QString>& map) +{ + Q_D(QmlEngine); + d->nameSpacePaths.unite(map); +} + +/*! + Adds a mapping from namespace URI \a ns to URL \a path. + + \sa nameSpacePaths +*/ +void QmlEngine::addNameSpacePath(const QString& ns, const QString& path) +{ + Q_D(QmlEngine); + d->nameSpacePaths.insertMulti(ns,path); +} + +/*! + Returns the mapping from namespace URIs to URLs. + + Namespaces in QML allow types to be specified by a URI, + using standard XML namespaces: + + \code + <Item xmlns:foo="xyz://abc/def"> + <foo:Bar/> + </Item> + \endcode + + Actual QML types can be defined in URLs, in which case a mapping + may be made from URIs (such as "xyz://abc/def/Bar.qml" above, to + URLs (such as "file:///opt/abcdef/Bar.qml"): + + \code + engine->addNameSpacePath("xyz://abc/def","file:///opt/abcdef"); + \endcode + + If only a prefix of the URI is mapped, the path of the URI is + mapped similarly to the URL: + + \code + engine->addNameSpacePath("xyz://abc","file:///opt/jkl"); + \endcode + + In the above case, "xyz://abc/def/Bar.qml" would then map to + "file:///opt/jkl/def/Bar.qml". + + \sa componentUrl +*/ +QMap<QString,QString> QmlEngine::nameSpacePaths() const +{ + Q_D(const QmlEngine); + return d->nameSpacePaths; +} + +/*! + Returns the URL for the component source \a src, as mapped + by the nameSpacePaths(), resolved relative to \a baseUrl. + + \sa nameSpacePaths +*/ +QUrl QmlEngine::componentUrl(const QUrl& src, const QUrl& baseUrl) const +{ + Q_D(const QmlEngine); + + // Find the most-specific namespace matching src. + // For files, multiple paths can be given, the first found is used. + QUrl r; + QMap<QString, QString>::const_iterator i = d->nameSpacePaths.constBegin(); + QString rns=QLatin1String(":"); // ns of r, if file found, initial an imposible namespace + QString srcstring = src.toString(); + while (i != d->nameSpacePaths.constEnd()) { + QString ns = i.key(); + QString path = i.value(); + if (ns != rns) { + if (srcstring.startsWith(ns) && (ns.length()==0 || srcstring[ns.length()]==QLatin1Char('/'))) { + QString file = ns.length()==0 ? srcstring : srcstring.mid(ns.length()+1); + QUrl cr = baseUrl.resolved(QUrl(path + QLatin1String("/") + file)); + QString lf = cr.toLocalFile(); + if (lf.isEmpty() || QFile::exists(lf)) { + r = cr; + rns = ns; + } + } + } + ++i; + } + if (r.isEmpty()) + r = baseUrl.resolved(src); + return r; +} + +/*! + Sets the common QNetworkAccessManager, \a network, used by all QML elements instantiated + by this engine. + + Any previously set manager is deleted and \a network is owned by the QmlEngine. This + method should only be called before any QmlComponents are instantiated. +*/ +void QmlEngine::setNetworkAccessManager(QNetworkAccessManager *network) +{ + Q_D(QmlEngine); + delete d->networkAccessManager; + d->networkAccessManager = network; +} + +/*! + Returns the common QNetworkAccessManager used by all QML elements instantiated by + this engine. + + The default implements no caching, cookiejar, etc., just a default + QNetworkAccessManager. +*/ +QNetworkAccessManager *QmlEngine::networkAccessManager() const +{ + Q_D(const QmlEngine); + if(!d->networkAccessManager) + d->networkAccessManager = new QNetworkAccessManager; + return d->networkAccessManager; +} + +/*! \internal */ +QScriptEngine *QmlEngine::scriptEngine() +{ + Q_D(QmlEngine); + return &d->scriptEngine; +} + +/*! + Returns the currently active QmlEngine. + + The active engine is the engine associated with the last activated + QmlContext. This method is thread-safe - the "active" engine is maintained + independently for each thread. +*/ +QmlEngine *QmlEngine::activeEngine() +{ + QmlEngineStack *stack = engineStack(); + if(!stack) return 0; + + QStack<QmlEngine *> *engines = stack->engines(); + if(!engines) { + qWarning("QmlEngine::activeEngine() cannot be called before the construction of QCoreApplication"); + return 0; + } + + if(engines->isEmpty()) + return 0; + else + return engines->top(); +} + + + +QmlExpressionPrivate::QmlExpressionPrivate(QmlExpression *b) +: q(b), ctxt(0), sseData(0), proxy(0), me(0), trackChange(false) +{ +} + +QmlExpressionPrivate::QmlExpressionPrivate(QmlExpression *b, void *expr, QmlRefCount *rc) +: q(b), ctxt(0), sse((const char *)expr, rc), sseData(0), proxy(0), me(0), trackChange(true) +{ +} + +QmlExpressionPrivate::QmlExpressionPrivate(QmlExpression *b, const QString &expr, bool ssecompile) +: q(b), ctxt(0), expression(expr), sseData(0), proxy(0), me(0), trackChange(true) +{ + if(ssecompile) { +#ifdef Q_ENABLE_PERFORMANCE_LOG + QFxPerfTimer<QFxPerf::BindCompile> pt; +#endif + sse.compile(expr.toLatin1()); + } +} + +QmlExpressionPrivate::~QmlExpressionPrivate() +{ + sse.deleteScriptState(sseData); + sseData = 0; + delete proxy; +} + +/*! + Create an invalid QmlExpression. + + As the expression will not have an associated QmlContext, this will be a + null expression object and its value will always be an invalid QVariant. + */ +QmlExpression::QmlExpression() +: d(new QmlExpressionPrivate(this)) +{ +} + +/*! \internal */ +QmlExpression::QmlExpression(QmlContext *ctxt, void *expr, + QmlRefCount *rc, QObject *me) +: d(new QmlExpressionPrivate(this, expr, rc)) +{ + d->ctxt = ctxt; + d->me = me; +} + +/*! \internal */ +QmlExpression::QmlExpression(QmlContext *ctxt, const QString &expr, + QObject *me, bool ssecompile) +: d(new QmlExpressionPrivate(this, expr, ssecompile)) +{ + d->ctxt = ctxt; + d->me = me; +} + +/*! + Create a QmlExpression object. + + The \a expression ECMAScript will be executed in the \a ctxt QmlContext. + If specified, the \a scope object's properties will also be in scope during + the expression's execution. +*/ +QmlExpression::QmlExpression(QmlContext *ctxt, const QString &expression, + QObject *scope) +: d(new QmlExpressionPrivate(this, expression, true)) +{ + d->ctxt = ctxt; + d->me = scope; +} + +/*! + Destroy the QmlExpression instance. +*/ +QmlExpression::~QmlExpression() +{ + delete d; d = 0; +} + +/*! + Returns the QmlEngine this expression is associated with, or 0 if there + is no association or the QmlEngine has been destroyed. +*/ +QmlEngine *QmlExpression::engine() const +{ + return d->ctxt->engine(); +} + +/*! + Returns teh QmlContext this expression is associated with, or 0 if there + is no association or the QmlContext has been destroyed. +*/ +QmlContext *QmlExpression::context() const +{ + return d->ctxt; +} + +/*! + Returns the expression string. +*/ +QString QmlExpression::expression() const +{ + if(d->sse.isValid()) + return QLatin1String(d->sse.expression()); + else + return d->expression; +} + +/*! + Clear the expression. +*/ +void QmlExpression::clearExpression() +{ + setExpression(QString()); +} + +/*! + Set the expression to \a expression. +*/ +void QmlExpression::setExpression(const QString &expression) +{ + if(d->sseData) { + d->sse.deleteScriptState(d->sseData); + d->sseData = 0; + } + + delete d->proxy; d->proxy = 0; + + d->expression = expression; + + if(d->expression.isEmpty()) + d->sse.clear(); + else + d->sse.compile(expression.toLatin1()); +} + +/*! + Called by QmlExpression each time the expression value changes from the + last time it was evaluated. The expression must have been evaluated at + least once (by calling QmlExpression::value()) before this callback will + be made. + + The default implementation does nothing. +*/ +void QmlExpression::valueChanged() +{ +} + +Q_DECLARE_METATYPE(QList<QObject *>); + +void BindExpressionProxy::changed() +{ + e->valueChanged(); +} + +/*! + Returns the value of the expression, or an invalid QVariant if the + expression is invalid or has an error. +*/ +QVariant QmlExpression::value() +{ + if(bindValueDebug()) + qWarning() << "QmlEngine: Evaluating:" << expression(); + QVariant rv; + if(!d->ctxt || (!d->sse.isValid() && d->expression.isEmpty())) + return rv; + +#ifdef Q_ENABLE_PERFORMANCE_LOG + QFxPerfTimer<QFxPerf::BindValue> perf; +#endif + + QmlBasicScript::CacheState cacheState = QmlBasicScript::Reset; + + QmlEnginePrivate *ep = engine()->d_func(); + QmlExpression *lastCurrentExpression = ep->currentExpression; + ep->currentExpression = this; + if(d->sse.isValid()) { +#ifdef Q_ENABLE_PERFORMANCE_LOG + QFxPerfTimer<QFxPerf::BindValueSSE> perfsse; +#endif + + context()->d_func()->defaultObjects.insert(context()->d_func()->highPriorityCount, d->me); + + if(!d->sseData) + d->sseData = d->sse.newScriptState(); + rv = d->sse.run(context(), d->sseData, &cacheState); + + context()->d_func()->defaultObjects.removeAt(context()->d_func()->highPriorityCount); + } else { +#ifdef Q_ENABLE_PERFORMANCE_LOG + QFxPerfTimer<QFxPerf::BindValueQt> perfqt; +#endif + context()->d_func()->defaultObjects.insert(context()->d_func()->highPriorityCount, d->me); + + QScriptEngine *scriptEngine = engine()->scriptEngine(); + QScriptValueList oldScopeChain = scriptEngine->currentContext()->scopeChain(); + for (int i = 0; i < oldScopeChain.size(); ++i) { + scriptEngine->currentContext()->popScope(); + } + for (int i = context()->d_func()->scopeChain.size() - 1; i > -1; --i) { + scriptEngine->currentContext()->pushScope(context()->d_func()->scopeChain.at(i)); + } + QScriptValue svalue = scriptEngine->evaluate(expression()); + context()->d_func()->defaultObjects.removeAt(context()->d_func()->highPriorityCount); + if(svalue.isArray()) { + int length = svalue.property(QLatin1String("length")).toInt32(); + if(length && svalue.property(0).isObject()) { + QList<QObject *> list; + for(int ii = 0; ii < length; ++ii) { + QScriptValue arrayItem = svalue.property(ii); + QObject *d = qvariant_cast<QObject *>(arrayItem.data().toVariant()); + if(d) { + list << d; + } else { + list << 0; + } + } + rv = QVariant::fromValue(list); + } + } /*else if (svalue.isVariant()) { + rv = svalue.toVariant(); + }*/ else if (svalue.isObject()) { + QScriptValue objValue = svalue.data(); + if (objValue.isValid()) + rv = objValue.toVariant(); + } + if(rv.isNull()) { + rv = svalue.toVariant(); + } + + for (int i = 0; i < context()->d_func()->scopeChain.size(); ++i) { + scriptEngine->currentContext()->popScope(); + } + for (int i = oldScopeChain.size() - 1; i > -1; --i) { + scriptEngine->currentContext()->pushScope(oldScopeChain.at(i)); + } + } + ep->currentExpression = lastCurrentExpression; + + if(cacheState != QmlBasicScript::NoChange) { + if(cacheState != QmlBasicScript::Incremental && d->proxy) { + delete d->proxy; + d->proxy = 0; + } + + if(trackChange() && ep->capturedProperties.count()) { + if(!d->proxy) + d->proxy = new BindExpressionProxy(this); + + static int changedIndex = -1; + if(changedIndex == -1) + changedIndex = BindExpressionProxy::staticMetaObject.indexOfSlot("changed()"); + + if(bindValueDebug()) + qWarning() << " Depends on:"; + + for(int ii = 0; ii < ep->capturedProperties.count(); ++ii) { + const QmlMetaProperty &prop = + ep->capturedProperties.at(ii); + + if(prop.hasChangedNotifier()) { + prop.connectNotifier(d->proxy, changedIndex); + if(bindValueDebug()) + qWarning() << " property" + << prop.name() + << prop.object() + << prop.object()->metaObject()->superClass()->className(); + } else if(bindValueDebug()) { + qWarning() << " non-subscribable property" + << prop.name() + << prop.object() + << prop.object()->metaObject()->superClass()->className(); + } + } + } + } + ep->capturedProperties.clear(); + + if(bindValueDebug()) + qWarning() << " Result:" << rv + << "(SSE: " << d->sse.isValid() << ")"; + return rv; +} + +/*! + Returns true if the expression results in a constant value. + QmlExpression::value() must have been invoked at least once before the + return from this method is valid. + */ +bool QmlExpression::isConstant() const +{ + return d->proxy == 0; +} + +/*! + Returns true if the changes are tracked in the expression's value. +*/ +bool QmlExpression::trackChange() const +{ + return d->trackChange; +} + +/*! + Set whether changes are tracked in the expression's value to \a trackChange. + + If true, the QmlExpression will monitor properties involved in the + expression's evaluation, and call QmlExpression::valueChanged() if they have + changed. This allows an application to ensure that any value associated + with the result of the expression remains up to date. + + If false, the QmlExpression will not montitor properties involved in the + expression's evaluation, and QmlExpression::valueChanged() will never be + called. This is more efficient if an application wants a "one off" + evaluation of the expression. + + By default, trackChange is true. +*/ +void QmlExpression::setTrackChange(bool trackChange) +{ + d->trackChange = trackChange; +} + +/*! + Returns the expression's scope object, if provided, otherwise 0. + + In addition to data provided by the expression's QmlContext, the scope + object's properties are also in scope during the expression's evaluation. +*/ +QObject *QmlExpression::scopeObject() const +{ + return d->me; +} + +/*! + \class QmlExpression + \brief The QmlExpression class evaluates ECMAScript in a QML context. +*/ + +/*! + \class QmlExpressionObject + \brief The QmlExpressionObject class extends QmlExpression with signals and slots. + + To remain as lightweight as possible, QmlExpression does not inherit QObject + and consequently cannot use signals or slots. For the cases where this is + more convenient in an application, QmlExpressionObject can be used instead. + + QmlExpressionObject behaves identically to QmlExpression, except that the + QmlExpressionObject::value() method is a slot, and the + QmlExpressionObject::valueChanged() callback is a signal. +*/ +/*! + Create a QmlExpression with the specified \a parent. + + As the expression will not have an associated QmlContext, this will be a + null expression object and its value will always be an invalid QVariant. +*/ +QmlExpressionObject::QmlExpressionObject(QObject *parent) +: QObject(parent) +{ +} + +/*! + Create a QmlExpressionObject with the specified \a parent. + + The \a expression ECMAScript will be executed in the \a ctxt QmlContext. + If specified, the \a scope object's properties will also be in scope during + the expression's execution. +*/ +QmlExpressionObject::QmlExpressionObject(QmlContext *ctxt, const QString &expression, QObject *scope, QObject *parent) +: QObject(parent), QmlExpression(ctxt, expression, scope, true) +{ +} + +/*! \internal */ +QmlExpressionObject::QmlExpressionObject(QmlContext *ctxt, const QString &expr, QObject *scope, bool sse) +: QmlExpression(ctxt, expr, scope, sse) +{ +} + +/*! \internal */ +QmlExpressionObject::QmlExpressionObject(QmlContext *ctxt, void *d, QmlRefCount *rc, QObject *me) +: QmlExpression(ctxt, d, rc, me) +{ +} + +/*! + Returns the value of the expression, or an invalid QVariant if the + expression is invalid or has an error. +*/ +QVariant QmlExpressionObject::value() +{ + return QmlExpression::value(); +} + +/*! + \fn void QmlExpressionObject::valueChanged() + + Emitted each time the expression value changes from the last time it was + evaluated. The expression must have been evaluated at least once (by + calling QmlExpressionObject::value()) before this signal will be emitted. +*/ + +QmlScriptClass::QmlScriptClass(QmlEngine *bindengine) +: QScriptClass(bindengine->scriptEngine()), engine(bindengine) +{ +} + +///////////////////////////////////////////////////////////// +/* + The QmlContextScriptClass handles property access for a QmlContext + via QtScript. + */ +QmlContextScriptClass::QmlContextScriptClass(QmlEngine *bindEngine) + : QmlScriptClass(bindEngine) +{ +} + +QmlContextScriptClass::~QmlContextScriptClass() +{ +} + +QScriptClass::QueryFlags +QmlContextScriptClass::queryProperty(const QScriptValue &object, + const QScriptString &name, + QueryFlags flags, uint *id) +{ + Q_UNUSED(flags); +#ifdef Q_ENABLE_PERFORMANCE_LOG + QFxPerfTimer<QFxPerf::ContextQuery> perf; +#endif + QmlContext *bindContext = + static_cast<QmlContext*>(object.data().toQObject()); + QueryFlags rv = 0; + + QString propName = name.toString(); + +#ifdef PROPERTY_DEBUG + qWarning() << "Query Context:" << propName << bindContext; +#endif + + *id = InvalidId; + if (bindContext->d_func()->variantProperties.contains(propName)) { + rv |= HandlesReadAccess; + *id = VariantPropertyId; + } else if (bindContext->d_func()->properties.contains(propName)) { + rv |= HandlesReadAccess; + *id = ObjectListPropertyId; + } + + for(int ii = 0; !rv && ii < bindContext->d_func()->defaultObjects.count(); ++ii) { + rv = engine->d_func()->queryObject(propName, id, + bindContext->d_func()->defaultObjects.at(ii)); + if(rv) + *id |= (ii << 24); + } + + return rv; +} + +QScriptValue QmlContextScriptClass::property(const QScriptValue &object, + const QScriptString &name, + uint id) +{ +#ifdef Q_ENABLE_PERFORMANCE_LOG + QFxPerfTimer<QFxPerf::ContextProperty> perf; +#endif + QmlContext *bindContext = + static_cast<QmlContext*>(object.data().toQObject()); + +#ifdef PROPERTY_DEBUG + QString propName = name.toString(); + qWarning() << "Context Property:" << propName << bindContext; +#endif + + uint basicId = id & QmlScriptClass::ClassIdMask; + + QScriptEngine *scriptEngine = engine->scriptEngine(); + + switch (basicId) { + case VariantPropertyId: + { + QString propName = name.toString(); + QScriptValue rv = scriptEngine->newVariant(bindContext->d_func()->variantProperties[propName]); +#ifdef PROPERTY_DEBUG + qWarning() << "Context Property: Resolved property" << propName + << "to context variant property list" << bindContext <<". Value:" << rv.toVariant(); +#endif + return rv; + } + case ObjectListPropertyId: + { + QString propName = name.toString(); + QObject *o = bindContext->d_func()->properties[propName]; + QScriptValue rv = scriptEngine->newObject(engine->d_func()->objectClass, scriptEngine->newVariant(QVariant::fromValue(o))); +#ifdef PROPERTY_DEBUG + qWarning() << "Context Property: Resolved property" << propName + << "to context object property list" << bindContext <<". Value:" << rv.toVariant(); +#endif + return rv; + } + default: + { + int objId = (id & ClassIdSelectorMask) >> 24; + QObject *obj = bindContext->d_func()->defaultObjects.at(objId); + QScriptValue rv = engine->d_func()->propertyObject(name, obj, + id & ~QmlScriptClass::ClassIdSelectorMask); + if(rv.isValid()) { +#ifdef PROPERTY_DEBUG + qWarning() << "~Property: Resolved property" << propName + << "to context default object" << bindContext << obj <<". Value:" << rv.toVariant(); +#endif + return rv; + } + break; + } + } + + return QScriptValue(); +} + +void QmlContextScriptClass::setProperty(QScriptValue &object, + const QScriptString &name, + uint id, + const QScriptValue &value) +{ + Q_UNUSED(name); + +#ifdef Q_ENABLE_PERFORMANCE_LOG + QFxPerfTimer<QFxPerf::ObjectSetProperty> perf; +#endif + QmlContext *bindContext = + static_cast<QmlContext*>(object.data().toQObject()); + +#ifdef PROPERTY_DEBUG + QString propName = name.toString(); + qWarning() << "Set QmlObject Property" << name.toString() << value.toVariant(); +#endif + + int objIdx = (id & QmlScriptClass::ClassIdSelectorMask) >> 24; + QObject *obj = bindContext->d_func()->defaultObjects.at(objIdx); + + QScriptEngine *scriptEngine = engine->scriptEngine(); + QScriptValue oldact = scriptEngine->currentContext()->activationObject(); + scriptEngine->currentContext()->setActivationObject(scriptEngine->globalObject()); + + QmlMetaProperty prop; + prop.restore(id, obj); + + QVariant v; + QObject *data = value.data().toQObject(); + if (data) { + v = QVariant::fromValue(data); + } else { + v = value.toVariant(); + } + prop.write(v); + + scriptEngine->currentContext()->setActivationObject(oldact); +} + +///////////////////////////////////////////////////////////// +/* + The QmlObjectScriptClass handles property access for QObjects + via QtScript. + */ +QmlObjectScriptClass::QmlObjectScriptClass(QmlEngine *bindEngine) + : QmlScriptClass(bindEngine) +{ + engine = bindEngine; +} + +QmlObjectScriptClass::~QmlObjectScriptClass() +{ +} + +QScriptClass::QueryFlags QmlObjectScriptClass::queryProperty(const QScriptValue &object, + const QScriptString &name, + QueryFlags flags, uint *id) +{ + Q_UNUSED(flags); +#ifdef Q_ENABLE_PERFORMANCE_LOG + QFxPerfTimer<QFxPerf::ObjectQuery> perf; +#endif + QObject *obj = object.data().toQObject(); + QueryFlags rv = 0; + QString propName = name.toString(); + +#ifdef PROPERTY_DEBUG + qWarning() << "Query QmlObject:" << propName << obj; +#endif + + if (obj) + rv = engine->d_func()->queryObject(propName, id, obj); + + return rv; +} + +QScriptValue QmlObjectScriptClass::property(const QScriptValue &object, + const QScriptString &name, + uint id) +{ +#ifdef Q_ENABLE_PERFORMANCE_LOG + QFxPerfTimer<QFxPerf::ObjectProperty> perf; +#endif + QObject *obj = object.data().toQObject(); + +#ifdef PROPERTY_DEBUG + QString propName = name.toString(); + qWarning() << "QmlObject Property:" << propName << obj; +#endif + + QScriptValue rv = engine->d_func()->propertyObject(name, obj, id); + if(rv.isValid()) { +#ifdef PROPERTY_DEBUG + qWarning() << "~Property: Resolved property" << propName + << "to object" << obj <<". Value:" << rv.toVariant(); +#endif + return rv; + } + + return QScriptValue(); +} + +void QmlObjectScriptClass::setProperty(QScriptValue &object, + const QScriptString &name, + uint id, + const QScriptValue &value) +{ + Q_UNUSED(name); + +#ifdef Q_ENABLE_PERFORMANCE_LOG + QFxPerfTimer<QFxPerf::ObjectSetProperty> perf; +#endif + QObject *obj = object.data().toQObject(); + +#ifdef PROPERTY_DEBUG + QString propName = name.toString(); + qWarning() << "Set QmlObject Property" << name.toString() << value.toVariant(); +#endif + + QScriptEngine *scriptEngine = engine->scriptEngine(); + QScriptValue oldact = scriptEngine->currentContext()->activationObject(); + scriptEngine->currentContext()->setActivationObject(scriptEngine->globalObject()); + + QmlMetaProperty prop; + prop.restore(id, obj); + + QVariant v; + QObject *data = value.data().toQObject(); + if (data) { + v = QVariant::fromValue(data); + } else { + v = value.toVariant(); + } + prop.write(v); + + scriptEngine->currentContext()->setActivationObject(oldact); +} + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlengine.h b/src/declarative/qml/qmlengine.h new file mode 100644 index 0000000..086595a --- /dev/null +++ b/src/declarative/qml/qmlengine.h @@ -0,0 +1,107 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLENGINE_H +#define QMLENGINE_H + +#include <QtCore/qobject.h> +#include <QtCore/qmap.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +class QmlComponent; +class QmlEnginePrivate; +class QmlExpression; +class QmlContext; +class QUrl; +class QScriptEngine; +class QNetworkAccessManager; +class Q_DECLARATIVE_EXPORT QmlEngine : public QObject +{ + Q_OBJECT +public: + QmlEngine(QObject *p = 0); + virtual ~QmlEngine(); + + static QmlEngine *activeEngine(); + + QmlContext *rootContext(); + QmlContext *activeContext(); + + void clearComponentCache(); + + void setNameSpacePaths(const QMap<QString,QString>& map); + void addNameSpacePaths(const QMap<QString,QString>& map); + void addNameSpacePath(const QString&,const QString&); + QMap<QString,QString> nameSpacePaths() const; + QUrl componentUrl(const QUrl& src, const QUrl& baseUrl) const; + + void setNetworkAccessManager(QNetworkAccessManager *); + QNetworkAccessManager *networkAccessManager() const; + +private: + // LK: move to the private class + QScriptEngine *scriptEngine(); + friend class QFxItem; // XXX + friend class QmlScriptPrivate; + friend class QmlCompositeTypeManager; + friend class QmlCompiler; + friend class QmlScriptClass; + friend class QmlContext; + friend class QmlContextPrivate; + friend class QmlExpression; + friend class QmlBasicScript; + friend class QmlVME; + friend class QmlComponent; + friend class QmlContextScriptClass; //### + friend class QmlObjectScriptClass; //### + Q_DECLARE_PRIVATE(QmlEngine) +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QMLENGINE_H diff --git a/src/declarative/qml/qmlengine_p.h b/src/declarative/qml/qmlengine_p.h new file mode 100644 index 0000000..b72c680 --- /dev/null +++ b/src/declarative/qml/qmlengine_p.h @@ -0,0 +1,215 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLENGINE_P_H +#define QMLENGINE_P_H + +#include <QScriptClass> +#include <QScriptValue> +#include <QScriptString> +#include <QtCore/qstring.h> +#include <QtCore/qlist.h> +#include <QtCore/qpair.h> +#include <QtCore/qstack.h> +#include <private/qobject_p.h> +#include <private/qmlclassfactory_p.h> +#include <private/qmlcompositetypemanager_p.h> +#include <qml.h> +#include <qmlbasicscript.h> +#include <qmlcontext.h> +#include <qmlengine.h> +#include <qmlexpression.h> +#include <QtScript/qscriptengine.h> + +QT_BEGIN_NAMESPACE +class QmlContext; +class QmlEngine; +class QmlContextPrivate; +class QmlExpression; +class QmlBasicScriptNodeCache; +class QmlContextScriptClass; +class QmlObjectScriptClass; +class QScriptEngineDebugger; +class QNetworkReply; +class QNetworkAccessManager; + +class QmlEnginePrivate : public QObjectPrivate +{ + Q_DECLARE_PUBLIC(QmlEngine) +public: + QmlEnginePrivate(QmlEngine *); + ~QmlEnginePrivate(); + + void init(); + + void contextActivated(QmlContext *); + void contextDeactivated(QmlContext *); + + bool fetchCache(QmlBasicScriptNodeCache &cache, const QString &propName, QObject *); + bool loadCache(QmlBasicScriptNodeCache &cache, const QString &propName, QmlContextPrivate *context); + + QScriptClass::QueryFlags queryObject(const QString &name, uint *id, QObject *); + QScriptValue propertyObject(const QScriptString &propName, QObject *, uint id = 0); + + QList<QmlMetaProperty> capturedProperties; + + QmlContext *rootContext; + QmlContext *currentBindContext; + QmlExpression *currentExpression; + QmlEngine *q; +#ifdef QT_SCRIPTTOOLS_LIB + QScriptEngineDebugger *debugger; +#endif + + QmlContextScriptClass *contextClass; + QmlObjectScriptClass *objectClass; + + QmlContext *setCurrentBindContext(QmlContext *); + QStack<QmlContext *> activeContexts; + + QScriptEngine scriptEngine; + + QList<QmlBindableValue *> currentBindValues; + QList<QmlParserStatus *> currentParserStatus; + QmlComponent *rootComponent; + mutable QNetworkAccessManager *networkAccessManager; + + QmlCompositeTypeManager typeManager; + QMap<QString,QString> nameSpacePaths; +}; + + +class BindExpressionProxy : public QObject +{ +Q_OBJECT +public: + BindExpressionProxy(QmlExpression *be) + :e(be) + { + } + +private: + QmlExpression *e; + +private Q_SLOTS: + void changed(); +}; + +class QmlScriptClass : public QScriptClass +{ +public: + enum ClassId + { + InvalidId = -1, + + ObjectListPropertyId = 0xC0000000, + FunctionId = 0x80000000, + VariantPropertyId = 0x40000000, + PropertyId = 0x00000000, + + ClassIdMask = 0xC0000000, + + ClassIdSelectorMask = 0x3F000000, + }; + + QmlScriptClass(QmlEngine *); + +protected: + QmlEngine *engine; +}; + +class QmlContextScriptClass : public QmlScriptClass +{ +public: + QmlContextScriptClass(QmlEngine *); + ~QmlContextScriptClass(); + + virtual QueryFlags queryProperty(const QScriptValue &object, + const QScriptString &name, + QueryFlags flags, uint *id); + virtual QScriptValue property(const QScriptValue &object, + const QScriptString &name, + uint id); + virtual void setProperty(QScriptValue &object, + const QScriptString &name, + uint id, + const QScriptValue &value); +}; + +class QmlObjectScriptClass : public QmlScriptClass +{ +public: + QmlObjectScriptClass(QmlEngine *); + ~QmlObjectScriptClass(); + + virtual QueryFlags queryProperty(const QScriptValue &object, + const QScriptString &name, + QueryFlags flags, uint *id); + virtual QScriptValue property(const QScriptValue &object, + const QScriptString &name, + uint id); + virtual void setProperty(QScriptValue &object, + const QScriptString &name, + uint id, + const QScriptValue &value); +}; + +class QmlExpressionPrivate +{ +public: + QmlExpressionPrivate(QmlExpression *); + QmlExpressionPrivate(QmlExpression *, const QString &expr, bool); + QmlExpressionPrivate(QmlExpression *, void *expr, QmlRefCount *rc); + ~QmlExpressionPrivate(); + + QmlExpression *q; + QmlContext *ctxt; + QString expression; + QmlBasicScript sse; + void *sseData; + BindExpressionProxy *proxy; + QObject *me; + bool trackChange; +}; +QT_END_NAMESPACE + +#endif // QMLENGINE_P_H + diff --git a/src/declarative/qml/qmlexpression.h b/src/declarative/qml/qmlexpression.h new file mode 100644 index 0000000..4f9502b --- /dev/null +++ b/src/declarative/qml/qmlexpression.h @@ -0,0 +1,115 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLEXPRESSION_H +#define QMLEXPRESSION_H + +#include <QtCore/qobject.h> +#include <QtCore/qvariant.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +class QString; +class QmlRefCount; +class QmlEngine; +class QmlContext; +class QmlExpressionPrivate; +class QmlBasicScript; +class Q_DECLARATIVE_EXPORT QmlExpression +{ +public: + QmlExpression(); + QmlExpression(QmlContext *, const QString &, QObject *); + QmlExpression(QmlContext *, const QString &, QObject *, bool); + QmlExpression(QmlContext *, void *, QmlRefCount *rc, QObject *me); + virtual ~QmlExpression(); + + QmlEngine *engine() const; + QmlContext *context() const; + + QString expression() const; + void clearExpression(); + virtual void setExpression(const QString &); + QVariant value(); + bool isConstant() const; + + bool trackChange() const; + void setTrackChange(bool); + + QObject *scopeObject() const; + +protected: + virtual void valueChanged(); + +private: + friend class BindExpressionProxy; + QmlExpressionPrivate *d; +}; + +// LK: can't we merge with QmlExpression???? +class Q_DECLARATIVE_EXPORT QmlExpressionObject : public QObject, + public QmlExpression +{ + Q_OBJECT +public: + QmlExpressionObject(QObject *parent = 0); + QmlExpressionObject(QmlContext *, const QString &, QObject *scope, QObject *parent = 0); + QmlExpressionObject(QmlContext *, const QString &, QObject *scope, bool); + QmlExpressionObject(QmlContext *, void *, QmlRefCount *, QObject *); + +public Q_SLOTS: + QVariant value(); + +Q_SIGNALS: + void valueChanged(); +}; + + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QMLEXPRESSION_H + diff --git a/src/declarative/qml/qmlinfo.cpp b/src/declarative/qml/qmlinfo.cpp new file mode 100644 index 0000000..dc7f44c --- /dev/null +++ b/src/declarative/qml/qmlinfo.cpp @@ -0,0 +1,97 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmlinfo.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QmlInfo + \brief The QmlInfo class prints warnings messages that include the file and line number for QML types. + + When QML types display warning messages, it improves tracibility if they include the + QML file and line number on which the particular instance was instantiated. + + QmlInfo statements work just like regular Qt qDebug() statements. To include the file + and line number, an object must be passed. If the file and line number is not available + for that instance (either it was not instantiated by the QML engine or location + information is disabled), "unknown location" will be used instead. + + For example, + + \code + qmlInfo(this) << "component property is a write-once property"; + \endcode + + prints + + \code + QML ComponentInstance (unknown location): component property is a write-once property + \endcode +*/ + +/*! + Construct a QmlInfo, using \a object for file and line number information. +*/ +QmlInfo::QmlInfo(QObject *object) +: QDebug(QtWarningMsg) +{ + *this << "QML"; + if(object) + *this << object->metaObject()->className(); + *this << "(unknown location):"; +} + +/*! + \internal +*/ +QmlInfo::~QmlInfo() +{ +} + +/*! + \fn QmlInfo qmlInfo(QObject *me) + \internal + + XXX - how do we document these? +*/ + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlinfo.h b/src/declarative/qml/qmlinfo.h new file mode 100644 index 0000000..da8144c --- /dev/null +++ b/src/declarative/qml/qmlinfo.h @@ -0,0 +1,69 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLINFO_H +#define QMLINFO_H + +#include <QtCore/qdebug.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +class Q_DECLARATIVE_EXPORT QmlInfo : public QDebug +{ +public: + QmlInfo(QObject *); + ~QmlInfo(); +}; + +Q_DECLARATIVE_EXPORT inline QmlInfo qmlInfo(QObject *me) +{ + return QmlInfo(me); +} + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QMLINFO_H diff --git a/src/declarative/qml/qmlinstruction.cpp b/src/declarative/qml/qmlinstruction.cpp new file mode 100644 index 0000000..9938022 --- /dev/null +++ b/src/declarative/qml/qmlinstruction.cpp @@ -0,0 +1,214 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "private/qmlinstruction_p.h" +#include "private/qmlcompiledcomponent_p.h" +#include <QDebug> + +QT_BEGIN_NAMESPACE +void QmlCompiledComponent::dump(QmlInstruction *instr, int idx) +{ + QByteArray lineNumber = QByteArray::number(instr->line); + if(instr->line == (unsigned short)-1) + lineNumber = "NA"; + const char *line = lineNumber.constData(); + + switch(instr->type) { + case QmlInstruction::Init: + qWarning() << idx << "\t" << line << "\t" << "INIT\t\t\t" << instr->init.dataSize; + break; + case QmlInstruction::CreateObject: + qWarning() << idx << "\t" << line << "\t" << "CREATE\t\t\t" << instr->create.type << "\t\t\t" << types.at(instr->create.type).className; + break; + case QmlInstruction::CreateCustomObject: + qWarning() << idx << "\t" << line << "\t" << "CREATE_CUSTOM\t\t" << instr->createCustom.type << "\t" << instr->createCustom.data << "\t\t" << types.at(instr->create.type).className; + break; + case QmlInstruction::SetId: + qWarning() << idx << "\t" << line << "\t" << "SETID\t\t\t" << instr->setId.value << "\t" << instr->setId.save << "\t\t" << primitives.at(instr->setId.value); + break; + case QmlInstruction::SetDefault: + qWarning() << idx << "\t" << line << "\t" << "SET_DEFAULT"; + break; + case QmlInstruction::CreateComponent: + qWarning() << idx << "\t" << line << "\t" << "CREATE_COMPONENT\t" << instr->createComponent.count; + break; + case QmlInstruction::StoreMetaObject: + qWarning() << idx << "\t" << line << "\t" << "STORE_META\t\t" << instr->storeMeta.data; + break; + case QmlInstruction::StoreReal: + qWarning() << idx << "\t" << line << "\t" << "STORE_REAL\t\t" << instr->storeReal.propertyIndex << "\t" << instr->storeReal.value; + break; + case QmlInstruction::StoreInteger: + qWarning() << idx << "\t" << line << "\t" << "STORE_INTEGER\t\t" << instr->storeInteger.propertyIndex << "\t" << instr->storeInteger.value; + break; + case QmlInstruction::StoreBool: + qWarning() << idx << "\t" << line << "\t" << "STORE_BOOL\t\t" << instr->storeBool.propertyIndex << "\t" << instr->storeBool.value; + break; + case QmlInstruction::StoreString: + qWarning() << idx << "\t" << line << "\t" << "STORE_STRING\t\t" << instr->storeString.propertyIndex << "\t" << instr->storeString.value << "\t\t" << primitives.at(instr->storeString.value); + break; + case QmlInstruction::StoreColor: + qWarning() << idx << "\t" << line << "\t" << "STORE_COLOR\t\t" << instr->storeColor.propertyIndex << "\t" << QString::number(instr->storeColor.value, 16); + break; + case QmlInstruction::StoreDate: + qWarning() << idx << "\t" << line << "\t" << "STORE_DATE\t\t" << instr->storeDate.propertyIndex << "\t" << instr->storeDate.value; + break; + case QmlInstruction::StoreTime: + qWarning() << idx << "\t" << line << "\t" << "STORE_TIME\t\t" << instr->storeTime.propertyIndex << "\t" << instr->storeTime.valueIndex; + break; + case QmlInstruction::StoreDateTime: + qWarning() << idx << "\t" << line << "\t" << "STORE_DATETIME\t\t" << instr->storeDateTime.propertyIndex << "\t" << instr->storeDateTime.valueIndex; + break; + case QmlInstruction::StorePoint: + qWarning() << idx << "\t" << line << "\t" << "STORE_POINT\t\t" << instr->storeRealPair.propertyIndex << "\t" << instr->storeRealPair.valueIndex; + break; + case QmlInstruction::StorePointF: + qWarning() << idx << "\t" << line << "\t" << "STORE_POINTF\t\t" << instr->storeRealPair.propertyIndex << "\t" << instr->storeRealPair.valueIndex; + break; + case QmlInstruction::StoreSize: + qWarning() << idx << "\t" << line << "\t" << "STORE_SIZE\t\t" << instr->storeRealPair.propertyIndex << "\t" << instr->storeRealPair.valueIndex; + break; + case QmlInstruction::StoreSizeF: + qWarning() << idx << "\t" << line << "\t" << "STORE_SIZEF\t\t" << instr->storeRealPair.propertyIndex << "\t" << instr->storeRealPair.valueIndex; + break; + case QmlInstruction::StoreRect: + qWarning() << idx << "\t" << line << "\t" << "STORE_RECT\t\t" << instr->storeRect.propertyIndex << "\t" << instr->storeRect.valueIndex; + break; + case QmlInstruction::StoreRectF: + qWarning() << idx << "\t" << line << "\t" << "STORE_RECTF\t\t" << instr->storeRect.propertyIndex << "\t" << instr->storeRect.valueIndex; + break; + case QmlInstruction::StoreVariant: + qWarning() << idx << "\t" << line << "\t" << "STORE_VARIANT\t\t" << instr->storeString.propertyIndex << "\t" << instr->storeString.value << "\t\t" << primitives.at(instr->storeString.value); + break; + case QmlInstruction::StoreObject: + qWarning() << idx << "\t" << line << "\t" << "STORE_OBJECT\t\t" << instr->storeObject.propertyIndex << "\t" << instr->storeObject.cast; + break; + case QmlInstruction::AssignCustomType: + qWarning() << idx << "\t" << line << "\t" << "ASSIGN_CUSTOMTYPE\t\t" << instr->assignCustomType.propertyIndex << "\t" << instr->assignCustomType.valueIndex; + break; + case QmlInstruction::StoreSignal: + qWarning() << idx << "\t" << line << "\t" << "STORE_SIGNAL\t\t" << instr->storeSignal.signalIndex << "\t" << instr->storeSignal.value << "\t\t" << primitives.at(instr->storeSignal.value); + break; + case QmlInstruction::AssignConstant: + qWarning() << idx << "\t" << line << "\t" << "ASSIGN_CONSTANT\t" << instr->assignConstant.property << "\t" << instr->assignConstant.constant << "\t\t" << datas.at(instr->assignConstant.property) << primitives.at(instr->assignConstant.constant); + break; + case QmlInstruction::AssignSignal: + qWarning() << idx << "\t" << line << "\t" << "ASSIGN_SIGNAL\t\t" << instr->assignSignal.signal << "\t" << instr->assignSignal.value << "\t\t" << datas.at(instr->assignSignal.signal) << primitives.at(instr->assignSignal.value); + break; + case QmlInstruction::AssignSignalObject: + qWarning() << idx << "\t" << line << "\t" << "ASSIGN_SIGNAL_OBJECT\t" << instr->assignSignalObject.signal << "\t\t\t" << datas.at(instr->assignSignalObject.signal); + break; + case QmlInstruction::AssignBinding: + qWarning() << idx << "\t" << line << "\t" << "ASSIGN_BINDING\t\t" << instr->assignBinding.property << "\t" << instr->assignBinding.value << "\t\t" << instr->assignBinding.context << datas.at(instr->assignBinding.property) << primitives.at(instr->assignBinding.value); + break; + case QmlInstruction::AssignCompiledBinding: + qWarning() << idx << "\t" << line << "\t" << "ASSIGN_COMPILED_BINDING\t" << instr->assignBinding.property << "\t" << instr->assignBinding.value << "\t\t" << instr->assignBinding.context << datas.at(instr->assignBinding.property); + break; + case QmlInstruction::AssignValueSource: + qWarning() << idx << "\t" << line << "\t" << "ASSIGN_VALUE_SOURCE\t" << instr->assignValueSource.property << "\t\t\t" << datas.at(instr->assignValueSource.property); + break; + case QmlInstruction::StoreBinding: + qWarning() << idx << "\t" << line << "\t" << "STORE_BINDING\t\t" << instr->assignBinding.property << "\t" << instr->assignBinding.value << "\t\t" << instr->assignBinding.context << primitives.at(instr->assignBinding.value); + break; + case QmlInstruction::StoreCompiledBinding: + qWarning() << idx << "\t" << line << "\t" << "STORE_COMPILED_BINDING\t" << instr->assignBinding.property << "\t" << instr->assignBinding.value << "\t\t" << instr->assignBinding.context; + break; + case QmlInstruction::StoreValueSource: + qWarning() << idx << "\t" << line << "\t" << "STORE_VALUE_SOURCE\t" << instr->assignValueSource.property; + break; + case QmlInstruction::TryBeginObject: + qWarning() << idx << "\t" << line << "\t" << "TRY_BEGIN"; + break; + case QmlInstruction::BeginObject: + qWarning() << idx << "\t" << line << "\t" << "BEGIN\t\t\t" << instr->begin.castValue; + break; + case QmlInstruction::TryCompleteObject: + qWarning() << idx << "\t" << line << "\t" << "TRY_COMPLETE"; + break; + case QmlInstruction::CompleteObject: + qWarning() << idx << "\t" << line << "\t" << "COMPLETE\t\t" << instr->complete.castValue; + break; + case QmlInstruction::AssignObject: + qWarning() << idx << "\t" << line << "\t" << "ASSIGN_OBJECT\t\t" << instr->assignObject.property << "\t" << instr->assignObject.castValue << "\t\t" << ((instr->assignObject.property == -1)?QByteArray("default"):datas.at(instr->assignObject.property)); + break; + case QmlInstruction::AssignObjectList: + qWarning() << idx << "\t" << line << "\t" << "ASSIGN_OBJECT_LIST\t" << instr->assignObject.property << "\t" << instr->assignObject.castValue << "\t\t" << ((instr->assignObject.property == -1)?QByteArray("default"):datas.at(instr->assignObject.property)); + break; + case QmlInstruction::FetchAttached: + qWarning() << idx << "\t" << line << "\t" << "FETCH_ATTACHED\t\t" << instr->fetchAttached.idx << "\t\t\t" << primitives.at(instr->fetchAttached.idx); + break; + case QmlInstruction::FetchQmlList: + qWarning() << idx << "\t" << line << "\t" << "FETCH_QMLLIST\t\t" << instr->fetchQmlList.property << "\t" << instr->fetchQmlList.type; + break; + case QmlInstruction::FetchQList: + qWarning() << idx << "\t" << line << "\t" << "FETCH_QLIST\t\t" << instr->fetch.property; + break; + case QmlInstruction::FetchObject: + qWarning() << idx << "\t" << line << "\t" << "FETCH\t\t\t" << instr->fetch.property; + break; + case QmlInstruction::ResolveFetchObject: + qWarning() << idx << "\t" << line << "\t" << "RESOLVE_FETCH\t\t" << instr->fetch.property << "\t\t\t" << datas.at(instr->fetch.property); + break; + case QmlInstruction::PopFetchedObject: + qWarning() << idx << "\t" << line << "\t" << "POP"; + break; + case QmlInstruction::PopQList: + qWarning() << idx << "\t" << line << "\t" << "POP_QLIST"; + break; + case QmlInstruction::NoOp: + qWarning() << idx << "\t" << line << "\t" << "NOOP"; + break; + case QmlInstruction::PushProperty: + qWarning() << idx << "\t" << line << "\t" << "PUSH_PROPERTY" << "\t\t" << instr->pushProperty.property; + break; + case QmlInstruction::AssignStackObject: + qWarning() << idx << "\t" << line << "\t" << "ASSIGN_STACK_OBJ" << "\t" << instr->assignStackObject.property << "\t" << instr->assignStackObject.object; + break; + case QmlInstruction::StoreStackObject: + qWarning() << idx << "\t" << line << "\t" << "STORE_STACK_OBJ" << "\t" << instr->assignStackObject.property << "\t" << instr->assignStackObject.object; + break; + default: + qWarning() << idx << "\t" << line << "\t" << "XXX UNKOWN INSTRUCTION"; + break; + } +} + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlinstruction_p.h b/src/declarative/qml/qmlinstruction_p.h new file mode 100644 index 0000000..40a0b84 --- /dev/null +++ b/src/declarative/qml/qmlinstruction_p.h @@ -0,0 +1,299 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLINSTRUCTION_P_H +#define QMLINSTRUCTION_P_H + +#include <qfxglobal.h> + + +QT_BEGIN_NAMESPACE +class QmlCompiledComponent; +class Q_DECLARATIVE_EXPORT QmlInstruction +{ +public: + enum Type { + // + // Object Creation + // + // CreateObject - Create a new object instance and push it on the + // object stack + // SetId - Set the id of the object on the top of the object stack + // SetDefault - Sets the instance on the top of the object stack to + // be the context's default object. + // StoreMetaObject - Assign the dynamic metaobject to object on the + // top of the stack. + Init, /* init */ + CreateObject, /* create */ + CreateCustomObject, /* createCustom */ + SetId, /* setId */ + SetDefault, + CreateComponent, /* createComponent */ + StoreMetaObject, /* storeMeta */ + + // + // Precomputed single assignment + // + // StoreReal - Store a qreal in a core property + // StoreInteger - Store a int or uint in a core property + // StoreBool - Store a bool in a core property + // StoreString - Store a QString in a core property + // StoreColor - Store a QColor in a core property + // StoreDate - Store a QDate in a core property + // StoreTime - Store a QTime in a core property + // StoreDateTime - Store a QDateTime in a core property + // StoreVariant - Store a QVariant in a core property + // StoreObject - Pop the object on the top of the object stack and + // store it in a core property + StoreReal, /* storeReal */ + StoreInstructionsStart = StoreReal, + StoreInteger, /* storeInteger */ + StoreBool, /* storeBool */ + StoreString, /* storeString */ + StoreColor, /* storeColor */ + StoreDate, /* storeDate */ + StoreTime, /* storeTime */ + StoreDateTime, /* storeDateTime */ + StorePoint, /* storeRealPair */ + StorePointF, /* storeRealPair */ + StoreSize, /* storeRealPair */ + StoreSizeF, /* storeRealPair */ + StoreRect, /* storeRect */ + StoreRectF, /* storeRect */ + StoreVariant, /* storeString */ + StoreObject, /* storeObject */ + StoreInstructionsEnd = StoreObject, + + StoreSignal, /* storeSignal */ + + StoreObjectQmlList, + + // XXX need to handle storing objects in variants + + // + // Unresolved single assignment + // + // AssignConstant - Store a value in a property. Will resolve into + // a Store* instruction. + // AssignSignal - Set a signal handler on the property. Will resolve + // into a Store*Signal instruction. + AssignConstant, /* assignConstant */ + AssignSignal, /* assignSignal */ + AssignSignalObject, /* assignSignalObject */ + AssignCustomType, /* assignCustomType */ + + AssignBinding, /* assignBinding */ + AssignCompiledBinding, /* assignBinding */ + AssignValueSource, /* assignValueSource */ + StoreBinding, /* assignBinding */ + StoreCompiledBinding, /* assignBinding */ + StoreValueSource, /* assignValueSource */ + + TryBeginObject, + BeginObject, /* begin */ + TryCompleteObject, + CompleteObject, /* complete */ + + AssignObject, /* assignObject */ + AssignObjectList, /* assignObject */ + + FetchAttached, /* fetchAttached */ + FetchQmlList, /* fetchQmlList */ + FetchQList, /* fetch */ + FetchObject, /* fetch */ + ResolveFetchObject, /* fetch */ + + // + // Stack manipulation + // + // PopFetchedObject - Remove an object from the object stack + // PopQList - Remove a list from the list stack + PopFetchedObject, + PopQList, + + // + // Expression optimizations + // + // PushProperty - Save the property for later use + // AssignStackObject - Assign the stack object + // StoreStackObject - Assign the stack object (no checks) + PushProperty, /* pushProperty */ + AssignStackObject, /* assignStackObject */ + StoreStackObject, /* assignStackObject */ + + + // + // Miscellaneous + // + // NoOp - Do nothing + NoOp + }; + Type type; + unsigned short line; + union { + struct { + int dataSize; + } init; + struct { + int type; + } create; + struct { + int data; + } storeMeta; + struct { + int type; + int data; + } createCustom; + struct { + int value; + int save; + } setId; + struct { + int property; + int constant; + } assignConstant; + struct { + int property; + int castValue; + } assignObject; + struct { + int property; + } assignValueSource; + struct { + int property; + int value; + short context; + short category; + } assignBinding; + struct { + int property; + bool isObject; + } fetch; + struct { + int property; + int type; + } fetchQmlList; + struct { + int castValue; + } complete; + struct { + int castValue; + } begin; + struct { + int propertyIndex; + float value; + } storeReal; + struct { + int propertyIndex; + int value; + } storeInteger; + struct { + int propertyIndex; + bool value; + } storeBool; + struct { + int propertyIndex; + int value; + } storeString; + struct { + int propertyIndex; + unsigned int value; + } storeColor; + struct { + int propertyIndex; + int value; + } storeDate; + struct { + int propertyIndex; + int valueIndex; + } storeTime; + struct { + int propertyIndex; + int valueIndex; + } storeDateTime; + struct { + int propertyIndex; + int valueIndex; + } storeRealPair; + struct { + int propertyIndex; + int valueIndex; + } storeRect; + struct { + int propertyIndex; + int cast; + } storeObject; + struct { + int propertyIndex; + int valueIndex; + } assignCustomType; + struct { + int signalIndex; + int value; + } storeSignal; + struct { + int signal; + int value; + } assignSignal; + struct { + int signal; + } assignSignalObject; + struct { + int count; + } createComponent; + struct { + int idx; + } fetchAttached; + struct { + int property; + } pushProperty; + struct { + int property; + int object; + } assignStackObject; + }; + + void dump(QmlCompiledComponent *); +}; + +#endif // QMLINSTRUCTION_P_H + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qmllist.h b/src/declarative/qml/qmllist.h new file mode 100644 index 0000000..3a1e665 --- /dev/null +++ b/src/declarative/qml/qmllist.h @@ -0,0 +1,125 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLLIST_H +#define QMLLIST_H + +#include <QtDeclarative/qmlprivate.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +template<typename T> +class QmlList : private QmlPrivate::ListInterface +{ +public: + virtual void append(T) = 0; + virtual void insert(int, T) = 0; + virtual T at(int) const = 0; + virtual void clear() = 0; + QmlList<T> &operator<<(T t) { append(t); return *this; } + +protected: + virtual int type() const { return qMetaTypeId<T>(); } + virtual void append(void *d) { const T &v = *(T *)d; append(v); } + virtual void insert(int i, void *d) { const T &v = *(T *)d; insert(i, v); } + virtual void at(int i, void *p) const { const T &v = at(i); *((T*)p) = v; } +}; + +template<typename T> +class QmlConcreteList : public QList<T>, public QmlList<T> +{ +public: + virtual void append(T v) { QList<T>::append(v); } + virtual void insert(int i, T v) { QList<T>::insert(i, v); } + virtual void clear() { QList<T>::clear(); } + virtual T at(int i) const { return QList<T>::at(i); } + virtual void removeAt(int i) { QList<T>::removeAt(i); } + virtual int count() const { return QList<T>::count(); } +}; + +#define QML_DECLARE_LIST_PROXY(ClassName, ListType, ListName) \ +class Qml_ProxyList_ ##ListName : public QmlList<ListType> \ +{ \ + public: \ + virtual void removeAt(int idx) \ + { \ + ClassName *p = (ClassName *)((char *)this + ((char *)(ClassName *)(0x10000000) - (char *)&((ClassName *)(0x10000000))->ListName)); \ + p->ListName ## _removeAt(idx); \ + } \ + virtual int count() const \ + { \ + ClassName *p = (ClassName *)((char *)this + ((char *)(ClassName *)(0x10000000) - (char *)&((ClassName *)(0x10000000))->ListName)); \ + return p->ListName ## _count(); \ + } \ + virtual void append(ListType v) \ + { \ + ClassName *p = (ClassName *)((char *)this + ((char *)(ClassName *)(0x10000000) - (char *)&((ClassName *)(0x10000000))->ListName)); \ + p->ListName ## _append(v); \ + } \ + virtual void insert(int idx, ListType v) \ + { \ + ClassName *p = (ClassName *)((char *)this + ((char *)(ClassName *)(0x10000000) - (char *)&((ClassName *)(0x10000000))->ListName)); \ + p->ListName ## _insert(idx, v); \ + } \ + virtual ListType at(int idx) const \ + { \ + ClassName *p = (ClassName *)((char *)this + ((char *)(ClassName *)(0x10000000) - (char *)&((ClassName *)(0x10000000))->ListName)); \ + return p->ListName ## _at(idx); \ + } \ + virtual void clear() \ + { \ + ClassName *p = (ClassName *)((char *)this + ((char *)(ClassName *)(0x10000000) - (char *)&((ClassName *)(0x10000000))->ListName)); \ + p->ListName ## _clear(); \ + } \ +}; \ +friend class Qml_ProxyList_ ##ListName ; \ +Qml_ProxyList_##ListName ListName; + + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QMLLIST_H diff --git a/src/declarative/qml/qmlmetaproperty.cpp b/src/declarative/qml/qmlmetaproperty.cpp new file mode 100644 index 0000000..79db6ce --- /dev/null +++ b/src/declarative/qml/qmlmetaproperty.cpp @@ -0,0 +1,847 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmlmetaproperty.h" +#include "qmlmetaproperty_p.h" +#include <qml.h> +#include <qfxperf.h> +#include <QStringList> +#include <qmlbindablevalue.h> +#include <qmlcontext.h> +#include "qmlboundsignal_p.h" +#include <math.h> +#include <QtCore/qdebug.h> + + +QT_BEGIN_NAMESPACE + +class QMetaPropertyEx : public QMetaProperty +{ +public: + QMetaPropertyEx() + : propertyType(-1) {} + + QMetaPropertyEx(const QMetaProperty &p) + : QMetaProperty(p), propertyType(p.userType()) {} + + QMetaPropertyEx(const QMetaPropertyEx &o) + : QMetaProperty(o), + propertyType(o.propertyType) {} + + QMetaPropertyEx &operator=(const QMetaPropertyEx &o) + { + static_cast<QMetaProperty *>(this)->operator=(o); + propertyType = o.propertyType; + return *this; + } + + private: + friend class QmlMetaProperty; + int propertyType; +}; + + +/*! + \class QmlMetaProperty + \brief The QmlMetaProperty class abstracts accessing QML properties. + */ + +/*! + Create an invalid QmlMetaProperty. +*/ +QmlMetaProperty::QmlMetaProperty() +: d(new QmlMetaPropertyPrivate) +{ +} + +QmlMetaProperty::~QmlMetaProperty() +{ + delete d; d = 0; +} + +// ### not thread safe +static QHash<const QMetaObject *, QMetaPropertyEx> qmlCacheDefProp; + +/*! + Creates a QmlMetaProperty for the default property of \a obj. If there is no + default property, an invalid QmlMetaProperty will be created. + */ +QmlMetaProperty::QmlMetaProperty(QObject *obj, QmlContext *ctxt) +: d(new QmlMetaPropertyPrivate) +{ + d->context = ctxt; + if(!obj) + return; + + d->object = obj; + QHash<const QMetaObject *, QMetaPropertyEx>::ConstIterator iter = + qmlCacheDefProp.find(obj->metaObject()); + if(iter != qmlCacheDefProp.end()) { + d->prop = *iter; + d->propType = iter->propertyType; + d->coreIdx = iter->propertyType; + } else { + QMetaPropertyEx p(QmlMetaType::defaultProperty(obj)); + d->prop = p; + d->propType = p.propertyType; + d->coreIdx = d->prop.propertyIndex(); + if(!QObjectPrivate::get(obj)->metaObject) + qmlCacheDefProp.insert(obj->metaObject(), d->prop); + } + if(d->prop.name() != 0) { + d->type = Property | Default; + d->name = QLatin1String(d->prop.name()); + } +} + +/*! + \internal + + Creates a QmlMetaProperty for the property at index \a idx of \a obj. + + The QmlMetaProperty is assigned category \a cat. + */ +QmlMetaProperty::QmlMetaProperty(QObject *obj, int idx, PropertyCategory cat, QmlContext *ctxt) +: d(new QmlMetaPropertyPrivate) +{ + d->context = ctxt; + d->object = obj; + d->type = Property; + d->category = cat; + QMetaPropertyEx p(obj->metaObject()->property(idx)); + d->prop = p; + d->propType = p.propertyType; + d->coreIdx = idx; + if(d->prop.name() != 0) + d->name = QLatin1String(d->prop.name()); +} + +// ### Not thread safe!!!! +static QHash<const QMetaObject *, QHash<QString, QMetaPropertyEx> > qmlCacheProps; +/*! + Creates a QmlMetaProperty for the property \a name of \a obj. + */ +QmlMetaProperty::QmlMetaProperty(QObject *obj, const QString &name, QmlContext *ctxt) +: d(new QmlMetaPropertyPrivate) +{ +#ifdef Q_ENABLE_PERFORMANCE_LOG + QFxPerfTimer<QFxPerf::MetaProperty> perf; +#endif + + d->context = ctxt; + d->name = name; + d->object = obj; + if(name.isEmpty() || !obj) + return; + + if(name.at(0).isUpper()) { + // Attached property + d->attachedFunc = QmlMetaType::attachedPropertiesFuncId(name.toLatin1()); + if(d->attachedFunc != -1) + d->type = Property | Attached; + return; + } else if(name.count() >= 3 && name.startsWith(QLatin1String("on")) && name.at(2).isUpper()) { + // Signal + QString signalName = name.mid(2); + signalName[0] = signalName.at(0).toLower(); + + d->findSignalInt(obj, signalName); + if(d->signal.signature() != 0) { + d->type = SignalProperty; + return; + } + } + + // Property + QHash<QString, QMetaPropertyEx> &props = qmlCacheProps[obj->metaObject()]; + QHash<QString, QMetaPropertyEx>::ConstIterator iter = props.find(name); + if(iter != props.end()) { + d->prop = *iter; + d->propType = iter->propertyType; + d->coreIdx = iter->propertyIndex(); + } else { + QMetaPropertyEx p = QmlMetaType::property(obj, name.toLatin1().constData()); + d->prop = p; + d->propType = p.propertyType; + d->coreIdx = p.propertyIndex(); + if (!QObjectPrivate::get(obj)->metaObject) + props.insert(name, p); + } + if(d->prop.name() != 0) + d->type = Property; + + if(d->type == Invalid) { + int sig = findSignal(obj, name.toLatin1()); + if(sig != -1) { + d->signal = obj->metaObject()->method(sig); + d->type = Signal; + d->coreIdx = sig; + } + } +} + +/*! + Create a copy of \a other. +*/ +QmlMetaProperty::QmlMetaProperty(const QmlMetaProperty &other) +: d(new QmlMetaPropertyPrivate(*other.d)) +{ +} + +/*! + Returns the property category. +*/ +QmlMetaProperty::PropertyCategory QmlMetaProperty::propertyCategory() const +{ + if(d->category == Unknown) { + int type = propertyType(); + if(!isValid()) + d->category = InvalidProperty; + else if(type == qMetaTypeId<QmlBindableValue *>()) + d->category = Bindable; + else if(QmlMetaType::isList(type)) + d->category = List; + else if(QmlMetaType::isQmlList(type)) + d->category = QmlList; + else if(QmlMetaType::isObject(type)) + d->category = Object; + else + d->category = Normal; + } + return d->category; +} + +/*! + Returns the property category of \a prop. +*/ +QmlMetaProperty::PropertyCategory +QmlMetaProperty::propertyCategory(const QMetaProperty &prop) +{ + if(prop.name()) { + int type = 0; + if(prop.type() == QVariant::LastType) + type = qMetaTypeId<QVariant>(); + else if(prop.type() == QVariant::UserType) + type = prop.userType(); + else + type = prop.type(); + + if(type == qMetaTypeId<QmlBindableValue *>()) + return Bindable; + else if(QmlMetaType::isList(type)) + return List; + else if(QmlMetaType::isQmlList(type)) + return QmlList; + else if(QmlMetaType::isObject(type)) + return Object; + else + return Normal; + } else { + return InvalidProperty; + } +} + +/*! + Returns the type name of the property, or 0 if the property has no type + name. +*/ +const char *QmlMetaProperty::propertyTypeName() const +{ + if(d->prop.name()) { + return d->prop.typeName(); + } else { + return 0; + } +} + +/*! + Returns true if \a other and this QmlMetaProperty represent the same + property. +*/ +bool QmlMetaProperty::operator==(const QmlMetaProperty &other) const +{ + return d->prop.name() == other.d->prop.name() && + d->signal.signature() == other.d->signal.signature() && + d->type == other.d->type && + d->object == other.d->object; +} + +/*! + Returns the QVariant type of the property, or QVariant::Invalid if the + property has no QVariant type. +*/ +int QmlMetaProperty::propertyType() const +{ + int rv = QVariant::Invalid; + + if(d->prop.name()) { + if(d->propType == (int)QVariant::LastType) + rv = qMetaTypeId<QVariant>(); + else + rv = d->propType; + } else if(d->attachedFunc) { + rv = qMetaTypeId<QObject *>(); + } + + return rv; +} + +/*! + Returns the type of the property. +*/ +QmlMetaProperty::Type QmlMetaProperty::type() const +{ + return (Type)d->type; +} + +/*! + Returns true if this QmlMetaProperty represents a regular Qt property. +*/ +bool QmlMetaProperty::isProperty() const +{ + return type() & Property; +} + +/*! + Returns true if this QmlMetaProperty represents a default property. +*/ +bool QmlMetaProperty::isDefault() const +{ + return type() & Default; +} + +/*! + Returns the QmlMetaProperty's QObject. +*/ +QObject *QmlMetaProperty::object() const +{ + return d->object; +} + +/*! + Assign \a other to this QmlMetaProperty. +*/ +QmlMetaProperty &QmlMetaProperty::operator=(const QmlMetaProperty &other) +{ + d->name = other.d->name; + d->prop = other.d->prop; + d->propType = other.d->propType; + d->type = other.d->type; + d->signal = other.d->signal; + d->coreIdx = other.d->coreIdx; + d->attachedFunc = other.d->attachedFunc; + d->object = other.d->object; + d->category = other.d->category; + return *this; +} + +/*! + Returns true if the property is writable, otherwise false. +*/ +bool QmlMetaProperty::isWritable() const +{ + if(propertyCategory() == List || propertyCategory() == QmlList) + return true; + else if(d->prop.name() != 0) + return d->prop.isWritable(); + else if(type() & SignalProperty) + return true; + else + return false; +} + +/*! + Returns true if the property is designable, otherwise false. +*/ +bool QmlMetaProperty::isDesignable() const +{ + if(d->prop.name() != 0) + return d->prop.isDesignable(); + else + return false; +} + +/*! + Returns true if the QmlMetaProperty refers to a valid property, otherwise + false. +*/ +bool QmlMetaProperty::isValid() const +{ + return type() != Invalid; +} + +/*! + Returns all of \a obj's Qt properties. +*/ +QStringList QmlMetaProperty::properties(QObject *obj) +{ + if(!obj) + return QStringList(); + + QStringList rv; + const QMetaObject *mo = obj->metaObject(); + for(int ii = 0; ii < mo->propertyCount(); ++ii) { + QMetaProperty prop = mo->property(ii); + rv << QLatin1String(prop.name()); + } + + return rv; +} + +/*! + Return the name of this property. +*/ +QString QmlMetaProperty::name() const +{ + return d->name; +} + +const QMetaProperty &QmlMetaProperty::property() const +{ + return d->prop; +} + +/*! + Returns the binding associated with this property, or 0 if no binding + exists. +*/ +QmlBindableValue *QmlMetaProperty::binding() +{ + if(!isProperty() || type() & Attached) + return 0; + + const QObjectList &children = object()->children(); + for(QObjectList::ConstIterator iter = children.begin(); + iter != children.end(); ++iter) { + QObject *child = *iter; + if(child->metaObject() == &QmlBindableValue::staticMetaObject) { + QmlBindableValue *v = static_cast<QmlBindableValue *>(child); + if(v->property() == *this) + return v; + } + } + return 0; +} + +/*! \internal */ +int QmlMetaProperty::findSignal(const QObject *obj, const char *name) +{ + const QMetaObject *mo = obj->metaObject(); + int methods = mo->methodCount(); + for(int ii = 0; ii < methods; ++ii) { + QMetaMethod method = mo->method(ii); + if(method.methodType() != QMetaMethod::Signal) + continue; + + QByteArray methodName = method.signature(); + int idx = methodName.indexOf('('); + methodName = methodName.left(idx); + + if(methodName == name) + return ii; + } + return -1; +} + +void QmlMetaPropertyPrivate::findSignalInt(QObject *obj, const QString &name) +{ + const QMetaObject *mo = obj->metaObject(); + + int methods = mo->methodCount(); + for(int ii = 0; ii < methods; ++ii) { + QMetaMethod method = mo->method(ii); + QString methodName = QLatin1String(method.signature()); + int idx = methodName.indexOf(QLatin1Char('(')); + methodName = methodName.left(idx); + + if(methodName == name) { + signal = method; + coreIdx = ii; + return; + } + } +} + +QObject *QmlMetaPropertyPrivate::attachedObject() const +{ + if(attachedFunc == -1) + return 0; + else + return QmlMetaType::attachedPropertiesFuncById(attachedFunc)(object); +} + +/*! + Returns the property value. +*/ +QVariant QmlMetaProperty::read() const +{ + if(type() & SignalProperty) { + + const QObjectList &children = object()->children(); + + for(int ii = 0; ii < children.count(); ++ii) { + QmlBoundSignal *sig = qobject_cast<QmlBoundSignal *>(children.at(ii)); + if(sig && sig->index() == d->coreIdx) + return sig->expression(); + } + } else if(type() & Property) { + if(type() & Attached) + return QVariant::fromValue(d->attachedObject()); + else + return d->prop.read(object()); + } + return QVariant(); +} + +Q_DECLARE_METATYPE(QList<QObject *>); +/*! + Set the property value to \a value. +*/ +void QmlMetaProperty::write(const QVariant &value) const +{ + if(type() & SignalProperty) { + + QString expr = value.toString(); + const QObjectList &children = object()->children(); + + for(int ii = 0; ii < children.count(); ++ii) { + QmlBoundSignal *sig = qobject_cast<QmlBoundSignal *>(children.at(ii)); + if(sig && sig->index() == d->coreIdx) { + if(expr.isEmpty()) { + sig->disconnect(); + sig->deleteLater(); + } else { + sig->setExpression(expr); + } + return; + } + } + + if(!expr.isEmpty()) { + // XXX scope + (void *)new QmlBoundSignal(QmlContext::activeContext(), expr, object(), d->coreIdx, object()); + } + + } else if(d->prop.name()) { + + if(d->prop.isEnumType()) { + QVariant v = value; + if (value.type() == QVariant::Double) { //enum values come through the script engine as doubles + double integral; + double fractional = modf(value.toDouble(), &integral); + if (qFuzzyCompare(fractional, (double)0.0)) + v.convert(QVariant::Int); + } + d->prop.write(object(), v); + } else { + if(!value.isValid()) + return; + + int t = propertyType(); + int vt = value.type(); + + if(vt == t || + value.userType() == t) { + + void *a[1]; + a[0] = (void *)value.constData(); + QMetaObject::metacall(object(), QMetaObject::WriteProperty, d->coreIdx, a); + + } else if(qMetaTypeId<QVariant>() == t) { + + d->prop.write(object(), value); + + } else if(propertyCategory() == Object) { + + QObject *o = QmlMetaType::toQObject(value); + if(o) + d->prop.write(object(), QmlMetaType::fromObject(o, propertyType())); + + } else if (propertyCategory() == List) { + + int listType = QmlMetaType::listType(t); + if(value.userType() == qMetaTypeId<QList<QObject *> >()) { + const QList<QObject *> &list = + qvariant_cast<QList<QObject *> >(value); + QVariant listVar = d->prop.read(object()); + QmlMetaType::clear(listVar); + for(int ii = 0; ii < list.count(); ++ii) { + QVariant v = QmlMetaType::fromObject(list.at(ii), listType); + QmlMetaType::append(listVar, v); + } + + } else if(vt == listType || + value.userType() == listType) { + QVariant listVar = d->prop.read(object()); + if (!QmlMetaType::append(listVar, value)) { + qWarning() << "QmlMetaProperty: Unable to assign object to list"; + } + } + } else if (propertyCategory() == QmlList) { + // XXX - optimize! + QVariant list = d->prop.read(object()); + QmlPrivate::ListInterface *li = + *(QmlPrivate::ListInterface **)list.constData(); + + int type = li->type(); + + if (QObject *obj = QmlMetaType::toQObject(value)) { + const QMetaObject *mo = + QmlMetaType::rawMetaObjectForType(type); + + const QMetaObject *objMo = obj->metaObject(); + bool found = false; + while(!found && objMo) { + if(objMo == mo) + found = true; + else + objMo = objMo->superClass(); + } + + if(!found) { + qWarning() << "Unable to assign object to list"; + return; + } + + // NOTE: This assumes a cast to QObject does not alter + // the object pointer + void *d = (void *)&obj; + li->append(d); + } + } else if(propertyCategory() == Normal) { + + switch(t) { + case QVariant::Double: + { + qreal r; + bool found = true; + if(vt == QVariant::Int) { + r = value.toInt(); + } else if(vt == QVariant::UInt) { + r = value.toUInt(); + } else { + found = false; + } + + if(found) { + void *a[1]; + a[0] = &r; + QMetaObject::metacall(object(), + QMetaObject::WriteProperty, + d->coreIdx, a); + return; + } + } + break; + + case QVariant::Int: + { + int i; + bool found = true; + if(vt == QVariant::Double) { + i = (int)value.toDouble(); + } else if(vt == QVariant::UInt) { + i = (int)value.toUInt(); + } else { + found = false; + } + + if(found) { + void *a[1]; + a[0] = &i; + QMetaObject::metacall(object(), + QMetaObject::WriteProperty, + d->coreIdx, a); + return; + } + } + break; + + case QVariant::String: + { + QString s; + bool found = true; + if(vt == QVariant::ByteArray) { + s = QLatin1String(value.toByteArray()); + } else { + found = false; + } + + if(found) { + void *a[1]; + a[0] = &s; + QMetaObject::metacall(object(), + QMetaObject::WriteProperty, + d->coreIdx, a); + return; + } + } + break; + + + default: + break; + } + d->prop.write(object(), value); + } + + } + } +} + +/*! + Returns true if the property has a change notifier signal, otherwise false. +*/ +bool QmlMetaProperty::hasChangedNotifier() const +{ + if(type() & Property && !(type() & Attached)) { + return d->prop.hasNotifySignal(); + } + return false; +} + +/*! + Connect the property's change notifier signal to the \a dest \a method. +*/ +bool QmlMetaProperty::connectNotifier(QObject *dest, int method) const +{ + if(!(type() & Property) || type() & Attached) + return false; + + if(d->prop.hasNotifySignal()) { + return QMetaObject::connect(d->object, d->prop.notifySignalIndex(), dest, method, Qt::DirectConnection); + } else { + return false; + } +} + +/*! + Connect the property's change notifier signal to the \a dest \a slot. +*/ +bool QmlMetaProperty::connectNotifier(QObject *dest, const char *slot) const +{ + if(!(type() & Property) || type() & Attached) + return false; + + if(d->prop.hasNotifySignal()) { + QByteArray signal(QByteArray("2") + d->prop.notifySignal().signature()); + return QObject::connect(d->object, signal.constData(), dest, slot); + } else { + return false; + } +} + +/*! \internal */ +void QmlMetaProperty::emitSignal() +{ + if(type() & Signal) { + if(d->signal.parameterTypes().isEmpty()) + d->object->metaObject()->activate(d->object, d->coreIdx, 0); + else + qWarning() << "QmlMetaProperty: Cannot emit signal with parameters"; + } +} + +/*! + Return the Qt metaobject index of the property. +*/ +int QmlMetaProperty::coreIndex() const +{ + return d->coreIdx; +} + +/*! + Returns the property information serialized into a single integer. + QmlMetaProperty uses the bottom 24 bits only. +*/ +quint32 QmlMetaProperty::save() const +{ + quint32 rv = 0; + if(type() & Attached) { + rv = d->attachedFunc; + } else if(type() != Invalid) { + rv = d->coreIdx; + } + + Q_ASSERT(rv <= 0xFFFF); + Q_ASSERT(type() <= 0xFF); + rv |= (type() << 16); + + return rv; +} + +/*! + Restore a QmlMetaProperty from a previously saved id. \a obj must be the + same object as used in the previous call to QmlMetaProperty::save(). Only + the bottom 24-bits are used, the high bits can be set to any value. +*/ +void QmlMetaProperty::restore(quint32 id, QObject *obj) +{ + *this = QmlMetaProperty(); + d->object = obj; + + id &= 0xFFFFFF; + d->type = id >> 16; + id &= 0xFFFF; + + if(d->type & Attached) { + d->attachedFunc = id; + } else if(d->type & Property) { + QMetaPropertyEx p(obj->metaObject()->property(id)); + d->prop = p; + d->propType = p.propertyType; + d->coreIdx = id; + } else if(d->type & SignalProperty || d->type & Signal) { + d->signal = obj->metaObject()->method(id); + d->coreIdx = id; + } +} + +/*! + Return the QMetaMethod for this property if it is a SignalProperty, + otherwise returns an invalid QMetaMethod. +*/ +QMetaMethod QmlMetaProperty::method() const +{ + return d->signal; +} + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlmetaproperty.h b/src/declarative/qml/qmlmetaproperty.h new file mode 100644 index 0000000..a2939f9 --- /dev/null +++ b/src/declarative/qml/qmlmetaproperty.h @@ -0,0 +1,137 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLMETAPROPERTY_H +#define QMLMETAPROPERTY_H + +#include <QtDeclarative/qfxglobal.h> +#include <QMetaProperty> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +class QObject; +class QmlBindableValue; +class QStringList; +class QVariant; +struct QMetaObject; +class QmlContext; + +class QmlMetaPropertyPrivate; +class Q_DECLARATIVE_EXPORT QmlMetaProperty +{ +public: + enum PropertyCategory { + Unknown, + InvalidProperty, + Bindable, + List, + QmlList, //XXX + Object, + Normal + }; + QmlMetaProperty(); + QmlMetaProperty(QObject *, QmlContext * = 0); + QmlMetaProperty(QObject *, const QString &, QmlContext * = 0); + QmlMetaProperty(const QmlMetaProperty &); + QmlMetaProperty &operator=(const QmlMetaProperty &); + QmlMetaProperty(QObject *, int, PropertyCategory = Unknown, QmlContext * = 0); + ~QmlMetaProperty(); + + static QStringList properties(QObject *); + QString name() const; + + QVariant read() const; + void write(const QVariant &) const; + void emitSignal(); + + bool hasChangedNotifier() const; + bool connectNotifier(QObject *dest, const char *slot) const; + bool connectNotifier(QObject *dest, int method) const; + + quint32 save() const; + void restore(quint32, QObject *); + + QMetaMethod method() const; + + enum Type { Invalid = 0x00, + Property = 0x01, + SignalProperty = 0x02, + Signal = 0x04, + Default = 0x08, + Attached = 0x10 }; + + Type type() const; + bool isProperty() const; + bool isDefault() const; + bool isWritable() const; + bool isDesignable() const; + bool isValid() const; + QObject *object() const; + + PropertyCategory propertyCategory() const; + static PropertyCategory propertyCategory(const QMetaProperty &); + + int propertyType() const; + const char *propertyTypeName() const; + + bool operator==(const QmlMetaProperty &) const; + + const QMetaProperty &property() const; + + QmlBindableValue *binding(); + static int findSignal(const QObject *, const char *); + + int coreIndex() const; +private: + friend class QmlEnginePrivate; + QmlMetaPropertyPrivate *d; +}; +typedef QList<QmlMetaProperty> QmlMetaProperties; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QMLMETAPROPERTY_H diff --git a/src/declarative/qml/qmlmetaproperty_p.h b/src/declarative/qml/qmlmetaproperty_p.h new file mode 100644 index 0000000..5c13f5e --- /dev/null +++ b/src/declarative/qml/qmlmetaproperty_p.h @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLMETAPROPERTY_P_H +#define QMLMETAPROPERTY_P_H + +class QmlContext; +class QmlMetaPropertyPrivate +{ +public: + QmlMetaPropertyPrivate() + : context(0), coreIdx(-1), type(QmlMetaProperty::Invalid), attachedFunc(-1), + object(0), propType(-1), category(QmlMetaProperty::Unknown) {} + QmlMetaPropertyPrivate(const QmlMetaPropertyPrivate &other) + : name(other.name), signal(other.signal), context(other.context), + coreIdx(other.coreIdx), type(other.type), attachedFunc(other.attachedFunc), + object(other.object), prop(other.prop), propType(other.propType), + category(other.category) {} + + QString name; + QMetaMethod signal; + QmlContext *context; + int coreIdx; + uint type; + int attachedFunc; + QObject *object; + QMetaProperty prop; + int propType; + + mutable QmlMetaProperty::PropertyCategory category; + + QObject *attachedObject() const; + void findSignalInt(QObject *, const QString &); +}; + +#endif // QMLMETAPROPERTY_P_H + diff --git a/src/declarative/qml/qmlmetatype.cpp b/src/declarative/qml/qmlmetatype.cpp new file mode 100644 index 0000000..584ccde --- /dev/null +++ b/src/declarative/qml/qmlmetatype.cpp @@ -0,0 +1,1164 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmlmetatype.h" +#include <QtCore/qdebug.h> +#include <QtCore/qstringlist.h> +#include <QtCore/qmetaobject.h> +#include <QtCore/qbitarray.h> +#include <QtCore/qreadwritelock.h> +#include <private/qmlproxymetaobject_p.h> + +#include <qmetatype.h> +#include <qobjectdefs.h> +#include <qdatetime.h> +#include <qbytearray.h> +#include <qreadwritelock.h> +#include <qstring.h> +#include <qstringlist.h> +#include <qvector.h> +#include <qlocale.h> +#include <QtCore/qcryptographichash.h> +#include <qmlcustomparser.h> + +QT_BEGIN_NAMESPACE +#ifdef QT_BOOTSTRAPPED +# ifndef QT_NO_GEOM_VARIANT +# define QT_NO_GEOM_VARIANT +# endif +#else +# include <qbitarray.h> +# include <qurl.h> +# include <qvariant.h> +#endif + +#ifndef QT_NO_GEOM_VARIANT +# include <qsize.h> +# include <qpoint.h> +# include <qrect.h> +# include <qline.h> +#endif +#define NS(x) QT_PREPEND_NAMESPACE(x) + +struct QmlMetaTypeData +{ + QList<QmlType *> types; + typedef QHash<int, QmlType *> Ids; + Ids idToType; + typedef QHash<QByteArray, QmlType *> Names; + Names nameToType; + typedef QHash<const QMetaObject *, QmlType *> MetaObjects; + MetaObjects metaObjectToType; + typedef QHash<QByteArray, QmlCustomParser *> CustomParsers; + CustomParsers customParsers; + typedef QHash<int, QmlMetaType::StringConverter> StringConverters; + StringConverters stringConverters; + + QBitArray objects; + QBitArray interfaces; + QBitArray qmllists; + QBitArray lists; +}; +Q_GLOBAL_STATIC(QmlMetaTypeData, metaTypeData); +Q_GLOBAL_STATIC(QReadWriteLock, metaTypeDataLock); + +class QmlTypePrivate +{ +public: + QmlTypePrivate(); + + void init() const; + + bool m_isInterface : 1; + const char *m_iid; + QByteArray m_name; + int m_typeId; int m_listId; int m_qmlListId; + QmlPrivate::Func m_opFunc; + const QMetaObject *m_baseMetaObject; + QmlAttachedPropertiesFunc m_attachedPropertiesFunc; + int m_parserStatusCast; + QmlPrivate::CreateFunc m_extFunc; + const QMetaObject *m_extMetaObject; + int m_index; + mutable volatile bool m_isSetup:1; + mutable QList<QmlProxyMetaObject::ProxyData> m_metaObjects; + mutable QByteArray m_hash; +}; + +QmlTypePrivate::QmlTypePrivate() +: m_isInterface(false), m_iid(0), m_typeId(0), m_listId(0), m_qmlListId(0), + m_opFunc(0), m_baseMetaObject(0), m_attachedPropertiesFunc(0), + m_parserStatusCast(-1), m_extFunc(0), m_extMetaObject(0), m_index(-1), m_isSetup(false) +{ +} + + +QmlType::QmlType(int type, int listType, int qmlListType, + QmlPrivate::Func opFunc, const char *iid, int index) +: d(new QmlTypePrivate) +{ + d->m_isInterface = true; + d->m_iid = iid; + d->m_typeId = type; + d->m_listId = listType; + d->m_qmlListId = qmlListType; + d->m_opFunc = opFunc; + d->m_index = index; + d->m_isSetup = true; +} + +QmlType::QmlType(int type, int listType, int qmlListType, + QmlPrivate::Func opFunc, const char *qmlName, + const QMetaObject *metaObject, + QmlAttachedPropertiesFunc attachedPropertiesFunc, + int parserStatusCast, QmlPrivate::CreateFunc extFunc, + const QMetaObject *extMetaObject, int index) +: d(new QmlTypePrivate) +{ + d->m_name = qmlName; + d->m_typeId = type; + d->m_listId = listType; + d->m_qmlListId = qmlListType; + d->m_opFunc = opFunc; + d->m_baseMetaObject = metaObject; + d->m_attachedPropertiesFunc = attachedPropertiesFunc; + d->m_parserStatusCast = parserStatusCast; + d->m_extFunc = extFunc; + d->m_index = index; + + if(extMetaObject) + d->m_extMetaObject = extMetaObject; +} + +QmlType::~QmlType() +{ + delete d; +} + +void QmlTypePrivate::init() const +{ + if(m_isSetup) return; + + QWriteLocker lock(metaTypeDataLock()); + if(m_isSetup) + return; + + // Setup extended meta object + // XXX - very inefficient + const QMetaObject *mo = m_baseMetaObject; + if(m_extFunc) { + QMetaObject *mmo = new QMetaObject; + *mmo = *m_extMetaObject; + mmo->d.superdata = mo; + QmlProxyMetaObject::ProxyData data = { mmo, m_extFunc, 0 }; + m_metaObjects << data; + } + + mo = mo->d.superdata; + while(mo) { + QmlType *t = metaTypeData()->metaObjectToType.value(mo); + if(t) { + if(t->d->m_extFunc) { + QMetaObject *mmo = new QMetaObject; + *mmo = *t->d->m_extMetaObject; + mmo->d.superdata = m_baseMetaObject; + if(!m_metaObjects.isEmpty()) + m_metaObjects.last().metaObject->d.superdata = mmo; + QmlProxyMetaObject::ProxyData data = { mmo, t->d->m_extFunc, 0 }; + m_metaObjects << data; + } + } + mo = mo->d.superdata; + } + + for(int ii = 0; ii < m_metaObjects.count(); ++ii) + m_metaObjects[ii].propertyOffset = + m_metaObjects.at(ii).metaObject->propertyOffset(); + + // Calculate hash + QByteArray hashData; + + const QMetaObject *myMetaObject = m_metaObjects.isEmpty()?m_baseMetaObject:m_metaObjects.first().metaObject; + + for(int ii = 0; ii < myMetaObject->propertyCount(); ++ii) { + QMetaProperty prop = myMetaObject->property(ii); + hashData.append(prop.type()); + hashData.append("|"); + hashData.append(prop.name()); + hashData.append("|"); + } + + for(int ii = 0; ii < myMetaObject->methodCount(); ++ii) { + QMetaMethod method = myMetaObject->method(ii); + hashData.append(method.signature()); + hashData.append("|"); + } + + m_hash = QCryptographicHash::hash(hashData, QCryptographicHash::Md5); + + m_isSetup = true; + lock.unlock(); +} + +QByteArray QmlType::typeName() const +{ + if(d->m_baseMetaObject) + return d->m_baseMetaObject->className(); + else + return QByteArray(); +} + +QByteArray QmlType::qmlTypeName() const +{ + return d->m_name; +} + +QByteArray QmlType::hash() const +{ + d->init(); + + return d->m_hash; +} + +QObject *QmlType::create() const +{ + d->init(); + + QVariant v; + QObject *rv = 0; + d->m_opFunc(QmlPrivate::Create, 0, v, v, (void **)&rv); + + if (rv && !d->m_metaObjects.isEmpty()) + (void *)new QmlProxyMetaObject(rv, &d->m_metaObjects); + + return rv; +} + +bool QmlType::isInterface() const +{ + return d->m_isInterface; +} + +int QmlType::typeId() const +{ + return d->m_typeId; +} + +int QmlType::qListTypeId() const +{ + return d->m_listId; +} + +int QmlType::qmlListTypeId() const +{ + return d->m_qmlListId; +} + +void QmlType::listClear(const QVariant &list) +{ + Q_ASSERT(list.userType() == qListTypeId()); + QVariant arg; + d->m_opFunc(QmlPrivate::Clear, 0, list, arg, 0); +} + +void QmlType::listAppend(const QVariant &list, const QVariant &item) +{ + Q_ASSERT(list.userType() == qListTypeId()); + d->m_opFunc(QmlPrivate::Append, 0, list, item, 0); +} + +QVariant QmlType::listAt(const QVariant &list, int idx) +{ + Q_ASSERT(list.userType() == qListTypeId()); + QVariant rv; + void *ptr = (void *)&rv; + d->m_opFunc(QmlPrivate::Value, idx, list, QVariant(), &ptr); + return rv; +} + +int QmlType::listCount(const QVariant &list) +{ + Q_ASSERT(list.userType() == qListTypeId()); + return d->m_opFunc(QmlPrivate::Length, 0, list, QVariant(), 0); +} + +const QMetaObject *QmlType::metaObject() const +{ + d->init(); + + if(d->m_metaObjects.isEmpty()) + return d->m_baseMetaObject; + else + return d->m_metaObjects.first().metaObject; + +} + +const QMetaObject *QmlType::baseMetaObject() const +{ + return d->m_baseMetaObject; +} + +QmlAttachedPropertiesFunc QmlType::attachedPropertiesFunction() const +{ + return d->m_attachedPropertiesFunc; +} + +int QmlType::parserStatusCast() const +{ + return d->m_parserStatusCast; +} + +QVariant QmlType::fromObject(QObject *obj) const +{ + QVariant rv; + QVariant *v_ptr = &rv; + QVariant vobj = QVariant::fromValue(obj); + d->m_opFunc(QmlPrivate::FromObject, 0, QVariant(), vobj, (void **)&v_ptr); + return rv; +} + +const char *QmlType::interfaceIId() const +{ + return d->m_iid; +} + +int QmlType::index() const +{ + return d->m_index; +} + +int QmlMetaType::registerInterface(const QmlPrivate::MetaTypeIds &id, + QmlPrivate::Func listFunction, + const char *iid) +{ + QWriteLocker lock(metaTypeDataLock()); + QmlMetaTypeData *data = metaTypeData(); + + int index = data->types.count(); + + QmlType *type = new QmlType(id.typeId, id.listId, id.qmlListId, + listFunction, iid, index); + + data->types.append(type); + data->idToType.insert(type->typeId(), type); + data->idToType.insert(type->qListTypeId(), type); + data->idToType.insert(type->qmlListTypeId(), type); + data->nameToType.insert(type->qmlTypeName(), type); + + if(data->interfaces.size() < id.typeId) + data->interfaces.resize(id.typeId + 16); + if(data->qmllists.size() < id.qmlListId) + data->qmllists.resize(id.qmlListId + 16); + if(data->lists.size() < id.listId) + data->lists.resize(id.listId + 16); + data->interfaces.setBit(id.typeId, true); + data->qmllists.setBit(id.qmlListId, true); + data->lists.setBit(id.listId, true); + + return index; +} + +int QmlMetaType::registerType(const QmlPrivate::MetaTypeIds &id, QmlPrivate::Func func, const char *cname, const QMetaObject *mo, QmlAttachedPropertiesFunc attach, int pStatus, int object, QmlPrivate::CreateFunc extFunc, const QMetaObject *extmo) +{ + Q_UNUSED(object); + QWriteLocker lock(metaTypeDataLock()); + QmlMetaTypeData *data = metaTypeData(); + + QString name = QLatin1String(cname); + for(int ii = 0; ii < name.count(); ++ii) { + if(!name.at(ii).isLetterOrNumber()) { + qWarning("QmlMetaType: Invalid QML name %s", cname); + return -1; + } + } + + int index = data->types.count(); + + QmlType *type = new QmlType(id.typeId, id.listId, id.qmlListId, + func, cname, mo, attach, pStatus, extFunc, + extmo, index); + + data->types.append(type); + data->idToType.insert(type->typeId(), type); + data->idToType.insert(type->qListTypeId(), type); + data->idToType.insert(type->qmlListTypeId(), type); + + if(!type->qmlTypeName().isEmpty()) + data->nameToType.insert(type->qmlTypeName(), type); + + data->metaObjectToType.insert(type->baseMetaObject(), type); + + if(data->objects.size() <= id.typeId) + data->objects.resize(id.typeId + 16); + if(data->qmllists.size() <= id.qmlListId) + data->qmllists.resize(id.qmlListId + 16); + if(data->lists.size() <= id.listId) + data->lists.resize(id.listId + 16); + data->objects.setBit(id.typeId, true); + data->qmllists.setBit(id.qmlListId, true); + data->lists.setBit(id.listId, true); + + return index; +} + +void QmlMetaType::registerCustomParser(const char *qmlName, + QmlCustomParser *parser) +{ + QWriteLocker lock(metaTypeDataLock()); + QmlMetaTypeData *data = metaTypeData(); + + Q_ASSERT(parser); + if(data->customParsers.contains(qmlName)) { + delete parser; + return; + } + + data->customParsers.insert(qmlName, parser); +} + +QmlCustomParser *QmlMetaType::customParser(const QByteArray &name) +{ + QReadLocker lock(metaTypeDataLock()); + QmlMetaTypeData *data = metaTypeData(); + + return data->customParsers.value(name); +} + + +int QmlMetaType::qmlParserStatusCast(int userType) +{ + QReadLocker lock(metaTypeDataLock()); + QmlMetaTypeData *data = metaTypeData(); + QmlType *type = data->idToType.value(userType); + if(type && type->typeId() == userType) + return type->parserStatusCast(); + else + return -1; +} + +QObject *QmlMetaType::toQObject(const QVariant &v) +{ + if(!isObject(v.userType())) + return 0; + + // NOTE: This assumes a cast to QObject does not alter the + // object pointer + QObject *rv = *(QObject **)v.constData(); + return rv; +} + +/* + Returns the item type for a list of type \a id. + */ +int QmlMetaType::listType(int id) +{ + QReadLocker lock(metaTypeDataLock()); + QmlMetaTypeData *data = metaTypeData(); + QmlType *type = data->idToType.value(id); + if(type && type->qListTypeId() == id) + return type->typeId(); + else + return 0; +} + +/* + Returns the item type for a qml list of type \a id. + */ +int QmlMetaType::qmlListType(int id) +{ + QReadLocker lock(metaTypeDataLock()); + QmlMetaTypeData *data = metaTypeData(); + QmlType *type = data->idToType.value(id); + if(type && type->qmlListTypeId() == id) + return type->typeId(); + else + return 0; +} + +bool QmlMetaType::clear(const QVariant &list) +{ + int userType = list.userType(); + QReadLocker lock(metaTypeDataLock()); + QmlMetaTypeData *data = metaTypeData(); + QmlType *type = data->idToType.value(userType); + lock.unlock(); + if(type && type->qListTypeId() == userType) { + type->listClear(list); + return true; + } else { + return false; + } +} + +bool QmlMetaType::append(const QVariant &list, const QVariant &item) +{ + int userType = list.userType(); + QReadLocker lock(metaTypeDataLock()); + QmlMetaTypeData *data = metaTypeData(); + QmlType *type = data->idToType.value(userType); + lock.unlock(); + if(type && type->qListTypeId() == userType && + item.userType() == type->typeId()) { + type->listAppend(list, item); + return true; + } else { + return false; + } +} + +QObject *QmlMetaType::create(const QByteArray &name) +{ + QReadLocker lock(metaTypeDataLock()); + QmlMetaTypeData *data = metaTypeData(); + lock.unlock(); + + QmlType *type = data->nameToType.value(name); + if(type) + return type->create(); + else + return 0; +} + +QVariant QmlMetaType::fromObject(QObject *obj, int typeId) +{ + QReadLocker lock(metaTypeDataLock()); + QmlMetaTypeData *data = metaTypeData(); + + QmlType *type = data->idToType.value(typeId); + if(type && type->typeId() == typeId) + return type->fromObject(obj); + else + return QVariant(); +} + +const QMetaObject *QmlMetaType::rawMetaObjectForType(int id) +{ + QReadLocker lock(metaTypeDataLock()); + QmlMetaTypeData *data = metaTypeData(); + + QmlType *type = data->idToType.value(id); + if(type && type->typeId() == id) + return type->baseMetaObject(); + else + return 0; +} + +const QMetaObject *QmlMetaType::rawMetaObjectForType(const QByteArray &name) +{ + QReadLocker lock(metaTypeDataLock()); + QmlMetaTypeData *data = metaTypeData(); + + QmlType *type = data->nameToType.value(name); + if(type) + return type->baseMetaObject(); + else + return 0; +} + +const QMetaObject *QmlMetaType::metaObjectForType(int id) +{ + QReadLocker lock(metaTypeDataLock()); + QmlMetaTypeData *data = metaTypeData(); + QmlType *type = data->idToType.value(id); + lock.unlock(); + + if(type && type->typeId() == id) + return type->metaObject(); + else + return 0; +} + +const QMetaObject *QmlMetaType::metaObjectForType(const QByteArray &name) +{ + QReadLocker lock(metaTypeDataLock()); + QmlMetaTypeData *data = metaTypeData(); + QmlType *type = data->nameToType.value(name); + lock.unlock(); + + if(type) + return type->metaObject(); + else + return 0; +} + +int QmlMetaType::type(const QByteArray &name) +{ + QReadLocker lock(metaTypeDataLock()); + QmlMetaTypeData *data = metaTypeData(); + + QmlType *type = data->nameToType.value(name); + if(type) + return type->typeId(); + else + return 0; +} + +int QmlMetaType::attachedPropertiesFuncId(const QByteArray &name) +{ + QReadLocker lock(metaTypeDataLock()); + QmlMetaTypeData *data = metaTypeData(); + + QmlType *type = data->nameToType.value(name); + if(type && type->attachedPropertiesFunction()) + return type->index(); + else + return -1; +} + +QmlAttachedPropertiesFunc QmlMetaType::attachedPropertiesFuncById(int id) +{ + if(id < 0) + return 0; + QReadLocker lock(metaTypeDataLock()); + QmlMetaTypeData *data = metaTypeData(); + return data->types.at(id)->attachedPropertiesFunction(); +} + +QmlAttachedPropertiesFunc +QmlMetaType::attachedPropertiesFunc(const QByteArray &name) +{ + QReadLocker lock(metaTypeDataLock()); + QmlMetaTypeData *data = metaTypeData(); + QmlType *type = data->nameToType.value(name); + if(type) + return type->attachedPropertiesFunction(); + else + return 0; +} + +QMetaProperty QmlMetaType::defaultProperty(const QMetaObject *metaObject) +{ + int idx = metaObject->indexOfClassInfo("DefaultProperty"); + while(idx == -1 && metaObject) { + metaObject = metaObject->superClass(); + if(metaObject) + idx = metaObject->indexOfClassInfo("DefaultProperty"); + } + if(-1 == idx) + return QMetaProperty(); + + QMetaClassInfo info = metaObject->classInfo(idx); + if(!info.value()) + return QMetaProperty(); + + idx = metaObject->indexOfProperty(info.value()); + if(-1 == idx) + return QMetaProperty(); + + return metaObject->property(idx); +} + +QMetaProperty QmlMetaType::defaultProperty(QObject *obj) +{ + if(!obj) + return QMetaProperty(); + + const QMetaObject *metaObject = obj->metaObject(); + return defaultProperty(metaObject); +} + +QMetaMethod QmlMetaType::defaultMethod(const QMetaObject *metaObject) +{ + int idx = metaObject->indexOfClassInfo("DefaultMethod"); + while(idx == -1 && metaObject) { + metaObject = metaObject->superClass(); + if(metaObject) + idx = metaObject->indexOfClassInfo("DefaultMethod"); + } + if(-1 == idx) + return QMetaMethod(); + + QMetaClassInfo info = metaObject->classInfo(idx); + if(!info.value()) + return QMetaMethod(); + + idx = metaObject->indexOfMethod(info.value()); + if(-1 == idx) + return QMetaMethod(); + + return metaObject->method(idx); +} + +QMetaMethod QmlMetaType::defaultMethod(QObject *obj) +{ + if(!obj) + return QMetaMethod(); + + const QMetaObject *metaObject = obj->metaObject(); + return defaultMethod(metaObject); +} + +/*! + */ +QMetaProperty QmlMetaType::property(QObject *obj, const QByteArray &bname) +{ + return property(obj, bname.constData()); +} + +/*! + */ +QMetaProperty QmlMetaType::property(QObject *obj, const char *name) +{ + if(!obj) + return QMetaProperty(); + + const QMetaObject *metaObject = obj->metaObject(); + + int idx = metaObject->indexOfProperty(name); + if(-1 == idx) + return QMetaProperty(); + + return metaObject->property(idx); +} + +bool QmlMetaType::isObject(int userType) +{ + QReadLocker lock(metaTypeDataLock()); + QmlMetaTypeData *data = metaTypeData(); + return userType >= 0 && userType < data->objects.size() && data->objects.testBit(userType); +} + +bool QmlMetaType::isInterface(int userType) +{ + QReadLocker lock(metaTypeDataLock()); + QmlMetaTypeData *data = metaTypeData(); + return userType >= 0 && userType < data->interfaces.size() && data->interfaces.testBit(userType); +} + +const char *QmlMetaType::interfaceIId(int userType) +{ + QReadLocker lock(metaTypeDataLock()); + QmlMetaTypeData *data = metaTypeData(); + QmlType *type = data->idToType.value(userType); + lock.unlock(); + if(type && type->isInterface() && type->typeId() == userType) + return type->interfaceIId(); + else + return 0; +} + +bool QmlMetaType::isObject(const QMetaObject *mo) +{ + while(mo) { + if(mo == &QObject::staticMetaObject) + return true; + mo = mo->superClass(); + } + return false; +} + +bool QmlMetaType::isQmlList(int userType) +{ + QReadLocker lock(metaTypeDataLock()); + QmlMetaTypeData *data = metaTypeData(); + return userType >= 0 && userType < data->qmllists.size() && data->qmllists.testBit(userType); +} + +bool QmlMetaType::isList(int userType) +{ + QReadLocker lock(metaTypeDataLock()); + QmlMetaTypeData *data = metaTypeData(); + return userType >= 0 && userType < data->lists.size() && data->lists.testBit(userType); +} + +bool QmlMetaType::isList(const QVariant &v) +{ + return (v.type() == QVariant::UserType && isList(v.userType())); +} + +int QmlMetaType::listCount(const QVariant &v) +{ + int userType = v.userType(); + + QReadLocker lock(metaTypeDataLock()); + QmlMetaTypeData *data = metaTypeData(); + QmlType *type = data->idToType.value(userType); + lock.unlock(); + + if(type && type->qListTypeId() == userType) + return type->listCount(v); + else + return 0; +} + +QVariant QmlMetaType::listAt(const QVariant &v, int idx) +{ + int userType = v.userType(); + + QReadLocker lock(metaTypeDataLock()); + QmlMetaTypeData *data = metaTypeData(); + QmlType *type = data->idToType.value(userType); + lock.unlock(); + + if(type && type->qListTypeId() == userType) + return type->listAt(v, idx); + else + return 0; +} + +/*! + A custom string convertor allows you to specify a function pointer that + returns a variant of \a type. For example, if you have written your own icon + class that you want to support as an object property assignable in QML: + + \code + int type = qRegisterMetaType<SuperIcon>("SuperIcon"); + QML::addCustomStringConvertor(type, &SuperIcon::pixmapFromString); + \endcode + + The function pointer must be of the form: + \code + QVariant (*StringConverter)(const QString &); + \endcode + */ +void QmlMetaType::registerCustomStringConverter(int type, StringConverter converter) +{ + QWriteLocker lock(metaTypeDataLock()); + + QmlMetaTypeData *data = metaTypeData(); + if(data->stringConverters.contains(type)) + return; + data->stringConverters.insert(type, converter); +} + +/*! + Return the custom string converter for \a type, previously installed through + registerCustomStringConverter() + */ +QmlMetaType::StringConverter QmlMetaType::customStringConverter(int type) +{ + QReadLocker lock(metaTypeDataLock()); + + QmlMetaTypeData *data = metaTypeData(); + return data->stringConverters.value(type); +} + +QmlType *QmlMetaType::qmlType(const QByteArray &name) +{ + QReadLocker lock(metaTypeDataLock()); + QmlMetaTypeData *data = metaTypeData(); + + return data->nameToType.value(name); +} + +QList<QByteArray> QmlMetaType::qmlTypeNames() +{ + QReadLocker lock(metaTypeDataLock()); + QmlMetaTypeData *data = metaTypeData(); + + return data->nameToType.keys(); +} + +/*! + Copies \a copy into \a data, assuming they both are of type \a type. If + \a copy is zero, a default type is copied. Returns true if the copy was + successful and false if not. + + \note This should move into QMetaType once complete + +*/ +bool QmlMetaType::copy(int type, void *data, const void *copy) +{ + if (copy) { + switch(type) { + case QMetaType::VoidStar: + case QMetaType::QObjectStar: + case QMetaType::QWidgetStar: + *static_cast<void **>(data) = *static_cast<void* const *>(copy); + return true; + case QMetaType::Long: + *static_cast<long *>(data) = *static_cast<const long*>(copy); + return true; + case QMetaType::Int: + *static_cast<int *>(data) = *static_cast<const int*>(copy); + return true; + case QMetaType::Short: + *static_cast<short *>(data) = *static_cast<const short*>(copy); + return true; + case QMetaType::Char: + *static_cast<char *>(data) = *static_cast<const char*>(copy); + return true; + case QMetaType::ULong: + *static_cast<ulong *>(data) = *static_cast<const ulong*>(copy); + return true; + case QMetaType::UInt: + *static_cast<uint *>(data) = *static_cast<const uint*>(copy); + return true; + case QMetaType::LongLong: + *static_cast<qlonglong *>(data) = *static_cast<const qlonglong*>(copy); + return true; + case QMetaType::ULongLong: + *static_cast<qulonglong *>(data) = *static_cast<const qulonglong*>(copy); + return true; + case QMetaType::UShort: + *static_cast<ushort *>(data) = *static_cast<const ushort*>(copy); + return true; + case QMetaType::UChar: + *static_cast<uchar *>(data) = *static_cast<const uchar*>(copy); + return true; + case QMetaType::Bool: + *static_cast<bool *>(data) = *static_cast<const bool*>(copy); + return true; + case QMetaType::Float: + *static_cast<float *>(data) = *static_cast<const float*>(copy); + return true; + case QMetaType::Double: + *static_cast<double *>(data) = *static_cast<const double*>(copy); + return true; + case QMetaType::QChar: + *static_cast<NS(QChar) *>(data) = *static_cast<const NS(QChar)*>(copy); + return true; +#ifndef QT_BOOTSTRAPPED + case QMetaType::QVariantMap: + *static_cast<NS(QVariantMap) *>(data) = *static_cast<const NS(QVariantMap)*>(copy); + return true; + case QMetaType::QVariantHash: + *static_cast<NS(QVariantHash) *>(data) = *static_cast<const NS(QVariantHash)*>(copy); + return true; + case QMetaType::QVariantList: + *static_cast<NS(QVariantList) *>(data) = *static_cast<const NS(QVariantList)*>(copy); + return true; +#endif + case QMetaType::QByteArray: + *static_cast<NS(QByteArray) *>(data) = *static_cast<const NS(QByteArray)*>(copy); + return true; + case QMetaType::QString: + *static_cast<NS(QString) *>(data) = *static_cast<const NS(QString)*>(copy); + return true; + case QMetaType::QStringList: + *static_cast<NS(QStringList) *>(data) = *static_cast<const NS(QStringList)*>(copy); + return true; +#ifndef QT_BOOTSTRAPPED + case QMetaType::QBitArray: + *static_cast<NS(QBitArray) *>(data) = *static_cast<const NS(QBitArray)*>(copy); + return true; +#endif + case QMetaType::QDate: + *static_cast<NS(QDate) *>(data) = *static_cast<const NS(QDate)*>(copy); + return true; + case QMetaType::QTime: + *static_cast<NS(QTime) *>(data) = *static_cast<const NS(QTime)*>(copy); + return true; + case QMetaType::QDateTime: + *static_cast<NS(QDateTime) *>(data) = *static_cast<const NS(QDateTime)*>(copy); + return true; +#ifndef QT_BOOTSTRAPPED + case QMetaType::QUrl: + *static_cast<NS(QUrl) *>(data) = *static_cast<const NS(QUrl)*>(copy); + return true; +#endif + case QMetaType::QLocale: + *static_cast<NS(QLocale) *>(data) = *static_cast<const NS(QLocale)*>(copy); + return true; +#ifndef QT_NO_GEOM_VARIANT + case QMetaType::QRect: + *static_cast<NS(QRect) *>(data) = *static_cast<const NS(QRect)*>(copy); + return true; + case QMetaType::QRectF: + *static_cast<NS(QRectF) *>(data) = *static_cast<const NS(QRectF)*>(copy); + return true; + case QMetaType::QSize: + *static_cast<NS(QSize) *>(data) = *static_cast<const NS(QSize)*>(copy); + return true; + case QMetaType::QSizeF: + *static_cast<NS(QSizeF) *>(data) = *static_cast<const NS(QSizeF)*>(copy); + return true; + case QMetaType::QLine: + *static_cast<NS(QLine) *>(data) = *static_cast<const NS(QLine)*>(copy); + return true; + case QMetaType::QLineF: + *static_cast<NS(QLineF) *>(data) = *static_cast<const NS(QLineF)*>(copy); + return true; + case QMetaType::QPoint: + *static_cast<NS(QPoint) *>(data) = *static_cast<const NS(QPoint)*>(copy); + return true; + case QMetaType::QPointF: + *static_cast<NS(QPointF) *>(data) = *static_cast<const NS(QPointF)*>(copy); + return true; +#endif +#ifndef QT_NO_REGEXP + case QMetaType::QRegExp: + *static_cast<NS(QRegExp) *>(data) = *static_cast<const NS(QRegExp)*>(copy); + return true; +#endif + case QMetaType::Void: + return true; + default: + ; + } + } else { + switch(type) { + case QMetaType::VoidStar: + case QMetaType::QObjectStar: + case QMetaType::QWidgetStar: + *static_cast<void **>(data) = 0; + return true; + case QMetaType::Long: + *static_cast<long *>(data) = long(0); + return true; + case QMetaType::Int: + *static_cast<int *>(data) = int(0); + return true; + case QMetaType::Short: + *static_cast<short *>(data) = short(0); + return true; + case QMetaType::Char: + *static_cast<char *>(data) = char(0); + return true; + case QMetaType::ULong: + *static_cast<ulong *>(data) = ulong(0); + return true; + case QMetaType::UInt: + *static_cast<uint *>(data) = uint(0); + return true; + case QMetaType::LongLong: + *static_cast<qlonglong *>(data) = qlonglong(0); + return true; + case QMetaType::ULongLong: + *static_cast<qulonglong *>(data) = qulonglong(0); + return true; + case QMetaType::UShort: + *static_cast<ushort *>(data) = ushort(0); + return true; + case QMetaType::UChar: + *static_cast<uchar *>(data) = uchar(0); + return true; + case QMetaType::Bool: + *static_cast<bool *>(data) = bool(false); + return true; + case QMetaType::Float: + *static_cast<float *>(data) = float(0); + return true; + case QMetaType::Double: + *static_cast<double *>(data) = double(); + return true; + case QMetaType::QChar: + *static_cast<NS(QChar) *>(data) = NS(QChar)(); + return true; +#ifndef QT_BOOTSTRAPPED + case QMetaType::QVariantMap: + *static_cast<NS(QVariantMap) *>(data) = NS(QVariantMap)(); + return true; + case QMetaType::QVariantHash: + *static_cast<NS(QVariantHash) *>(data) = NS(QVariantHash)(); + return true; + case QMetaType::QVariantList: + *static_cast<NS(QVariantList) *>(data) = NS(QVariantList)(); + return true; +#endif + case QMetaType::QByteArray: + *static_cast<NS(QByteArray) *>(data) = NS(QByteArray)(); + return true; + case QMetaType::QString: + *static_cast<NS(QString) *>(data) = NS(QString)(); + return true; + case QMetaType::QStringList: + *static_cast<NS(QStringList) *>(data) = NS(QStringList)(); + return true; +#ifndef QT_BOOTSTRAPPED + case QMetaType::QBitArray: + *static_cast<NS(QBitArray) *>(data) = NS(QBitArray)(); + return true; +#endif + case QMetaType::QDate: + *static_cast<NS(QDate) *>(data) = NS(QDate)(); + return true; + case QMetaType::QTime: + *static_cast<NS(QTime) *>(data) = NS(QTime)(); + return true; + case QMetaType::QDateTime: + *static_cast<NS(QDateTime) *>(data) = NS(QDateTime)(); + return true; +#ifndef QT_BOOTSTRAPPED + case QMetaType::QUrl: + *static_cast<NS(QUrl) *>(data) = NS(QUrl)(); + return true; +#endif + case QMetaType::QLocale: + *static_cast<NS(QLocale) *>(data) = NS(QLocale)(); + return true; +#ifndef QT_NO_GEOM_VARIANT + case QMetaType::QRect: + *static_cast<NS(QRect) *>(data) = NS(QRect)(); + return true; + case QMetaType::QRectF: + *static_cast<NS(QRectF) *>(data) = NS(QRectF)(); + return true; + case QMetaType::QSize: + *static_cast<NS(QSize) *>(data) = NS(QSize)(); + return true; + case QMetaType::QSizeF: + *static_cast<NS(QSizeF) *>(data) = NS(QSizeF)(); + return true; + case QMetaType::QLine: + *static_cast<NS(QLine) *>(data) = NS(QLine)(); + return true; + case QMetaType::QLineF: + *static_cast<NS(QLineF) *>(data) = NS(QLineF)(); + return true; + case QMetaType::QPoint: + *static_cast<NS(QPoint) *>(data) = NS(QPoint)(); + return true; + case QMetaType::QPointF: + *static_cast<NS(QPointF) *>(data) = NS(QPointF)(); + return true; +#endif +#ifndef QT_NO_REGEXP + case QMetaType::QRegExp: + *static_cast<NS(QRegExp) *>(data) = NS(QRegExp)(); + return true; +#endif + case QMetaType::Void: + return true; + default: + ; + } + } + + return false; +} + +void qmlRegisterCustomParser(const char *qmlName, QmlCustomParser *parser) +{ + QmlMetaType::registerCustomParser(qmlName, parser); +} + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlmetatype.h b/src/declarative/qml/qmlmetatype.h new file mode 100644 index 0000000..3daa14b --- /dev/null +++ b/src/declarative/qml/qmlmetatype.h @@ -0,0 +1,258 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLMETATYPE_H +#define QMLMETATYPE_H + +#include <QtCore/qglobal.h> +#include <QtCore/qvariant.h> +#include <QtCore/qbitarray.h> +#include <QtDeclarative/qmlprivate.h> +#include <QtDeclarative/qmlparserstatus.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +class QmlType; +class QmlCustomParser; +class Q_DECLARATIVE_EXPORT QmlMetaType +{ +public: + static int registerType(const QmlPrivate::MetaTypeIds &, QmlPrivate::Func, const char *, const QMetaObject *, QmlAttachedPropertiesFunc, int pStatus, int object, QmlPrivate::CreateFunc extFunc, const QMetaObject *extmo); + static int registerInterface(const QmlPrivate::MetaTypeIds &, QmlPrivate::Func, const char *); + static void registerCustomParser(const char *, QmlCustomParser *); + + static QmlCustomParser *customParser(const QByteArray &); + + static bool copy(int type, void *data, const void *copy = 0); + + static QmlType *qmlType(const QByteArray &); + static QList<QByteArray> qmlTypeNames(); + + static QMetaProperty defaultProperty(const QMetaObject *); + static QMetaProperty defaultProperty(QObject *); + static QMetaMethod defaultMethod(const QMetaObject *); + static QMetaMethod defaultMethod(QObject *); + static QMetaProperty property(QObject *, const QByteArray &); + static QMetaProperty property(QObject *, const char *); + static QObject *toQObject(const QVariant &); + static int qmlParserStatusCast(int); + static int listType(int); + static int type(const QByteArray &); + static int type(const QString &); + static bool clear(const QVariant &); + static bool append(const QVariant &, const QVariant &); + static QVariant fromObject(QObject *, int type); + static QObject *create(const QByteArray &); + static const QMetaObject *rawMetaObjectForType(const QByteArray &); + static const QMetaObject *rawMetaObjectForType(int); + static const QMetaObject *metaObjectForType(const QByteArray &); + static const QMetaObject *metaObjectForType(int); + static int attachedPropertiesFuncId(const QByteArray &); + static QmlAttachedPropertiesFunc attachedPropertiesFuncById(int); + static QmlAttachedPropertiesFunc attachedPropertiesFunc(const QByteArray &); + + static bool isInterface(int); + static const char *interfaceIId(int); + static bool isObject(int); + static bool isObject(const QMetaObject *); + static bool isList(int); + static bool isList(const QVariant &); + static bool isQmlList(int); + static int qmlListType(int); + static int listCount(const QVariant &); + static QVariant listAt(const QVariant &, int); + + typedef QVariant (*StringConverter)(const QString &); + static void registerCustomStringConverter(int, StringConverter); + static StringConverter customStringConverter(int); +}; + +class QmlTypePrivate; +class QmlType +{ +public: + QByteArray typeName() const; + QByteArray qmlTypeName() const; + + QByteArray hash() const; + + QObject *create() const; + + bool isInterface() const; + int typeId() const; + int qListTypeId() const; + int qmlListTypeId() const; + + void listClear(const QVariant &); + void listAppend(const QVariant &, const QVariant &); + QVariant listAt(const QVariant &, int); + int listCount(const QVariant &); + + const QMetaObject *metaObject() const; + const QMetaObject *baseMetaObject() const; + + QmlAttachedPropertiesFunc attachedPropertiesFunction() const; + + int parserStatusCast() const; + QVariant fromObject(QObject *) const; + const char *interfaceIId() const; + + int index() const; +private: + friend class QmlMetaType; + friend class QmlTypePrivate; + QmlType(int, int, int, QmlPrivate::Func, const char *, int); + QmlType(int, int, int, QmlPrivate::Func, const char *, const QMetaObject *, QmlAttachedPropertiesFunc, int, QmlPrivate::CreateFunc, const QMetaObject *, int); + ~QmlType(); + + QmlTypePrivate *d; +}; + +template<typename T> +int qmlRegisterType(const char *typeName) +{ + QByteArray name(typeName); + QmlPrivate::MetaTypeIds ids = { + qRegisterMetaType<T *>(QByteArray(name + "*").constData()), + qRegisterMetaType<T *>(QByteArray("QList<" + name + "*>*").constData()), + qRegisterMetaType<T *>(QByteArray("QmlList<" + name + "*>*").constData()) + }; + + return QmlMetaType::registerType(ids, QmlPrivate::list_nocreate_op<T>, 0, + &T::staticMetaObject, + QmlPrivate::attachedPropertiesFunc<T>(), + QmlPrivate::StaticCastSelector<T,QmlParserStatus>::cast(), + QmlPrivate::StaticCastSelector<T,QObject>::cast(), + 0, 0); +} + +template<typename T> +int qmlRegisterType(const char *qmlName, const char *typeName) +{ + QByteArray name(typeName); + QmlPrivate::MetaTypeIds ids = { + qRegisterMetaType<T *>(QByteArray(name + "*").constData()), + qRegisterMetaType<T *>(QByteArray("QList<" + name + "*>*").constData()), + qRegisterMetaType<T *>(QByteArray("QmlList<" + name + "*>*").constData()) + }; + + return QmlMetaType::registerType(ids, QmlPrivate::list_op<T>, qmlName, + &T::staticMetaObject, + QmlPrivate::attachedPropertiesFunc<T>(), + QmlPrivate::StaticCastSelector<T,QmlParserStatus>::cast(), + QmlPrivate::StaticCastSelector<T,QObject>::cast(), + 0, 0); +} + +template<typename T, typename E> +int qmlRegisterExtendedType(const char *typeName) +{ + QByteArray name(typeName); + QmlPrivate::MetaTypeIds ids = { + qRegisterMetaType<T *>(QByteArray(name + "*").constData()), + qRegisterMetaType<T *>(QByteArray("QList<" + name + "*>*").constData()), + qRegisterMetaType<T *>(QByteArray("QmlList<" + name + "*>*").constData()) + }; + + QmlAttachedPropertiesFunc attached = + QmlPrivate::attachedPropertiesFunc<E>(); + if(!attached) + attached = QmlPrivate::attachedPropertiesFunc<T>(); + + return QmlMetaType::registerType(ids, QmlPrivate::list_nocreate_op<T>, 0, + &T::staticMetaObject, attached, + QmlPrivate::StaticCastSelector<T,QmlParserStatus>::cast(), + QmlPrivate::StaticCastSelector<T,QObject>::cast(), + &QmlPrivate::CreateParent<E>::create, &E::staticMetaObject); +} + +template<typename T, typename E> +int qmlRegisterExtendedType(const char *qmlName, const char *typeName) +{ + QByteArray name(typeName); + QmlPrivate::MetaTypeIds ids = { + qRegisterMetaType<T *>(QByteArray(name + "*").constData()), + qRegisterMetaType<T *>(QByteArray("QList<" + name + "*>*").constData()), + qRegisterMetaType<T *>(QByteArray("QmlList<" + name + "*>*").constData()) + }; + + QmlAttachedPropertiesFunc attached = + QmlPrivate::attachedPropertiesFunc<E>(); + if(!attached) + attached = QmlPrivate::attachedPropertiesFunc<T>(); + + return QmlMetaType::registerType(ids, QmlPrivate::list_op<T>, + qmlName, + &T::staticMetaObject, + attached, + QmlPrivate::StaticCastSelector<T,QmlParserStatus>::cast(), + QmlPrivate::StaticCastSelector<T,QObject>::cast(), + &QmlPrivate::CreateParent<E>::create, + &E::staticMetaObject); +} + +template<typename T> +int qmlRegisterInterface(const char *typeName) +{ + QByteArray name(typeName); + QmlPrivate::MetaTypeIds ids = { + qRegisterMetaType<T *>(QByteArray(name + "*").constData()), + qRegisterMetaType<T *>(QByteArray("QList<" + name + "*>*").constData()), + qRegisterMetaType<T *>(QByteArray("QmlList<" + name + "*>*").constData()) + }; + + return QmlMetaType::registerInterface(ids, + QmlPrivate::list_interface_op<T>, + qobject_interface_iid<T *>()); +} + +void qmlRegisterCustomParser(const char *qmlName, QmlCustomParser *); + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QMLMETATYPE_H + diff --git a/src/declarative/qml/qmlparser.cpp b/src/declarative/qml/qmlparser.cpp new file mode 100644 index 0000000..54db32e --- /dev/null +++ b/src/declarative/qml/qmlparser.cpp @@ -0,0 +1,167 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmlparser_p.h" +#include <QStack> +#include <qmlpropertyvaluesource.h> +#include <QColor> +#include <QPointF> +#include <QSizeF> +#include <QRectF> +#include <private/qmlvme_p.h> +#include <qmlbindablevalue.h> +#include <qfxperf.h> +#include <qml.h> +#include "private/qmlcomponent_p.h" +#include <qmlcomponent.h> +#include <qmlbasicscript.h> +#include "private/qmetaobjectbuilder_p.h" +#include <private/qmlvmemetaobject_p.h> +#include "private/qmlxmlparser_p.h" +#include <private/qmlcompiler_p.h> + +QT_BEGIN_NAMESPACE + +using namespace QmlParser; + +QmlParser::Object::Object() +: type(-1), metatype(0), extObject(0), defaultProperty(0), line(-1), + dynamicPropertiesProperty(0), dynamicSignalsProperty(0) +{ +} + +QmlParser::Object::~Object() +{ + if(defaultProperty) defaultProperty->release(); + foreach(Property *prop, properties) + prop->release(); + if(dynamicPropertiesProperty) dynamicPropertiesProperty->release(); + if(dynamicSignalsProperty) dynamicSignalsProperty->release(); +} + +const QMetaObject *Object::metaObject() const +{ + if(extObject && metatype) + return extObject; + else + return metatype; +} + +QmlParser::Property *Object::getDefaultProperty() +{ + if(!defaultProperty) + defaultProperty = new Property; + return defaultProperty; +} + +Property *QmlParser::Object::getProperty(const QByteArray &name, bool create) +{ + if(!properties.contains(name)) { + if(create) + properties.insert(name, new Property(name)); + else + return 0; + } + return properties[name]; +} + +QmlParser::Object::DynamicProperty::DynamicProperty() +: isDefaultProperty(false), type(Variant), defaultValue(0) +{ +} + +QmlParser::Object::DynamicProperty::DynamicProperty(const DynamicProperty &o) +: isDefaultProperty(o.isDefaultProperty), + type(o.type), + name(o.name), + onValueChanged(o.onValueChanged), + defaultValue(o.defaultValue) +{ +} + +QmlParser::Object::DynamicSignal::DynamicSignal() +{ +} + +QmlParser::Object::DynamicSignal::DynamicSignal(const DynamicSignal &o) +: name(o.name) +{ +} + +QmlParser::Property::Property() +: type(0), index(-1), value(0), isDefault(true), line(-1) +{ +} + +QmlParser::Property::Property(const QByteArray &n) +: type(0), index(-1), value(0), name(n), isDefault(false), line(-1) +{ +} + +QmlParser::Property::~Property() +{ + foreach(Value *value, values) + value->release(); + if(value) value->release(); +} + +Object *QmlParser::Property::getValue() +{ + if(!value) value = new Object; + return value; +} + +void QmlParser::Property::addValue(Value *v) +{ + values << v; +} + +QmlParser::Value::Value() +: type(Unknown), object(0), line(-1) +{ +} + +QmlParser::Value::~Value() +{ + if(object) object->release(); +} + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlparser_p.h b/src/declarative/qml/qmlparser_p.h new file mode 100644 index 0000000..9d3f3f6 --- /dev/null +++ b/src/declarative/qml/qmlparser_p.h @@ -0,0 +1,209 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLPARSER_P_H +#define QMLPARSER_P_H + +#include <QByteArray> +#include <QList> +#include <qml.h> +#include "qmlcomponent_p.h" +#include <private/qmlrefcount_p.h> +#include "qmlcompiledcomponent_p.h" + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) +class QmlXmlParser; + +/* + XXX + + These types are created (and owned) by the QmlXmlParser and consumed by the + QmlCompiler. During the compilation phase the compiler will update some of + the fields for both its own use and for the use of the upcoming QmlDom API. + + The types are part of the generic sounding "QmlParser" namespace for legacy + reasons (there used to be more in this namespace) and will be cleaned up and + migrated into a more appropriate location shortly. +*/ +namespace QmlParser +{ + class Property; + class Object : public QmlRefCount + { + public: + Object(); + virtual ~Object(); + + // Type of the object. The integer is an index into the + // QmlCompiledData::types array, or -1 if the object is a fetched + // object. + int type; + // The name of this type + QByteArray typeName; + // The id assigned to the object (if any). + QByteArray id; + // Custom parsed data + QByteArray custom; + // Returns the metaobject for this type, or 0 if not available. + // Internally selectd between the metatype and extObject variables + const QMetaObject *metaObject() const; + + // The compile time metaobject for this type + const QMetaObject *metatype; + // The synthesized metaobject, if QML added signals or properties to + // this type. Otherwise null + QMetaObject *extObject; + + Property *getDefaultProperty(); + Property *getProperty(const QByteArray &name, bool create=true); + + Property *defaultProperty; + QHash<QByteArray, Property *> properties; + + qint64 line; + + struct DynamicProperty { + DynamicProperty(); + DynamicProperty(const DynamicProperty &); + + enum Type { Variant, Int, Bool, Real, String, Color, Date }; + + bool isDefaultProperty; + Type type; + QByteArray name; + QString onValueChanged; + QmlParser::Property *defaultValue; + }; + struct DynamicSignal { + DynamicSignal(); + DynamicSignal(const DynamicSignal &); + + QByteArray name; + }; + + // The "properties" property + Property *dynamicPropertiesProperty; + // The "signals" property + Property *dynamicSignalsProperty; + // The list of dynamic properties described in the "properties" property + QList<DynamicProperty> dynamicProperties; + // The list of dynamic signals described in the "signals" property + QList<DynamicSignal> dynamicSignals; + }; + + class Value : public QmlRefCount + { + public: + Value(); + virtual ~Value(); + + enum Type { + // The type of this value assignment is not yet known + Unknown, + // This is used as a literal property assignment + Literal, + // This is used as a property binding assignment + PropertyBinding, + // This is used as a QmlPropertyValueSource assignment + ValueSource, + // This is used as a property QObject assignment + CreatedObject, + // This is used as a signal object assignment + SignalObject, + // This is used as a signal expression assignment + SignalExpression, + // This is used as an implicit component creation + Component, + // This is used as an id assignment only + Id + }; + Type type; + + // Primitive value + QString primitive; + // Object value + Object *object; + + qint64 line; + }; + + class Property : public QmlRefCount + { + public: + Property(); + Property(const QByteArray &n); + virtual ~Property(); + + Object *getValue(); + void addValue(Value *v); + + // The QVariant::Type of the property, or 0 (QVariant::Invalid) if + // unknown. + int type; + // The metaobject index of this property, or -1 if unknown. + int index; + + // The list of values assigned to this property. Content in values + // and value are mutually exclusive + QList<Value *> values; + // The accessed property. This is used to represent dot properties. + // Content in value and values are mutually exclusive. + Object *value; + // The property name + QByteArray name; + // True if this property was accessed as the default property. + bool isDefault; + + qint64 line; + }; +} + +#endif // QMLPARSER_P_H + + +QT_END_NAMESPACE + +QT_END_HEADER diff --git a/src/declarative/qml/qmlparserstatus.cpp b/src/declarative/qml/qmlparserstatus.cpp new file mode 100644 index 0000000..3bb421d --- /dev/null +++ b/src/declarative/qml/qmlparserstatus.cpp @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmlparserstatus.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QmlParserStatus + \brief provides updates on the parser state. +*/ + +/*! + Invoked after class creation, but before any properties have been set. +*/ +void QmlParserStatus::classBegin() +{ +} + +/*! + Invoked after all properties have been set to their static values. At this + point bindings are still to be evaluated. +*/ +void QmlParserStatus::classComplete() +{ +} + +/*! + Invoked after the root component that caused this instantiation has + completed construction. At this point all static values and binding values + have been assigned to the class. +*/ +void QmlParserStatus::componentComplete() +{ +} + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlparserstatus.h b/src/declarative/qml/qmlparserstatus.h new file mode 100644 index 0000000..1ec50ba --- /dev/null +++ b/src/declarative/qml/qmlparserstatus.h @@ -0,0 +1,69 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLPARSERSTATUS_H +#define QMLPARSERSTATUS_H + +#include <QtCore/qobject.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +class Q_DECLARATIVE_EXPORT QmlParserStatus +{ +public: + virtual ~QmlParserStatus() {} + + virtual void classBegin(); + virtual void classComplete(); + virtual void componentComplete(); +}; +Q_DECLARE_INTERFACE(QmlParserStatus, "com.trolltech.qml.QmlParserStatus"); + + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QMLPARSERSTATUS_H diff --git a/src/declarative/qml/qmlprivate.cpp b/src/declarative/qml/qmlprivate.cpp new file mode 100644 index 0000000..21b19e8 --- /dev/null +++ b/src/declarative/qml/qmlprivate.cpp @@ -0,0 +1,48 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmlprivate.h" + +QT_BEGIN_NAMESPACE + +QmlPrivate::InstanceType::InstanceType(int) {} + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlprivate.h b/src/declarative/qml/qmlprivate.h new file mode 100644 index 0000000..183f42b --- /dev/null +++ b/src/declarative/qml/qmlprivate.h @@ -0,0 +1,365 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLPRIVATE_H +#define QMLPRIVATE_H + +#include <QtCore/qglobal.h> +#ifndef Q_OS_WIN32 +#include <stdint.h> +#endif +#include <QtCore/qvariant.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +typedef QObject *(*QmlAttachedPropertiesFunc)(QObject *); + +namespace QmlPrivate +{ + class ListInterface + { + public: + virtual ~ListInterface() {} + virtual int type() const = 0; + virtual void append(void *) = 0; + virtual void insert(int, void *) = 0; + virtual void removeAt(int) = 0; + virtual void at(int, void *) const = 0; + virtual int count() const = 0; + virtual void clear() = 0; + }; + + enum ListOp { Append, Set, Insert, Prepend, Length, FromObject, + Object, Create, Value, Clear }; + + template<typename T> + int list_op(ListOp op, int val, + const QVariant &vlist, + const QVariant &value, + void **out); + + template<typename T> + int list_nocreate_op(ListOp op, int val, + const QVariant &vlist, + const QVariant &value, + void **out); + + template<typename T> + int list_interface_op(ListOp op, int val, + const QVariant &vlist, + const QVariant &value, + void **out); + + template<class From, class To, int N> + struct StaticCastSelectorClass + { + static inline int cast() { return -1; } + }; + + template<class From, class To> + struct StaticCastSelectorClass<From, To, sizeof(int)> + { +#ifndef Q_OS_SYMBIAN + static inline int cast() { return (int)((intptr_t)static_cast<To *>((From *)0x10000000)) - 0x10000000; } +#else + static inline int cast() { return (int)(static_cast<To *>((From *)0x10000000)) - 0x10000000; } +#endif + }; + + template<class From, class To> + struct StaticCastSelector + { + typedef int yes_type; + typedef char no_type; + + static yes_type check(To *); + static no_type check(...); + + static inline int cast() + { + return StaticCastSelectorClass<From, To, sizeof(check((From *)0))>::cast(); + } + }; + + template<typename T, int N> + struct AttachedPropertySelector + { + static inline QmlAttachedPropertiesFunc func() + { + return 0; + } + }; + template<typename T> + struct AttachedPropertySelector<T, 1> + { + static inline QmlAttachedPropertiesFunc func() + { + return &T::qmlAttachedProperties; + } + }; + + template < typename T > + class has_attachedProperties { + typedef int yes_type; + typedef char no_type; + + template<typename S, QObject *(S::*)(QObject *)> + struct dummy {}; + + template<typename S, QObject *(S::*)(QObject *) const> + struct dummy_const {}; + + template<typename S, QObject *(*) (QObject *)> + struct dummy_static {}; + + template<typename S> + static no_type check(dummy<S, &S::qmlAttachedProperties> *); + + template<typename S> + static no_type check(dummy_const<S, &S::qmlAttachedProperties> *); + + template<typename S> + static yes_type check(dummy_static<S, &S::qmlAttachedProperties> *); + + template<typename S> + static no_type check(...); + + public: + static bool const value = sizeof(check<T>(0)) == sizeof(yes_type); + }; + + template<typename T> + inline QmlAttachedPropertiesFunc attachedPropertiesFunc() + { + return AttachedPropertySelector<T, has_attachedProperties<T>::value>::func(); + } + + struct MetaTypeIds { + int typeId; + int listId; + int qmlListId; + }; + typedef int (*Func)(QmlPrivate::ListOp, int, const QVariant &, const QVariant &, void **); + typedef QObject *(*CreateFunc)(QObject *); + + template<typename T> + struct CreateParent { + static QObject *create(QObject *other) { + return new T(other); + } + }; + + template<typename T> + struct CreateNoParent { + static QObject *create() { + return new T; + } + }; + + struct Q_DECLARATIVE_EXPORT InstanceType { + InstanceType(int); + }; + + template<typename T> + struct Define { + static InstanceType instance; + }; + + template<typename T> + struct ExtCreate { + static QObject *create(QObject *other) { + return new T(other); + } + }; +}; + +template<typename T> +int QmlPrivate::list_op(QmlPrivate::ListOp op, int val, + const QVariant &vlist, + const QVariant &value, + void **out) +{ + if(op == QmlPrivate::Create) { + QObject *obj = static_cast<QObject *>(new T); + *((QObject **)out) = obj; + return 0; + } + QList<T *> *list = vlist.value<QList<T *> *>(); + switch(op) { + case QmlPrivate::Append: + list->append(value.value<T *>()); + break; + case QmlPrivate::Set: + (*list)[val] = value.value<T *>(); + break; + case QmlPrivate::Insert: + list->insert(val, value.value<T *>()); + break; + case QmlPrivate::Prepend: + list->prepend(value.value<T *>()); + break; + case QmlPrivate::Length: + return list->count(); + break; + case QmlPrivate::Clear: + list->clear(); + return 0; + break; + case QmlPrivate::Create: + break; + case QmlPrivate::Object: + *out = static_cast<QObject *>(value.value<T *>()); + break; + case QmlPrivate::FromObject: + { + QObject *fromObj = value.value<QObject *>(); + T *me = qobject_cast<T *>(fromObj); + if(me) { + *((QVariant *)*out) = QVariant::fromValue(me); + } + } + break; + case QmlPrivate::Value: + *((QVariant *)*out) = QVariant::fromValue(list->at(val)); + break; + } + return 0; +} + +template<typename T> +int QmlPrivate::list_nocreate_op(QmlPrivate::ListOp op, int val, + const QVariant &vlist, + const QVariant &value, + void **out) +{ + QList<T *> *list = vlist.value<QList<T *> *>(); + switch(op) { + case QmlPrivate::Append: + list->append(value.value<T *>()); + break; + case QmlPrivate::Set: + (*list)[val] = value.value<T *>(); + break; + case QmlPrivate::Insert: + list->insert(val, value.value<T *>()); + break; + case QmlPrivate::Prepend: + list->prepend(value.value<T *>()); + break; + case QmlPrivate::Length: + return list->count(); + break; + case QmlPrivate::Clear: + list->clear(); + return 0; + break; + case QmlPrivate::Create: + break; + case QmlPrivate::Object: + *out = static_cast<QObject *>(value.value<T *>()); + break; + case QmlPrivate::FromObject: + { + QObject *fromObj = value.value<QObject *>(); + T *me = qobject_cast<T *>(fromObj); + if(me) { + *((QVariant *)*out) = QVariant::fromValue(me); + } + } + break; + case QmlPrivate::Value: + *((QVariant *)*out) = QVariant::fromValue(list->at(val)); + break; + } + return 0; +} + +template<typename T> +int QmlPrivate::list_interface_op(QmlPrivate::ListOp op, int val, + const QVariant &vlist, + const QVariant &value, + void **out) +{ + QList<T *> *list = vlist.value<QList<T *> *>(); + switch(op) { + case QmlPrivate::Append: + list->append(value.value<T *>()); + break; + case QmlPrivate::Set: + (*list)[val] = value.value<T *>(); + break; + case QmlPrivate::Insert: + list->insert(val, value.value<T *>()); + break; + case QmlPrivate::Prepend: + list->prepend(value.value<T *>()); + break; + case QmlPrivate::Length: + return list->count(); + break; + case QmlPrivate::Clear: + list->clear(); + return 0; + break; + case QmlPrivate::Create: + break; + case QmlPrivate::Object: + break; + case QmlPrivate::FromObject: + break; + case QmlPrivate::Value: + *((QVariant *)*out) = QVariant::fromValue(list->at(val)); + break; + } + return 0; +} + + +#endif // QMLPRIVATE_H + + +QT_END_NAMESPACE + +QT_END_HEADER diff --git a/src/declarative/qml/qmlpropertyvaluesource.cpp b/src/declarative/qml/qmlpropertyvaluesource.cpp new file mode 100644 index 0000000..78b0495 --- /dev/null +++ b/src/declarative/qml/qmlpropertyvaluesource.cpp @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmlpropertyvaluesource.h" +#include "qml.h" + + +QT_BEGIN_NAMESPACE +/*! + \class QmlPropertyValueSource + \brief The QmlPropertyValueSource class is inherited by property value sources such as animations and bindings. + */ +QML_DEFINE_NOCREATE_TYPE(QmlPropertyValueSource); + +QmlPropertyValueSource::QmlPropertyValueSource(QObject *parent) + : QObject(parent) + +{ +} + +QmlPropertyValueSource::QmlPropertyValueSource(QObjectPrivate &dd, QObject *parent) + : QObject(dd, parent) +{ +} + +/*! + Set the target \a property for the value source. This method will be called + by the QML engine when assigning a value source. + + The default implementation does nothing. +*/ +void QmlPropertyValueSource::setTarget(const QmlMetaProperty &property) +{ + Q_UNUSED(property); +} + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlpropertyvaluesource.h b/src/declarative/qml/qmlpropertyvaluesource.h new file mode 100644 index 0000000..6ef2e38 --- /dev/null +++ b/src/declarative/qml/qmlpropertyvaluesource.h @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLPROPERTYVALUESOURCE_H +#define QMLPROPERTYVALUESOURCE_H + +#include <qfxglobal.h> +#include <qml.h> +#include <QObject> + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) +class QObjectPrivate; +class QmlMetaProperty; +class Q_DECLARATIVE_EXPORT QmlPropertyValueSource : public QObject +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QObject) + +public: + QmlPropertyValueSource(QObject *parent); + virtual void setTarget(const QmlMetaProperty &); + +protected: + QmlPropertyValueSource(QObjectPrivate &dd, QObject *parent); + +private: + Q_DISABLE_COPY(QmlPropertyValueSource) +}; +QML_DECLARE_TYPE(QmlPropertyValueSource); + +#endif // QMLPROPERTYVALUESOURCE_H + + +QT_END_NAMESPACE + +QT_END_HEADER diff --git a/src/declarative/qml/qmlproxymetaobject.cpp b/src/declarative/qml/qmlproxymetaobject.cpp new file mode 100644 index 0000000..3b9f6ca --- /dev/null +++ b/src/declarative/qml/qmlproxymetaobject.cpp @@ -0,0 +1,113 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmlproxymetaobject_p.h" + + +QT_BEGIN_NAMESPACE +QmlProxyMetaObject::QmlProxyMetaObject(QObject *obj, QList<ProxyData> *mList) +: metaObjects(mList), proxies(0), parent(0), object(obj) +{ +#ifdef QMLPROXYMETAOBJECT_DEBUG + qWarning() << "QmlProxyMetaObject" << obj->metaObject()->className(); +#endif + + *static_cast<QMetaObject *>(this) = *metaObjects->last().metaObject; + + QObjectPrivate *op = QObjectPrivate::get(obj); + if(op->metaObject) + parent = static_cast<QAbstractDynamicMetaObject*>(op->metaObject); + + op->metaObject = this; + +#ifdef QMLPROXYMETAOBJECT_DEBUG + const QMetaObject *mo = obj->metaObject(); + while(mo) { + qWarning() << " " << mo->className(); + mo = mo->superClass(); + } +#endif +} + +QmlProxyMetaObject::~QmlProxyMetaObject() +{ + if(parent) + delete parent; + parent = 0; + + if(proxies) + delete [] proxies; + proxies = 0; +} + +int QmlProxyMetaObject::metaCall(QMetaObject::Call c, int id, void **a) +{ + if((c == QMetaObject::ReadProperty || + c == QMetaObject::WriteProperty) && + id >= metaObjects->last().propertyOffset) { + + for(int ii = 0; ii < metaObjects->count(); ++ii) { + const ProxyData &data = metaObjects->at(ii); + if(id >= data.propertyOffset) { + if(!proxies) { + proxies = new QObject*[metaObjects->count()]; + ::memset(proxies, 0, + sizeof(QObject *) * metaObjects->count()); + } + + if(!proxies[ii]) + proxies[ii] = data.createFunc(object); + + int proxyOffset = proxies[ii]->metaObject()->propertyOffset(); + int proxyId = id - data.propertyOffset + proxyOffset; + + return proxies[ii]->qt_metacall(c, proxyId, a); + } + } + } + + if(parent) + return parent->metaCall(c, id, a); + else + return object->qt_metacall(c, id, a); +} + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlproxymetaobject_p.h b/src/declarative/qml/qmlproxymetaobject_p.h new file mode 100644 index 0000000..594e7a3 --- /dev/null +++ b/src/declarative/qml/qmlproxymetaobject_p.h @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLPROXYMETAOBJECT_P_H +#define QMLPROXYMETAOBJECT_P_H + +#include <QMetaObject> +#include <private/qmetaobjectbuilder_p.h> +#include <private/qobject_p.h> +#include <QObject> +#include <qml.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) +class QmlProxyMetaObject : public QAbstractDynamicMetaObject +{ +public: + struct ProxyData { + typedef QObject *(*CreateFunc)(QObject *); + QMetaObject *metaObject; + CreateFunc createFunc; + int propertyOffset; + }; + + QmlProxyMetaObject(QObject *, QList<ProxyData> *); + virtual ~QmlProxyMetaObject(); + +protected: + virtual int metaCall(QMetaObject::Call _c, int _id, void **_a); + +private: + QList<ProxyData> *metaObjects; + QObject **proxies; + + QAbstractDynamicMetaObject *parent; + QObject *object; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QMLPROXYMETAOBJECT_P_H + diff --git a/src/declarative/qml/qmlrefcount.cpp b/src/declarative/qml/qmlrefcount.cpp new file mode 100644 index 0000000..4e47ee1 --- /dev/null +++ b/src/declarative/qml/qmlrefcount.cpp @@ -0,0 +1,66 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmlrefcount_p.h" + +QmlRefCount::QmlRefCount() +: refCount(1) +{ +} + +QmlRefCount::~QmlRefCount() +{ +} + +void QmlRefCount::addref() +{ + Q_ASSERT(refCount > 0); + ++refCount; +} + +void QmlRefCount::release() +{ + Q_ASSERT(refCount > 0); + --refCount; + if(refCount == 0) + delete this; +} + diff --git a/src/declarative/qml/qmlrefcount_p.h b/src/declarative/qml/qmlrefcount_p.h new file mode 100644 index 0000000..90b50a8 --- /dev/null +++ b/src/declarative/qml/qmlrefcount_p.h @@ -0,0 +1,69 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLREFCOUNT_P_H +#define QMLREFCOUNT_P_H + +#include <qglobal.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +class QmlRefCount +{ +public: + QmlRefCount(); + virtual ~QmlRefCount(); + void addref(); + void release(); + +private: + int refCount; +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QMLREFCOUNT_P_H diff --git a/src/declarative/qml/qmlstringconverters.cpp b/src/declarative/qml/qmlstringconverters.cpp new file mode 100644 index 0000000..82d6eee --- /dev/null +++ b/src/declarative/qml/qmlstringconverters.cpp @@ -0,0 +1,212 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtGui/qcolor.h> +#include <QtCore/qpoint.h> +#include <QtCore/qrect.h> +#include <QtCore/qsize.h> +#include <QtCore/qvariant.h> +#include "qmlstringconverters_p.h" + +QT_BEGIN_NAMESPACE + +static uchar fromHex(const uchar c, const uchar c2) +{ + uchar rv = 0; + if(c >= '0' && c <= '9') + rv += (c - '0') * 16; + else if(c >= 'A' && c <= 'F') + rv += (c - 'A' + 10) * 16; + else if(c >= 'a' && c <= 'f') + rv += (c - 'a' + 10) * 16; + + if(c2 >= '0' && c2 <= '9') + rv += (c2 - '0'); + else if(c2 >= 'A' && c2 <= 'F') + rv += (c2 - 'A' + 10); + else if(c2 >= 'a' && c2 <= 'f') + rv += (c2 - 'a' + 10); + + return rv; +} + +static uchar fromHex(const QString &s, int idx) +{ + uchar c = s.at(idx).toAscii(); + uchar c2 = s.at(idx + 1).toAscii(); + return fromHex(c, c2); +} + +QVariant QmlStringConverters::variantFromString(const QString &s) +{ + if(s.isEmpty()) + return QVariant(s); + if(s.startsWith(QLatin1Char('\'')) && s.endsWith(QLatin1Char('\''))) { + QString data = s.mid(1, s.length() - 2); + return QVariant(data); + } + bool ok = false; + QRectF r = rectFFromString(s, &ok); + if(ok) return QVariant(r); + QColor c = colorFromString(s, &ok); + if(ok) return QVariant(c); + QPointF p = pointFFromString(s, &ok); + if(ok) return QVariant(p); + QSizeF sz = sizeFFromString(s, &ok); + if(ok) return QVariant(sz); + bool b = boolFromString(s, &ok); + if(ok) return QVariant(b); + + return QVariant(s); +} + +QColor QmlStringConverters::colorFromString(const QString &s, bool *ok) +{ + if(s.startsWith(QLatin1Char('#')) && s.length() == 9) { + uchar a = fromHex(s, 1); + uchar r = fromHex(s, 3); + uchar g = fromHex(s, 5); + uchar b = fromHex(s, 7); + if(ok) *ok = true; + return QColor(r, g, b, a); + } else { + QColor rv; + if(s.startsWith(QLatin1Char('#')) || QColor::colorNames().contains(s.toLower())) + rv = QColor(s); + if(ok) *ok = rv.isValid(); + return rv; + } +} + +//expects input of "x,y" +QPointF QmlStringConverters::pointFFromString(const QString &s, bool *ok) +{ + if (s.count(QLatin1Char(',')) != 1) { + if (ok) + *ok = false; + return QPointF(); + } + + bool xGood, yGood; + int index = s.indexOf(QLatin1Char(',')); + qreal xCoord = s.left(index).toDouble(&xGood); + qreal yCoord = s.mid(index+1).toDouble(&yGood); + if (!xGood || !yGood) { + if (ok) + *ok = false; + return QPointF(); + } + + if (ok) + *ok = true; + return QPointF(xCoord, yCoord); +} + +//expects input of "widthxheight" +QSizeF QmlStringConverters::sizeFFromString(const QString &s, bool *ok) +{ + if (s.count(QLatin1Char('x')) != 1) { + if (ok) + *ok = false; + return QSizeF(); + } + + bool wGood, hGood; + int index = s.indexOf(QLatin1Char('x')); + qreal width = s.left(index).toDouble(&wGood); + qreal height = s.mid(index+1).toDouble(&hGood); + if (!wGood || !hGood) { + if (ok) + *ok = false; + return QSizeF(); + } + + if (ok) + *ok = true; + return QSizeF(width, height); +} + +//expects input of "x,y,widthxheight" //### use space instead of second comma? +QRectF QmlStringConverters::rectFFromString(const QString &s, bool *ok) +{ + if (s.count(QLatin1Char(',')) != 2 || s.count(QLatin1Char('x')) != 1) { + if (ok) + *ok = false; + return QRectF(); + } + + bool xGood, yGood, wGood, hGood; + int index = s.indexOf(QLatin1Char(',')); + qreal x = s.left(index).toDouble(&xGood); + int index2 = s.indexOf(QLatin1Char(','), index+1); + qreal y = s.mid(index+1, index2-index-1).toDouble(&yGood); + index = s.indexOf(QLatin1Char('x'), index2+1); + qreal width = s.mid(index2+1, index-index2-1).toDouble(&wGood); + qreal height = s.mid(index+1).toDouble(&hGood); + if (!xGood || !yGood || !wGood || !hGood) { + if (ok) + *ok = false; + return QRectF(); + } + + if (ok) + *ok = true; + return QRectF(x, y, width, height); +} + +bool QmlStringConverters::boolFromString(const QString &str, bool *ok) +{ + if (str.isEmpty() || str == QLatin1String("false") || str == QLatin1String("0")) { + if (ok) + *ok = true; + return false; + } else if (str == QLatin1String("true") || str == QLatin1String("1")) { + if (ok) + *ok = true; + return true; + } + + if (ok) + *ok = false; + return true; +} + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlstringconverters_p.h b/src/declarative/qml/qmlstringconverters_p.h new file mode 100644 index 0000000..ed1f959 --- /dev/null +++ b/src/declarative/qml/qmlstringconverters_p.h @@ -0,0 +1,68 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLSTRINGCONVERTERS_P_H +#define QMLSTRINGCONVERTERS_P_H + +#include <QtCore/qglobal.h> +class QColor; +class QPointF; +class QSizeF; +class QRectF; +class QString; +class QByteArray; + +QT_BEGIN_NAMESPACE + +// XXX - Bauhaus currently uses these methods which is why they're exported +namespace QmlStringConverters +{ + QVariant Q_DECLARATIVE_EXPORT variantFromString(const QString &); + QColor Q_DECLARATIVE_EXPORT colorFromString(const QString &, bool *ok = 0); + QPointF Q_DECLARATIVE_EXPORT pointFFromString(const QString &, bool *ok = 0); + QSizeF Q_DECLARATIVE_EXPORT sizeFFromString(const QString &, bool *ok = 0); + QRectF Q_DECLARATIVE_EXPORT rectFFromString(const QString &, bool *ok = 0); + bool Q_DECLARATIVE_EXPORT boolFromString(const QString &, bool *ok = 0); +}; + +QT_END_NAMESPACE + +#endif // QMLSTRINGCONVERTERS_P_H diff --git a/src/declarative/qml/qmlvme.cpp b/src/declarative/qml/qmlvme.cpp new file mode 100644 index 0000000..966ef8a --- /dev/null +++ b/src/declarative/qml/qmlvme.cpp @@ -0,0 +1,1345 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmlvme_p.h" +#include <qfxperf.h> +#include <private/qmlboundsignal_p.h> +#include <private/qmlstringconverters_p.h> +#include "private/qmetaobjectbuilder_p.h" +#include <qml.h> +#include <qmlcustomparser.h> +#include <qperformancelog.h> +#include <QStack> +#include <private/qmlcompiledcomponent_p.h> +#include <QColor> +#include <QPointF> +#include <QSizeF> +#include <QRectF> +#include <qmlengine.h> +#include <qmlcontext.h> +#include <qmlcomponent.h> +#include <qmlbindablevalue.h> +#include <private/qmlengine_p.h> +#include <private/qmlcomponent_p.h> +#include "private/qmlvmemetaobject_p.h" +#include <QtCore/qdebug.h> + +QT_BEGIN_NAMESPACE +Q_DECLARE_PERFORMANCE_LOG(QFxCompiler) { + Q_DECLARE_PERFORMANCE_METRIC(InstrCreateObject); + Q_DECLARE_PERFORMANCE_METRIC(InstrCreateCustomObject); + Q_DECLARE_PERFORMANCE_METRIC(InstrSetId); + Q_DECLARE_PERFORMANCE_METRIC(InstrSetDefault); + Q_DECLARE_PERFORMANCE_METRIC(InstrCreateComponent); + Q_DECLARE_PERFORMANCE_METRIC(InstrStoreMetaObject); + Q_DECLARE_PERFORMANCE_METRIC(InstrStoreReal); + Q_DECLARE_PERFORMANCE_METRIC(InstrStoreInteger); + Q_DECLARE_PERFORMANCE_METRIC(InstrStoreBool); + Q_DECLARE_PERFORMANCE_METRIC(InstrStoreString); + Q_DECLARE_PERFORMANCE_METRIC(InstrStoreColor); + Q_DECLARE_PERFORMANCE_METRIC(InstrStoreDate); + Q_DECLARE_PERFORMANCE_METRIC(InstrStoreDateTime); + Q_DECLARE_PERFORMANCE_METRIC(InstrStoreTime); + Q_DECLARE_PERFORMANCE_METRIC(InstrStorePoint); + Q_DECLARE_PERFORMANCE_METRIC(InstrStoreSize); + Q_DECLARE_PERFORMANCE_METRIC(InstrStoreVariant); + Q_DECLARE_PERFORMANCE_METRIC(InstrStoreObject); + Q_DECLARE_PERFORMANCE_METRIC(InstrStoreSignal); + Q_DECLARE_PERFORMANCE_METRIC(InstrStoreObjectQmlList); + Q_DECLARE_PERFORMANCE_METRIC(InstrAssignConstant); + Q_DECLARE_PERFORMANCE_METRIC(InstrAssignSignal); + Q_DECLARE_PERFORMANCE_METRIC(InstrAssignSignalObject); + Q_DECLARE_PERFORMANCE_METRIC(InstrAssignBinding); + Q_DECLARE_PERFORMANCE_METRIC(InstrAssignCompiledBinding); + Q_DECLARE_PERFORMANCE_METRIC(InstrAssignValueSource); + Q_DECLARE_PERFORMANCE_METRIC(InstrStoreBinding); + Q_DECLARE_PERFORMANCE_METRIC(InstrStoreCompiledBinding); + Q_DECLARE_PERFORMANCE_METRIC(InstrStoreValueSource); + Q_DECLARE_PERFORMANCE_METRIC(InstrTryBeginObject); + Q_DECLARE_PERFORMANCE_METRIC(InstrBeginObject); + Q_DECLARE_PERFORMANCE_METRIC(InstrTryCompleteObject); + Q_DECLARE_PERFORMANCE_METRIC(InstrCompleteObject); + Q_DECLARE_PERFORMANCE_METRIC(InstrAssignObject); + Q_DECLARE_PERFORMANCE_METRIC(InstrAssignObjectList); + Q_DECLARE_PERFORMANCE_METRIC(InstrFetchAttached); + Q_DECLARE_PERFORMANCE_METRIC(InstrFetchQmlList); + Q_DECLARE_PERFORMANCE_METRIC(InstrFetchQList); + Q_DECLARE_PERFORMANCE_METRIC(InstrFetchObject); + Q_DECLARE_PERFORMANCE_METRIC(InstrResolveFetchObject); + Q_DECLARE_PERFORMANCE_METRIC(InstrPopFetchedObject); + Q_DECLARE_PERFORMANCE_METRIC(InstrPopQList); + Q_DECLARE_PERFORMANCE_METRIC(InstrPushProperty); + Q_DECLARE_PERFORMANCE_METRIC(InstrAssignStackObject); + Q_DECLARE_PERFORMANCE_METRIC(InstrStoreStackObject); + Q_DECLARE_PERFORMANCE_METRIC(InstrNoOp); + Q_DECLARE_PERFORMANCE_METRIC(Dummy); +} + +Q_DEFINE_PERFORMANCE_LOG(QFxCompiler, "QFxCompiler") { + Q_DEFINE_PERFORMANCE_METRIC(InstrCreateObject, "CreateObject"); + Q_DEFINE_PERFORMANCE_METRIC(InstrCreateCustomObject, "CreateCustomObject"); + Q_DEFINE_PERFORMANCE_METRIC(InstrSetId, "SetId"); + Q_DEFINE_PERFORMANCE_METRIC(InstrSetDefault, "SetDefault"); + Q_DEFINE_PERFORMANCE_METRIC(InstrCreateComponent, "CreateComponent"); + Q_DEFINE_PERFORMANCE_METRIC(InstrStoreMetaObject, "StoreMetaObject"); + Q_DEFINE_PERFORMANCE_METRIC(InstrStoreReal, "StoreReal"); + Q_DEFINE_PERFORMANCE_METRIC(InstrStoreInteger, "StoreInteger"); + Q_DEFINE_PERFORMANCE_METRIC(InstrStoreBool, "StoreBool"); + Q_DEFINE_PERFORMANCE_METRIC(InstrStoreString, "StoreString"); + Q_DEFINE_PERFORMANCE_METRIC(InstrStoreColor, "StoreColor"); + Q_DEFINE_PERFORMANCE_METRIC(InstrStoreDate, "StoreDate"); + Q_DEFINE_PERFORMANCE_METRIC(InstrStoreDateTime, "StoreDateTime"); + Q_DEFINE_PERFORMANCE_METRIC(InstrStoreTime, "StoreTime"); + Q_DEFINE_PERFORMANCE_METRIC(InstrStorePoint, "StorePoint(F)"); + Q_DEFINE_PERFORMANCE_METRIC(InstrStoreSize, "StoreSize(F)"); + Q_DEFINE_PERFORMANCE_METRIC(InstrStoreVariant, "StoreVariant"); + Q_DEFINE_PERFORMANCE_METRIC(InstrStoreObject, "StoreObject"); + Q_DEFINE_PERFORMANCE_METRIC(InstrStoreSignal, "StoreSignal"); + Q_DEFINE_PERFORMANCE_METRIC(InstrStoreObjectQmlList, "StoreObjectQmlList"); + Q_DEFINE_PERFORMANCE_METRIC(InstrAssignConstant, "AssignConstant"); + Q_DEFINE_PERFORMANCE_METRIC(InstrAssignSignal, "AssignSignal"); + Q_DEFINE_PERFORMANCE_METRIC(InstrAssignSignalObject, "AssignSignalObject"); + Q_DEFINE_PERFORMANCE_METRIC(InstrAssignBinding, "AssignBinding"); + Q_DEFINE_PERFORMANCE_METRIC(InstrAssignCompiledBinding, "AssignCompiledBinding"); + Q_DEFINE_PERFORMANCE_METRIC(InstrAssignValueSource, "AssignValueSource"); + Q_DEFINE_PERFORMANCE_METRIC(InstrStoreBinding, "StoreBinding"); + Q_DEFINE_PERFORMANCE_METRIC(InstrStoreCompiledBinding, "StoreCompiledBinding"); + Q_DEFINE_PERFORMANCE_METRIC(InstrStoreValueSource, "StoreValueSource"); + Q_DEFINE_PERFORMANCE_METRIC(InstrTryBeginObject, "TryBeginObject"); + Q_DEFINE_PERFORMANCE_METRIC(InstrBeginObject, "BeginObject"); + Q_DEFINE_PERFORMANCE_METRIC(InstrTryCompleteObject, "TryCompleteObject"); + Q_DEFINE_PERFORMANCE_METRIC(InstrCompleteObject, "CompleteObject"); + Q_DEFINE_PERFORMANCE_METRIC(InstrAssignObject, "AssignObject"); + Q_DEFINE_PERFORMANCE_METRIC(InstrAssignObjectList, "AssignObjectList"); + Q_DEFINE_PERFORMANCE_METRIC(InstrFetchAttached, "FetchAttached"); + Q_DEFINE_PERFORMANCE_METRIC(InstrFetchQmlList, "FetchQmlList"); + Q_DEFINE_PERFORMANCE_METRIC(InstrFetchQList, "FetchQList"); + Q_DEFINE_PERFORMANCE_METRIC(InstrFetchObject, "FetchObject"); + Q_DEFINE_PERFORMANCE_METRIC(InstrResolveFetchObject, "ResolveFetchObject"); + Q_DEFINE_PERFORMANCE_METRIC(InstrPopFetchedObject, "PopFetchedObject"); + Q_DEFINE_PERFORMANCE_METRIC(InstrPopQList, "PopQList"); + Q_DEFINE_PERFORMANCE_METRIC(InstrPushProperty, "PushProperty"); + Q_DEFINE_PERFORMANCE_METRIC(InstrAssignStackObject, "AssignStackObject"); + Q_DEFINE_PERFORMANCE_METRIC(InstrStoreStackObject, "StoreStackObject"); + Q_DEFINE_PERFORMANCE_METRIC(InstrNoOp, "NoOp"); + Q_DEFINE_PERFORMANCE_METRIC(Dummy, "Dummy"); +} + +static inline int qIndexOfProperty(QObject *o, const char *name) +{ + int idx = o->metaObject()->indexOfProperty(name); + return idx; +} + +QmlVME::QmlVME() +: exceptionLine(-1) +{ +} + +#define VME_EXCEPTION(desc) \ + { \ + exceptionLine = instr.line; \ + QDebug d(&exceptionDescription); \ + d << desc; \ + break; \ + } + +struct ListInstance +{ + ListInstance() {} + ListInstance(const QVariant &l, int t) + : list(l), type(t), qmlListInterface(0) {} + ListInstance(QmlPrivate::ListInterface *q, int t) + : type(t), qmlListInterface(q) {} + + QVariant list; + int type; + QmlPrivate::ListInterface *qmlListInterface; +}; + +QObject *QmlVME::run(QmlContext *ctxt, QmlCompiledComponent *comp, int start, int count) +{ + // XXX - All instances of QmlContext::activeContext() here should be + // replaced with the use of ctxt. However, this cannot be done until + // behaviours stop modifying the active context and expecting the + // instantiation to notice. Instead, QmlParserStatus::beginClass() should + // be able to return a QmlContext that is used for expressions and + // sub-instances on that type. + Q_ASSERT(comp); + Q_ASSERT(ctxt); + const QList<QmlCompiledComponent::TypeReference> &types = comp->types; + const QList<QString> &primitives = comp->primitives; + const QList<QByteArray> &datas = comp->datas; + const QList<QMetaObject *> &mos = comp->mos; + const QList<QmlCompiledData::CustomTypeData> &customTypeData = comp->customTypeData; + +#ifdef Q_ENABLE_PERFORMANCE_LOG + QFxPerfTimer<QFxPerf::CompileRun> cr; +#endif + + QList<QmlParserStatus *> parserStatuses; + QList<QmlBindableValue *> bindableValues; + + QStack<QObject *> stack; + QStack<ListInstance> qliststack; + + QStack<QmlMetaProperty> pushedProperties; + QObject **savedObjects = 0; + + if(start == -1) start = 0; + if(count == -1) count = comp->bytecode.count(); + + for(int ii = start; !isError() && ii < (start + count); ++ii) { + QmlInstruction &instr = comp->bytecode[ii]; + + if(instr.type >= QmlInstruction::StoreInstructionsStart && + instr.type <= QmlInstruction::StoreInstructionsEnd) { + + runStoreInstruction(stack, instr, comp); + + } else { + + switch(instr.type) { + case QmlInstruction::Init: + { + if(instr.init.dataSize) { + savedObjects = new QObject*[instr.init.dataSize]; + ::memset(savedObjects, 0, + sizeof(QObject *)*instr.init.dataSize); + } + } + break; + + case QmlInstruction::CreateObject: + { +#ifdef Q_ENABLE_PERFORMANCE_LOG + QFxCompilerTimer<QFxCompiler::InstrCreateObject> cc; +#endif + QObject *o = types.at(instr.create.type).createInstance(); + if(!o) + VME_EXCEPTION("Unable to create object of type" << types.at(instr.create.type).className); + + if(!stack.isEmpty()) { + QObject *parent = stack.top(); + o->setParent(parent); + } + stack.push(o); + } + break; + + case QmlInstruction::CreateCustomObject: + { +#ifdef Q_ENABLE_PERFORMANCE_LOG + QFxCompilerTimer<QFxCompiler::InstrCreateCustomObject> cc; +#endif + QVariant v = + types.at(instr.createCustom.type).parser->create(datas.at(instr.createCustom.data)); + // XXX + QObject *o = QmlMetaType::toQObject(v); + if(!o) + VME_EXCEPTION("Unable to create" << types.at(instr.create.type).className); + + if(!stack.isEmpty()) { + QObject *parent = stack.top(); + o->setParent(parent); + } + stack.push(o); + } + break; + + case QmlInstruction::SetId: + { +#ifdef Q_ENABLE_PERFORMANCE_LOG + QFxCompilerTimer<QFxCompiler::InstrSetId> cc; +#endif + QObject *target = stack.top(); + QmlContext *ctxt = + QmlContext::activeContext(); + ctxt->setContextProperty(primitives.at(instr.setId.value), target); + + if(instr.setId.save != -1) + savedObjects[instr.setId.save] = target; + } + break; + + + case QmlInstruction::SetDefault: + { +#ifdef Q_ENABLE_PERFORMANCE_LOG + QFxCompilerTimer<QFxCompiler::InstrSetDefault> cc; +#endif + QObject *target = stack.top(); + QmlContext::activeContext()->addDefaultObject(target); + } + break; + + case QmlInstruction::CreateComponent: + { +#ifdef Q_ENABLE_PERFORMANCE_LOG + QFxCompilerTimer<QFxCompiler::InstrCreateComponent> cc; +#endif + QObject *qcomp = new QmlComponent(ctxt->engine(), comp, ii + 1, instr.createComponent.count, stack.isEmpty() ? 0 : stack.top()); + stack.push(qcomp); + ii += instr.createComponent.count; + } + break; + + case QmlInstruction::StoreMetaObject: + { +#ifdef Q_ENABLE_PERFORMANCE_LOG + QFxCompilerTimer<QFxCompiler::InstrStoreMetaObject> cc; +#endif + QObject *target = stack.top(); + new QmlVMEMetaObject(target, mos.at(instr.storeMeta.data), comp); + } + break; + + case QmlInstruction::AssignCustomType: + { + QObject *target = stack.top(); + void *a[1]; + QmlCompiledComponent::CustomTypeData data = customTypeData.at(instr.assignCustomType.valueIndex); + const QString &primitive = primitives.at(data.index); + QmlMetaType::StringConverter converter = + QmlMetaType::customStringConverter(data.type); + QVariant v = (*converter)(primitive); + + QMetaProperty prop = + target->metaObject()->property(instr.assignCustomType.propertyIndex); + if (v.isNull() || ((int)prop.type() != data.type && prop.userType() != data.type)) + VME_EXCEPTION("Cannot assign value" << primitive << "to property" << prop.name()); + + a[0] = (void *)v.data(); + QMetaObject::metacall(target, QMetaObject::WriteProperty, + instr.assignCustomType.propertyIndex, a); + } + break; + + case QmlInstruction::AssignSignal: + { +#ifdef Q_ENABLE_PERFORMANCE_LOG + QFxCompilerTimer<QFxCompiler::InstrAssignSignal> cc; +#endif + // Fixup instruction + QObject *target = stack.top(); + int sigIdx = instr.assignSignal.signal; + const QByteArray &pr = datas.at(sigIdx); + + QmlMetaProperty prop(target, QLatin1String(pr)); + if(prop.type() & QmlMetaProperty::SignalProperty) { + int coreIdx = prop.coreIndex(); + int primRef = instr.assignSignal.value; + instr.type = QmlInstruction::StoreSignal; + instr.storeSignal.signalIndex = coreIdx; + instr.storeSignal.value = primRef; + --ii; + } else if(prop.type() & QmlMetaProperty::Property) { + int prop = sigIdx; + int primRef = instr.assignSignal.value; + instr.type = QmlInstruction::AssignConstant; + instr.assignConstant.property = prop; + instr.assignConstant.constant = primRef; + --ii; + } else { + VME_EXCEPTION("Cannot assign a signal to property" << pr); + } + } + break; + + case QmlInstruction::AssignSignalObject: + { +#ifdef Q_ENABLE_PERFORMANCE_LOG + QFxCompilerTimer<QFxCompiler::InstrAssignSignalObject> cc; +#endif + // XXX optimize + + QObject *assign = stack.pop(); + QObject *target = stack.top(); + int sigIdx = instr.assignSignalObject.signal; + const QByteArray &pr = datas.at(sigIdx); + + QmlMetaProperty prop(target, QLatin1String(pr)); + if(prop.type() & QmlMetaProperty::SignalProperty) { + + QMetaMethod method = QmlMetaType::defaultMethod(assign); + if(method.signature() == 0) + VME_EXCEPTION("Cannot assign object type" << assign->metaObject()->className() << "with no default method"); + + if(!QMetaObject::checkConnectArgs(prop.method().signature(), method.signature())) + VME_EXCEPTION("Cannot connect mismatched signal/slot" << method.signature() << prop.method().signature()); + + QMetaObject::connect(target, prop.coreIndex(), assign, method.methodIndex()); + + } else if(prop.type() & QmlMetaProperty::Property) { + instr.type = QmlInstruction::AssignObject; + instr.assignObject.castValue = 0; + instr.assignObject.property = sigIdx; + --ii; + } else { + VME_EXCEPTION("Cannot assign an object to signal property" << pr); + } + + + } + break; + + case QmlInstruction::StoreSignal: + { +#ifdef Q_ENABLE_PERFORMANCE_LOG + QFxCompilerTimer<QFxCompiler::InstrStoreSignal> cc; +#endif + QObject *target = stack.top(); + // XXX scope + QMetaMethod signal = + target->metaObject()->method(instr.storeSignal.signalIndex); + + if(signal.parameterTypes().isEmpty()) { + (void *)new QmlBoundSignal(QmlContext::activeContext(), primitives.at(instr.storeSignal.value), target, instr.storeSignal.signalIndex, target); + } else { + (void *)new QmlBoundSignalProxy(new QmlContext(QmlContext::activeContext(), target), primitives.at(instr.storeSignal.value), target, instr.storeSignal.signalIndex, target); + } + } + break; + + case QmlInstruction::AssignConstant: + { +#ifdef Q_ENABLE_PERFORMANCE_LOG + QFxCompilerTimer<QFxCompiler::InstrAssignConstant> cc; +#endif + // Fixup instruction + QObject *target = stack.top(); + int propIdx = instr.assignConstant.property; + int idx = instr.assignConstant.constant; + QByteArray pr; + if(propIdx == -1) { + pr = QmlMetaType::defaultProperty(target).name(); + if(pr.isEmpty()) + VME_EXCEPTION("Cannot resolve defalt property on type" << target->metaObject()->className()); + } else { + pr = datas.at(propIdx); + } + + int coreIdx = qIndexOfProperty(target, pr); + + if(coreIdx != -1) { + QMetaProperty prop = + target->metaObject()->property(coreIdx); + bool replace = !prop.isDynamic(); + + QmlInstruction *writeInstr = 0; + QmlInstruction dummy; + if(replace) { + writeInstr = &instr; + } else { + writeInstr = &dummy; + dummy = instr; + } + + QmlCompiler::StoreInstructionResult r = QmlCompiler::generateStoreInstruction(*comp, *writeInstr, prop, + coreIdx, idx, &primitives.at(idx)); + if(r != QmlCompiler::Ok) { + if(prop.isEnumType()){ + VME_EXCEPTION(primitives.at(idx) << "is not a valid enumeration value"); + } else if (r == QmlCompiler::UnknownType) { + VME_EXCEPTION("Property" << prop.name() << "is of an unknown type"); + } else if (r == QmlCompiler::InvalidData) { + VME_EXCEPTION("Cannot assign value" << primitives.at(idx) << "to property" << prop.name()); + } else if (r == QmlCompiler::ReadOnly) { + VME_EXCEPTION("Cannot assign value" << primitives.at(idx) << "to read-only property" << prop.name()); + } else { + VME_EXCEPTION("Invalid property assignment for property" << prop.name()); + } + } else { + runStoreInstruction(stack, *writeInstr, comp); + } + + } else { + VME_EXCEPTION("Unknown property" << pr); + } + } + break; + + case QmlInstruction::TryBeginObject: + { +#ifdef Q_ENABLE_PERFORMANCE_LOG + QFxCompilerTimer<QFxCompiler::InstrTryBeginObject> cc; +#endif + QObject *target = stack.top(); + QmlParserStatus *status = + qobject_cast<QmlParserStatus *>(target); + + if(status) { + instr.type = QmlInstruction::BeginObject; + instr.begin.castValue = int(reinterpret_cast<char *>(status) - reinterpret_cast<char *>(target)); + --ii; + } else { + instr.type = QmlInstruction::NoOp; + } + } + break; + + case QmlInstruction::BeginObject: + { +#ifdef Q_ENABLE_PERFORMANCE_LOG + QFxCompilerTimer<QFxCompiler::InstrBeginObject> cc; +#endif + QObject *target = stack.top(); + QmlParserStatus *status = reinterpret_cast<QmlParserStatus *>(reinterpret_cast<char *>(target) + instr.begin.castValue); + status->classBegin(); + parserStatuses << status; + } + break; + + case QmlInstruction::TryCompleteObject: + { +#ifdef Q_ENABLE_PERFORMANCE_LOG + QFxCompilerTimer<QFxCompiler::InstrTryCompleteObject> cc; +#endif + QObject *target = stack.top(); + QmlParserStatus *status = + qobject_cast<QmlParserStatus *>(target); + + if(status) { + instr.type = QmlInstruction::CompleteObject; + instr.complete.castValue = int(reinterpret_cast<char *>(status) - reinterpret_cast<char *>(target)); + --ii; + } else { + instr.type = QmlInstruction::NoOp; + } + } + break; + + case QmlInstruction::CompleteObject: + { +#ifdef Q_ENABLE_PERFORMANCE_LOG + QFxCompilerTimer<QFxCompiler::InstrCompleteObject> cc; +#endif + QObject *target = stack.top(); + QmlParserStatus *status = reinterpret_cast<QmlParserStatus *>(reinterpret_cast<char *>(target) + instr.complete.castValue); + status->classComplete(); + } + break; + + case QmlInstruction::AssignCompiledBinding: + case QmlInstruction::AssignBinding: + { +#ifdef Q_ENABLE_PERFORMANCE_LOG + QFxCompilerTimer<QFxCompiler::InstrAssignBinding> cc; +#endif + QObject *target = stack.top(); + const QByteArray &pr = datas.at(instr.fetch.property); + int idx = qIndexOfProperty(target, pr); + + // XXX - need to check if the type is QmlBindableValue* + if(idx == -1) { + VME_EXCEPTION("Unknown property" << pr); + } else { + if(QmlInstruction::AssignCompiledBinding == instr.type) + instr.type = QmlInstruction::StoreCompiledBinding; + else + instr.type = QmlInstruction::StoreBinding; + instr.assignBinding.property = idx; + instr.assignBinding.category = QmlMetaProperty::Unknown; + } + ii--; + } + break; + + case QmlInstruction::AssignValueSource: + { + QObject *target = stack.at(stack.count() - 2); + int propIdx = instr.assignValueSource.property; + QByteArray pr; + if(propIdx == -1) { + pr = QmlMetaType::defaultProperty(target).name(); + if(pr.isEmpty()) + VME_EXCEPTION("Unable to resolve default property"); + } else { + pr = datas.at(propIdx); + } + + int coreIdx = qIndexOfProperty(target, pr); + if(coreIdx != -1) { + instr.type = QmlInstruction::StoreValueSource; + instr.assignValueSource.property = coreIdx; + ii--; + } else { + VME_EXCEPTION("Unknown property" << pr); + } + } + break; + + case QmlInstruction::PushProperty: + { +#ifdef Q_ENABLE_PERFORMANCE_LOG + QFxCompilerTimer<QFxCompiler::InstrPushProperty> cc; +#endif + QObject *target = stack.top(); + QmlMetaProperty mp(target, instr.pushProperty.property, + QmlMetaProperty::Object); + pushedProperties.push(mp); + } + break; + + case QmlInstruction::StoreCompiledBinding: + { +#ifdef Q_ENABLE_PERFORMANCE_LOG + QFxCompilerTimer<QFxCompiler::InstrStoreCompiledBinding> cc; +#endif + QObject *target = stack.top(); + QObject *context = + stack.at(stack.count() - 1 - instr.assignBinding.context); + + QmlMetaProperty mp(target, instr.assignBinding.property, + (QmlMetaProperty::PropertyCategory)instr.assignBinding.category); + if (!mp.isWritable()) + VME_EXCEPTION("Cannot assign a binding to read-only property" << mp.name()); + + QmlBindableValue *bind = new QmlBindableValue((void *)datas.at(instr.assignBinding.value).constData(), comp, context, 0); + QFx_setParent_noEvent(bind, target); + + bind->setTarget(mp); + bindableValues << bind; + } + break; + + case QmlInstruction::StoreBinding: + { +#ifdef Q_ENABLE_PERFORMANCE_LOG + QFxCompilerTimer<QFxCompiler::InstrStoreBinding> cc; +#endif + QObject *target = stack.top(); + QObject *context = + stack.at(stack.count() - 1 - instr.assignBinding.context); + + QmlMetaProperty mp(target, instr.assignBinding.property, + (QmlMetaProperty::PropertyCategory)instr.assignBinding.category); + if (!mp.isWritable()) + VME_EXCEPTION("Cannot assign a binding to read-only property" << mp.name()); + + QmlBindableValue *bind = new QmlBindableValue(primitives.at(instr.assignBinding.value), context, false); + QFx_setParent_noEvent(bind, target); + + bind->setTarget(mp); + bindableValues << bind; + } + break; + + case QmlInstruction::StoreValueSource: + { +#ifdef Q_ENABLE_PERFORMANCE_LOG + QFxCompilerTimer<QFxCompiler::InstrStoreValueSource> cc; +#endif + QObject *assign = stack.pop(); + QmlPropertyValueSource *vs = + static_cast<QmlPropertyValueSource *>(assign); + QObject *target = stack.top(); + vs->setParent(target); + vs->setTarget(QmlMetaProperty(target, instr.assignValueSource.property)); + } + break; + + case QmlInstruction::AssignObjectList: + { +#ifdef Q_ENABLE_PERFORMANCE_LOG + QFxCompilerTimer<QFxCompiler::InstrAssignObjectList> cc; +#endif + QObject *assign = stack.pop(); + const ListInstance &list = qliststack.top(); + if(list.qmlListInterface) { + int type = list.type; + + void *d = 0; + void *ptr = 0; + bool found = false; + + if(QmlMetaType::isInterface(type)) { + const char *iid = QmlMetaType::interfaceIId(type); + if(iid) + ptr = assign->qt_metacast(iid); + if(ptr) { + d = &ptr; + found = true; + } + } else { + const QMetaObject *mo = + QmlMetaType::rawMetaObjectForType(type); + + const QMetaObject *assignMo = assign->metaObject(); + while(!found && assignMo) { + if(assignMo == mo) + found = true; + else + assignMo = assignMo->superClass(); + } + + // NOTE: This assumes a cast to QObject does not alter + // the object pointer + d = (void *)&assign; + } + + + if(!found) + VME_EXCEPTION("Cannot assign object to list"); + + list.qmlListInterface->append(d); + + } else { + int type = list.type; + + if(QmlMetaType::isInterface(type)) { + void *ptr = 0; + const char *iid = QmlMetaType::interfaceIId(type); + if(iid) + ptr = assign->qt_metacast(iid); + QVariant v(list.type, &ptr); + QmlMetaType::append(list.list, v); + } else { + QVariant v = QmlMetaType::fromObject(assign, list.type); + QmlMetaType::append(list.list, v); + } + } + } + break; + + case QmlInstruction::AssignObject: + { +#ifdef Q_ENABLE_PERFORMANCE_LOG + QFxCompilerTimer<QFxCompiler::InstrAssignObject> cc; +#endif + QObject *assign = stack.pop(); + QObject *target = stack.top(); + + QByteArray property; + if(instr.assignObject.property == -1) { + // XXX - optimize! + property = + QmlMetaType::defaultProperty(target).name(); + } else { + property = datas.at(instr.assignObject.property); + } + + int coreIdx = qIndexOfProperty(target, property); + + if(coreIdx != -1) { + QMetaProperty prop = + target->metaObject()->property(coreIdx); + int t = prop.userType(); + // XXX - optimize! + if(QmlMetaType::isList(t)) { + QVariant list = prop.read(target); + int listtype = QmlMetaType::listType(t); + QVariant v = QmlMetaType::fromObject(assign, listtype); + QmlMetaType::append(list, v); + } else if(QmlMetaType::isQmlList(t)) { + + // XXX - optimize! + QVariant list = prop.read(target); + QmlPrivate::ListInterface *li = + *(QmlPrivate::ListInterface **)list.constData(); + + int type = li->type(); + + const QMetaObject *mo = + QmlMetaType::rawMetaObjectForType(type); + + const QMetaObject *assignMo = assign->metaObject(); + bool found = false; + while(!found && assignMo) { + if(assignMo == mo) + found = true; + else + assignMo = assignMo->superClass(); + } + + if(!found) + VME_EXCEPTION("Cannot assign object to list"); + + // NOTE: This assumes a cast to QObject does not alter + // the object pointer + void *d = (void *)&assign; + li->append(d); + + } else if(QmlMetaType::isInterface(t)) { + const char *iid = QmlMetaType::interfaceIId(t); + bool ok = false; + if(iid) { + void *ptr = assign->qt_metacast(iid); + if(ptr) { + void *a[1]; + a[0] = &ptr; + QMetaObject::metacall(target, QMetaObject::WriteProperty, + coreIdx, a); + ok = true; + } + } + + if(!ok) + VME_EXCEPTION("Cannot assign object to interface property" << property); + + } else if(prop.userType() == -1 /* means qvariant */) { + prop.write(target, qVariantFromValue(assign)); + } else { + const QMetaObject *propmo = + QmlMetaType::rawMetaObjectForType(t); + + bool isPropertyValue = false; + bool isAssignable = false; + const QMetaObject *c = assign->metaObject(); + while(c) { + isPropertyValue = isPropertyValue || (c == &QmlPropertyValueSource::staticMetaObject); + isAssignable = isAssignable || (c == propmo); + c = c->superClass(); + } + + if(isAssignable) { + // XXX - optimize! + QVariant v = QmlMetaType::fromObject(assign, t); + prop.write(target, v); + } else if(isPropertyValue) { + QmlPropertyValueSource *vs = + static_cast<QmlPropertyValueSource *>(assign); + vs->setParent(target); + vs->setTarget(QmlMetaProperty(target, coreIdx)); + } else { + VME_EXCEPTION("Cannot assign to" << property); + } + } + + + } else { + VME_EXCEPTION("Cannot assign to non-existant property" << property); + } + + } + break; + + case QmlInstruction::FetchAttached: + { +#ifdef Q_ENABLE_PERFORMANCE_LOG + QFxCompilerTimer<QFxCompiler::InstrFetchAttached> cc; +#endif + QObject *target = stack.top(); + + QmlAttachedPropertiesFunc attachFunc = + QmlMetaType::attachedPropertiesFunc(datas.at(instr.fetchAttached.idx)); + if(!attachFunc) + VME_EXCEPTION("No such attached object" << primitives.at(instr.fetchAttached.idx)); + + QObject *qmlObject = attachFunc(target); + if(!qmlObject) + VME_EXCEPTION("Internal error - unable to create attached object" << primitives.at(instr.fetchAttached.idx)); + + stack.push(qmlObject); + } + break; + + case QmlInstruction::FetchQmlList: + { +#ifdef Q_ENABLE_PERFORMANCE_LOG + QFxCompilerTimer<QFxCompiler::InstrFetchQmlList> cc; +#endif + QObject *target = stack.top(); + + void *a[1]; + // We know that QmlList<*> can be converted to + // QmlPrivate::ListInterface + QmlPrivate::ListInterface *list = 0; + a[0] = &list; + QMetaObject::metacall(target, QMetaObject::ReadProperty, + instr.fetchQmlList.property, a); + if(!list) + VME_EXCEPTION("Cannot assign to null list"); + + qliststack.push(ListInstance(list, instr.fetchQmlList.type)); + } + break; + + case QmlInstruction::FetchQList: + { +#ifdef Q_ENABLE_PERFORMANCE_LOG + QFxCompilerTimer<QFxCompiler::InstrFetchQList> cc; +#endif + QObject *target = stack.top(); + QMetaProperty prop = + target->metaObject()->property(instr.fetch.property); + QVariant v = prop.read(target); + qliststack.push(ListInstance(v, QmlMetaType::listType(prop.userType()))); + } + break; + + case QmlInstruction::ResolveFetchObject: + { +#ifdef Q_ENABLE_PERFORMANCE_LOG + QFxCompilerTimer<QFxCompiler::InstrResolveFetchObject> cc; +#endif + QObject *target = stack.top(); + const QByteArray &pr = datas.at(instr.fetch.property); + int idx = qIndexOfProperty(target, pr); + if(idx == -1) + VME_EXCEPTION("Cannot resolve property" << pr); + QMetaProperty prop = target->metaObject()->property(idx); + instr.type = QmlInstruction::FetchObject; + instr.fetch.property = idx; + if(QmlMetaType::isObject(prop.userType())) { + instr.fetch.isObject = true; + } else if(prop.userType() == -1) { + instr.fetch.isObject = false; + } else { + VME_EXCEPTION("Cannot set properties on" << prop.name() << "as it is of unknown type"); + } + ii--; + } + break; + + case QmlInstruction::FetchObject: + { +#ifdef Q_ENABLE_PERFORMANCE_LOG + QFxCompilerTimer<QFxCompiler::InstrFetchObject> cc; +#endif + QObject *target = stack.top(); + + QObject *obj = 0; + if(instr.fetch.isObject) { + // NOTE: This assumes a cast to QObject does not alter the + // object pointer + void *a[1]; + a[0] = &obj; + QMetaObject::metacall(target, QMetaObject::ReadProperty, + instr.fetch.property, a); + } else { + void *a[1]; + QVariant var; + a[0] = &var; + QMetaObject::metacall(target, QMetaObject::ReadProperty, + instr.fetch.property, a); + obj = QmlMetaType::toQObject(var); + + } + + if(!obj) + VME_EXCEPTION("Cannot set properties on" << target->metaObject()->property(instr.fetch.property).name() << "as it is null"); + + stack.push(obj); + } + break; + + case QmlInstruction::PopQList: + { +#ifdef Q_ENABLE_PERFORMANCE_LOG + QFxCompilerTimer<QFxCompiler::InstrPopQList> cc; +#endif + qliststack.pop(); + } + break; + + case QmlInstruction::PopFetchedObject: + { +#ifdef Q_ENABLE_PERFORMANCE_LOG + QFxCompilerTimer<QFxCompiler::InstrPopFetchedObject> cc; +#endif + stack.pop(); + } + break; + + case QmlInstruction::AssignStackObject: + { +#ifdef Q_ENABLE_PERFORMANCE_LOG + QFxCompilerTimer<QFxCompiler::InstrAssignStackObject> cc; +#endif + + QObject *obj = savedObjects[instr.assignStackObject.object]; + const QmlMetaProperty &prop = + pushedProperties.at(instr.assignStackObject.property); + + + const QMetaObject *mo = + QmlMetaType::rawMetaObjectForType(prop.propertyType()); + const QMetaObject *assignMo = obj->metaObject(); + + bool found = false; + while(!found && assignMo) { + if(assignMo == mo) + found = true; + else + assignMo = assignMo->superClass(); + } + + if(!found) + VME_EXCEPTION("Unable to assign object"); + + instr.type = QmlInstruction::StoreStackObject; + --ii; + } + break; + + case QmlInstruction::StoreStackObject: + { +#ifdef Q_ENABLE_PERFORMANCE_LOG + QFxCompilerTimer<QFxCompiler::InstrStoreStackObject> cc; +#endif + + const QmlMetaProperty &prop = + pushedProperties.at(instr.assignStackObject.property); + QObject *obj = savedObjects[instr.assignStackObject.object]; + + // NOTE: This assumes a cast to QObject does not alter the + // object pointer + void *a[1]; + a[0] = (void *)&obj; + QMetaObject::metacall(prop.object(), QMetaObject::WriteProperty, + prop.coreIndex(), a); + } + break; + + case QmlInstruction::NoOp: + { +#ifdef Q_ENABLE_PERFORMANCE_LOG + QFxCompilerTimer<QFxCompiler::InstrNoOp> cc; +#endif + } + break; + + default: + qFatal("QmlCompiledComponent: Internal error - unknown instruction %d", instr.type); + break; + } + } + } + + if(isError()) { + if(!stack.isEmpty()) { + delete stack.at(0); + } + return 0; + } + + QmlEnginePrivate *ep = ctxt->engine()->d_func(); + ep->currentBindValues << bindableValues; + ep->currentParserStatus << parserStatuses; + + comp->dumpPost(); + + if(savedObjects) + delete [] savedObjects; + + if(stack.isEmpty()) + return 0; + else + return stack.top(); + return 0; +} + +bool QmlVME::isError() const +{ + return exceptionLine != -1; +} + +qint64 QmlVME::errorLine() const +{ + return exceptionLine; +} + +QString QmlVME::errorDescription() const +{ + return exceptionDescription; +} + +void QmlVME::runStoreInstruction(QStack<QObject *> &stack, + QmlInstruction &instr, + QmlCompiledData *comp) +{ + const QList<QString> &primitives = comp->primitives; + const QList<int> &intData = comp->intData; + const QList<float> &floatData = comp->floatData; + + switch(instr.type) { + case QmlInstruction::StoreVariant: + { +#ifdef Q_ENABLE_PERFORMANCE_LOG + QFxCompilerTimer<QFxCompiler::InstrStoreVariant> cc; +#endif + QObject *target = stack.top(); + void *a[1]; + // XXX - can be more efficient + QVariant v = QmlStringConverters::variantFromString(primitives.at(instr.storeString.value)); + a[0] = (void *)&v; + QMetaObject::metacall(target, QMetaObject::WriteProperty, + instr.storeString.propertyIndex, a); + } + break; + + case QmlInstruction::StoreString: + { +#ifdef Q_ENABLE_PERFORMANCE_LOG + QFxCompilerTimer<QFxCompiler::InstrStoreString> cc; +#endif + QObject *target = stack.top(); + void *a[1]; + a[0] = (void *)&primitives.at(instr.storeString.value); + QMetaObject::metacall(target, QMetaObject::WriteProperty, + instr.storeString.propertyIndex, a); + } + break; + + case QmlInstruction::StoreReal: + { +#ifdef Q_ENABLE_PERFORMANCE_LOG + QFxCompilerTimer<QFxCompiler::InstrStoreReal> cc; +#endif + QObject *target = stack.top(); + qreal r = instr.storeReal.value; + void *a[1]; + a[0] = &r; + QMetaObject::metacall(target, QMetaObject::WriteProperty, + instr.storeReal.propertyIndex, a); + } + break; + + case QmlInstruction::StoreBool: + { +#ifdef Q_ENABLE_PERFORMANCE_LOG + QFxCompilerTimer<QFxCompiler::InstrStoreBool> cc; +#endif + QObject *target = stack.top(); + void *a[1]; + a[0] = (void *)&instr.storeBool.value; + QMetaObject::metacall(target, QMetaObject::WriteProperty, + instr.storeBool.propertyIndex, a); + } + break; + + case QmlInstruction::StoreInteger: + { +#ifdef Q_ENABLE_PERFORMANCE_LOG + QFxCompilerTimer<QFxCompiler::InstrStoreInteger> cc; +#endif + QObject *target = stack.top(); + void *a[1]; + a[0] = (void *)&instr.storeInteger.value; + QMetaObject::metacall(target, QMetaObject::WriteProperty, + instr.storeReal.propertyIndex, a); + } + break; + + case QmlInstruction::StoreColor: + { +#ifdef Q_ENABLE_PERFORMANCE_LOG + QFxCompilerTimer<QFxCompiler::InstrStoreColor> cc; +#endif + QObject *target = stack.top(); + void *a[1]; + QColor c = QColor::fromRgba(instr.storeColor.value); + a[0] = (void *)&c; + QMetaObject::metacall(target, QMetaObject::WriteProperty, + instr.storeColor.propertyIndex, a); + } + break; + + case QmlInstruction::StoreDate: + { +#ifdef Q_ENABLE_PERFORMANCE_LOG + QFxCompilerTimer<QFxCompiler::InstrStoreDate> cc; +#endif + QObject *target = stack.top(); + void *a[1]; + QDate d = QDate::fromJulianDay(instr.storeDate.value); + a[0] = (void *)&d; + QMetaObject::metacall(target, QMetaObject::WriteProperty, + instr.storeDate.propertyIndex, a); + } + break; + + case QmlInstruction::StoreTime: + { +#ifdef Q_ENABLE_PERFORMANCE_LOG + //QFxCompilerTimer<QFxCompiler::InstrStoreTime> cc; +#endif + QObject *target = stack.top(); + void *a[1]; + QTime t; + t.setHMS(intData.at(instr.storeTime.valueIndex), + intData.at(instr.storeTime.valueIndex+1), + intData.at(instr.storeTime.valueIndex+2), + intData.at(instr.storeTime.valueIndex+3)); + a[0] = (void *)&t; + QMetaObject::metacall(target, QMetaObject::WriteProperty, + instr.storeTime.propertyIndex, a); + } + break; + + case QmlInstruction::StoreDateTime: + { +#ifdef Q_ENABLE_PERFORMANCE_LOG + //QFxCompilerTimer<QFxCompiler::InstrStoreDateTime> cc; +#endif + QObject *target = stack.top(); + void *a[1]; + QTime t; + t.setHMS(intData.at(instr.storeDateTime.valueIndex+1), + intData.at(instr.storeDateTime.valueIndex+2), + intData.at(instr.storeDateTime.valueIndex+3), + intData.at(instr.storeDateTime.valueIndex+4)); + QDateTime dt(QDate::fromJulianDay(intData.at(instr.storeDateTime.valueIndex)), t); + a[0] = (void *)&dt; + QMetaObject::metacall(target, QMetaObject::WriteProperty, + instr.storeDateTime.propertyIndex, a); + } + break; + + case QmlInstruction::StorePoint: + { +#ifdef Q_ENABLE_PERFORMANCE_LOG + QFxCompilerTimer<QFxCompiler::InstrStorePoint> cc; +#endif + QObject *target = stack.top(); + void *a[1]; + QPoint p = QPointF(floatData.at(instr.storeRealPair.valueIndex), + floatData.at(instr.storeRealPair.valueIndex+1)).toPoint(); + a[0] = (void *)&p; + QMetaObject::metacall(target, QMetaObject::WriteProperty, + instr.storeRealPair.propertyIndex, a); + } + break; + + case QmlInstruction::StorePointF: + { +#ifdef Q_ENABLE_PERFORMANCE_LOG + QFxCompilerTimer<QFxCompiler::InstrStorePoint> cc; +#endif + QObject *target = stack.top(); + void *a[1]; + QPointF p(floatData.at(instr.storeRealPair.valueIndex), + floatData.at(instr.storeRealPair.valueIndex+1)); + a[0] = (void *)&p; + QMetaObject::metacall(target, QMetaObject::WriteProperty, + instr.storeRealPair.propertyIndex, a); + } + break; + + case QmlInstruction::StoreSize: + { +#ifdef Q_ENABLE_PERFORMANCE_LOG + QFxCompilerTimer<QFxCompiler::InstrStoreSize> cc; +#endif + QObject *target = stack.top(); + void *a[1]; + QSize p = QSizeF(floatData.at(instr.storeRealPair.valueIndex), + floatData.at(instr.storeRealPair.valueIndex+1)).toSize(); + a[0] = (void *)&p; + QMetaObject::metacall(target, QMetaObject::WriteProperty, + instr.storeRealPair.propertyIndex, a); + } + break; + + case QmlInstruction::StoreSizeF: + { +#ifdef Q_ENABLE_PERFORMANCE_LOG + QFxCompilerTimer<QFxCompiler::InstrStoreSize> cc; +#endif + QObject *target = stack.top(); + void *a[1]; + QSizeF s(floatData.at(instr.storeRealPair.valueIndex), + floatData.at(instr.storeRealPair.valueIndex+1)); + a[0] = (void *)&s; + QMetaObject::metacall(target, QMetaObject::WriteProperty, + instr.storeRealPair.propertyIndex, a); + } + break; + + case QmlInstruction::StoreRect: + { +#ifdef Q_ENABLE_PERFORMANCE_LOG + //QFxCompilerTimer<QFxCompiler::InstrStoreRect> cc; +#endif + QObject *target = stack.top(); + void *a[1]; + QRect r = QRectF(floatData.at(instr.storeRect.valueIndex), + floatData.at(instr.storeRect.valueIndex+1), + floatData.at(instr.storeRect.valueIndex+2), + floatData.at(instr.storeRect.valueIndex+3)).toRect(); + a[0] = (void *)&r; + QMetaObject::metacall(target, QMetaObject::WriteProperty, + instr.storeRect.propertyIndex, a); + } + break; + + case QmlInstruction::StoreRectF: + { +#ifdef Q_ENABLE_PERFORMANCE_LOG + //QFxCompilerTimer<QFxCompiler::InstrStoreRect> cc; +#endif + QObject *target = stack.top(); + void *a[1]; + QRectF r(floatData.at(instr.storeRect.valueIndex), + floatData.at(instr.storeRect.valueIndex+1), + floatData.at(instr.storeRect.valueIndex+2), + floatData.at(instr.storeRect.valueIndex+3)); + a[0] = (void *)&r; + QMetaObject::metacall(target, QMetaObject::WriteProperty, + instr.storeRect.propertyIndex, a); + } + break; + + case QmlInstruction::StoreObject: + { +#ifdef Q_ENABLE_PERFORMANCE_LOG + QFxCompilerTimer<QFxCompiler::InstrStoreObject> cc; +#endif + QObject *assignObj = stack.pop(); + QObject *target = stack.top(); + + void *a[1]; + void *obj = (void *)(((char *)assignObj) + instr.storeObject.cast); + a[0] = (void *)&obj; + + QMetaObject::metacall(target, QMetaObject::WriteProperty, + instr.storeObject.propertyIndex, a); + } + break; + default: + qFatal("QmlCompiledComponent: Internal error - unknown instruction %d", instr.type); + break; + } + +} + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlvme_p.h b/src/declarative/qml/qmlvme_p.h new file mode 100644 index 0000000..2a3be06 --- /dev/null +++ b/src/declarative/qml/qmlvme_p.h @@ -0,0 +1,75 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLVME_P_H +#define QMLVME_P_H + +#include <QString> +#include <QStack> +class QObject; + +QT_BEGIN_NAMESPACE +class QmlInstruction; +class QmlCompiledComponent; +class QmlCompiledData; +class QmlContext; + +class QmlVME +{ +public: + QmlVME(); + + QObject *run(QmlContext *, QmlCompiledComponent *, int start = -1, int end = -1); + + bool isError() const; + qint64 errorLine() const; + QString errorDescription() const; + +private: + void runStoreInstruction(QStack<QObject *> &stack, + QmlInstruction &, QmlCompiledData *); + + qint64 exceptionLine; + QString exceptionDescription; +}; + +QT_END_NAMESPACE +#endif // QMLVME_P_H diff --git a/src/declarative/qml/qmlvmemetaobject.cpp b/src/declarative/qml/qmlvmemetaobject.cpp new file mode 100644 index 0000000..2b1060b --- /dev/null +++ b/src/declarative/qml/qmlvmemetaobject.cpp @@ -0,0 +1,140 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmlvmemetaobject_p.h" +#include <qml.h> +#include <private/qmlrefcount_p.h> +#include <QColor> +#include <QDate> + + +QT_BEGIN_NAMESPACE +QmlVMEMetaObject::QmlVMEMetaObject(QObject *obj, + const QMetaObject *other, + QmlRefCount *rc) +: object(obj), ref(rc) +{ + if(ref) + ref->addref(); + + *static_cast<QMetaObject *>(this) = *other; + this->d.superdata = obj->metaObject(); + QObjectPrivate::get(obj)->metaObject = this; + + baseProp = propertyOffset(); + baseSig = methodOffset(); + data = new QVariant[propertyCount() - baseProp]; + vTypes.resize(propertyCount() - baseProp); + + for(int ii = baseProp; ii < propertyCount(); ++ii) { + QMetaProperty prop = property(ii); + if((int)prop.type() != -1) { + data[ii - baseProp] = QVariant((QVariant::Type)prop.userType()); + } else { + vTypes.setBit(ii - baseProp, true); + } + } +} + +QmlVMEMetaObject::~QmlVMEMetaObject() +{ + if(ref) + ref->release(); + delete [] data; +} + +int QmlVMEMetaObject::metaCall(QMetaObject::Call c, int id, void **a) +{ + if(id >= baseProp) { + int propId = id - baseProp; + bool needActivate = false; + + if(vTypes.testBit(propId)) { + if(c == QMetaObject::ReadProperty) { + *reinterpret_cast<QVariant *>(a[0]) = data[propId]; + } else if(c == QMetaObject::WriteProperty) { + needActivate = + (data[propId] != *reinterpret_cast<QVariant *>(a[0])); + data[propId] = *reinterpret_cast<QVariant *>(a[0]); + } + } else { + if(c == QMetaObject::ReadProperty) { + switch(data[propId].type()) { + case QVariant::Int: + *reinterpret_cast<int *>(a[0]) = data[propId].toInt(); + break; + case QVariant::Bool: + *reinterpret_cast<bool *>(a[0]) = data[propId].toBool(); + break; + case QVariant::Double: + *reinterpret_cast<double *>(a[0]) = data[propId].toDouble(); + break; + case QVariant::String: + *reinterpret_cast<QString *>(a[0]) = data[propId].toString(); + break; + case QVariant::Color: + *reinterpret_cast<QColor *>(a[0]) = data[propId].value<QColor>(); + break; + case QVariant::Date: + *reinterpret_cast<QDate *>(a[0]) = data[propId].toDate(); + break; + default: + qFatal("Unknown type"); + break; + } + } else if(c == QMetaObject::WriteProperty) { + + QVariant value = QVariant((QVariant::Type)data[propId].type(), a[0]); + needActivate = (data[propId] != value); + data[propId] = value; + } + } + + if(c == QMetaObject::WriteProperty && needActivate) { + activate(object, baseSig + propId, 0); + } + + return id; + } else { + return object->qt_metacall(c, id, a); + } +} +QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlvmemetaobject_p.h b/src/declarative/qml/qmlvmemetaobject_p.h new file mode 100644 index 0000000..3fb1c46 --- /dev/null +++ b/src/declarative/qml/qmlvmemetaobject_p.h @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLVMEMETAOBJECT_P_H +#define QMLVMEMETAOBJECT_P_H + +#include <qml.h> +#include <QMetaObject> +#include <QBitArray> +#include <private/qobject_p.h> + +QT_BEGIN_NAMESPACE +class QmlRefCount; +class QmlVMEMetaObject : public QAbstractDynamicMetaObject +{ +public: + QmlVMEMetaObject(QObject *, const QMetaObject *, QmlRefCount * = 0); + ~QmlVMEMetaObject(); + +protected: + virtual int metaCall(QMetaObject::Call _c, int _id, void **_a); + +private: + QObject *object; + QmlRefCount *ref; + int baseProp; + int baseSig; + QVariant *data; + QBitArray vTypes; +}; + +QT_END_NAMESPACE +#endif // QMLVMEMETAOBJECT_P_H diff --git a/src/declarative/qml/qmlxmlparser.cpp b/src/declarative/qml/qmlxmlparser.cpp new file mode 100644 index 0000000..f001bda --- /dev/null +++ b/src/declarative/qml/qmlxmlparser.cpp @@ -0,0 +1,384 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qmlxmlparser_p.h" +#include "qmlcustomparser.h" +#include <qfxperf.h> +#include <QXmlStreamReader> +#include <QStack> +#include "qmlparser_p.h" +#include <private/qmlparser_p.h> +#include <QtCore/qdebug.h> + +QT_BEGIN_NAMESPACE +using namespace QmlParser; + +struct QmlXmlParserState { + QmlXmlParserState() : object(0), property(0) {} + QmlXmlParserState(Object *o) : object(o), property(0) {} + QmlXmlParserState(Object *o, Property *p) : object(o), property(p) {} + + Object *object; + Property *property; +}; + +struct QmlXmlParserStateStack : public QStack<QmlXmlParserState> +{ + void pushObject(Object *obj) + { + push(QmlXmlParserState(obj)); + } + + void pushProperty(const QString &name, int lineNumber) + { + const QmlXmlParserState &state = top(); + if(state.property) { + QmlXmlParserState s(state.property->getValue(), + state.property->getValue()->getProperty(name.toLatin1())); + s.property->line = lineNumber; + push(s); + } else { + QmlXmlParserState s(state.object, + state.object->getProperty(name.toLatin1())); + s.property->line = lineNumber; + push(s); + } + } +}; + +QmlXmlParser::~QmlXmlParser() +{ + if(root) + root->release(); +} + +QmlXmlParser::QmlXmlParser() +: root(0) +{ +} + +static QString flatXml(QXmlStreamReader& reader) +{ + QString result; + int depth=0; + QStringRef ns = reader.namespaceUri(); + while (depth>=0) { + switch (reader.tokenType()) { + case QXmlStreamReader::StartElement: + result += QLatin1Char('<'); + result += reader.name(); + if (reader.namespaceUri() != ns || depth==0) { + result += QLatin1String(" xmlns=\""); + result += reader.namespaceUri(); + result += QLatin1Char('"'); + } + foreach(QXmlStreamAttribute attr, reader.attributes()) { + result += QLatin1Char(' '); + result += attr.name(); + result += QLatin1String("=\""); + result += attr.value(); // XXX escape + result += QLatin1Char('"'); + } + result += QLatin1Char('>'); + ++depth; + break; + case QXmlStreamReader::EndElement: + result += QLatin1String("</"); + result += reader.name(); + result += QLatin1Char('>'); + --depth; + break; + case QXmlStreamReader::Characters: + result += reader.text(); + break; + default: + reader.raiseError(QLatin1String("Only StartElement, EndElement, and Characters permitted")); + break; + } + if (depth>=0) + reader.readNext(); + } + return result; +} + +bool QmlXmlParser::parse(const QByteArray &data, const QUrl &url) +{ +#ifdef Q_ENABLE_PERFORMANCE_LOG + QFxPerfTimer<QFxPerf::XmlParsing> pt; +#endif + + QString fileDisplayName; + if (url.isEmpty()) { + fileDisplayName = QLatin1String("<unspecified file>"); + } else if (url.scheme() == QLatin1String("file")) { + fileDisplayName = url.toLocalFile(); + } else { + fileDisplayName = url.toString(); + } + if (data.isEmpty()) { + _error = QLatin1String("No Qml was specified for parsing @") + fileDisplayName; + return false; + } + + QmlXmlParserStateStack states; + + QXmlStreamReader reader; + reader.addData(data); + + while(!reader.atEnd()) { + switch(reader.readNext()) { + case QXmlStreamReader::Invalid: + case QXmlStreamReader::NoToken: + case QXmlStreamReader::StartDocument: + case QXmlStreamReader::EndDocument: + break; + + case QXmlStreamReader::StartElement: + { + QString name = reader.name().toString(); + QString nameSpace = reader.namespaceUri().toString(); + int line = reader.lineNumber(); + bool isType = name.at(0).isUpper() && !name.contains(QLatin1Char('.')); + QString qualifiedname; + if (!nameSpace.isEmpty()) { + qualifiedname = nameSpace; + qualifiedname += QLatin1Char('/'); + } + qualifiedname += name; + QByteArray qualifiednameL1 = qualifiedname.toLatin1(); + QXmlStreamAttributes attrs = reader.attributes(); + + if (isType) { + // Class + int typeId = _typeNames.indexOf(qualifiedname); + if(typeId == -1) { + typeId = _typeNames.count(); + _typeNames.append(qualifiedname); + } + + Object *obj = new Object; + obj->type = typeId; + obj->typeName = qualifiednameL1; + obj->line = line; + + QmlCustomParser *customparser = QmlMetaType::customParser(qualifiednameL1); + if (customparser) { + bool ok; + obj->custom = customparser->compile(reader, &ok); + if (reader.tokenType() != QXmlStreamReader::EndElement) { + reader.raiseError(QLatin1String("Parser for ") + qualifiedname + QLatin1String(" did not end on end element")); + ok = false; + } + if (!ok) { + delete obj; + break; + } + } + + + if(!root) { + root = obj; + states.pushObject(obj); + } else { + const QmlXmlParserState &state = states.top(); + Value *v = new Value; + v->object = obj; + v->line = line; + if(state.property) + state.property->addValue(v); + else + state.object->getDefaultProperty()->addValue(v); + states.pushObject(obj); + } + } else { + // Property + if (!root) { + reader.raiseError(QLatin1String("Can't have a property with no object")); + break; + } + QStringList str = name.split(QLatin1Char('.')); + for(int ii = 0; ii < str.count(); ++ii) { + QString s = str.at(ii); + states.pushProperty(s, line); + } + if (!nameSpace.isEmpty()) { + // Pass non-QML as flat text property value + const QmlXmlParserState &state = states.top(); + Value *v = new Value; + v->primitive = flatXml(reader); + v->line = line; + state.property->addValue(v); + } + } + + // (even custom parsed content gets properties set) + foreach(QXmlStreamAttribute attr, attrs) { + QStringList str = attr.name().toString().split(QLatin1Char('.')); + + for(int ii = 0; ii < str.count(); ++ii) { + QString s = str.at(ii); + states.pushProperty(s, line); + } + + const QmlXmlParserState &state = states.top(); + Value *v = new Value; + v->primitive = attr.value().toString(); + v->line = reader.lineNumber(); + state.property->addValue(v); + + for(int ii = str.count() - 1; ii >= 0; --ii) + states.pop(); + } + } + + // Custom parsers and namespaced properties move + // the reader to the end element, so we handle that + // BEFORE continuing. + // + if (reader.tokenType()!=QXmlStreamReader::EndElement) + break; + // ELSE fallthrough to EndElement... + case QXmlStreamReader::EndElement: + { + QString name = reader.name().toString(); + Q_ASSERT(!name.isEmpty()); + if(name.at(0).isUpper() && !name.contains(QLatin1Char('.'))) { + // Class + states.pop(); + } else { + // Property + QStringList str = name.split(QLatin1Char('.')); + for(int ii = 0; ii < str.count(); ++ii) + states.pop(); + } + } + break; + case QXmlStreamReader::Characters: + if(!reader.isWhitespace()) { + const QmlXmlParserState &state = states.top(); + Value *v = new Value; + v->primitive = reader.text().toString(); + v->line = reader.lineNumber(); + if(state.property) + state.property->addValue(v); + else + state.object->getDefaultProperty()->addValue(v); + } + break; + + case QXmlStreamReader::Comment: + case QXmlStreamReader::DTD: + case QXmlStreamReader::EntityReference: + break; + case QXmlStreamReader::ProcessingInstruction: + if(reader.processingInstructionTarget() == QLatin1String("qtfx")) { + QString str = reader.processingInstructionData().toString(); + QString token, data; + int idx = str.indexOf(QLatin1Char(':')); + if(-1 != idx) { + token = str.left(idx); + data = str.mid(idx + 1); + } else { + token = str; + } + token = token.trimmed(); + data = data.trimmed(); + + // <?qtfx namespacepath: namespace=path> + + if(token == QLatin1String("namespacepath")) { + int eq=data.indexOf(QLatin1Char('=')); + if (eq>=0) { + _nameSpacePaths.insertMulti(data.left(eq),data.mid(eq+1)); + } + } else { + str = str.trimmed(); + qWarning().nospace() << "Unknown processing instruction " << str.toLatin1().constData() << " @" << fileDisplayName.toLatin1().constData() << ":" << reader.lineNumber(); + } + } + break; + } + } + + if(reader.hasError()) { + if (root) { + root->release(); + root = 0; + } + _error = reader.errorString() + QLatin1String(" @") + fileDisplayName + + QLatin1String(":") + QString::number(reader.lineNumber()); + } + + return root != 0; +} + +QMap<QString,QString> QmlXmlParser::nameSpacePaths() const +{ + return _nameSpacePaths; +} + +QStringList QmlXmlParser::types() const +{ + return _typeNames; +} + +QmlParser::Object *QmlXmlParser::tree() const +{ + return root; +} + +QString QmlXmlParser::errorDescription() const +{ + return _error; +} + +void QmlXmlParser::clear() +{ + if(root) { + root->release(); + root = 0; + } + _nameSpacePaths.clear(); + _typeNames.clear(); + _error.clear(); +} + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlxmlparser_p.h b/src/declarative/qml/qmlxmlparser_p.h new file mode 100644 index 0000000..3680172 --- /dev/null +++ b/src/declarative/qml/qmlxmlparser_p.h @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the either Technology Preview License Agreement or the +** Beta Release License Agreement. +** +** 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 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain +** additional rights. These rights are described in the Nokia Qt LGPL +** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this +** package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3.0 as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU General Public License version 3.0 requirements will be +** met: http://www.gnu.org/copyleft/gpl.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at qt-sales@nokia.com. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLXMLPARSER_P_H +#define QMLXMLPARSER_P_H + +#include <QList> +#include <QUrl> +#include <qml.h> + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) + +namespace QmlParser { + class Object; +} + +class QByteArray; +class QmlXmlParser +{ +public: + QmlXmlParser(); + ~QmlXmlParser(); + + bool parse(const QByteArray &data, const QUrl &url=QUrl()); + QString errorDescription() const; + + QMap<QString,QString> nameSpacePaths() const; + QStringList types() const; + + QmlParser::Object *tree() const; + + void clear(); + +private: + QMap<QString,QString> _nameSpacePaths; + QmlParser::Object *root; + QStringList _typeNames; + QString _error; +}; + +#endif // QMLXMLPARSER_P_H + + +QT_END_NAMESPACE + +QT_END_HEADER diff --git a/src/declarative/qml/script/generator/generator.pro b/src/declarative/qml/script/generator/generator.pro new file mode 100644 index 0000000..1b2a4c7 --- /dev/null +++ b/src/declarative/qml/script/generator/generator.pro @@ -0,0 +1,11 @@ +###################################################################### +# Automatically generated by qmake (2.01a) Mon Apr 2 20:15:52 2007 +###################################################################### + +TEMPLATE = app +TARGET = +DEPENDPATH += . +INCLUDEPATH += . + +# Input +SOURCES += main.cpp diff --git a/src/declarative/qml/script/generator/main.cpp b/src/declarative/qml/script/generator/main.cpp new file mode 100644 index 0000000..676671f --- /dev/null +++ b/src/declarative/qml/script/generator/main.cpp @@ -0,0 +1,135 @@ +/**************************************************************************** +** +** This file is part of the $PACKAGE_NAME$. +** +** Copyright (C) $THISYEAR$ $COMPANY_NAME$. +** +** $QT_EXTENDED_DUAL_LICENSE$ +** +****************************************************************************/ + +#include <QList> +#include <QByteArray> + + +QT_BEGIN_NAMESPACE +struct Keyword { + const char *lexem; + const char *token; +}; + +struct State +{ + State(const char* token) : token(token) + { + ::memset(next, 0, sizeof(next)); + } + State(const State &other) : token(other.token) + { + ::memcpy(next, other.next, sizeof(next)); + } + State &operator=(const State &other) + { + token = other.token; + ::memcpy(next, other.next, sizeof(next)); + return *this; + } + + QByteArray token; + int next[128]; +}; + +Keyword keywords[] = +{ + {"<", "LANGLE" }, + {">", "RANGLE" }, + {"+", "PLUS" }, + {"-", "MINUS" }, + {"*", "STAR" }, + {"==", "EQUALS" }, + {"&&", "AND" }, + {".", "DOT"}, + {"true", "TOKEN_TRUE"}, + {"false", "TOKEN_FALSE"}, + {" ", "WHITESPACE"}, + {"\t", "WHITESPACE"}, + {0, 0} +}; + +bool is_character(char s) +{ + return (s >= 'a' && s <= 'z') || + (s >= 'A' && s <= 'Z') || + (s >= '0' && s <= '9') || + s == '_'; +} + +void newState(QList<State> &states, const char *token, const char *lexem) +{ + int state = 0; + bool character = is_character(*lexem); + + while(*lexem) { + int next = states[state].next[(int)*lexem]; + + if(!next) { + next = states.size(); + states += State(character?"CHARACTER":"INCOMPLETE"); + states[state].next[(int)*lexem] = next; + } + + state = next; + ++lexem; + character = character && is_character(*lexem); + } + + states[state].token = token; +} + +void newState(QList<State> &states, const char *token, char lexem) +{ + int next = states[0].next[(int)lexem]; + if(!next) { + next = states.size(); + states += State(token); + states[0].next[(int)lexem] = next; + } else { + states[next].token = token; + } +} + +int main() +{ + QList<State> states; + states += State("NOTOKEN"); + + // identifiers + for (int cc = 'a'; cc <= 'z'; ++cc) + newState(states, "CHARACTER", cc); + for (int cc = 'A'; cc <= 'Z'; ++cc) + newState(states, "CHARACTER", cc); + newState(states, "CHARACTER", '_'); + + // add digits + for(int cc = '0'; cc <= '9'; ++cc) + newState(states, "DIGIT", cc); + + // keywords + for(int ii = 0; keywords[ii].lexem; ++ii) + newState(states, keywords[ii].token, keywords[ii].lexem); + + ::printf("static const struct\n{\n" + " Token token;\n" + " char next[128];\n" + "} keywords[] = {\n"); + + for(int ii = 0; ii < states.size(); ++ii) { + printf("%s { %s, { ", ii?",\n":"", states[ii].token.data()); + for(int jj = 0; jj < 128; jj++) + printf("%s%d", jj?",":"", states[ii].next[jj]); + printf(" } }"); + } + + printf("\n};\n"); +} +QT_END_NAMESPACE diff --git a/src/declarative/qml/script/instructions.h b/src/declarative/qml/script/instructions.h new file mode 100644 index 0000000..a21cbce --- /dev/null +++ b/src/declarative/qml/script/instructions.h @@ -0,0 +1,32 @@ +#ifndef _INSTRUCTIONS_H_ +#define _INSTRUCTIONS_H_ + +struct ScriptInstruction { + enum { + Load, // fetch + Fetch, // fetch + + Add, // NA + Subtract, // NA + Multiply, // NA + Equals, // NA + And, // NA + + Int, // integer + Bool, // boolean + } type; + + union { + struct { + int idx; + } fetch; + struct { + int value; + } integer; + struct { + bool value; + } boolean; + }; +}; + +#endif // _INSTRUCTIONS_H_ diff --git a/src/declarative/qml/script/keywords.cpp b/src/declarative/qml/script/keywords.cpp new file mode 100644 index 0000000..4cde65b --- /dev/null +++ b/src/declarative/qml/script/keywords.cpp @@ -0,0 +1,89 @@ +static const struct +{ + Token token; + char next[128]; +} keywords[] = { + { NOTOKEN, { 0,0,0,0,0,0,0,0,0,82,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,81,0,0,0,0,0,71,0,0,0,68,66,0,67,73,0,54,55,56,57,58,59,60,61,62,63,0,0,64,69,65,0,0,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,0,0,0,0,53,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,77,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,74,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { DIGIT, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { DIGIT, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { DIGIT, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { DIGIT, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { DIGIT, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { DIGIT, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { DIGIT, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { DIGIT, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { DIGIT, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { DIGIT, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { LANGLE, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { RANGLE, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { PLUS, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { MINUS, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { STAR, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { INCOMPLETE, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,70,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { EQUALS, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { INCOMPLETE, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,72,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { AND, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { DOT, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,75,0,0,0,0,0,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,76,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { TOKEN_TRUE, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,78,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,79,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { CHARACTER, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,80,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { TOKEN_FALSE, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { WHITESPACE, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } }, + { WHITESPACE, { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } } +}; diff --git a/src/declarative/qml/script/lexer.cpp b/src/declarative/qml/script/lexer.cpp new file mode 100644 index 0000000..d3ef935 --- /dev/null +++ b/src/declarative/qml/script/lexer.cpp @@ -0,0 +1,139 @@ +/**************************************************************************** +** +** This file is part of the $PACKAGE_NAME$. +** +** Copyright (C) $THISYEAR$ $COMPANY_NAME$. +** +** $QT_EXTENDED_DUAL_LICENSE$ +** +****************************************************************************/ + +#include <QByteArray> +#include "lexer.h" +#include "keywords.cpp" +#include <QDebug> + + +QT_BEGIN_NAMESPACE +QList<LexerToken> tokenize(const char *text) +{ + QList<LexerToken> rv; + + int lineNo = 0; + int charNo = 0; + int state = 0; + int tokenStart = 0; + bool other = false; + + const char *textprog = text; + + bool done = false; + while (!done) { + char textchar = *textprog; + done = !textchar; + + if (other) { + if (keywords[state].next[(int)textchar]) { + + // Do other token + LexerToken token; + token.token = OTHER; + token.start = tokenStart; + token.end = textprog - text - 1; + token.line = lineNo + 1; + token.offset = charNo - (token.end - token.start); + tokenStart = token.end + 1; + rv.append(token); + other = false; + + } else { + goto continue_loop; + } + } + + if (keywords[state].next[(int)textchar]) { + + state = keywords[state].next[(int)textchar]; + + } else if (0 == state || + keywords[state].token == INCOMPLETE) { + + other = true; + if (keywords[state].token == INCOMPLETE) { + state = 0; + continue; + } + + } else { + + // Token completed + Token tokenType = keywords[state].token; + bool tokenCollapsed = false; + if (tokenType == CHARACTER || + tokenType == DIGIT || + tokenType == WHITESPACE) { + + Token lastTokenType = + rv.isEmpty()?NOTOKEN:rv.last().token; + if (tokenType == lastTokenType) { + + rv.last().end = textprog - text - 1; + tokenStart = rv.last().end + 1; + + tokenCollapsed = true; + } + } + + if (!tokenCollapsed) { + LexerToken token; + token.token = keywords[state].token; + token.start = tokenStart; + token.end = textprog - text - 1; + token.line = lineNo + 1; + token.offset = charNo - (token.end - token.start); + tokenStart = token.end + 1; + rv.append(token); + } + + state = keywords[0].next[(int)textchar]; + if (0 == state) + other = true; + } + +continue_loop: + // Reset error reporting variables + if (textchar == '\n') { + ++lineNo; + charNo = 0; + } else { + charNo++; + } + + // Increment ptrs + ++textprog; + } + + if (other && ((textprog - text - 1) != tokenStart)) { + // Do other token + LexerToken token; + token.token = OTHER; + token.start = tokenStart; + token.end = textprog - text - 1; + token.line = lineNo + 1; + token.offset = charNo - (token.end - token.start); + tokenStart = token.end + 1; + rv.append(token); + other = false; + } + return rv; +} + +void dumpTokens(const char *text, const QList<LexerToken> &tokens) +{ + for (int ii = 0; ii < tokens.count(); ++ii) { + QByteArray ba(text + tokens.at(ii).start, tokens.at(ii).end - tokens.at(ii).start + 1); + qWarning() << tokens.at(ii).line << ":" << tokens.at(ii).offset << tokenToString(tokens.at(ii).token) << "(" << tokens.at(ii).start << "-" << tokens.at(ii).end << ")" << ba; + } +} + +QT_END_NAMESPACE diff --git a/src/declarative/qml/script/lexer.h b/src/declarative/qml/script/lexer.h new file mode 100644 index 0000000..7781ee8 --- /dev/null +++ b/src/declarative/qml/script/lexer.h @@ -0,0 +1,54 @@ +/**************************************************************************** +** +** This file is part of the $PACKAGE_NAME$. +** +** Copyright (C) $THISYEAR$ $COMPANY_NAME$. +** +** $QT_EXTENDED_DUAL_LICENSE$ +** +****************************************************************************/ + +#ifndef LEXER_H +#define LEXER_H + +#include <QList> +#include "tokens.h" + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) +struct LexerToken +{ + LexerToken() : token(NOTOKEN), start(-1), end(-1), line(-1), offset(-1) {} + LexerToken(const LexerToken &other) : token(other.token), + start(other.start), + end(other.end), + line(other.line), + offset(other.offset) {} + LexerToken &operator=(const LexerToken &other) { + token = other.token; + start = other.start; + end = other.end; + line = other.line; + offset = other.offset; + return *this; + } + + Token token; + int start; + int end; + int line; + int offset; +}; + +QList<LexerToken> tokenize(const char *text); +void dumpTokens(const char *text, const QList<LexerToken> &tokens); + + +QT_END_NAMESPACE + +QT_END_HEADER +#endif diff --git a/src/declarative/qml/script/qmlbasicscript.cpp b/src/declarative/qml/script/qmlbasicscript.cpp new file mode 100644 index 0000000..4f40016 --- /dev/null +++ b/src/declarative/qml/script/qmlbasicscript.cpp @@ -0,0 +1,923 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $TROLLTECH_DUAL_LICENSE$ +** +****************************************************************************/ + +#include "qmlbasicscript.h" +#include "qmlbasicscript_p.h" +#include "lexer.h" +#include <QColor> +#include <QDebug> +#include <private/qmlengine_p.h> +#include <private/qmlcontext_p.h> +#include <QStack> +#include <qfxperf.h> +#include <private/qmlrefcount_p.h> + + +QT_BEGIN_NAMESPACE +DEFINE_BOOL_CONFIG_OPTION(scriptWarnings, QML_SCRIPT_WARNINGS); + +class QmlBasicScriptPrivate +{ +public: + enum Flags { OwnData = 0x00000001 }; + + int size; + int stateSize; + int instructionCount; + int exprLen; + + ScriptInstruction *instructions() const { return (ScriptInstruction *)((char *)this + sizeof(QmlBasicScriptPrivate)); } + + const char *expr() const + { + return (const char *)(instructions() + instructionCount); + } + + const char *data() const + { + return (const char *)(instructions() + instructionCount) + exprLen + 1; + } + + static unsigned int alignRound(int s) + { + if(s % 4) + s += 4 - (s % 4); + return s; + } +}; + +QDebug operator<<(QDebug lhs, const QmlBasicScriptNodeCache &rhs) +{ + switch(rhs.type) { + case QmlBasicScriptNodeCache::Invalid: + lhs << "Invalid"; + break; + case QmlBasicScriptNodeCache::Core: + lhs << "Core" << rhs.object << rhs.core; + break; + case QmlBasicScriptNodeCache::Attached: + lhs << "Attached" << rhs.object << rhs.attached; + break; + case QmlBasicScriptNodeCache::Signal: + lhs << "Signal" << rhs.object << rhs.core; + break; + case QmlBasicScriptNodeCache::SignalProperty: + lhs << "SignalProperty" << rhs.object << rhs.core; + break; + case QmlBasicScriptNodeCache::Explicit: + lhs << "Explicit" << rhs.object; + break; + case QmlBasicScriptNodeCache::Variant: + lhs << "Variant" << rhs.context; + break; + case QmlBasicScriptNodeCache::ScriptValue: + lhs << "ScriptValue" << rhs.context; + break; + } + + return lhs; +} + +void QmlBasicScriptNodeCache::clear() +{ + object = 0; + metaObject = 0; + type = Invalid; +} + +static QVariant toObjectOrVariant(const QVariant &v) +{ + switch(v.type()) { + case QVariant::String: + case QVariant::UInt: + case QVariant::Int: + case 135: + case QVariant::Double: + case QVariant::Color: + case QVariant::Bool: + default: + return v; + case QVariant::UserType: + { + QObject *o = QmlMetaType::toQObject(v); + if (o) + return qVariantFromValue(o); + else + return v; + } + break; + } +} + +static QVariant fetch_value(QObject *o, int idx, int type) +{ + switch(type) { + case QVariant::String: + { + QString val; + void *args[] = { &val, 0 }; + QMetaObject::metacall(o, QMetaObject::ReadProperty, idx, args); + return QVariant(val); + } + break; + case QVariant::UInt: + { + uint val; + void *args[] = { &val, 0 }; + QMetaObject::metacall(o, QMetaObject::ReadProperty, idx, args); + return QVariant(val); + } + break; + case QVariant::Int: + { + int val; + void *args[] = { &val, 0 }; + QMetaObject::metacall(o, QMetaObject::ReadProperty, idx, args); + return QVariant(val); + } + break; + case 135: + case QVariant::Double: + { + qreal val; + void *args[] = { &val, 0 }; + QMetaObject::metacall(o, QMetaObject::ReadProperty, idx, args); + return QVariant(val); + } + break; + case QVariant::Color: + { + QColor val; + void *args[] = { &val, 0 }; + QMetaObject::metacall(o, QMetaObject::ReadProperty, idx, args); + return QVariant(val); + } + break; + case QVariant::Bool: + { + bool val; + void *args[] = { &val, 0 }; + QMetaObject::metacall(o, QMetaObject::ReadProperty, idx, args); + return QVariant(val); + } + break; + default: + { + if(QmlMetaType::isObject(type)) { + // NOTE: This assumes a cast to QObject does not alter the + // object pointer + QObject *val = 0; + void *args[] = { &val, 0 }; + QMetaObject::metacall(o, QMetaObject::ReadProperty, idx, args); + return QVariant::fromValue(val); + } else { + QVariant var = o->metaObject()->property(idx).read(o); + if(QmlMetaType::isObject(var.userType())) { + QObject *obj = 0; + obj = *(QObject **)var.data(); + var = QVariant::fromValue(obj); + } + return var; + } + } + break; + }; +} + +QVariant QmlBasicScriptNodeCache::value(const char *name) const +{ + //QFxPerfTimer<QFxPerf::BasicScriptValue> pt; + switch(type) { + case Invalid: + break; + case Core: + return fetch_value(object, core, coreType); + break; + case Attached: + return qVariantFromValue(static_cast<QObject *>(attached)); + break; + case Signal: + // XXX + Q_ASSERT(!"Not implemented"); + break; + case SignalProperty: + break; + case Explicit: + return qVariantFromValue(object); + break; + case Variant: + return toObjectOrVariant(context->variantProperties[QLatin1String(name)]); + break; + case ScriptValue: + return qVariantFromValue(context->properties[QLatin1String(name)]); + break; + }; + return QVariant(); +} + +struct QmlBasicScriptCompiler +{ + QmlBasicScriptCompiler() + : script(0), stateSize(0), src(0), idx(0) {} + QmlBasicScript *script; + QList<LexerToken> tokens; + int stateSize; + const char *src; + int idx; + + bool compile(); + bool compileExpr(); + + bool parseFetch(); + bool parseName(); + bool parseConstant(); + void skipWhitespace(); + + QByteArray data; + QList<ScriptInstruction> bytecode; + + QByteArray string(int, int); + Token token() const; + bool atEnd() const; + void adv(); + int index() const; +}; + +/*! + \class QmlBasicScript + \brief The QmlBasicScript class provides a fast implementation of a limited subset of JavaScript bindings. + + QmlBasicScript instances are used to accelerate binding. Instead of using + the slower, fully fledged JavaScript engine, many simple bindings can be + evaluated using the QmlBasicScript engine. + + To see if the QmlBasicScript engine can handle a binding, call compile() + and check the return value, or isValid() afterwards. + + To evaluate the binding, the QmlBasicScript instance needs some memory in + which to cache state. This may be allocated by calling newScriptState() + and destroyed by calling deleteScriptState(). The state data is then passed + to the run() method when evaluating the binding. + + To further accelerate binding, QmlBasicScript can return a precompiled + version of itself that can be saved for future use. Call compileData() to + get an opaque pointer to the compiled state, and compileDataSize() for the + size of this data in bytes. This data can be saved and passed to future + instances of the QmlBasicScript constructor. The initial copy of compile + data is owned by the QmlBindScript instance on which compile() was called. +*/ + +/*! + Create a new QmlBasicScript instance. +*/ +QmlBasicScript::QmlBasicScript() +: flags(0), d(0), rc(0) +{ +} + +/*! + Create a new QmlBasicScript instance from saved \a data. + + \a data \b must be data previously acquired from calling compileData() on a + previously created QmlBasicScript instance. Any other data will almost + certainly cause the QmlBasicScript engine to crash. + + \a data must continue to be valid throughout the QmlBasicScript instance + life. It does not assume ownership of the memory. + + If \a owner is set, it is referenced on creation and dereferenced on + destruction of this instance. +*/ +QmlBasicScript::QmlBasicScript(const char *data, QmlRefCount *owner) +: flags(0), d((QmlBasicScriptPrivate *)data), rc(owner) +{ + if(rc) rc->addref(); +} + +/*! + Return the text of the script expression. + */ +QByteArray QmlBasicScript::expression() const +{ + if(!d) + return QByteArray(); + else + return QByteArray(d->expr()); +} + +/*! + Destroy the script instance. +*/ +QmlBasicScript::~QmlBasicScript() +{ + if(flags & QmlBasicScriptPrivate::OwnData) + free(d); + if(rc) rc->release(); + d = 0; + rc = 0; +} + +/*! + Clear this script. The object will then be in its initial state, as though + it were freshly constructed with default constructor. +*/ +void QmlBasicScript::clear() +{ + if(flags & QmlBasicScriptPrivate::OwnData) + free(d); + if(rc) rc->release(); + d = 0; + rc = 0; + flags = 0; +} + +/*! + Return the script state memory for this script instance. This memory should + only be destroyed by calling deleteScriptState(). + */ +void *QmlBasicScript::newScriptState() +{ + if(!d) { + return 0; + } else { + void *rv = ::malloc(d->stateSize * sizeof(QmlBasicScriptNodeCache)); + ::memset(rv, 0, d->stateSize * sizeof(QmlBasicScriptNodeCache)); + return rv; + } +} + +/*! + Delete the \a data previously allocated by newScriptState(). + */ +void QmlBasicScript::deleteScriptState(void *data) +{ + if(!data) return; + Q_ASSERT(d); + clearCache(data); + free(data); +} + +/*! + Dump the script instructions to stderr for debugging. + */ +void QmlBasicScript::dump() +{ + if(!d) + return; + + qWarning() << d->instructionCount << "instructions:"; + const char *data = d->data(); + for(int ii = 0; ii < d->instructionCount; ++ii) { + const ScriptInstruction &instr = d->instructions()[ii]; + + switch(instr.type) { + case ScriptInstruction::Load: + qWarning().nospace() << "LOAD\t\t" << instr.fetch.idx << "\t\t" + << QByteArray(data + instr.fetch.idx); + break; + case ScriptInstruction::Fetch: + qWarning().nospace() << "FETCH\t\t" << instr.fetch.idx << "\t\t" + << QByteArray(data + instr.fetch.idx); + break; + case ScriptInstruction::Add: + qWarning().nospace() << "ADD"; + break; + case ScriptInstruction::Subtract: + qWarning().nospace() << "SUBTRACT"; + break; + case ScriptInstruction::Multiply: + qWarning().nospace() << "MULTIPLY"; + break; + case ScriptInstruction::Equals: + qWarning().nospace() << "EQUALS"; + break; + case ScriptInstruction::Int: + qWarning().nospace() << "INT\t\t" << instr.integer.value; + break; + case ScriptInstruction::Bool: + qWarning().nospace() << "BOOL\t\t" << instr.boolean.value; + break; + default: + qWarning().nospace() << "UNKNOWN"; + break; + } + } +} + +/*! + Return true if this is a valid script binding, otherwise returns false. + */ +bool QmlBasicScript::isValid() const +{ + return d != 0; +} + +/*! + Compile \a src and return true if the compilation is successful, otherwise + returns false. + */ +bool QmlBasicScript::compile(const QByteArray &src) +{ + bool rv = compile(src.constData()); + return rv; +} + +/*! + \overload + + Compile \a src and return true if the compilation is successful, otherwise + returns false. + */ +bool QmlBasicScript::compile(const char *src) +{ + if(!src) return false; + + QmlBasicScriptCompiler bsc; + bsc.script = this; + bsc.tokens = tokenize(src); + bsc.src = src; + // dumpTokens(src, bsc.tokens); + + if(d) { + if(flags & QmlBasicScriptPrivate::OwnData) + free(d); + d = 0; + flags = 0; + } + + if(bsc.compile()) { + int len = ::strlen(src); + flags = QmlBasicScriptPrivate::OwnData; + int size = sizeof(QmlBasicScriptPrivate) + + bsc.bytecode.count() * sizeof(ScriptInstruction) + + QmlBasicScriptPrivate::alignRound(bsc.data.count() + len + 1); + d = (QmlBasicScriptPrivate *) malloc(size); + d->size = size; + d->stateSize = bsc.stateSize; + d->instructionCount = bsc.bytecode.count(); + d->exprLen = len; + ::memcpy((char *)d->expr(), src, len + 1); + for(int ii = 0; ii < d->instructionCount; ++ii) + d->instructions()[ii] = bsc.bytecode.at(ii); + ::memcpy((char *)d->data(), bsc.data.constData(), bsc.data.count()); + } + + return d != 0; +} + +void QmlBasicScriptCompiler::skipWhitespace() +{ + while(idx < tokens.count() && tokens.at(idx).token == WHITESPACE) + ++idx; +} + +bool QmlBasicScriptCompiler::compile() +{ + if(!compileExpr()) + return false; + + skipWhitespace(); + + if(atEnd()) + return true; + + int t = token(); + if(t != AND) + return false; + + adv(); + skipWhitespace(); + if(!compileExpr()) + return false; + + ScriptInstruction instr; + instr.type = ScriptInstruction::And; + bytecode.append(instr); + + skipWhitespace(); + + return atEnd(); +} + +bool QmlBasicScriptCompiler::compileExpr() +{ + /* + EXPRESSION := <NAME><OPERATOR>[<CONSTANT>|<NAME>] + */ + + if(!parseName()) + return false; + + skipWhitespace(); + + if(atEnd()) + return true; + + int t = token(); + switch(t) { + case PLUS: + case MINUS: + /* + case LANGLE: + case RANGLE: + */ + case STAR: + case EQUALS: + break; + default: + return true; + } + adv(); + + skipWhitespace(); + + if(!parseConstant() && + !parseName()) + return false; + + ScriptInstruction instr; + switch(t) { + case PLUS: + instr.type = ScriptInstruction::Add; + break; + case MINUS: + instr.type = ScriptInstruction::Subtract; + break; + case STAR: + instr.type = ScriptInstruction::Multiply; + break; + case EQUALS: + instr.type = ScriptInstruction::Equals; + break; + default: + break; + } + bytecode.append(instr); + + skipWhitespace(); + + return true; +} + +bool QmlBasicScriptCompiler::parseName() +{ + skipWhitespace(); + + bool named = false; + bool seenchar = false; + bool seendot = false; + int namestart = -1; + bool pushed = false; + while(!atEnd()) { + int t = token(); + if(t == CHARACTER) { + named = true; + seendot = false; + seenchar = true; + namestart = index(); + adv(); + } else if(t == DIGIT) { + if(!seenchar) break; + adv(); + } else if(t == DOT) { + seendot = true; + if(namestart == -1) + break; + + seenchar = false; + QByteArray name = string(namestart, index() - 1); + int nref = data.count(); + data.append(name); + data.append('\0'); + ScriptInstruction instr; + if(pushed) + instr.type = ScriptInstruction::Fetch; + else + instr.type = ScriptInstruction::Load; + pushed = true; + instr.fetch.idx = nref; + bytecode.append(instr); + ++stateSize; + namestart = -1; + adv(); + } else { + break; + } + } + + if(namestart != -1) { + QByteArray name = string(namestart, index() - 1); + int nref = data.count(); + data.append(name); + data.append('\0'); + ScriptInstruction instr; + if(pushed) + instr.type = ScriptInstruction::Fetch; + else + instr.type = ScriptInstruction::Load; + pushed = true; + instr.fetch.idx = nref; + bytecode.append(instr); + ++stateSize; + } + + if(seendot) + return false; + else + return named; +} + +bool QmlBasicScriptCompiler::parseConstant() +{ + switch(token()) { + case DIGIT: + { + ScriptInstruction instr; + instr.type = ScriptInstruction::Int; + instr.integer.value = string(index(), index()).toUInt(); + bytecode.append(instr); + adv(); + } + break; + case TOKEN_TRUE: + case TOKEN_FALSE: + { + ScriptInstruction instr; + instr.type = ScriptInstruction::Bool; + instr.boolean.value = (token() == TOKEN_TRUE); + bytecode.append(instr); + adv(); + } + break; + + default: + return false; + } + + return true; +} + +bool QmlBasicScriptCompiler::atEnd() const +{ + return idx >= tokens.count(); +} + +Token QmlBasicScriptCompiler::token() const +{ + return tokens.at(idx).token; +} + +void QmlBasicScriptCompiler::adv() +{ + ++idx; +} + +int QmlBasicScriptCompiler::index() const +{ + return idx; +} + +QByteArray QmlBasicScriptCompiler::string(int from, int to) +{ + QByteArray rv; + for(int ii = from; ii <= to; ++ii) { + const LexerToken &token = tokens.at(ii); + rv.append(QByteArray(src + token.start, token.end - token.start + 1)); + } + return rv; +} + +/*! + \internal +*/ +void QmlBasicScript::clearCache(void *voidCache) +{ + QmlBasicScriptNodeCache *dataCache = + reinterpret_cast<QmlBasicScriptNodeCache *>(voidCache); + + for(int ii = 0; ii < d->stateSize; ++ii) { + if(!dataCache[ii].isCore() && !dataCache[ii].isExplicit() && + dataCache[ii].object) { + QMetaObject::removeGuard(&dataCache[ii].object); + dataCache[ii].object = 0; + } + dataCache[ii].clear(); + } +} + +void QmlBasicScript::guard(QmlBasicScriptNodeCache &n) +{ + if(n.object) { + if(n.isExplicit()) { + } else if(n.isCore()) { + n.metaObject = + n.object->metaObject(); + } else { + QMetaObject::addGuard(&n.object); + } + } +} + +bool QmlBasicScript::valid(QmlBasicScriptNodeCache &n, QObject *obj) +{ + return n.object == obj && + (!n.isCore() || obj->metaObject() == n.metaObject); +} + + +/*! + \enum QmlBasicScript::CacheState + \value NoChange The query has not change. Any previous monitoring is still + valid. + \value Incremental The query has been incrementally changed. Any previous + monitoring is still valid, but needs to have the fresh properties added to + it. + \value Reset The entire query has been reset from the beginning. Any previous + monitoring is now invalid. +*/ + +/*! + Run the script in \a context and return the result. \a voidCache should + contain state memory previously acquired from newScript. + */ +QVariant QmlBasicScript::run(QmlContext *context, void *voidCache, CacheState *cached) +{ + if(!isValid()) + return QVariant(); + + QmlBasicScriptNodeCache *dataCache = + reinterpret_cast<QmlBasicScriptNodeCache *>(voidCache); + int dataCacheItem; + QStack<QVariant> stack; + + bool resetting = false; + bool hasReset = false; + + const char *data = d->data(); + + if(dataCache[0].type == QmlBasicScriptNodeCache::Invalid) { + resetting = true; + hasReset = true; + } + + CacheState state = NoChange; + + dataCacheItem = 0; + for(int idx = 0; idx < d->instructionCount; ++idx) { + const ScriptInstruction &instr = d->instructions()[idx]; + + switch(instr.type) { + case ScriptInstruction::Load: // either an object or a property + case ScriptInstruction::Fetch: // can only be a property + { + const char *id = data + instr.fetch.idx; + QmlBasicScriptNodeCache &n = dataCache[dataCacheItem]; + + if(instr.type == ScriptInstruction::Load) { + + if(n.type == QmlBasicScriptNodeCache::Invalid) { + context->engine()->d_func()->loadCache(n, QLatin1String(id), static_cast<QmlContextPrivate*>(context->d_ptr)); + state = Incremental; + } + + } else { // instr.type == ScriptInstruction::Fetch + + QVariant o = stack.pop(); + QObject *obj = qvariant_cast<QObject *>(o); + if(!obj) { + if(n.type == QmlBasicScriptNodeCache::Invalid) { + if(scriptWarnings()) + qWarning() << "QmlBasicScript: Unable to convert" << o; + *cached = state; + return QVariant(); + } else { + clearCache(dataCache); + *cached = Reset; + CacheState dummy; + return run(context, voidCache, &dummy); + } + } else if(n.type == QmlBasicScriptNodeCache::Invalid) { + context->engine()->d_func()->fetchCache(n, QLatin1String(id), obj); + guard(n); + state = Incremental; + } else if(!valid(n, obj)) { + clearCache(dataCache); + *cached = Reset; + CacheState dummy; + return run(context, voidCache, &dummy); + } + + } + + QVariant var = n.value(id); + stack.push(var); + ++dataCacheItem; + } + break; + case ScriptInstruction::Int: + stack.push(QVariant(instr.integer.value)); + break; + case ScriptInstruction::Bool: + stack.push(QVariant(instr.boolean.value)); + break; + case ScriptInstruction::Add: + { + QVariant rhs = stack.pop(); + QVariant lhs = stack.pop(); + + stack.push(rhs.toDouble() + lhs.toDouble()); + } + break; + case ScriptInstruction::Subtract: + { + QVariant rhs = stack.pop(); + QVariant lhs = stack.pop(); + + stack.push(lhs.toDouble() - rhs.toDouble()); + } + break; + case ScriptInstruction::Multiply: + { + QVariant rhs = stack.pop(); + QVariant lhs = stack.pop(); + + stack.push(rhs.toDouble() * lhs.toDouble()); + } + break; + case ScriptInstruction::Equals: + { + QVariant rhs = stack.pop(); + QVariant lhs = stack.pop(); + + stack.push(rhs == lhs); + } + break; + case ScriptInstruction::And: + { + QVariant rhs = stack.pop(); + QVariant lhs = stack.pop(); + + stack.push(rhs.toBool() && lhs.toBool()); + } + break; + default: + break; + } + } + + *cached = state; + + if(stack.isEmpty()) + return QVariant(); + else + return stack.top(); +} + +/*! + Return a pointer to the script's compile data, or null if there is no data. + */ +const char *QmlBasicScript::compileData() const +{ + return (const char *)d; +} + +/*! + Return the size of the script's compile data, or zero if there is no data. + The size will always be a multiple of 4. + */ +unsigned int QmlBasicScript::compileDataSize() const +{ + if(d) + return d->size; + else + return 0; +} + +bool QmlBasicScript::isSingleLoad() const +{ + if(!d) + return false; + + return d->instructionCount == 1 && + d->instructions()[0].type == ScriptInstruction::Load; +} + +QByteArray QmlBasicScript::singleLoadTarget() const +{ + if(!isSingleLoad()) + return QByteArray(); + + // We know there is one instruction and it is a load + return QByteArray(d->data() + d->instructions()[0].fetch.idx); +} + + +QT_END_NAMESPACE diff --git a/src/declarative/qml/script/qmlbasicscript.h b/src/declarative/qml/script/qmlbasicscript.h new file mode 100644 index 0000000..d465f04 --- /dev/null +++ b/src/declarative/qml/script/qmlbasicscript.h @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $TROLLTECH_DUAL_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLBASICSCRIPT_H +#define QMLBASICSCRIPT_H + +#include "instructions.h" +#include <QList> +#include <QByteArray> +#include "lexer.h" +#include <QVariant> + + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Declarative) +class QmlRefCount; +class QmlContext; +class QmlBasicScriptPrivate; +class QmlBasicScriptNodeCache; +class QmlBasicScript +{ +public: + QmlBasicScript(); + QmlBasicScript(const char *, QmlRefCount * = 0); + ~QmlBasicScript(); + + // Always 4-byte aligned + const char *compileData() const; + unsigned int compileDataSize() const; + + QByteArray expression() const; + + bool compile(const QByteArray &); + bool compile(const char *); + bool isValid() const; + + void clear(); + + void dump(); + void *newScriptState(); + void deleteScriptState(void *); + + enum CacheState { NoChange, Incremental, Reset }; + QVariant run(QmlContext *, void *, CacheState *); + + // Optimization opportunities + bool isSingleLoad() const; + QByteArray singleLoadTarget() const; + +private: + int flags; + QmlBasicScriptPrivate *d; + QmlRefCount *rc; + + void clearCache(void *); + void guard(QmlBasicScriptNodeCache &); + bool valid(QmlBasicScriptNodeCache &, QObject *); +}; + +#endif // QMLBASICSCRIPT_H + + +QT_END_NAMESPACE + +QT_END_HEADER diff --git a/src/declarative/qml/script/qmlbasicscript_p.h b/src/declarative/qml/script/qmlbasicscript_p.h new file mode 100644 index 0000000..bcb7d00 --- /dev/null +++ b/src/declarative/qml/script/qmlbasicscript_p.h @@ -0,0 +1,52 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Contact: Qt Software Information (qt-info@nokia.com) +** +** This file is part of the $MODULE$ of the Qt Toolkit. +** +** $TROLLTECH_DUAL_LICENSE$ +** +****************************************************************************/ + +#ifndef QMLBASICSCRIPT_P_H +#define QMLBASICSCRIPT_P_H + +QT_BEGIN_NAMESPACE + +class QObject; +class QmlContextPrivate; +class QDebug; +class QByteArray; + +class QmlBasicScriptNodeCache +{ +public: + QObject *object; + const QMetaObject *metaObject; + enum { Invalid, + Core, + Attached, + Signal, + SignalProperty, + Explicit, + Variant, + ScriptValue } type; + union { + int core; + QObject *attached; + QmlContextPrivate *context; + }; + int coreType; + + bool isCore() const { return type == Core; } + bool isExplicit() const { return type == Explicit; } + void clear(); + QVariant value(const char *) const; +}; + +QDebug operator<<(QDebug, const QmlBasicScriptNodeCache &); + +#endif // QMLBASICSCRIPT_P_H + +QT_END_NAMESPACE diff --git a/src/declarative/qml/script/script.pri b/src/declarative/qml/script/script.pri new file mode 100644 index 0000000..6c43efe --- /dev/null +++ b/src/declarative/qml/script/script.pri @@ -0,0 +1,11 @@ +SOURCES += \ + qml/script/tokens.cpp \ + qml/script/lexer.cpp \ + qml/script/qmlbasicscript.cpp + +HEADERS += \ + qml/script/tokens.h \ + qml/script/lexer.h \ + qml/script/instructions.h \ + qml/script/qmlbasicscript.h \ + qml/script/qmlbasicscript_p.h diff --git a/src/declarative/qml/script/tokens.cpp b/src/declarative/qml/script/tokens.cpp new file mode 100644 index 0000000..51b46f0 --- /dev/null +++ b/src/declarative/qml/script/tokens.cpp @@ -0,0 +1,44 @@ +/**************************************************************************** +** +** This file is part of the $PACKAGE_NAME$. +** +** Copyright (C) $THISYEAR$ $COMPANY_NAME$. +** +** $QT_EXTENDED_DUAL_LICENSE$ +** +****************************************************************************/ + +#include "tokens.h" + + +/*! + \relates <tokens.h> + Returns a string representation of token \a tok. +*/ +const char *tokenToString(Token tok) +{ + switch(tok) { +#define CASE(X) case X: return #X; + CASE(NOTOKEN) + CASE(INCOMPLETE) + CASE(WHITESPACE) + CASE(LANGLE) + CASE(RANGLE) + CASE(PLUS) + CASE(MINUS) + CASE(STAR) + CASE(EQUALS) + CASE(DOT) + CASE(CHARACTER) + CASE(DIGIT) + CASE(OTHER) + CASE(AND) + case TOKEN_TRUE: + return "TRUE"; + case TOKEN_FALSE: + return "FALSE"; +#undef CASE + } + return 0; +} + diff --git a/src/declarative/qml/script/tokens.h b/src/declarative/qml/script/tokens.h new file mode 100644 index 0000000..753e40c --- /dev/null +++ b/src/declarative/qml/script/tokens.h @@ -0,0 +1,36 @@ +/**************************************************************************** +** +** This file is part of the $PACKAGE_NAME$. +** +** Copyright (C) $THISYEAR$ $COMPANY_NAME$. +** +** $QT_EXTENDED_DUAL_LICENSE$ +** +****************************************************************************/ + +#ifndef TOKENS_H +#define TOKENS_H + +enum Token { + // Lexer tokens + NOTOKEN, + INCOMPLETE, + WHITESPACE, + LANGLE, + RANGLE, + PLUS, + MINUS, + STAR, + EQUALS, + AND, + DOT, + CHARACTER, + DIGIT, + TOKEN_TRUE, + TOKEN_FALSE, + OTHER +}; + +const char *tokenToString(Token); + +#endif |