From 6207a3a04080f1d4423a50c4b2a2aeb93052a392 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Fri, 25 Sep 2009 17:15:19 +1000 Subject: Prototype a QScriptDeclarativeClass that fits better with qml --- src/script/bridge/bridge.pri | 8 +- src/script/bridge/qscriptdeclarativeclass.cpp | 221 +++++++++++++++++++++++++ src/script/bridge/qscriptdeclarativeclass_p.h | 127 ++++++++++++++ src/script/bridge/qscriptdeclarativeobject.cpp | 186 +++++++++++++++++++++ src/script/bridge/qscriptdeclarativeobject_p.h | 110 ++++++++++++ src/script/bridge/qscriptobject_p.h | 3 +- 6 files changed, 652 insertions(+), 3 deletions(-) create mode 100644 src/script/bridge/qscriptdeclarativeclass.cpp create mode 100644 src/script/bridge/qscriptdeclarativeclass_p.h create mode 100644 src/script/bridge/qscriptdeclarativeobject.cpp create mode 100644 src/script/bridge/qscriptdeclarativeobject_p.h diff --git a/src/script/bridge/bridge.pri b/src/script/bridge/bridge.pri index 666a07e..09e2dfb 100644 --- a/src/script/bridge/bridge.pri +++ b/src/script/bridge/bridge.pri @@ -5,7 +5,9 @@ SOURCES += \ $$PWD/qscriptvariant.cpp \ $$PWD/qscriptqobject.cpp \ $$PWD/qscriptglobalobject.cpp \ - $$PWD/qscriptactivationobject.cpp + $$PWD/qscriptactivationobject.cpp \ + $$PWD/qscriptdeclarativeobject.cpp \ + $$PWD/qscriptdeclarativeclass.cpp HEADERS += \ $$PWD/qscriptfunction_p.h \ @@ -14,4 +16,6 @@ HEADERS += \ $$PWD/qscriptvariant_p.h \ $$PWD/qscriptqobject_p.h \ $$PWD/qscriptglobalobject_p.h \ - $$PWD/qscriptactivationobject_p.h + $$PWD/qscriptactivationobject_p.h \ + $$PWD/qscriptdeclarativeobject_p.h \ + $$PWD/qscriptdeclarativeclass_p.h diff --git a/src/script/bridge/qscriptdeclarativeclass.cpp b/src/script/bridge/qscriptdeclarativeclass.cpp new file mode 100644 index 0000000..47b693f --- /dev/null +++ b/src/script/bridge/qscriptdeclarativeclass.cpp @@ -0,0 +1,221 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtScript 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 Technology Preview License Agreement accompanying +** this package. +** +** 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.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qscriptdeclarativeclass_p.h" +#include "qscriptdeclarativeobject_p.h" +#include "qscriptobject_p.h" +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QScriptDeclarativeClassPrivate +{ +public: + QScriptDeclarativeClassPrivate() {} + + QScriptEngine *engine; + QScriptDeclarativeClass *q_ptr; +}; + +void QScriptDeclarativeClass::destroyPersistentIdentifier(void **d) +{ + ((JSC::Identifier *)d)->JSC::Identifier::~Identifier(); +} + +void QScriptDeclarativeClass::initPersistentIdentifier(void **d, Identifier *i, const QString &str) +{ + QScriptEnginePrivate *p = + static_cast(QObjectPrivate::get(d_ptr->engine)); + JSC::ExecState* exec = p->currentFrame; + + new (*d) JSC::Identifier(exec, (UChar *)str.constData(), str.size()); + *i = (Identifier)((JSC::Identifier *)*d)->ustring().rep(); +} + +void QScriptDeclarativeClass::initPersistentIdentifier(void **d, Identifier *i, const Identifier &id) +{ + QScriptEnginePrivate *p = + static_cast(QObjectPrivate::get(d_ptr->engine)); + JSC::ExecState* exec = p->currentFrame; + + new (*d) JSC::Identifier(exec, (JSC::UString::Rep *)id); + *i = id; +} + +QScriptDeclarativeClass::QScriptDeclarativeClass(QScriptEngine *engine) +: d_ptr(new QScriptDeclarativeClassPrivate) +{ + Q_ASSERT(sizeof(void*) == sizeof(JSC::Identifier)); + d_ptr->q_ptr = this; + d_ptr->engine = engine; +} + +QScriptValue QScriptDeclarativeClass::newObject(QScriptEngine *engine, + QScriptDeclarativeClass *scriptClass, + Object object) +{ + Q_ASSERT(engine); + Q_ASSERT(scriptClass); + + QScriptEnginePrivate *p = static_cast(QObjectPrivate::get(engine)); + + JSC::ExecState* exec = p->currentFrame; + QScriptObject *result = new (exec) QScriptObject(p->scriptObjectStructure); + result->setDelegate(new QScript::DeclarativeObjectDelegate(scriptClass, object)); + return p->scriptValueFromJSCValue(result); +} + +QScriptDeclarativeClass *QScriptDeclarativeClass::scriptClass(const QScriptValue &v) +{ + QScriptValuePrivate *d = QScriptValuePrivate::get(v); + if (!d || !d->isJSC() || !d->jscValue.isObject(&QScriptObject::info)) + return 0; + QScriptObject *scriptObject = static_cast(JSC::asObject(d->jscValue)); + QScriptObjectDelegate *delegate = scriptObject->delegate(); + if (!delegate || (delegate->type() != QScriptObjectDelegate::DeclarativeClassObject)) + return 0; + return static_cast(delegate)->scriptClass(); +} + +QScriptDeclarativeClass::Object QScriptDeclarativeClass::object(const QScriptValue &v) +{ + QScriptValuePrivate *d = QScriptValuePrivate::get(v); + if (!d || !d->isJSC() || !d->jscValue.isObject(&QScriptObject::info)) + return 0; + QScriptObject *scriptObject = static_cast(JSC::asObject(d->jscValue)); + QScriptObjectDelegate *delegate = scriptObject->delegate(); + if (!delegate || (delegate->type() != QScriptObjectDelegate::DeclarativeClassObject)) + return 0; + return static_cast(delegate)->object(); +} + +QScriptDeclarativeClass::~QScriptDeclarativeClass() +{ +} + +QScriptEngine *QScriptDeclarativeClass::engine() const +{ + return d_ptr->engine; +} + +/* +QScriptDeclarativeClass::PersistentIdentifier * +QScriptDeclarativeClass::createPersistentIdentifier(const QString &str) +{ + QScriptEnginePrivate *p = + static_cast(QObjectPrivate::get(d_ptr->engine)); + JSC::ExecState* exec = p->currentFrame; + + PersistentIdentifierPrivate *rv = new PersistentIdentifierPrivate; + rv->identifierValue = JSC::Identifier(exec, (UChar *)str.constData(), str.size()); + rv->identifier = (void *)rv->identifierValue.ustring().rep(); + return rv; +} + +QScriptDeclarativeClass::PersistentIdentifier * +QScriptDeclarativeClass::createPersistentIdentifier(const Identifier &id) +{ + QScriptEnginePrivate *p = + static_cast(QObjectPrivate::get(d_ptr->engine)); + JSC::ExecState* exec = p->currentFrame; + + PersistentIdentifierPrivate *rv = new PersistentIdentifierPrivate; + rv->identifierValue = JSC::Identifier(exec, (JSC::UString::Rep *)id); + rv->identifier = (void *)rv->identifierValue.ustring().rep(); + return rv; +} +*/ + + +QString QScriptDeclarativeClass::toString(const Identifier &identifier) +{ + JSC::UString::Rep *r = (JSC::UString::Rep *)identifier; + return QString((QChar *)r->data(), r->size()); +} + +QScriptClass::QueryFlags +QScriptDeclarativeClass::queryProperty(const Object &object, const Identifier &name, + QScriptClass::QueryFlags flags) +{ + Q_UNUSED(object); + Q_UNUSED(name); + Q_UNUSED(flags); + return 0; +} + +QScriptValue QScriptDeclarativeClass::property(const Object &object, const Identifier &name) +{ + Q_UNUSED(object); + Q_UNUSED(name); + return QScriptValue(); +} + +void QScriptDeclarativeClass::setProperty(const Object &object, const Identifier &name, + const QScriptValue &value) +{ + Q_UNUSED(object); + Q_UNUSED(name); + Q_UNUSED(value); +} + +QScriptValue::PropertyFlags +QScriptDeclarativeClass::propertyFlags(const Object &object, const Identifier &name) +{ + Q_UNUSED(object); + Q_UNUSED(name); + return 0; +} + +QStringList QScriptDeclarativeClass::propertyNames(const Object &object) +{ + Q_UNUSED(object); + return QStringList(); +} + +void QScriptDeclarativeClass::destroyed(const Object &object) +{ + Q_UNUSED(object); +} + diff --git a/src/script/bridge/qscriptdeclarativeclass_p.h b/src/script/bridge/qscriptdeclarativeclass_p.h new file mode 100644 index 0000000..5705a51 --- /dev/null +++ b/src/script/bridge/qscriptdeclarativeclass_p.h @@ -0,0 +1,127 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtScript 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 Technology Preview License Agreement accompanying +** this package. +** +** 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.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSCRIPTDECLARATIVECLASS_P_H +#define QSCRIPTDECLARATIVECLASS_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QScriptDeclarativeClassPrivate; +class PersistentIdentifierPrivate; +class Q_SCRIPT_EXPORT QScriptDeclarativeClass +{ +public: + typedef void* Identifier; + typedef void* Object; + + static QScriptValue newObject(QScriptEngine *, QScriptDeclarativeClass *, Object); + static QScriptDeclarativeClass *scriptClass(const QScriptValue &); + static Object object(const QScriptValue &); + + template + class PersistentIdentifier : public T { + public: + Identifier identifier; + + ~PersistentIdentifier() { QScriptDeclarativeClass::destroyPersistentIdentifier(&d); } + private: + friend class QScriptDeclarativeClass; + PersistentIdentifier() : identifier(0), d(0) {} + void *d; + }; + + QScriptDeclarativeClass(QScriptEngine *engine); + virtual ~QScriptDeclarativeClass(); + + QScriptEngine *engine() const; + + template + PersistentIdentifier *createPersistentIdentifier(const QString &str) { + PersistentIdentifier *rv = new PersistentIdentifier; + initPersistentIdentifier(&rv->d, &rv->identifier, str); + return rv; + } + template + PersistentIdentifier *createPersistentIdentifier(const Identifier &id) { + PersistentIdentifier *rv = new PersistentIdentifier; + initPersistentIdentifier(&rv->d, &rv->identifier, id); + return rv; + } + + QString toString(const Identifier &); + + virtual QScriptClass::QueryFlags queryProperty(const Object &, const Identifier &, + QScriptClass::QueryFlags flags); + + virtual QScriptValue property(const Object &, const Identifier &); + virtual void setProperty(const Object &, const Identifier &name, const QScriptValue &); + virtual QScriptValue::PropertyFlags propertyFlags(const Object &, const Identifier &); + + virtual QStringList propertyNames(const Object &); + + virtual void destroyed(const Object &); + + static void destroyPersistentIdentifier(void **); + void initPersistentIdentifier(void **, Identifier *, const QString &); + void initPersistentIdentifier(void **, Identifier *, const Identifier &); + +protected: + QScopedPointer d_ptr; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/script/bridge/qscriptdeclarativeobject.cpp b/src/script/bridge/qscriptdeclarativeobject.cpp new file mode 100644 index 0000000..62c2686 --- /dev/null +++ b/src/script/bridge/qscriptdeclarativeobject.cpp @@ -0,0 +1,186 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtScript 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 Technology Preview License Agreement accompanying +** this package. +** +** 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.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "config.h" +#include "qscriptdeclarativeobject_p.h" + +#include "../api/qscriptengine.h" +#include "../api/qscriptengine_p.h" +#include "../api/qscriptcontext.h" +#include "../api/qscriptcontext_p.h" +#include "../api/qscriptclass.h" +#include "../api/qscriptclasspropertyiterator.h" + +#include "Error.h" +#include "PropertyNameArray.h" + +#include + +Q_DECLARE_METATYPE(QScriptContext*) +Q_DECLARE_METATYPE(QScriptValue) +Q_DECLARE_METATYPE(QScriptValueList) + +QT_BEGIN_NAMESPACE + +namespace QScript +{ + +DeclarativeObjectDelegate::DeclarativeObjectDelegate(QScriptDeclarativeClass *c, + QScriptDeclarativeClass::Object &o) +: m_class(c), m_object(o) +{ +} + +DeclarativeObjectDelegate::~DeclarativeObjectDelegate() +{ + m_class->destroyed(m_object); +} + +QScriptObjectDelegate::Type DeclarativeObjectDelegate::type() const +{ + return DeclarativeClassObject; +} + +bool DeclarativeObjectDelegate::getOwnPropertySlot(QScriptObject* object, + JSC::ExecState *exec, + const JSC::Identifier &propertyName, + JSC::PropertySlot &slot) +{ + QScriptEnginePrivate *engine = scriptEngineFromExec(exec); + QScriptDeclarativeClass::Identifier identifier = (void *)propertyName.ustring().rep(); + + QScriptClass::QueryFlags flags = + m_class->queryProperty(m_object, identifier, QScriptClass::HandlesReadAccess); + if (flags & QScriptClass::HandlesReadAccess) { + QScriptValue value = m_class->property(m_object, identifier); + slot.setValue(engine->scriptValueToJSCValue(value)); + return true; + } + + return QScriptObjectDelegate::getOwnPropertySlot(object, exec, propertyName, slot); +} + +void DeclarativeObjectDelegate::put(QScriptObject* object, JSC::ExecState *exec, + const JSC::Identifier &propertyName, + JSC::JSValue value, JSC::PutPropertySlot &slot) +{ + QScriptEnginePrivate *engine = scriptEngineFromExec(exec); + QScriptDeclarativeClass::Identifier identifier = (void *)propertyName.ustring().rep(); + + QScriptClass::QueryFlags flags = + m_class->queryProperty(m_object, identifier, QScriptClass::HandlesWriteAccess); + if (flags & QScriptClass::HandlesWriteAccess) { + m_class->setProperty(m_object, identifier, engine->scriptValueFromJSCValue(value)); + return; + } + QScriptObjectDelegate::put(object, exec, propertyName, value, slot); +} + +bool DeclarativeObjectDelegate::deleteProperty(QScriptObject* object, JSC::ExecState *exec, + const JSC::Identifier &propertyName, + bool checkDontDelete) +{ + return QScriptObjectDelegate::deleteProperty(object, exec, propertyName, checkDontDelete); +} + +bool DeclarativeObjectDelegate::getPropertyAttributes(const QScriptObject* object, + JSC::ExecState *exec, + const JSC::Identifier &propertyName, + unsigned &attribs) const +{ + QScriptEnginePrivate *engine = scriptEngineFromExec(exec); + QScriptDeclarativeClass::Identifier identifier = (void *)propertyName.ustring().rep(); + + QScriptClass::QueryFlags flags = + m_class->queryProperty(m_object, identifier, QScriptClass::HandlesReadAccess); + if (flags & QScriptClass::HandlesReadAccess) { + QScriptValue::PropertyFlags flags = m_class->propertyFlags(m_object, identifier); + attribs = 0; + if (flags & QScriptValue::ReadOnly) + attribs |= JSC::ReadOnly; + if (flags & QScriptValue::SkipInEnumeration) + attribs |= JSC::DontEnum; + if (flags & QScriptValue::Undeletable) + attribs |= JSC::DontDelete; + if (flags & QScriptValue::PropertyGetter) + attribs |= JSC::Getter; + if (flags & QScriptValue::PropertySetter) + attribs |= JSC::Setter; + attribs |= flags & QScriptValue::UserRange; + return true; + } + return QScriptObjectDelegate::getPropertyAttributes(object, exec, propertyName, attribs); +} + +void DeclarativeObjectDelegate::getPropertyNames(QScriptObject* object, JSC::ExecState *exec, + JSC::PropertyNameArray &propertyNames, + unsigned listedAttributes) +{ + QScriptEnginePrivate *engine = scriptEngineFromExec(exec); + + QStringList properties = m_class->propertyNames(m_object); + for (int ii = 0; ii < properties.count(); ++ii) { + const QString &name = properties.at(ii); + propertyNames.add(JSC::Identifier(exec, name)); + } + + QScriptObjectDelegate::getPropertyNames(object, exec, propertyNames, listedAttributes); +} + +JSC::CallType DeclarativeObjectDelegate::getCallData(QScriptObject *object, JSC::CallData &callData) +{ + return QScriptObjectDelegate::getCallData(object, callData); +} + +JSC::ConstructType DeclarativeObjectDelegate::getConstructData(QScriptObject* object, JSC::ConstructData &constructData) +{ + return QScriptObjectDelegate::getConstructData(object, constructData); +} + +bool DeclarativeObjectDelegate::hasInstance(QScriptObject* object, JSC::ExecState *exec, + JSC::JSValue value, JSC::JSValue proto) +{ + return QScriptObjectDelegate::hasInstance(object, exec, value, proto); +} + +} // namespace QScript + +QT_END_NAMESPACE diff --git a/src/script/bridge/qscriptdeclarativeobject_p.h b/src/script/bridge/qscriptdeclarativeobject_p.h new file mode 100644 index 0000000..87375d8 --- /dev/null +++ b/src/script/bridge/qscriptdeclarativeobject_p.h @@ -0,0 +1,110 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtScript 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 Technology Preview License Agreement accompanying +** this package. +** +** 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.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSCRIPTDECLARATIVEOBJECT_P_H +#define QSCRIPTDECLARATIVEOBJECT_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include + +#include "qscriptobject_p.h" +#include "qscriptdeclarativeclass_p.h" + +QT_BEGIN_NAMESPACE + +class QScriptClass; + +namespace QScript +{ + +class DeclarativeObjectDelegate : public QScriptObjectDelegate +{ +public: + DeclarativeObjectDelegate(QScriptDeclarativeClass *c, QScriptDeclarativeClass::Object &o); + ~DeclarativeObjectDelegate(); + + virtual Type type() const; + + QScriptDeclarativeClass *scriptClass() const { return m_class; } + QScriptDeclarativeClass::Object object() const { return m_object; } + + virtual bool getOwnPropertySlot(QScriptObject*, JSC::ExecState*, + const JSC::Identifier& propertyName, + JSC::PropertySlot&); + virtual void put(QScriptObject*, JSC::ExecState* exec, + const JSC::Identifier& propertyName, + JSC::JSValue, JSC::PutPropertySlot&); + virtual bool deleteProperty(QScriptObject*, JSC::ExecState*, + const JSC::Identifier& propertyName, + bool checkDontDelete = true); + virtual bool getPropertyAttributes(const QScriptObject*, JSC::ExecState*, + const JSC::Identifier&, + unsigned&) const; + virtual void getPropertyNames(QScriptObject*, JSC::ExecState*, + JSC::PropertyNameArray&, + unsigned listedAttributes = JSC::Structure::Prototype); + + virtual JSC::CallType getCallData(QScriptObject*, JSC::CallData&); + virtual JSC::ConstructType getConstructData(QScriptObject*, JSC::ConstructData&); + + virtual bool hasInstance(QScriptObject*, JSC::ExecState*, + JSC::JSValue value, JSC::JSValue proto); + +private: + QScriptDeclarativeClass *m_class; + QScriptDeclarativeClass::Object m_object; +}; + +} // namespace QScript + +QT_END_NAMESPACE + +#endif diff --git a/src/script/bridge/qscriptobject_p.h b/src/script/bridge/qscriptobject_p.h index c1cee31..a5858ac 100644 --- a/src/script/bridge/qscriptobject_p.h +++ b/src/script/bridge/qscriptobject_p.h @@ -127,7 +127,8 @@ public: enum Type { QtObject, Variant, - ClassObject + ClassObject, + DeclarativeClassObject }; QScriptObjectDelegate(); -- cgit v0.12 From f9f878ca1fff08b6ea24507a84adfeb16d8938b6 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Mon, 28 Sep 2009 18:51:54 +1000 Subject: Add two step compile/evaluate support to QScript --- src/script/api/qscriptengine.cpp | 173 +++++++++++++++++++++++++++++++++++++++ src/script/api/qscriptengine.h | 26 ++++++ 2 files changed, 199 insertions(+) diff --git a/src/script/api/qscriptengine.cpp b/src/script/api/qscriptengine.cpp index fb14940..7256f27 100644 --- a/src/script/api/qscriptengine.cpp +++ b/src/script/api/qscriptengine.cpp @@ -340,6 +340,24 @@ public: JSC::JSValue prototype; }; +class QScriptProgramPrivate +{ +public: + QScriptProgramPrivate() : refcount(1), hasException(false) { } + + void addref() { ++refcount; } + void release() { if (--refcount) delete this; } + + int refcount; + + bool hasException; + QScriptValue exception; + + JSC::SourceCode source; + WTF::RefPtr evalNode; +}; + + namespace QScript { @@ -2114,7 +2132,112 @@ QScriptSyntaxCheckResult QScriptEnginePrivate::checkSyntax(const QString &progra return QScriptSyntaxCheckResult(p); } +QScriptProgram QScriptEngine::compile(const QString &program, const QString &fileName, int lineNumber) +{ + Q_D(QScriptEngine); + + QScriptProgram rv; + rv.d = new QScriptProgramPrivate; + + JSC::JSLock lock(false); // ### hmmm + QBoolBlocker inEval(d->inEval, true); + currentContext()->activationObject(); //force the creation of a context for native function; + + JSC::UString jscProgram = program; + JSC::UString jscFileName = fileName; + JSC::ExecState* exec = d->currentFrame; + + JSC::SourceCode &source = rv.d->source; + source = JSC::makeSource(jscProgram, jscFileName, lineNumber); + + intptr_t sourceId = source.provider()->asID(); + JSC::Debugger* debugger = d->originalGlobalObject()->debugger(); + if (debugger) + debugger->evaluateStart(sourceId); + + exec->clearException(); + JSC::DynamicGlobalObjectScope dynamicGlobalObjectScope(exec, exec->scopeChain()->globalObject()); + + int errorLine; + JSC::UString errorMessage; + WTF::RefPtr &evalNode = rv.d->evalNode; + evalNode = exec->globalData().parser->parse(exec, exec->dynamicGlobalObject()->debugger(), source, &errorLine, &errorMessage); + if (!evalNode) { + JSC::JSValue exceptionValue = JSC::Error::create(exec, JSC::SyntaxError, errorMessage, errorLine, source.provider()->asID(), 0); + exec->setException(exceptionValue); + + if (debugger) { + debugger->exceptionThrow(JSC::DebuggerCallFrame(exec, exceptionValue), sourceId, false); + debugger->evaluateStop(exceptionValue, sourceId); + } + + rv.d->hasException = true; + rv.d->exception = d->scriptValueFromJSCValue(exceptionValue); + } else if (debugger) { + debugger->evaluateStop(JSC::JSValue(), sourceId); + } + + return rv; +} + +QScriptValue QScriptEngine::evaluate(const QScriptProgram &program) +{ + Q_D(QScriptEngine); + + if (0 == program.d) + return QScriptValue(); + else if (program.d->hasException) + return program.d->exception; + else if (!program.d->evalNode) + return QScriptValue(); + + JSC::JSLock lock(false); // ### hmmm + QBoolBlocker inEval(d->inEval, true); + currentContext()->activationObject(); //force the creation of a context for native function; + + JSC::ExecState* exec = d->currentFrame; + + intptr_t sourceId = program.d->source.provider()->asID(); + JSC::Debugger* debugger = d->originalGlobalObject()->debugger(); + if (debugger) + debugger->evaluateStart(sourceId); + + exec->clearException(); + JSC::DynamicGlobalObjectScope dynamicGlobalObjectScope(exec, exec->scopeChain()->globalObject()); + + WTF::RefPtr &evalNode = program.d->evalNode; + + JSC::JSValue thisValue = d->thisForContext(exec); + JSC::JSObject* thisObject = (!thisValue || thisValue.isUndefinedOrNull()) ? exec->dynamicGlobalObject() : thisValue.toObject(exec); + JSC::JSValue exceptionValue; + d->timeoutChecker()->setShouldAbort(false); + JSC::JSValue result = exec->interpreter()->execute(evalNode.get(), exec, thisObject, exec->scopeChain(), &exceptionValue); + + if (d->timeoutChecker()->shouldAbort()) { + if (d->abortResult.isError()) + exec->setException(d->scriptValueToJSCValue(d->abortResult)); + if (debugger) + debugger->evaluateStop(d->scriptValueToJSCValue(d->abortResult), sourceId); + + return d->abortResult; + } + + if (exceptionValue) { + exec->setException(exceptionValue); + + if (debugger) + debugger->evaluateStop(exceptionValue, sourceId); + + return d->scriptValueFromJSCValue(exceptionValue); + } + + if (debugger) + debugger->evaluateStop(result, sourceId); + + Q_ASSERT(!exec->hadException()); + return d->scriptValueFromJSCValue(result); +} /*! Evaluates \a program, using \a lineNumber as the base line number, @@ -3708,6 +3831,9 @@ QScriptValue QScriptEngine::objectById(qint64 id) const return const_cast(d)->scriptValueFromJSCValue((JSC::JSCell*)id); } + + + /*! \since 4.5 \class QScriptSyntaxCheckResult @@ -3836,4 +3962,51 @@ Q_AUTOTEST_EXPORT bool qt_script_isJITEnabled() } #endif +QScriptProgram::QScriptProgram() +: d(0) +{ +} + +QScriptProgram::~QScriptProgram() +{ + if (d) d->release(); +} + +QScriptProgram::QScriptProgram(const QScriptProgram &c) +: d(c.d) +{ + if (d) d->addref(); +} + +QScriptProgram &QScriptProgram::operator=(const QScriptProgram &c) +{ + if (c.d) c.d->addref(); + if (d) d->release(); + d = c.d; + return *this; +} + +bool QScriptProgram::isNull() const +{ + return d == 0; +} + +bool QScriptProgram::hasSyntaxError() const +{ + if (d) return d->hasException; + else return false; +} + +QScriptValue QScriptProgram::syntaxError() const +{ + if (d) return d->exception; + else return QScriptValue(); +} + +QString QScriptProgram::programSource() const +{ + if (d) return d->source.toString(); + else return QString(); +} + QT_END_NAMESPACE diff --git a/src/script/api/qscriptengine.h b/src/script/api/qscriptengine.h index 701f9c6..71266cc 100644 --- a/src/script/api/qscriptengine.h +++ b/src/script/api/qscriptengine.h @@ -120,6 +120,29 @@ private: friend class QScriptEnginePrivate; }; +class QScriptProgramPrivate; +class Q_SCRIPT_EXPORT QScriptProgram +{ +public: + QScriptProgram(); + QScriptProgram(const QScriptProgram &); + ~QScriptProgram(); + + QScriptProgram &operator=(const QScriptProgram &); + + bool isNull() const; + + bool hasSyntaxError() const; + QScriptValue syntaxError() const; + + QString programSource() const; + +private: + friend class QScriptEngine; + QScriptProgramPrivate *d; +}; + +class QScriptCode; class Q_SCRIPT_EXPORT QScriptEngine #ifndef QT_NO_QOBJECT : public QObject @@ -164,6 +187,9 @@ public: bool canEvaluate(const QString &program) const; static QScriptSyntaxCheckResult checkSyntax(const QString &program); + QScriptProgram compile(const QString &program, const QString &fileName = QString(), int lineNumber = 1); + QScriptValue evaluate(const QScriptProgram &); + QScriptValue evaluate(const QString &program, const QString &fileName = QString(), int lineNumber = 1); bool isEvaluating() const; -- cgit v0.12 From 061c85a17ecb303676b548e6daef6e64967ca1e7 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Mon, 28 Sep 2009 21:21:25 +1000 Subject: Use QScriptProgram to speed up binding creation --- src/declarative/qml/qmlcompileddata.cpp | 2 ++ src/declarative/qml/qmlcompiler.cpp | 3 +++ src/declarative/qml/qmlcompiler_p.h | 6 +++--- src/declarative/qml/qmlexpression.cpp | 21 ++++++++++++++++++++- 4 files changed, 28 insertions(+), 4 deletions(-) diff --git a/src/declarative/qml/qmlcompileddata.cpp b/src/declarative/qml/qmlcompileddata.cpp index b2e2d40..a46d893 100644 --- a/src/declarative/qml/qmlcompileddata.cpp +++ b/src/declarative/qml/qmlcompileddata.cpp @@ -159,6 +159,8 @@ QmlCompiledData::~QmlCompiledData() if (types.at(ii).ref) types.at(ii).ref->release(); } + + qDeleteAll(programs); } QObject *QmlCompiledData::TypeReference::createInstance(QmlContext *ctxt, const QBitField &bindings) const diff --git a/src/declarative/qml/qmlcompiler.cpp b/src/declarative/qml/qmlcompiler.cpp index 02cd813..e67f79a 100644 --- a/src/declarative/qml/qmlcompiler.cpp +++ b/src/declarative/qml/qmlcompiler.cpp @@ -2296,7 +2296,10 @@ bool QmlCompiler::completeComponentBuild() expression = rewriteBinding(expression); quint32 length = expression.length(); + quint32 pc = output->programs.length(); + output->programs.append(0); binding.compiledData = + QByteArray((const char *)&pc, sizeof(quint32)) + QByteArray((const char *)&length, sizeof(quint32)) + QByteArray((const char *)expression.constData(), expression.length() * sizeof(QChar)); diff --git a/src/declarative/qml/qmlcompiler_p.h b/src/declarative/qml/qmlcompiler_p.h index 00637e3..447c421 100644 --- a/src/declarative/qml/qmlcompiler_p.h +++ b/src/declarative/qml/qmlcompiler_p.h @@ -69,6 +69,7 @@ class QmlEngine; class QmlComponent; class QmlContext; +class QScriptProgram; class QmlCompiledData : public QmlRefCount { public: @@ -106,6 +107,7 @@ public: QList datas; QList locations; QList bytecode; + QList programs; void dumpInstructions(); private: @@ -253,12 +255,10 @@ private: struct ComponentCompileState { ComponentCompileState() - : parserStatusCount(0), savedObjects(0), - pushedProperties(0), root(0) {} + : parserStatusCount(0), pushedProperties(0), root(0) {} QHash ids; QHash idIndexes; int parserStatusCount; - int savedObjects; int pushedProperties; QHash bindings; diff --git a/src/declarative/qml/qmlexpression.cpp b/src/declarative/qml/qmlexpression.cpp index db9d39f..adf5261 100644 --- a/src/declarative/qml/qmlexpression.cpp +++ b/src/declarative/qml/qmlexpression.cpp @@ -45,6 +45,7 @@ #include "qmlcontext_p.h" #include "qmlrewrite_p.h" #include "QtCore/qdebug.h" +#include "qmlcompiler_p.h" Q_DECLARE_METATYPE(QList); @@ -74,8 +75,26 @@ void QmlExpressionPrivate::init(QmlContext *ctxt, void *expr, QmlRefCount *rc, if (*data == BasicScriptEngineData) { sse.load((const char *)(data + 1), rc); } else { - expression = QString::fromRawData((QChar *)(data + 2), data[1]); + QmlCompiledData *dd = (QmlCompiledData *)rc; + expressionRewritten = true; + expression = QString::fromRawData((QChar *)(data + 3), data[2]); + + int progIdx = *(data + 1); + QmlEngine *engine = ctxt->engine(); + QScriptEngine *scriptEngine = QmlEnginePrivate::getScriptEngine(engine); + if (!dd->programs.at(progIdx)) { + dd->programs[progIdx] = new QScriptProgram(scriptEngine->compile(expression)); + } + + QmlContextPrivate *ctxtPriv = ctxt->d_func(); + QScriptContext *scriptContext = scriptEngine->pushContext(); + for (int i = ctxtPriv->scopeChain.size() - 1; i > -1; --i) + scriptContext->pushScope(ctxtPriv->scopeChain.at(i)); + + expressionFunction = scriptEngine->evaluate(*dd->programs[progIdx]); + expressionFunctionValid = true; + scriptEngine->popContext(); } QmlAbstractExpression::setContext(ctxt); -- cgit v0.12 From c4190288ca68eca9b84ccab67d860517a6a8e7c5 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Tue, 29 Sep 2009 21:50:31 +1000 Subject: Use placement new correctly --- src/script/bridge/qscriptdeclarativeclass.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/script/bridge/qscriptdeclarativeclass.cpp b/src/script/bridge/qscriptdeclarativeclass.cpp index 47b693f..c753379 100644 --- a/src/script/bridge/qscriptdeclarativeclass.cpp +++ b/src/script/bridge/qscriptdeclarativeclass.cpp @@ -70,8 +70,8 @@ void QScriptDeclarativeClass::initPersistentIdentifier(void **d, Identifier *i, static_cast(QObjectPrivate::get(d_ptr->engine)); JSC::ExecState* exec = p->currentFrame; - new (*d) JSC::Identifier(exec, (UChar *)str.constData(), str.size()); - *i = (Identifier)((JSC::Identifier *)*d)->ustring().rep(); + new (d) JSC::Identifier(exec, (UChar *)str.constData(), str.size()); + *i = (Identifier)((JSC::Identifier *)d)->ustring().rep(); } void QScriptDeclarativeClass::initPersistentIdentifier(void **d, Identifier *i, const Identifier &id) @@ -80,7 +80,7 @@ void QScriptDeclarativeClass::initPersistentIdentifier(void **d, Identifier *i, static_cast(QObjectPrivate::get(d_ptr->engine)); JSC::ExecState* exec = p->currentFrame; - new (*d) JSC::Identifier(exec, (JSC::UString::Rep *)id); + new (d) JSC::Identifier(exec, (JSC::UString::Rep *)id); *i = id; } -- cgit v0.12 From 49527e854a9edb0a92e64264d6efac6be46cf0ed Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Wed, 30 Sep 2009 11:07:07 +1000 Subject: Create a property cache for synthesized metaobjects --- src/declarative/qml/qml.pri | 6 +- src/declarative/qml/qmlcompileddata.cpp | 3 + src/declarative/qml/qmlcompiler.cpp | 6 +- src/declarative/qml/qmlcompiler_p.h | 3 + src/declarative/qml/qmldeclarativedata_p.h | 3 + src/declarative/qml/qmlengine.cpp | 14 ++- src/declarative/qml/qmlengine_p.h | 18 +++- src/declarative/qml/qmlinstruction.cpp | 2 +- src/declarative/qml/qmlinstruction_p.h | 2 +- src/declarative/qml/qmlmetaproperty.cpp | 71 +++------------ src/declarative/qml/qmlmetaproperty_p.h | 22 ----- src/declarative/qml/qmlpropertycache.cpp | 137 +++++++++++++++++++++++++++++ src/declarative/qml/qmlpropertycache_p.h | 100 +++++++++++++++++++++ src/declarative/qml/qmlvme.cpp | 9 +- 14 files changed, 303 insertions(+), 93 deletions(-) create mode 100644 src/declarative/qml/qmlpropertycache.cpp create mode 100644 src/declarative/qml/qmlpropertycache_p.h diff --git a/src/declarative/qml/qml.pri b/src/declarative/qml/qml.pri index 8349e29..216adb1 100644 --- a/src/declarative/qml/qml.pri +++ b/src/declarative/qml/qml.pri @@ -34,7 +34,8 @@ SOURCES += qml/qmlparser.cpp \ qml/qmlxmlhttprequest.cpp \ qml/qmlsqldatabase.cpp \ qml/qmetaobjectbuilder.cpp \ - qml/qmlwatcher.cpp + qml/qmlwatcher.cpp \ + qml/qmlpropertycache.cpp HEADERS += qml/qmlparser_p.h \ qml/qmlinstruction_p.h \ @@ -86,7 +87,8 @@ HEADERS += qml/qmlparser_p.h \ qml/qmlxmlhttprequest_p.h \ qml/qmlsqldatabase_p.h \ qml/qmetaobjectbuilder_p.h \ - qml/qmlwatcher_p.h + qml/qmlwatcher_p.h \ + qml/qmlpropertycache_p.h # for qtscript debugger contains(QT_CONFIG, scripttools):QT += scripttools diff --git a/src/declarative/qml/qmlcompileddata.cpp b/src/declarative/qml/qmlcompileddata.cpp index a46d893..a603d4e 100644 --- a/src/declarative/qml/qmlcompileddata.cpp +++ b/src/declarative/qml/qmlcompileddata.cpp @@ -160,6 +160,9 @@ QmlCompiledData::~QmlCompiledData() types.at(ii).ref->release(); } + for (int ii = 0; ii < propertyCaches.count(); ++ii) + propertyCaches.at(ii)->release(); + qDeleteAll(programs); } diff --git a/src/declarative/qml/qmlcompiler.cpp b/src/declarative/qml/qmlcompiler.cpp index e67f79a..0b4ac20 100644 --- a/src/declarative/qml/qmlcompiler.cpp +++ b/src/declarative/qml/qmlcompiler.cpp @@ -647,7 +647,7 @@ void QmlCompiler::compileTree(Object *tree) Q_ASSERT(tree->metatype); static_cast(output->root) = *tree->metaObject(); - if (!tree->metadata.isEmpty()) + if (!tree->metadata.isEmpty()) QmlEnginePrivate::get(engine)->registerCompositeType(output); } @@ -807,7 +807,9 @@ void QmlCompiler::genObject(QmlParser::Object *obj) meta.line = -1; meta.storeMeta.data = output->indexForByteArray(obj->metadata); meta.storeMeta.aliasData = output->indexForByteArray(obj->synthdata); - meta.storeMeta.slotData = -1; + meta.storeMeta.propertyCache = output->propertyCaches.count(); + // ### Surely the creation of this property cache could be more efficient + output->propertyCaches << QmlPropertyCache::create(engine, obj->metaObject()); output->bytecode << meta; } diff --git a/src/declarative/qml/qmlcompiler_p.h b/src/declarative/qml/qmlcompiler_p.h index 447c421..677aba7 100644 --- a/src/declarative/qml/qmlcompiler_p.h +++ b/src/declarative/qml/qmlcompiler_p.h @@ -62,6 +62,7 @@ #include #include #include +#include QT_BEGIN_NAMESPACE @@ -99,6 +100,7 @@ public: int index; int type; }; + QAbstractDynamicMetaObject root; QList primitives; QList floatData; @@ -108,6 +110,7 @@ public: QList locations; QList bytecode; QList programs; + QList propertyCaches; void dumpInstructions(); private: diff --git a/src/declarative/qml/qmldeclarativedata_p.h b/src/declarative/qml/qmldeclarativedata_p.h index ade961f..b4c87b8 100644 --- a/src/declarative/qml/qmldeclarativedata_p.h +++ b/src/declarative/qml/qmldeclarativedata_p.h @@ -60,6 +60,7 @@ QT_BEGIN_NAMESPACE class QmlCompiledData; class QmlAbstractBinding; class QmlContext; +class QmlPropertyCache; class QmlDeclarativeData : public QDeclarativeData { public: @@ -85,6 +86,8 @@ public: QHash *attachedProperties; + QmlPropertyCache *propertyCache; + static QmlDeclarativeData *get(const QObject *object, bool create = false) { QObjectPrivate *priv = QObjectPrivate::get(const_cast(object)); diff --git a/src/declarative/qml/qmlengine.cpp b/src/declarative/qml/qmlengine.cpp index 72603ed..757670b 100644 --- a/src/declarative/qml/qmlengine.cpp +++ b/src/declarative/qml/qmlengine.cpp @@ -41,11 +41,12 @@ #undef QT3_SUPPORT // don't want it here - it just causes bugs (which is why we removed it) -#include +#include #include #include #include #include +#include #ifdef QT_SCRIPTTOOLS_LIB #include @@ -192,6 +193,8 @@ QmlEnginePrivate::~QmlEnginePrivate() contextClass = 0; delete objectClass; objectClass = 0; + delete objectClass2; + objectClass2 = 0; delete valueTypeClass; valueTypeClass = 0; delete typeNameClass; @@ -211,6 +214,9 @@ QmlEnginePrivate::~QmlEnginePrivate() clear(parserStatus[ii]); for(QHash::ConstIterator iter = m_compositeTypes.constBegin(); iter != m_compositeTypes.constEnd(); ++iter) (*iter)->release(); + for(QHash::Iterator iter = propertyCache.begin(); iter != propertyCache.end(); ++iter) + (*iter)->release(); + } void QmlEnginePrivate::clear(SimpleList &bvs) @@ -236,6 +242,7 @@ void QmlEnginePrivate::init() scriptEngine.installTranslatorFunctions(); contextClass = new QmlContextScriptClass(q); objectClass = new QmlObjectScriptClass(q); + objectClass2 = new QScriptDeclarativeClass(&scriptEngine); valueTypeClass = new QmlValueTypeScriptClass(q); typeNameClass = new QmlTypeNameScriptClass(q); rootContext = new QmlContext(q,true); @@ -700,7 +707,7 @@ QObject *qmlAttachedPropertiesObjectById(int id, const QObject *object, bool cre QmlDeclarativeData::QmlDeclarativeData(QmlContext *ctxt) : context(ctxt), bindings(0), bindingBitsSize(0), bindingBits(0), outerContext(0), lineNumber(0), columnNumber(0), deferredComponent(0), - deferredIdx(0), attachedProperties(0) + deferredIdx(0), attachedProperties(0), propertyCache(0) { } @@ -725,6 +732,9 @@ void QmlDeclarativeData::destroyed(QObject *object) if (bindingBits) free(bindingBits); + if (propertyCache) + propertyCache->release(); + delete this; } diff --git a/src/declarative/qml/qmlengine_p.h b/src/declarative/qml/qmlengine_p.h index 74e24d4..68019e2 100644 --- a/src/declarative/qml/qmlengine_p.h +++ b/src/declarative/qml/qmlengine_p.h @@ -72,6 +72,7 @@ #include #include #include +#include QT_BEGIN_NAMESPACE @@ -88,6 +89,7 @@ class QScriptEngineDebugger; class QNetworkReply; class QNetworkAccessManager; class QmlAbstractBinding; +class QScriptDeclarativeClass; class QmlEnginePrivate : public QObjectPrivate { @@ -149,6 +151,7 @@ public: } resolveData; QmlContextScriptClass *contextClass; QmlObjectScriptClass *objectClass; + QScriptDeclarativeClass *objectClass2; QmlValueTypeScriptClass *valueTypeClass; QmlTypeNameScriptClass *typeNameClass; // Used by DOM Core 3 API @@ -212,10 +215,17 @@ public: // ### Fixme typedef QHash, bool> FunctionCache; FunctionCache functionCache; - QHash propertyCache; - static QmlMetaObjectCache *cache(QmlEnginePrivate *priv, QObject *obj) { - if (!priv || !obj || QObjectPrivate::get(obj)->metaObject) return 0; - return &priv->propertyCache[obj->metaObject()]; + QHash propertyCache; + QmlPropertyCache *cache(QObject *obj) { + Q_Q(QmlEngine); + if (!obj || QObjectPrivate::get(obj)->metaObject) return 0; + const QMetaObject *mo = obj->metaObject(); + QmlPropertyCache *rv = propertyCache.value(mo); + if (!rv) { + rv = QmlPropertyCache::create(q, mo); + propertyCache.insert(mo, rv); + } + return rv; } struct Imports { diff --git a/src/declarative/qml/qmlinstruction.cpp b/src/declarative/qml/qmlinstruction.cpp index b71c6e3..18439f4 100644 --- a/src/declarative/qml/qmlinstruction.cpp +++ b/src/declarative/qml/qmlinstruction.cpp @@ -69,7 +69,7 @@ void QmlCompiledData::dump(QmlInstruction *instr, int idx) 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 << "\t" << instr->storeMeta.slotData; + qWarning() << idx << "\t" << line << "\t" << "STORE_META\t\t" << instr->storeMeta.data << "\t"; break; case QmlInstruction::StoreFloat: qWarning() << idx << "\t" << line << "\t" << "STORE_FLOAT\t\t" << instr->storeFloat.propertyIndex << "\t" << instr->storeFloat.value; diff --git a/src/declarative/qml/qmlinstruction_p.h b/src/declarative/qml/qmlinstruction_p.h index 2c9ceac..e62bfdf 100644 --- a/src/declarative/qml/qmlinstruction_p.h +++ b/src/declarative/qml/qmlinstruction_p.h @@ -175,8 +175,8 @@ public: } create; struct { int data; - int slotData; int aliasData; + int propertyCache; } storeMeta; struct { int value; diff --git a/src/declarative/qml/qmlmetaproperty.cpp b/src/declarative/qml/qmlmetaproperty.cpp index efc4a2b..f7882dc 100644 --- a/src/declarative/qml/qmlmetaproperty.cpp +++ b/src/declarative/qml/qmlmetaproperty.cpp @@ -58,56 +58,6 @@ Q_DECLARE_METATYPE(QList); QT_BEGIN_NAMESPACE -QmlMetaObjectCache::QmlMetaObjectCache() -: propertyCache(0) -{ -} - -void QmlMetaObjectCache::init(const QMetaObject *metaObject) -{ - if (propertyCache || !metaObject) - return; - - int propCount = metaObject->propertyCount(); - - propertyCache = new Data[propCount]; - for (int ii = 0; ii < propCount; ++ii) { - QMetaProperty p = metaObject->property(ii); - propertyCache[ii].propType = p.userType(); - propertyCache[ii].coreIndex = ii; - propertyCache[ii].name = QLatin1String(p.name()); - - propertyNameCache.insert(propertyCache[ii].name, ii); - } -} - -QmlMetaObjectCache::~QmlMetaObjectCache() -{ - delete [] propertyCache; -} - -QmlMetaObjectCache::Data * -QmlMetaObjectCache::property(int index, const QMetaObject *metaObject) -{ - init(metaObject); - - return propertyCache + index; -} - -QmlMetaObjectCache::Data * -QmlMetaObjectCache::property(const QString &name, const QMetaObject *metaObject) -{ - init(metaObject); - - QHash::ConstIterator iter = propertyNameCache.find(name); - - if (iter != propertyNameCache.end()) { - return propertyCache + *iter; - } else { - return 0; - } -} - /*! \class QmlMetaProperty \brief The QmlMetaProperty class abstracts accessing QML properties. @@ -258,11 +208,17 @@ void QmlMetaPropertyPrivate::initProperty(QObject *obj, const QString &name) } // Property - QmlMetaObjectCache *cache = QmlEnginePrivate::cache(enginePrivate, obj); + QmlPropertyCache *cache = 0; + QmlDeclarativeData *ddata = QmlDeclarativeData::get(obj); + if (ddata) + cache = ddata->propertyCache; + if (!cache) + cache = enginePrivate?enginePrivate->cache(obj):0; + if (cache) { - QmlMetaObjectCache::Data *data = - cache->property(name, obj->metaObject()); - if (data) { + QmlPropertyCache::Data *data = cache->property(name); + + if (data && !data->isFunction) { type = QmlMetaProperty::Property; propType = data->propType; coreIdx = data->coreIndex; @@ -272,7 +228,7 @@ void QmlMetaPropertyPrivate::initProperty(QObject *obj, const QString &name) QMetaProperty p = QmlMetaType::property(obj, name.toUtf8().constData()); propType = p.userType(); coreIdx = p.propertyIndex(); - if (p.name()) + if (p.name()) type = QmlMetaProperty::Property; } } @@ -1186,13 +1142,12 @@ void QmlMetaProperty::restore(quint32 id, QObject *obj, QmlContext *ctxt) } else if (d->type & Property) { - QmlMetaObjectCache *cache = QmlEnginePrivate::cache(enginePrivate, obj); + QmlPropertyCache *cache = enginePrivate?enginePrivate->cache(obj):0; d->coreIdx = id; if (cache) { - QmlMetaObjectCache::Data *data = - cache->property(id, obj->metaObject()); + QmlPropertyCache::Data *data = cache->property(id); d->propType = data->propType; d->name = data->name; } else { diff --git a/src/declarative/qml/qmlmetaproperty_p.h b/src/declarative/qml/qmlmetaproperty_p.h index 1ccf913..0d96174 100644 --- a/src/declarative/qml/qmlmetaproperty_p.h +++ b/src/declarative/qml/qmlmetaproperty_p.h @@ -58,28 +58,6 @@ QT_BEGIN_NAMESPACE -class QmlMetaObjectCache -{ -public: - QmlMetaObjectCache(); - ~QmlMetaObjectCache(); - - struct Data { - int propType; - int coreIndex; - QString name; - }; - - Data *property(const QString &, const QMetaObject *); - Data *property(int, const QMetaObject *); - -private: - void init(const QMetaObject *); - - Data *propertyCache; - QHash propertyNameCache; -}; - class QmlContext; class QmlMetaPropertyPrivate { diff --git a/src/declarative/qml/qmlpropertycache.cpp b/src/declarative/qml/qmlpropertycache.cpp new file mode 100644 index 0000000..f88b3a3 --- /dev/null +++ b/src/declarative/qml/qmlpropertycache.cpp @@ -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$ +** +****************************************************************************/ + +#include "qmlpropertycache_p.h" +#include "qmlengine_p.h" + +QmlPropertyCache::QmlPropertyCache() +{ +} + +QmlPropertyCache::~QmlPropertyCache() +{ + for (int ii = 0; ii < indexCache.count(); ++ii) + indexCache.at(ii)->release(); + + for (StringCache::ConstIterator iter = stringCache.begin(); + iter != stringCache.end(); ++iter) + (*iter)->release(); + + for (IdentifierCache::ConstIterator iter = identifierCache.begin(); + iter != identifierCache.end(); ++iter) + (*iter)->release(); +} + +// ### Optimize - check engine for the parent meta object etc. +QmlPropertyCache *QmlPropertyCache::create(QmlEngine *engine, const QMetaObject *metaObject) +{ + Q_ASSERT(engine); + Q_ASSERT(metaObject); + + QmlPropertyCache *cache = new QmlPropertyCache; + + QmlEnginePrivate *enginePriv = QmlEnginePrivate::get(engine); + + // ### The properties/methods should probably be spliced on a per-metaobject basis + int propCount = metaObject->propertyCount(); + + cache->indexCache.resize(propCount); + for (int ii = propCount - 1; ii >= 0; --ii) { + QMetaProperty p = metaObject->property(ii); + QString propName = QLatin1String(p.name()); + + QScriptDeclarativeClass::PersistentIdentifier *data = + enginePriv->objectClass2->createPersistentIdentifier(propName); + data->propType = p.userType(); + data->coreIndex = ii; + data->name = propName; + + cache->indexCache[ii] = data; + + if (cache->stringCache.contains(propName)) + continue; + + cache->stringCache.insert(propName, data); + cache->identifierCache.insert(data->identifier, data); + data->addref(); + data->addref(); + } + + int methodCount = metaObject->methodCount(); + for (int ii = methodCount - 1; ii >= 0; --ii) { + QMetaMethod m = metaObject->method(ii); + QString methodName = QLatin1String(m.signature()); + + int parenIdx = methodName.indexOf(QLatin1Char('(')); + Q_ASSERT(parenIdx != -1); + methodName = methodName.left(parenIdx); + + if (cache->stringCache.contains(methodName)) + continue; + + QScriptDeclarativeClass::PersistentIdentifier *data = + enginePriv->objectClass2->createPersistentIdentifier(methodName); + cache->stringCache.insert(methodName, data); + cache->identifierCache.insert(data->identifier, data); + data->addref(); + data->addref(); + + data->isFunction = true; + } + + return cache; +} + +QmlPropertyCache::Data * +QmlPropertyCache::property(int index) const +{ + if (index < 0 || index >= indexCache.count()) + return 0; + + return indexCache.at(index); +} + +QmlPropertyCache::Data * +QmlPropertyCache::property(const QString &str) const +{ + return stringCache.value(str); +} + diff --git a/src/declarative/qml/qmlpropertycache_p.h b/src/declarative/qml/qmlpropertycache_p.h new file mode 100644 index 0000000..c10fafa --- /dev/null +++ b/src/declarative/qml/qmlpropertycache_p.h @@ -0,0 +1,100 @@ +/**************************************************************************** +** +** 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 QMLPROPERTYCACHE_P_H +#define QMLPROPERTYCACHE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QmlEngine; +class QMetaProperty; +class QmlPropertyCache : public QmlRefCount +{ +public: + QmlPropertyCache(); + virtual ~QmlPropertyCache(); + + struct Data : public QmlRefCount { + Data() : isFunction(false) {} + + bool isFunction; + int propType; + int coreIndex; + QString name; + }; + + static QmlPropertyCache *create(QmlEngine *, const QMetaObject *); + + Data *property(const QScriptDeclarativeClass::Identifier &id) const { + return identifierCache.value(id); + } + + Data *property(const QString &) const; + Data *property(int) const; + +private: + typedef QVector *> IndexCache; + typedef QHash *> StringCache; + typedef QHash *> IdentifierCache; + + IndexCache indexCache; + StringCache stringCache; + IdentifierCache identifierCache; +}; + +QT_END_NAMESPACE + +#endif // QMLPROPERTYCACHE_P_H diff --git a/src/declarative/qml/qmlvme.cpp b/src/declarative/qml/qmlvme.cpp index 44b17e6..a5d2732 100644 --- a/src/declarative/qml/qmlvme.cpp +++ b/src/declarative/qml/qmlvme.cpp @@ -143,6 +143,7 @@ QObject *QmlVME::run(QStack &stack, QmlContext *ctxt, const QList &customTypeData = comp->customTypeData; const QList &intData = comp->intData; const QList &floatData = comp->floatData; + const QList &propertyCaches = comp->propertyCaches; QmlEnginePrivate::SimpleList bindValues; @@ -259,9 +260,15 @@ QObject *QmlVME::run(QStack &stack, QmlContext *ctxt, const QByteArray &metadata = datas.at(instr.storeMeta.data); QMetaObjectBuilder::fromRelocatableData(&mo, 0, metadata); - const QmlVMEMetaData *data = (const QmlVMEMetaData *)datas.at(instr.storeMeta.aliasData).constData(); + const QmlVMEMetaData *data = + (const QmlVMEMetaData *)datas.at(instr.storeMeta.aliasData).constData(); (void)new QmlVMEMetaObject(target, &mo, data, comp); + + QmlDeclarativeData *ddata = QmlDeclarativeData::get(target, true); + if (ddata->propertyCache) ddata->propertyCache->release(); + ddata->propertyCache = propertyCaches.at(instr.storeMeta.propertyCache); + ddata->propertyCache->addref(); } break; -- cgit v0.12 From dff7f0593d86e90eb14c805a96ebbda778f45a82 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Wed, 30 Sep 2009 18:13:04 +1000 Subject: Improve script lookup caching --- demos/declarative/samegame/content/samegame.js | 3 + src/declarative/qml/qml.pri | 10 +- src/declarative/qml/qmlcompiler.cpp | 20 +- src/declarative/qml/qmlcompiler_p.h | 4 +- src/declarative/qml/qmlcontext.cpp | 47 ++-- src/declarative/qml/qmlcontext_p.h | 10 +- src/declarative/qml/qmlcontextscriptclass.cpp | 190 +++++++++++++++++ src/declarative/qml/qmlcontextscriptclass_p.h | 89 ++++++++ src/declarative/qml/qmlengine.cpp | 264 +---------------------- src/declarative/qml/qmlengine_p.h | 62 +----- src/declarative/qml/qmlinstruction_p.h | 2 +- src/declarative/qml/qmlintegercache.cpp | 108 ++++++++++ src/declarative/qml/qmlintegercache_p.h | 103 +++++++++ src/declarative/qml/qmlmetaproperty.cpp | 2 +- src/declarative/qml/qmlobjectscriptclass.cpp | 283 +++++++++++++++++++++++++ src/declarative/qml/qmlobjectscriptclass_p.h | 98 +++++++++ src/declarative/qml/qmlpropertycache.cpp | 20 +- src/declarative/qml/qmlpropertycache_p.h | 37 +++- src/declarative/qml/qmlvme.cpp | 4 +- src/script/api/qscriptvalue.cpp | 5 + src/script/bridge/qscriptdeclarativeclass.cpp | 13 ++ src/script/bridge/qscriptdeclarativeclass_p.h | 2 + 22 files changed, 1021 insertions(+), 355 deletions(-) create mode 100644 src/declarative/qml/qmlcontextscriptclass.cpp create mode 100644 src/declarative/qml/qmlcontextscriptclass_p.h create mode 100644 src/declarative/qml/qmlintegercache.cpp create mode 100644 src/declarative/qml/qmlintegercache_p.h create mode 100644 src/declarative/qml/qmlobjectscriptclass.cpp create mode 100644 src/declarative/qml/qmlobjectscriptclass_p.h diff --git a/demos/declarative/samegame/content/samegame.js b/demos/declarative/samegame/content/samegame.js index e42b7cc..4a9179b 100755 --- a/demos/declarative/samegame/content/samegame.js +++ b/demos/declarative/samegame/content/samegame.js @@ -38,6 +38,7 @@ function initBoard() scoreName.forceClose(); dialog.forceClose(); + var a = new Date(); //Initialize Board board = new Array(maxIndex); gameCanvas.score = 0; @@ -48,6 +49,8 @@ function initBoard() } } timer = new Date(); + + print(timer.valueOf() - a.valueOf()); } var fillFound;//Set after a floodFill call to the number of tiles found diff --git a/src/declarative/qml/qml.pri b/src/declarative/qml/qml.pri index 216adb1..1a6dad3 100644 --- a/src/declarative/qml/qml.pri +++ b/src/declarative/qml/qml.pri @@ -35,7 +35,10 @@ SOURCES += qml/qmlparser.cpp \ qml/qmlsqldatabase.cpp \ qml/qmetaobjectbuilder.cpp \ qml/qmlwatcher.cpp \ - qml/qmlpropertycache.cpp + qml/qmlpropertycache.cpp \ + qml/qmlintegercache.cpp \ + qml/qmlobjectscriptclass.cpp \ + qml/qmlcontextscriptclass.cpp HEADERS += qml/qmlparser_p.h \ qml/qmlinstruction_p.h \ @@ -88,7 +91,10 @@ HEADERS += qml/qmlparser_p.h \ qml/qmlsqldatabase_p.h \ qml/qmetaobjectbuilder_p.h \ qml/qmlwatcher_p.h \ - qml/qmlpropertycache_p.h + qml/qmlpropertycache_p.h \ + qml/qmlintegercache_p.h \ + qml/qmlobjectscriptclass_p.h \ + qml/qmlcontextscriptclass_p.h # for qtscript debugger contains(QT_CONFIG, scripttools):QT += scripttools diff --git a/src/declarative/qml/qmlcompiler.cpp b/src/declarative/qml/qmlcompiler.cpp index 0b4ac20..5cb2158 100644 --- a/src/declarative/qml/qmlcompiler.cpp +++ b/src/declarative/qml/qmlcompiler.cpp @@ -633,7 +633,7 @@ void QmlCompiler::compileTree(Object *tree) init.line = 0; init.init.bindingsSize = compileState.bindings.count(); init.init.parserStatusSize = compileState.parserStatusCount; - init.init.idSize = compileState.ids.count(); + init.init.contextCache = genContextCache(); output->bytecode << init; genObject(tree); @@ -964,7 +964,7 @@ void QmlCompiler::genComponent(QmlParser::Object *obj) init.type = QmlInstruction::Init; init.init.bindingsSize = compileState.bindings.count(); init.init.parserStatusSize = compileState.parserStatusCount; - init.init.idSize = compileState.ids.count(); + init.init.contextCache = genContextCache(); init.line = obj->location.start.line; output->bytecode << init; @@ -2263,6 +2263,22 @@ void QmlCompiler::genBindingAssignment(QmlParser::Value *binding, output->bytecode << store; } +int QmlCompiler::genContextCache() +{ + if (compileState.ids.count() == 0) + return -1; + + QmlIntegerCache *cache = new QmlIntegerCache(engine); + + for (QHash::ConstIterator iter = compileState.ids.begin(); + iter != compileState.ids.end(); + ++iter) + cache->add(iter.key(), (*iter)->idIndex); + + output->contextCaches.append(cache); + return output->contextCaches.count() - 1; +} + bool QmlCompiler::completeComponentBuild() { for (int ii = 0; ii < compileState.aliasingObjects.count(); ++ii) { diff --git a/src/declarative/qml/qmlcompiler_p.h b/src/declarative/qml/qmlcompiler_p.h index 677aba7..1cb66c7 100644 --- a/src/declarative/qml/qmlcompiler_p.h +++ b/src/declarative/qml/qmlcompiler_p.h @@ -63,6 +63,7 @@ #include #include #include +#include QT_BEGIN_NAMESPACE @@ -111,6 +112,7 @@ public: QList bytecode; QList programs; QList propertyCaches; + QList contextCaches; void dumpInstructions(); private: @@ -232,7 +234,7 @@ private: QmlParser::Property *prop, QmlParser::Object *obj, QmlParser::Property *valueTypeProperty = 0); - + int genContextCache(); int componentTypeRef(); diff --git a/src/declarative/qml/qmlcontext.cpp b/src/declarative/qml/qmlcontext.cpp index 97ab375..1c9d177 100644 --- a/src/declarative/qml/qmlcontext.cpp +++ b/src/declarative/qml/qmlcontext.cpp @@ -55,7 +55,7 @@ QT_BEGIN_NAMESPACE QmlContextPrivate::QmlContextPrivate() -: parent(0), engine(0), isInternal(false), notifyIndex(-1), +: parent(0), engine(0), isInternal(false), propertyNames(0), notifyIndex(-1), highPriorityCount(0), expressions(0), idValues(0), idValueCount(0) { } @@ -103,8 +103,8 @@ void QmlContextPrivate::init() //set scope chain QScriptEngine *scriptEngine = QmlEnginePrivate::getScriptEngine(engine); - QScriptValue scopeObj = - scriptEngine->newObject(QmlEnginePrivate::get(engine)->contextClass, scriptEngine->newVariant(QVariant::fromValue((QObject*)q))); + QScriptValue scopeObj = QmlEnginePrivate::get(engine)->contextClass->newContext(q); + //### no longer need to push global object once we switch to JSC (test with objects added to globalObject) //if (parent) // scopeChain = parent->d_func()->scopeChain; @@ -304,6 +304,9 @@ QmlContext::~QmlContext() d->contextObjects.clear(); delete [] d->idValues; + + if (d->propertyNames) + d->propertyNames->release(); } void QmlContextPrivate::invalidateEngines() @@ -361,13 +364,16 @@ void QmlContext::setContextProperty(const QString &name, const QVariant &value) QObject *o = QmlMetaType::toQObject(value); setContextProperty(name, o); } else { - QHash::ConstIterator iter = d->propertyNames.find(name); - if(iter == d->propertyNames.end()) { - d->propertyNames.insert(name, d->idValueCount + d->propertyValues.count()); + + if (!d->propertyNames) d->propertyNames = new QmlIntegerCache(d->engine); + + int idx = d->propertyNames->value(name); + if (idx == -1) { + d->propertyNames->add(name, d->idValueCount + d->propertyValues.count()); d->propertyValues.append(value); } else { - d->propertyValues[*iter] = value; - QMetaObject::activate(this, *iter + d->notifyIndex, 0); + d->propertyValues[idx] = value; + QMetaObject::activate(this, idx + d->notifyIndex, 0); } } } @@ -380,15 +386,19 @@ void QmlContextPrivate::setIdProperty(const QString &name, int idx, notifyIndex = q->metaObject()->methodCount(); } - propertyNames.insert(name, idx); + propertyNames->add(name, idx); idValues[idx].priv = this; idValues[idx] = obj; } -void QmlContextPrivate::setIdPropertyCount(int count) +void QmlContextPrivate::setIdPropertyData(QmlIntegerCache *data) { - idValues = new ContextGuard[count]; - idValueCount = count; + Q_ASSERT(!propertyNames); + propertyNames = data; + propertyNames->addref(); + + idValueCount = data->count(); + idValues = new ContextGuard[idValueCount]; } /*! @@ -402,14 +412,15 @@ void QmlContext::setContextProperty(const QString &name, QObject *value) if (d->notifyIndex == -1) d->notifyIndex = this->metaObject()->methodCount(); - QHash::ConstIterator iter = d->propertyNames.find(name); - if(iter == d->propertyNames.end()) { - d->propertyNames.insert(name, d->idValueCount + d->propertyValues.count()); + if (!d->propertyNames) d->propertyNames = new QmlIntegerCache(d->engine); + int idx = d->propertyNames->value(name); + + if (idx == -1) { + d->propertyNames->add(name, d->idValueCount + d->propertyValues.count()); d->propertyValues.append(QVariant::fromValue(value)); } else { - int idx = *iter; - d->propertyValues[*iter] = QVariant::fromValue(value); - QMetaObject::activate(this, *iter + d->notifyIndex, 0); + d->propertyValues[idx] = QVariant::fromValue(value); + QMetaObject::activate(this, idx + d->notifyIndex, 0); } } diff --git a/src/declarative/qml/qmlcontext_p.h b/src/declarative/qml/qmlcontext_p.h index b305408..64faa6d 100644 --- a/src/declarative/qml/qmlcontext_p.h +++ b/src/declarative/qml/qmlcontext_p.h @@ -61,6 +61,7 @@ #include #include #include +#include QT_BEGIN_NAMESPACE @@ -82,7 +83,8 @@ public: QmlEngine *engine; bool isInternal; - QHash propertyNames; + QmlIntegerCache *propertyNames; +// QHash propertyNames; QList propertyValues; int notifyIndex; @@ -125,9 +127,13 @@ public: ContextGuard *idValues; int idValueCount; void setIdProperty(const QString &, int, QObject *); - void setIdPropertyCount(int); + void setIdPropertyData(QmlIntegerCache *); void destroyed(ContextGuard *); + static QmlContextPrivate *get(QmlContext *context) { + return static_cast(QObjectPrivate::get(context)); + } + // Only used for debugging QList > instances; }; diff --git a/src/declarative/qml/qmlcontextscriptclass.cpp b/src/declarative/qml/qmlcontextscriptclass.cpp new file mode 100644 index 0000000..baea60a --- /dev/null +++ b/src/declarative/qml/qmlcontextscriptclass.cpp @@ -0,0 +1,190 @@ +/**************************************************************************** +** +** 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 "qmlcontextscriptclass_p.h" +#include +#include + +QT_BEGIN_NAMESPACE + +struct ContextData { + ContextData(QmlContext *c) : context(c) {} + QGuard context; +}; + +/* + The QmlContextScriptClass handles property access for a QmlContext + via QtScript. + */ +QmlContextScriptClass::QmlContextScriptClass(QmlEngine *bindEngine) +: QScriptDeclarativeClass(QmlEnginePrivate::getScriptEngine(bindEngine)), engine(bindEngine), + lastPropertyIndex(-1), lastDefaultObject(-1) +{ +} + +QmlContextScriptClass::~QmlContextScriptClass() +{ +} + +QScriptValue QmlContextScriptClass::newContext(QmlContext *context) +{ + QScriptEngine *scriptEngine = QmlEnginePrivate::getScriptEngine(engine); + + return newObject(scriptEngine, this, (Object)new ContextData(context)); +} + +QScriptClass::QueryFlags +QmlContextScriptClass::queryProperty(const Object &object, const Identifier &name, + QScriptClass::QueryFlags flags) +{ + Q_UNUSED(flags); + QmlContext *bindContext = ((ContextData *)object)->context.data(); + if (!bindContext) + return 0; + + QmlEnginePrivate *ep = QmlEnginePrivate::get(engine); + QmlContextPrivate *cp = QmlContextPrivate::get(bindContext); + + lastPropertyIndex = -1; + lastDefaultObject = -1; + + lastPropertyIndex = cp->propertyNames?cp->propertyNames->value(name):-1; + if (lastPropertyIndex != -1) + return QScriptClass::HandlesReadAccess; + + // ### Check for attached properties +#if 0 + QmlType *type = 0; ImportedNamespace *ns = 0; + if (currentExpression && bindContext == currentExpression->context() && + propName.at(0).isUpper() && resolveType(bindContext->d_func()->imports, propName.toUtf8(), &type, 0, 0, 0, &ns)) { + + if (type || ns) { + // Must be either an attached property, or an enum + resolveData.object = bindContext->d_func()->defaultObjects.first(); + resolveData.type = type; + resolveData.ns = ns; + return QScriptClass::HandlesReadAccess; + } + + } +#endif + + for (int ii = 0; ii < cp->defaultObjects.count(); ++ii) { + QScriptClass::QueryFlags rv = + ep->objectClass->queryProperty(cp->defaultObjects.at(ii), name, flags); + + if (rv) { + lastDefaultObject = ii; + return rv; + } + } + + return 0; +} + +QScriptValue QmlContextScriptClass::property(const Object &object, const Identifier &name) +{ + Q_UNUSED(object); + + Q_ASSERT(lastPropertyIndex != -1 || lastDefaultObject != -1); + + QmlContext *bindContext = ((ContextData *)object)->context.data(); + Q_ASSERT(bindContext); + + QmlEnginePrivate *ep = QmlEnginePrivate::get(engine); + QmlContextPrivate *cp = QmlContextPrivate::get(bindContext); + + + // ### Check for attached properties +#if 0 + if (resolveData.type || resolveData.ns) { + QmlTypeNameBridge tnb = { + resolveData.object, + resolveData.type, + resolveData.ns + }; + return scriptEngine.newObject(typeNameClass, scriptEngine.newVariant(qVariantFromValue(tnb))); + } +#endif + + if (lastPropertyIndex != -1) { + + QScriptValue rv; + if (lastPropertyIndex < cp->idValueCount) { + rv = ep->objectClass->newQObject(cp->idValues[lastPropertyIndex].data()); + } else { + QVariant value = cp->propertyValues.at(lastPropertyIndex); + if (QmlMetaType::isObject(value.userType())) { + rv = ep->objectClass->newQObject(QmlMetaType::toQObject(value)); + } else { + // ### Shouldn't this be qScriptValueFromValue() + rv = ep->scriptEngine.newVariant(value); + } + } + + ep->capturedProperties << + QmlEnginePrivate::CapturedProperty(bindContext, -1, + lastPropertyIndex + cp->notifyIndex); + + return rv; + } else { + + // Default object property + return ep->objectClass->property(cp->defaultObjects.at(lastDefaultObject), name); + + } +} + +void QmlContextScriptClass::setProperty(const Object &object, const Identifier &name, + const QScriptValue &value) +{ + Q_ASSERT(lastDefaultObject != -1); + + QmlContext *bindContext = ((ContextData *)object)->context.data(); + Q_ASSERT(bindContext); + + QmlEnginePrivate *ep = QmlEnginePrivate::get(engine); + QmlContextPrivate *cp = QmlContextPrivate::get(bindContext); + + ep->objectClass->setProperty(cp->defaultObjects.at(lastDefaultObject), name, value); +} + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlcontextscriptclass_p.h b/src/declarative/qml/qmlcontextscriptclass_p.h new file mode 100644 index 0000000..9ef090d --- /dev/null +++ b/src/declarative/qml/qmlcontextscriptclass_p.h @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** 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 QMLCONTEXTSCRIPTCLASS_P_H +#define QMLCONTEXTSCRIPTCLASS_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include + +QT_BEGIN_NAMESPACE + +class QmlEngine; +class QmlContext; +class QmlContextScriptClass : public QScriptDeclarativeClass +{ +public: + QmlContextScriptClass(QmlEngine *); + ~QmlContextScriptClass(); + + QScriptValue newContext(QmlContext *); + +protected: + virtual QScriptClass::QueryFlags queryProperty(const Object &, const Identifier &, + QScriptClass::QueryFlags flags); + virtual QScriptValue property(const Object &, const Identifier &); + virtual void setProperty(const Object &, const Identifier &name, const QScriptValue &); + +private: + QmlEngine *engine; + + int lastPropertyIndex; + int lastDefaultObject; + + uint m_id; +}; + +QT_END_NAMESPACE + +#endif // QMLCONTEXTSCRIPTCLASS_P_H + diff --git a/src/declarative/qml/qmlengine.cpp b/src/declarative/qml/qmlengine.cpp index 757670b..d680fa1 100644 --- a/src/declarative/qml/qmlengine.cpp +++ b/src/declarative/qml/qmlengine.cpp @@ -193,8 +193,6 @@ QmlEnginePrivate::~QmlEnginePrivate() contextClass = 0; delete objectClass; objectClass = 0; - delete objectClass2; - objectClass2 = 0; delete valueTypeClass; valueTypeClass = 0; delete typeNameClass; @@ -242,7 +240,6 @@ void QmlEnginePrivate::init() scriptEngine.installTranslatorFunctions(); contextClass = new QmlContextScriptClass(q); objectClass = new QmlObjectScriptClass(q); - objectClass2 = new QScriptDeclarativeClass(&scriptEngine); valueTypeClass = new QmlValueTypeScriptClass(q); typeNameClass = new QmlTypeNameScriptClass(q); rootContext = new QmlContext(q,true); @@ -288,95 +285,6 @@ struct QmlValueTypeReference { }; Q_DECLARE_METATYPE(QmlValueTypeReference); -//////////////////////////////////////////////////////////////////// -QScriptClass::QueryFlags -QmlEnginePrivate::queryContext(const QString &propName, uint *id, - QmlContext *bindContext) -{ - resolveData.safetyCheckId++; - *id = resolveData.safetyCheckId; - resolveData.clear(); - - QHash::Iterator contextProperty = - bindContext->d_func()->propertyNames.find(propName); - - if (contextProperty != bindContext->d_func()->propertyNames.end()) { - - resolveData.context = bindContext; - resolveData.contextIndex = *contextProperty; - - return QScriptClass::HandlesReadAccess; - } - - QmlType *type = 0; ImportedNamespace *ns = 0; - if (currentExpression && bindContext == currentExpression->context() && - propName.at(0).isUpper() && resolveType(bindContext->d_func()->imports, propName.toUtf8(), &type, 0, 0, 0, &ns)) { - - if (type || ns) { - // Must be either an attached property, or an enum - resolveData.object = bindContext->d_func()->defaultObjects.first(); - resolveData.type = type; - resolveData.ns = ns; - return QScriptClass::HandlesReadAccess; - } - - } - - QScriptClass::QueryFlags rv = 0; - for (int ii = 0; !rv && ii < bindContext->d_func()->defaultObjects.count(); ++ii) { - rv = queryObject(propName, id, - bindContext->d_func()->defaultObjects.at(ii)); - } - - return rv; -} - -QScriptValue QmlEnginePrivate::propertyContext(const QScriptString &name, uint id) -{ - Q_ASSERT(id == resolveData.safetyCheckId); - - if (resolveData.type || resolveData.ns) { - QmlTypeNameBridge tnb = { - resolveData.object, - resolveData.type, - resolveData.ns - }; - return scriptEngine.newObject(typeNameClass, scriptEngine.newVariant(qVariantFromValue(tnb))); - } else if (resolveData.context) { - QmlContext *bindContext = resolveData.context; - QmlContextPrivate *contextPrivate = bindContext->d_func(); - int index = resolveData.contextIndex; - - QScriptValue rv; - if (index < contextPrivate->idValueCount) { - rv = scriptEngine.newObject(objectClass, scriptEngine.newVariant(QVariant::fromValue(contextPrivate->idValues[index].data()))); - } else { - QVariant value = contextPrivate->propertyValues.at(index); - if (QmlMetaType::isObject(value.userType())) { - rv = scriptEngine.newObject(objectClass, scriptEngine.newVariant(value)); - } else { - rv = scriptEngine.newVariant(value); - } - } - capturedProperties << QmlEnginePrivate::CapturedProperty(bindContext, -1, index + contextPrivate->notifyIndex); - return rv; - - } else { - - return propertyObject(name, resolveData.object, id); - - } - - return QScriptValue(); -} - -void QmlEnginePrivate::setPropertyContext(const QScriptValue &value, uint id) -{ - // As context properties cannot be written, we can assume that the - // write is a object property write - setPropertyObject(value, id); -} - void QmlEnginePrivate::setPropertyObject(const QScriptValue &value, uint id) { Q_ASSERT(id == resolveData.safetyCheckId); @@ -430,7 +338,7 @@ QmlEnginePrivate::queryObject(const QString &propName, return rv; } -QScriptValue QmlEnginePrivate::propertyObject(const QScriptString &propName, +QScriptValue QmlEnginePrivate::propertyObject(const QString &propName, QObject *obj, uint id) { Q_ASSERT(id == resolveData.safetyCheckId); @@ -461,7 +369,7 @@ QScriptValue QmlEnginePrivate::propertyObject(const QScriptString &propName, if (!varobj) varobj = qvariant_cast(var); if (varobj) { - return scriptEngine.newObject(objectClass, scriptEngine.newVariant(QVariant::fromValue(varobj))); + return objectClass->newQObject(varobj); } else { return qScriptValueFromValue(&scriptEngine, var); } @@ -784,8 +692,8 @@ void QmlDeclarativeData::setBindingBit(QObject *obj, int bit) QScriptValue QmlEnginePrivate::qmlScriptObject(QObject* object, QmlEngine* engine) { - QScriptEngine *scriptEngine = QmlEnginePrivate::getScriptEngine(engine); - return scriptEngine->newObject(engine->d_func()->objectClass, scriptEngine->newQObject(object, QScriptEngine::AutoOwnership)); + QmlEnginePrivate *enginePriv = QmlEnginePrivate::get(engine); + return enginePriv->objectClass->newQObject(object); } /*! @@ -901,7 +809,7 @@ QScriptValue QmlEnginePrivate::createQmlObject(QScriptContext *ctxt, QScriptEngi QUrl url; if(ctxt->argumentCount() > 2) url = QUrl(ctxt->argument(2).toString()); - QObject *parentArg = ctxt->argument(1).data().toQObject(); + QObject *parentArg = activeEnginePriv->objectClass->toQObject(ctxt->argument(1)); QmlContext *qmlCtxt = qmlContext(parentArg); url = qmlCtxt->resolvedUrl(url); QmlComponent component(activeEngine, qml.toUtf8(), url); @@ -1138,13 +1046,15 @@ QVariant QmlScriptClass::toVariant(QmlEngine *engine, const QScriptValue &val) QmlEnginePrivate *ep = static_cast(QObjectPrivate::get(engine)); + QScriptDeclarativeClass *dc = QScriptDeclarativeClass::scriptClass(val); + if (dc == ep->objectClass) + return QVariant::fromValue(ep->objectClass->toQObject(val)); + else if (dc == ep->contextClass) + return QVariant(); + QScriptClass *sc = val.scriptClass(); if (!sc) { return val.toVariant(); - } else if (sc == ep->contextClass) { - return QVariant(); - } else if (sc == ep->objectClass) { - return QVariant::fromValue(val.data().toQObject()); } else if (sc == ep->valueTypeClass) { QmlValueTypeReference ref = qvariant_cast(val.data().toVariant()); @@ -1160,56 +1070,6 @@ QVariant QmlScriptClass::toVariant(QmlEngine *engine, const QScriptValue &val) } ///////////////////////////////////////////////////////////// -/* - 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); - QmlContext *bindContext = - static_cast(object.data().toQObject()); - - QString propName = name.toString(); - - QmlEnginePrivate *ep = QmlEnginePrivate::get(engine); - return ep->queryContext(propName, id, bindContext); -} - -QScriptValue QmlContextScriptClass::property(const QScriptValue &object, - const QScriptString &name, - uint id) -{ - Q_UNUSED(object); - - QmlEnginePrivate *ep = QmlEnginePrivate::get(engine); - return ep->propertyContext(name, id); -} - -void QmlContextScriptClass::setProperty(QScriptValue &object, - const QScriptString &name, - uint id, - const QScriptValue &value) -{ - Q_UNUSED(object); - Q_UNUSED(name); - - QmlEnginePrivate::get(engine)->setPropertyContext(value, id); -} - -///////////////////////////////////////////////////////////// QmlTypeNameScriptClass::QmlTypeNameScriptClass(QmlEngine *engine) : QmlScriptClass(engine), object(0), type(0) { @@ -1365,108 +1225,6 @@ void QmlValueTypeScriptClass::setProperty(QScriptValue &object, ref.type->write(ref.object, ref.property); } -///////////////////////////////////////////////////////////// -/* - The QmlObjectScriptClass handles property access for QObjects - via QtScript. It is also used to provide a more useful API in - QtScript for QML. - */ - -QScriptValue QmlObjectToString(QScriptContext *context, QScriptEngine *engine) -{ - QObject* obj = context->thisObject().data().toQObject(); - QString ret = QLatin1String("Qml Object, "); - if(obj){ - //###Should this be designer or developer details? Dev for now. - //TODO: Can we print the id too? - ret += QLatin1String("\""); - ret += obj->objectName(); - ret += QLatin1String("\" "); - ret += QLatin1String(obj->metaObject()->className()); - ret += QLatin1String("(0x"); - ret += QString::number((quintptr)obj,16); - ret += QLatin1String(")"); - }else{ - ret += QLatin1String("null"); - } - return engine->newVariant(ret); -} - -QScriptValue QmlObjectDestroy(QScriptContext *context, QScriptEngine *engine) -{ - QObject* obj = context->thisObject().data().toQObject(); - if(obj){ - int delay = 0; - if(context->argumentCount() > 0) - delay = context->argument(0).toInt32(); - QTimer::singleShot(delay, obj, SLOT(deleteLater())); - //### Should this be delayed as well? - context->thisObject().setData(QScriptValue(engine, 0)); - } - return engine->nullValue(); -} - -QmlObjectScriptClass::QmlObjectScriptClass(QmlEngine *bindEngine) - : QmlScriptClass(bindEngine) -{ - engine = bindEngine; - QScriptEngine *scriptEngine = QmlEnginePrivate::getScriptEngine(bindEngine); - prototypeObject = scriptEngine->newObject(); - prototypeObject.setProperty(QLatin1String("toStr"),//TODO: Why won't toString work? - scriptEngine->newFunction(QmlObjectToString)); - prototypeObject.setProperty(QLatin1String("destroy"), - scriptEngine->newFunction(QmlObjectDestroy)); -} - -QmlObjectScriptClass::~QmlObjectScriptClass() -{ -} - -QScriptValue QmlObjectScriptClass::prototype() const -{ - return prototypeObject; -} - -QScriptClass::QueryFlags QmlObjectScriptClass::queryProperty(const QScriptValue &object, - const QScriptString &name, - QueryFlags flags, uint *id) -{ - Q_UNUSED(flags); - QObject *obj = object.data().toQObject(); - QueryFlags rv = 0; - QString propName = name.toString(); - - if (obj) - rv = QmlEnginePrivate::get(engine)->queryObject(propName, id, obj); - - return rv; -} - -QScriptValue QmlObjectScriptClass::property(const QScriptValue &object, - const QScriptString &name, - uint id) -{ - QObject *obj = object.data().toQObject(); - - QScriptValue rv = - QmlEnginePrivate::get(engine)->propertyObject(name, obj, id); - if (rv.isValid()) - return rv; - - return QScriptValue(); -} - -void QmlObjectScriptClass::setProperty(QScriptValue &object, - const QScriptString &name, - uint id, - const QScriptValue &value) -{ - Q_UNUSED(name); - Q_UNUSED(object); - QmlEnginePrivate::get(engine)->setPropertyObject(value, id); -} - - struct QmlEnginePrivate::ImportedNamespace { QStringList urls; QList majversions; diff --git a/src/declarative/qml/qmlengine_p.h b/src/declarative/qml/qmlengine_p.h index 68019e2..764cc6c 100644 --- a/src/declarative/qml/qmlengine_p.h +++ b/src/declarative/qml/qmlengine_p.h @@ -73,6 +73,8 @@ #include #include #include +#include +#include QT_BEGIN_NAMESPACE @@ -100,13 +102,9 @@ public: void init(); - QScriptClass::QueryFlags queryContext(const QString &name, uint *id, - QmlContext *); - QScriptValue propertyContext(const QScriptString &propName, uint id); - void setPropertyContext(const QScriptValue &, uint id); QScriptClass::QueryFlags queryObject(const QString &name, uint *id, QObject *); - QScriptValue propertyObject(const QScriptString &propName, QObject *, + QScriptValue propertyObject(const QString &propName, QObject *, uint id = 0); void setPropertyObject(const QScriptValue &, uint id); @@ -151,7 +149,6 @@ public: } resolveData; QmlContextScriptClass *contextClass; QmlObjectScriptClass *objectClass; - QScriptDeclarativeClass *objectClass2; QmlValueTypeScriptClass *valueTypeClass; QmlTypeNameScriptClass *typeNameClass; // Used by DOM Core 3 API @@ -215,6 +212,7 @@ public: // ### Fixme typedef QHash, bool> FunctionCache; FunctionCache functionCache; + QHash propertyCache; QmlPropertyCache *cache(QObject *obj) { Q_Q(QmlEngine); @@ -285,19 +283,6 @@ public: class QmlScriptClass : public QScriptClass { public: - enum ClassId - { - InvalidId = -1, - - FunctionId = 0x80000000, - VariantPropertyId = 0x40000000, - PropertyId = 0x00000000, - - ClassIdMask = 0xC0000000, - - ClassIdSelectorMask = 0x3F000000, - }; - QmlScriptClass(QmlEngine *); static QVariant toVariant(QmlEngine *, const QScriptValue &); @@ -305,45 +290,6 @@ 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 QScriptValue prototype () const; - QScriptValue prototypeObject; - - 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 QmlTypeNameScriptClass : public QmlScriptClass { public: diff --git a/src/declarative/qml/qmlinstruction_p.h b/src/declarative/qml/qmlinstruction_p.h index e62bfdf..38b3191 100644 --- a/src/declarative/qml/qmlinstruction_p.h +++ b/src/declarative/qml/qmlinstruction_p.h @@ -165,7 +165,7 @@ public: struct { int bindingsSize; int parserStatusSize; - int idSize; + int contextCache; } init; struct { int type; diff --git a/src/declarative/qml/qmlintegercache.cpp b/src/declarative/qml/qmlintegercache.cpp new file mode 100644 index 0000000..1bc4086 --- /dev/null +++ b/src/declarative/qml/qmlintegercache.cpp @@ -0,0 +1,108 @@ +/**************************************************************************** +** +** 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 "qmlintegercache_p.h" +#include +#include + +QT_BEGIN_NAMESPACE + +QmlIntegerCache::QmlIntegerCache(QmlEngine *e) +: engine(e) +{ +} + +QmlIntegerCache::~QmlIntegerCache() +{ + qDeleteAll(stringCache); +} + +void QmlIntegerCache::add(const QString &id, int value) +{ + Q_ASSERT(!stringCache.contains(id)); + + QmlEnginePrivate *enginePriv = QmlEnginePrivate::get(engine); + + // ### use contextClass + QScriptDeclarativeClass::PersistentIdentifier *d = + enginePriv->objectClass->createPersistentIdentifier(id); + d->value = value; + + stringCache.insert(id, d); + identifierCache.insert(d->identifier, d); +} + +int QmlIntegerCache::value(const QString &id) +{ + Data *d = stringCache.value(id); + return d?d->value:-1; +} + +QmlIntegerCache *QmlIntegerCache::createForEnums(QmlType *type, QmlEngine *engine) +{ + Q_ASSERT(type); + Q_ASSERT(engine); + + QmlIntegerCache *cache = new QmlIntegerCache(engine); + + const QMetaObject *mo = type->metaObject(); + + for (int ii = mo->enumeratorCount() - 1; ii >= 0; --ii) { + QMetaEnum enumerator = mo->enumerator(ii); + + for (int jj = 0; jj < enumerator.keyCount(); ++jj) { + QString name = QLatin1String(enumerator.key(jj)); + int value = enumerator.value(jj); + + if (!name.at(0).isUpper()) + continue; + + if (cache->stringCache.contains(name)) + continue; + + cache->add(name, value); + } + } + + return cache; +} + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlintegercache_p.h b/src/declarative/qml/qmlintegercache_p.h new file mode 100644 index 0000000..fda80c6 --- /dev/null +++ b/src/declarative/qml/qmlintegercache_p.h @@ -0,0 +1,103 @@ +/**************************************************************************** +** +** 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 QMLINTEGERCACHE_P_H +#define QMLINTEGERCACHE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QmlType; +class QmlEngine; +class QmlIntegerCache : public QmlRefCount +{ +public: + QmlIntegerCache(QmlEngine *); + virtual ~QmlIntegerCache(); + + inline int count() const; + void add(const QString &, int); + int value(const QString &); + inline int value(const QScriptDeclarativeClass::Identifier &id) const; + + static QmlIntegerCache *createForEnums(QmlType *, QmlEngine *); +private: + struct Data { + int value; + }; + + typedef QHash *> StringCache; + typedef QHash *> IdentifierCache; + + StringCache stringCache; + IdentifierCache identifierCache; + QmlEngine *engine; +}; + +int QmlIntegerCache::value(const QScriptDeclarativeClass::Identifier &id) const +{ + Data *d = identifierCache.value(id); + return d?d->value:-1; +} + +int QmlIntegerCache::count() const +{ + return stringCache.count(); +} + +QT_END_NAMESPACE + +#endif // QMLINTEGERCACHE_P_H + diff --git a/src/declarative/qml/qmlmetaproperty.cpp b/src/declarative/qml/qmlmetaproperty.cpp index f7882dc..ec143a7 100644 --- a/src/declarative/qml/qmlmetaproperty.cpp +++ b/src/declarative/qml/qmlmetaproperty.cpp @@ -218,7 +218,7 @@ void QmlMetaPropertyPrivate::initProperty(QObject *obj, const QString &name) if (cache) { QmlPropertyCache::Data *data = cache->property(name); - if (data && !data->isFunction) { + if (data && !(data->flags & QmlPropertyCache::Data::IsFunction)) { type = QmlMetaProperty::Property; propType = data->propType; coreIdx = data->coreIndex; diff --git a/src/declarative/qml/qmlobjectscriptclass.cpp b/src/declarative/qml/qmlobjectscriptclass.cpp new file mode 100644 index 0000000..0ae1809 --- /dev/null +++ b/src/declarative/qml/qmlobjectscriptclass.cpp @@ -0,0 +1,283 @@ +/**************************************************************************** +** +** 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 "qmlobjectscriptclass_p.h" +#include +#include +#include + +QT_BEGIN_NAMESPACE + +struct ObjectData { + ObjectData(QObject *o) : object(o) {} + QGuard object; +}; + +static QScriptValue QmlObjectToString(QScriptContext *context, QScriptEngine *engine) +{ + QObject* obj = context->thisObject().data().toQObject(); + QString ret = QLatin1String("Qml Object, "); + if(obj){ + //###Should this be designer or developer details? Dev for now. + //TODO: Can we print the id too? + ret += QLatin1String("\""); + ret += obj->objectName(); + ret += QLatin1String("\" "); + ret += QLatin1String(obj->metaObject()->className()); + ret += QLatin1String("(0x"); + ret += QString::number((quintptr)obj,16); + ret += QLatin1String(")"); + }else{ + ret += QLatin1String("null"); + } + return engine->newVariant(ret); +} + +static QScriptValue QmlObjectDestroy(QScriptContext *context, QScriptEngine *engine) +{ + QObject* obj = context->thisObject().toQObject(); + if(obj){ + int delay = 0; + if(context->argumentCount() > 0) + delay = context->argument(0).toInt32(); + obj->deleteLater(); + //### Should this be delayed as well? + context->thisObject().setData(QScriptValue(engine, 0)); + } + return engine->nullValue(); +} + +/* + The QmlObjectScriptClass handles property access for QObjects + via QtScript. It is also used to provide a more useful API in + QtScript for QML. + */ +QmlObjectScriptClass::QmlObjectScriptClass(QmlEngine *bindEngine) +: QScriptDeclarativeClass(QmlEnginePrivate::getScriptEngine(bindEngine)), lastData(0), + engine(bindEngine) +{ + engine = bindEngine; + QScriptEngine *scriptEngine = QmlEnginePrivate::getScriptEngine(bindEngine); + + m_destroy = scriptEngine->newFunction(QmlObjectDestroy); + m_destroyId = createPersistentIdentifier(QLatin1String("destroy")); +} + +QmlObjectScriptClass::~QmlObjectScriptClass() +{ + delete m_destroyId; +} + +QScriptValue QmlObjectScriptClass::newQObject(QObject *object) +{ + QScriptEngine *scriptEngine = QmlEnginePrivate::getScriptEngine(engine); + + return newObject(scriptEngine, this, (Object)new ObjectData(object)); +} + +QObject *QmlObjectScriptClass::toQObject(const QScriptValue &value) const +{ + return value.toQObject(); +} + +QScriptClass::QueryFlags +QmlObjectScriptClass::queryProperty(const Object &object, const Identifier &name, + QScriptClass::QueryFlags flags) +{ + return queryProperty(toQObject(object), name, flags); +} + +QScriptClass::QueryFlags +QmlObjectScriptClass::queryProperty(QObject *obj, const Identifier &name, + QScriptClass::QueryFlags flags) +{ + Q_UNUSED(flags); + lastData = 0; + + if (name == m_destroyId->identifier) + return QScriptClass::HandlesReadAccess; + + if (!obj) + return 0; + + QmlEnginePrivate *enginePrivate = QmlEnginePrivate::get(engine); + QmlPropertyCache *cache = 0; + QmlDeclarativeData *ddata = QmlDeclarativeData::get(obj); + if (ddata) + cache = ddata->propertyCache; + if (!cache) { + cache = enginePrivate->cache(obj); + if (ddata) { cache->addref(); ddata->propertyCache = cache; } + } + + if (cache) { + QmlPropertyCache::Data *property = cache->property(name); + if (!property) return 0; + + if (flags == QScriptClass::HandlesReadAccess) { + lastData = property; + return QScriptClass::HandlesReadAccess; + } else if (property->propType > 0 && property->propType < QVariant::UserType) { + lastData = property; + return flags; + } + } + + // Fallback + return QmlEnginePrivate::get(engine)->queryObject(toString(name), &m_id, obj); +} + +QScriptValue QmlObjectScriptClass::property(const Object &object, const Identifier &name) +{ + return property(toQObject(object), name); +} + +QScriptValue QmlObjectScriptClass::property(QObject *obj, const Identifier &name) +{ + if (name == m_destroyId->identifier) + return m_destroy; + + QScriptEngine *scriptEngine = QmlEnginePrivate::getScriptEngine(engine); + QmlEnginePrivate *enginePriv = QmlEnginePrivate::get(engine); + + if (!obj) { + return QScriptValue(); + } else if (lastData) { + + if (lastData->flags & QmlPropertyCache::Data::IsFunction) { + // ### Optimize + QScriptValue sobj = scriptEngine->newQObject(obj); + return sobj.property(toString(name)); + } else { + QVariant var = obj->metaObject()->property(lastData->coreIndex).read(obj); + if (!(lastData->flags & QmlPropertyCache::Data::IsConstant)) { + enginePriv->capturedProperties << + QmlEnginePrivate::CapturedProperty(obj, lastData->coreIndex, + lastData->notifyIndex); + } + + if (lastData->flags & QmlPropertyCache::Data::IsQObjectDerived) { + QObject *rv = *(QObject **)var.constData(); + return newQObject(rv); + } else { + return qScriptValueFromValue(scriptEngine, var); + } + } + + } else { + return QmlEnginePrivate::get(engine)->propertyObject(toString(name), obj, m_id); + } +} + +void QmlObjectScriptClass::setProperty(const Object &object, + const Identifier &name, + const QScriptValue &value) +{ + return setProperty(toQObject(object), name, value); +} + +void QmlObjectScriptClass::setProperty(QObject *obj, + const Identifier &name, + const QScriptValue &value) +{ + Q_UNUSED(name); + Q_UNUSED(object); + + QScriptEngine *scriptEngine = QmlEnginePrivate::getScriptEngine(engine); + QmlEnginePrivate *enginePriv = QmlEnginePrivate::get(engine); + + if (!obj) { + return; + } else if (lastData) { + switch (lastData->propType) { + case 1: + { + bool b = value.toBoolean(); + void *a[1]; + a[0] = &b; + QMetaObject::metacall(obj, QMetaObject::WriteProperty, lastData->coreIndex, a); + } + break; + + case 2: + { + int b = value.toInteger(); + void *a[1]; + a[0] = &b; + QMetaObject::metacall(obj, QMetaObject::WriteProperty, lastData->coreIndex, a); + } + break; + + case 6: + { + double b = value.toNumber(); + void *a[1]; + a[0] = &b; + QMetaObject::metacall(obj, QMetaObject::WriteProperty, lastData->coreIndex, a); + } + break; + + default: + { + QMetaProperty p = obj->metaObject()->property(lastData->coreIndex); + p.write(obj, value.toVariant()); + } + } + } else { + QmlEnginePrivate::get(engine)->setPropertyObject(value, m_id); + } +} + +QObject *QmlObjectScriptClass::toQObject(const Object &object, bool *ok) +{ + if (ok) *ok = true; + + ObjectData *data = (ObjectData*)object; + return data->object.data(); +} + +void QmlObjectScriptClass::destroyed(const Object &object) +{ + ObjectData *data = (ObjectData*)object; + delete data; +} + +QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlobjectscriptclass_p.h b/src/declarative/qml/qmlobjectscriptclass_p.h new file mode 100644 index 0000000..c25718c --- /dev/null +++ b/src/declarative/qml/qmlobjectscriptclass_p.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 QMLOBJECTSCRIPTCLASS_P_H +#define QMLOBJECTSCRIPTCLASS_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QmlEngine; +class QmlObjectScriptClass : public QScriptDeclarativeClass +{ +public: + QmlObjectScriptClass(QmlEngine *); + ~QmlObjectScriptClass(); + + QScriptValue newQObject(QObject *); + QObject *toQObject(const QScriptValue &) const; + + QScriptClass::QueryFlags queryProperty(QObject *, const Identifier &, + QScriptClass::QueryFlags flags); + QScriptValue property(QObject *, const Identifier &); + void setProperty(QObject *, const Identifier &name, const QScriptValue &); + +protected: + virtual QScriptClass::QueryFlags queryProperty(const Object &, const Identifier &, + QScriptClass::QueryFlags flags); + + virtual QScriptValue property(const Object &, const Identifier &); + virtual void setProperty(const Object &, const Identifier &name, const QScriptValue &); + virtual QObject *toQObject(const Object &, bool *ok = 0); + virtual void destroyed(const Object &); + +private: + uint m_id; + QmlPropertyCache::Data *lastData; + struct Dummy {}; + PersistentIdentifier *m_destroyId; + QScriptValue m_destroy; + QmlEngine *engine; +}; + +QT_END_NAMESPACE + +#endif // QMLOBJECTSCRIPTCLASS_P_H + diff --git a/src/declarative/qml/qmlpropertycache.cpp b/src/declarative/qml/qmlpropertycache.cpp index f88b3a3..95b819a 100644 --- a/src/declarative/qml/qmlpropertycache.cpp +++ b/src/declarative/qml/qmlpropertycache.cpp @@ -42,6 +42,8 @@ #include "qmlpropertycache_p.h" #include "qmlengine_p.h" +QT_BEGIN_NAMESPACE + QmlPropertyCache::QmlPropertyCache() { } @@ -78,12 +80,19 @@ QmlPropertyCache *QmlPropertyCache::create(QmlEngine *engine, const QMetaObject QMetaProperty p = metaObject->property(ii); QString propName = QLatin1String(p.name()); - QScriptDeclarativeClass::PersistentIdentifier *data = - enginePriv->objectClass2->createPersistentIdentifier(propName); + QScriptDeclarativeClass::PersistentIdentifier *data = + enginePriv->objectClass->createPersistentIdentifier(propName); + data->propType = p.userType(); data->coreIndex = ii; + data->notifyIndex = p.notifySignalIndex(); data->name = propName; + if (p.isConstant()) + data->flags |= Data::IsConstant; + if (QmlMetaType::isObject(data->propType)) + data->flags |= Data::IsQObjectDerived; + cache->indexCache[ii] = data; if (cache->stringCache.contains(propName)) @@ -107,14 +116,14 @@ QmlPropertyCache *QmlPropertyCache::create(QmlEngine *engine, const QMetaObject if (cache->stringCache.contains(methodName)) continue; - QScriptDeclarativeClass::PersistentIdentifier *data = - enginePriv->objectClass2->createPersistentIdentifier(methodName); + QScriptDeclarativeClass::PersistentIdentifier *data = + enginePriv->objectClass->createPersistentIdentifier(methodName); cache->stringCache.insert(methodName, data); cache->identifierCache.insert(data->identifier, data); data->addref(); data->addref(); - data->isFunction = true; + data->flags |= Data::IsFunction; } return cache; @@ -135,3 +144,4 @@ QmlPropertyCache::property(const QString &str) const return stringCache.value(str); } +QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlpropertycache_p.h b/src/declarative/qml/qmlpropertycache_p.h index c10fafa..21c8ef3 100644 --- a/src/declarative/qml/qmlpropertycache_p.h +++ b/src/declarative/qml/qmlpropertycache_p.h @@ -67,33 +67,50 @@ public: QmlPropertyCache(); virtual ~QmlPropertyCache(); - struct Data : public QmlRefCount { - Data() : isFunction(false) {} + struct Data { + inline Data(); - bool isFunction; + enum Flag { IsFunction = 0x00000001, + IsQObjectDerived = 0x00000002, + IsConstant = 0x00000004 }; + Q_DECLARE_FLAGS(Flags, Flag) + + Flags flags; int propType; int coreIndex; + int notifyIndex; QString name; }; static QmlPropertyCache *create(QmlEngine *, const QMetaObject *); - Data *property(const QScriptDeclarativeClass::Identifier &id) const { - return identifierCache.value(id); - } - + inline Data *property(const QScriptDeclarativeClass::Identifier &id) const; Data *property(const QString &) const; Data *property(int) const; private: - typedef QVector *> IndexCache; - typedef QHash *> StringCache; - typedef QHash *> IdentifierCache; + struct RData : public Data, public QmlRefCount {}; + + typedef QVector *> IndexCache; + typedef QHash *> StringCache; + typedef QHash *> IdentifierCache; IndexCache indexCache; StringCache stringCache; IdentifierCache identifierCache; }; +Q_DECLARE_OPERATORS_FOR_FLAGS(QmlPropertyCache::Data::Flags); + +QmlPropertyCache::Data::Data() +: flags(0), propType(0), coreIndex(-1), notifyIndex(-1) +{ +} + +QmlPropertyCache::Data * +QmlPropertyCache::property(const QScriptDeclarativeClass::Identifier &id) const +{ + return identifierCache.value(id); +} QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlvme.cpp b/src/declarative/qml/qmlvme.cpp index a5d2732..4ba412b 100644 --- a/src/declarative/qml/qmlvme.cpp +++ b/src/declarative/qml/qmlvme.cpp @@ -166,8 +166,8 @@ QObject *QmlVME::run(QStack &stack, QmlContext *ctxt, if (instr.init.parserStatusSize) parserStatus = QmlEnginePrivate::SimpleList(instr.init.parserStatusSize); - if (instr.init.idSize) - cp->setIdPropertyCount(instr.init.idSize); + if (instr.init.contextCache != -1) + cp->setIdPropertyData(comp->contextCaches.at(instr.init.contextCache)); } break; diff --git a/src/script/api/qscriptvalue.cpp b/src/script/api/qscriptvalue.cpp index f2716e4..d8b4822 100644 --- a/src/script/api/qscriptvalue.cpp +++ b/src/script/api/qscriptvalue.cpp @@ -71,6 +71,7 @@ #include "bridge/qscriptclassobject_p.h" #include "bridge/qscriptvariant_p.h" #include "bridge/qscriptqobject_p.h" +#include "bridge/qscriptdeclarativeclass_p.h" /*! \since 4.3 @@ -1529,6 +1530,8 @@ QVariant QScriptValue::toVariant() const #endif else if (isArray()) return QScriptEnginePrivate::variantListFromArray(*this); + else if (QScriptDeclarativeClass *dc = QScriptDeclarativeClass::scriptClass(*this)) + return dc->toVariant(QScriptDeclarativeClass::object(*this)); // try to convert to primitive JSC::ExecState *exec = d->engine->currentFrame; JSC::JSValue savedException; @@ -1619,6 +1622,8 @@ QObject *QScriptValue::toQObject() const if (isQObject()) { QScriptObject *object = static_cast(JSC::asObject(d->jscValue)); return static_cast(object->delegate())->value(); + } else if (QScriptDeclarativeClass *dc = QScriptDeclarativeClass::scriptClass(*this)) { + return dc->toQObject(QScriptDeclarativeClass::object(*this)); } else if (isVariant()) { QVariant var = toVariant(); int type = var.userType(); diff --git a/src/script/bridge/qscriptdeclarativeclass.cpp b/src/script/bridge/qscriptdeclarativeclass.cpp index c753379..c017e13 100644 --- a/src/script/bridge/qscriptdeclarativeclass.cpp +++ b/src/script/bridge/qscriptdeclarativeclass.cpp @@ -46,6 +46,7 @@ #include #include #include +#include #include QT_BEGIN_NAMESPACE @@ -219,3 +220,15 @@ void QScriptDeclarativeClass::destroyed(const Object &object) Q_UNUSED(object); } +QObject *QScriptDeclarativeClass::toQObject(const Object &, bool *ok) +{ + if (ok) *ok = false; + return 0; +} + +QVariant QScriptDeclarativeClass::toVariant(const Object &, bool *ok) +{ + if (ok) *ok = false; + return QVariant(); +} + diff --git a/src/script/bridge/qscriptdeclarativeclass_p.h b/src/script/bridge/qscriptdeclarativeclass_p.h index 5705a51..a00a286 100644 --- a/src/script/bridge/qscriptdeclarativeclass_p.h +++ b/src/script/bridge/qscriptdeclarativeclass_p.h @@ -112,6 +112,8 @@ public: virtual QStringList propertyNames(const Object &); + virtual QObject *toQObject(const Object &, bool *ok = 0); + virtual QVariant toVariant(const Object &, bool *ok = 0); virtual void destroyed(const Object &); static void destroyPersistentIdentifier(void **); -- cgit v0.12 From 99cf375f554fe01cf47fd4e1a291d4bba62b4018 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Wed, 30 Sep 2009 18:51:45 +1000 Subject: Minor QmlMetaProperty cleanup --- src/declarative/qml/qmlmetaproperty.cpp | 53 ++++++++++++++++++++------------- src/declarative/qml/qmlmetaproperty_p.h | 2 ++ 2 files changed, 35 insertions(+), 20 deletions(-) diff --git a/src/declarative/qml/qmlmetaproperty.cpp b/src/declarative/qml/qmlmetaproperty.cpp index ec143a7..fbe41dd 100644 --- a/src/declarative/qml/qmlmetaproperty.cpp +++ b/src/declarative/qml/qmlmetaproperty.cpp @@ -646,28 +646,11 @@ QVariant QmlMetaProperty::read() const if (sig && sig->index() == d->coreIdx) return sig->expression()->expression(); } + } else if (type() & Property) { - if (type() & Attached) { - return QVariant::fromValue(d->attachedObject()); - } else if(type() & ValueTypeProperty) { - QmlEnginePrivate *ep = d->context?static_cast(QObjectPrivate::get(d->context->engine())):0; - QmlValueType *valueType = 0; - if (ep) - valueType = ep->valueTypes[d->valueTypeId]; - else - valueType = QmlValueTypeFactory::valueType(d->valueTypeId); - Q_ASSERT(valueType); - - valueType->read(object(), d->coreIdx); - QVariant rv = - valueType->metaObject()->property(d->valueTypeIdx).read(valueType); - if (!ep) - delete valueType; - return rv; - } else { - return d->object->metaObject()->property(d->coreIdx).read(object()); - } + return d->readValueProperty(); + } return QVariant(); } @@ -696,6 +679,36 @@ void QmlMetaPropertyPrivate::writeSignalProperty(const QVariant &value) } } +QVariant QmlMetaPropertyPrivate::readValueProperty() +{ + if (type & QmlMetaProperty::Attached) { + + return QVariant::fromValue(attachedObject()); + + } else if(type & QmlMetaProperty::ValueTypeProperty) { + + QmlEnginePrivate *ep = context?QmlEnginePrivate::get(context->engine()):0; + QmlValueType *valueType = 0; + if (ep) + valueType = ep->valueTypes[valueTypeId]; + else + valueType = QmlValueTypeFactory::valueType(valueTypeId); + Q_ASSERT(valueType); + + valueType->read(object, coreIdx); + QVariant rv = + valueType->metaObject()->property(valueTypeIdx).read(valueType); + if (!ep) + delete valueType; + return rv; + + } else { + + return object->metaObject()->property(coreIdx).read(object.data()); + + } +} + void QmlMetaPropertyPrivate::writeValueProperty(const QVariant &value, QmlMetaProperty::WriteSource source) { diff --git a/src/declarative/qml/qmlmetaproperty_p.h b/src/declarative/qml/qmlmetaproperty_p.h index 0d96174..3193aaf 100644 --- a/src/declarative/qml/qmlmetaproperty_p.h +++ b/src/declarative/qml/qmlmetaproperty_p.h @@ -98,6 +98,8 @@ public: QmlMetaProperty::PropertyCategory propertyCategory() const; void writeSignalProperty(const QVariant &); + + QVariant readValueProperty(); void writeValueProperty(const QVariant &, QmlMetaProperty::WriteSource); static quint32 saveValueType(int, int); -- cgit v0.12 From 69c58d7e1c5713d1d6badeffc6c45eeacb1ba2d8 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Thu, 1 Oct 2009 13:25:49 +1000 Subject: QmlMetaProperty cleanup --- src/declarative/qml/qmlmetaproperty.cpp | 550 ++++++++++++++----------------- src/declarative/qml/qmlmetaproperty_p.h | 40 +-- src/declarative/qml/qmlpropertycache.cpp | 55 +++- src/declarative/qml/qmlpropertycache_p.h | 35 +- 4 files changed, 348 insertions(+), 332 deletions(-) diff --git a/src/declarative/qml/qmlmetaproperty.cpp b/src/declarative/qml/qmlmetaproperty.cpp index fbe41dd..477377e 100644 --- a/src/declarative/qml/qmlmetaproperty.cpp +++ b/src/declarative/qml/qmlmetaproperty.cpp @@ -72,9 +72,7 @@ QmlMetaProperty::QmlMetaProperty() d->q = this; } -/*! - The destructor deletes its heap data. - */ +/*! \internal */ QmlMetaProperty::~QmlMetaProperty() { delete d; d = 0; @@ -114,11 +112,9 @@ void QmlMetaPropertyPrivate::initDefault(QObject *obj) object = obj; QMetaProperty p = QmlMetaType::defaultProperty(obj); - name = QLatin1String(p.name()); - propType = p.userType();; - coreIdx = p.propertyIndex(); - if (!name.isEmpty()) - type = QmlMetaProperty::Property | QmlMetaProperty::Default; + core.load(p); + if (core.isValid()) + isDefaultProperty = true; } /*! @@ -129,15 +125,12 @@ void QmlMetaPropertyPrivate::initDefault(QObject *obj) QmlMetaProperty::QmlMetaProperty(QObject *obj, int idx, QmlContext *ctxt) : d(new QmlMetaPropertyPrivate) { + Q_ASSERT(obj); + d->q = this; d->context = ctxt; d->object = obj; - d->type = Property; - QMetaProperty p = obj->metaObject()->property(idx); - d->propType = p.userType(); - d->coreIdx = idx; - if (p.name() != 0) - d->name = QLatin1String(p.name()); + d->core.load(obj->metaObject()->property(idx)); } /*! @@ -168,7 +161,6 @@ void QmlMetaPropertyPrivate::initProperty(QObject *obj, const QString &name) if (context && context->engine()) enginePrivate = QmlEnginePrivate::get(context->engine()); - this->name = name; object = obj; if (name.isEmpty() || !obj) @@ -185,8 +177,6 @@ void QmlMetaPropertyPrivate::initProperty(QObject *obj, const QString &name) enginePrivate->resolveType(typeData->imports, name.toLatin1(), &t, 0, 0, 0, 0); if (t && t->attachedPropertiesFunction()) { attachedFunc = t->index(); - if (attachedFunc != -1) - type = QmlMetaProperty::Property | QmlMetaProperty::Attached; } typeData->release(); } @@ -200,9 +190,9 @@ void QmlMetaPropertyPrivate::initProperty(QObject *obj, const QString &name) QString signalName = name.mid(2); signalName[0] = signalName.at(0).toLower(); - findSignalInt(obj, signalName); - if (signal.signature() != 0) { - type = QmlMetaProperty::SignalProperty; + QMetaMethod method = findSignal(obj, signalName); + if (method.signature()) { + core.load(method); return; } } @@ -218,18 +208,13 @@ void QmlMetaPropertyPrivate::initProperty(QObject *obj, const QString &name) if (cache) { QmlPropertyCache::Data *data = cache->property(name); - if (data && !(data->flags & QmlPropertyCache::Data::IsFunction)) { - type = QmlMetaProperty::Property; - propType = data->propType; - coreIdx = data->coreIndex; - } + if (data && !(data->flags & QmlPropertyCache::Data::IsFunction)) + core = *data; + } else { - // Can't cache + // No cache available QMetaProperty p = QmlMetaType::property(obj, name.toUtf8().constData()); - propType = p.userType(); - coreIdx = p.propertyIndex(); - if (p.name()) - type = QmlMetaProperty::Property; + core.load(p); } } @@ -279,33 +264,31 @@ QmlMetaProperty::PropertyCategory QmlMetaProperty::propertyCategory() const QmlMetaProperty::PropertyCategory QmlMetaPropertyPrivate::propertyCategory() const { - if (category == QmlMetaProperty::Unknown) { + uint type = q->type(); + + if (type & QmlMetaProperty::ValueTypeProperty) { + return QmlMetaProperty::Normal; + } else if (type & QmlMetaProperty::Attached) { + return QmlMetaProperty::Object; + } else if (type & QmlMetaProperty::Property) { int type = propertyType(); - if (type == QmlMetaProperty::Invalid) - category = QmlMetaProperty::InvalidProperty; - else if (type < QVariant::UserType) - category = QmlMetaProperty::Normal; + if (type == QVariant::Invalid) + return QmlMetaProperty::InvalidProperty; + else if ((uint)type < QVariant::UserType) + return QmlMetaProperty::Normal; else if (type == qMetaTypeId()) - category = QmlMetaProperty::Bindable; - else { - QmlMetaType::TypeCategory tc = QmlMetaType::typeCategory(type); - switch(tc) { - case QmlMetaType::Object: - category = QmlMetaProperty::Object; - break; - case QmlMetaType::QmlList: - category = QmlMetaProperty::QmlList; - break; - case QmlMetaType::List: - category = QmlMetaProperty::List; - break; - case QmlMetaType::Unknown: - category = QmlMetaProperty::Normal; - break; - } - } + return QmlMetaProperty::Bindable; + else if (core.flags & QmlPropertyCache::Data::IsQObjectDerived) + return QmlMetaProperty::Object; + else if (core.flags & QmlPropertyCache::Data::IsQmlList) + return QmlMetaProperty::QmlList; + else if (core.flags & QmlPropertyCache::Data::IsQList) + return QmlMetaProperty::List; + else + return QmlMetaProperty::Normal; + } else { + return QmlMetaProperty::InvalidProperty; } - return category; } /*! @@ -314,8 +297,21 @@ QmlMetaPropertyPrivate::propertyCategory() const */ const char *QmlMetaProperty::propertyTypeName() const { - if (!d->name.isEmpty() && d->object) { - return d->object->metaObject()->property(d->coreIdx).typeName(); + if (type() & ValueTypeProperty) { + + QmlEnginePrivate *ep = d->context?QmlEnginePrivate::get(d->context->engine()):0; + QmlValueType *valueType = 0; + if (ep) valueType = ep->valueTypes[d->core.propType]; + else valueType = QmlValueTypeFactory::valueType(d->core.propType); + Q_ASSERT(valueType); + + const char *rv = valueType->metaObject()->property(d->valueTypeCoreIdx).typeName(); + + if (!ep) delete valueType; + + return rv; + } else if (d->object && type() & Property && d->core.isValid()) { + return d->object->metaObject()->property(d->core.coreIndex).typeName(); } else { return 0; } @@ -327,10 +323,13 @@ const char *QmlMetaProperty::propertyTypeName() const */ bool QmlMetaProperty::operator==(const QmlMetaProperty &other) const { - return d->name == other.d->name && - d->signal.signature() == other.d->signal.signature() && - d->type == other.d->type && - d->object == other.d->object; + // category is intentially omitted here as it is generated + // from the other members + return d->object == other.d->object && + d->core == other.d->core && + d->valueTypeCoreIdx == other.d->valueTypeCoreIdx && + d->valueTypePropType == other.d->valueTypePropType && + d->attachedFunc == other.d->attachedFunc; } /*! @@ -344,18 +343,19 @@ int QmlMetaProperty::propertyType() const int QmlMetaPropertyPrivate::propertyType() const { - int rv = QVariant::Invalid; - - if (!name.isEmpty()) { - if (propType == (int)QVariant::LastType) - rv = qMetaTypeId(); + uint type = q->type(); + if (type & QmlMetaProperty::ValueTypeProperty) { + return valueTypePropType; + } else if (type & QmlMetaProperty::Attached) { + return qMetaTypeId(); + } else if (type & QmlMetaProperty::Property) { + if (core.propType == (int)QVariant::LastType) + return qMetaTypeId(); else - rv = propType; - } else if (attachedFunc) { - rv = qMetaTypeId(); - } - - return rv; + return core.propType; + } else { + return QVariant::Invalid; + } } /*! @@ -363,7 +363,16 @@ int QmlMetaPropertyPrivate::propertyType() const */ QmlMetaProperty::Type QmlMetaProperty::type() const { - return (Type)d->type; + if (d->core.flags & QmlPropertyCache::Data::IsFunction) + return SignalProperty; + else if (d->attachedFunc != -1) + return Attached; + else if (d->valueTypeCoreIdx != -1) + return (Type)(Property | ValueTypeProperty); + else if (d->core.isValid()) + return (Type)(Property | ((d->isDefaultProperty)?Default:0)); + else + return Invalid; } /*! @@ -395,17 +404,16 @@ QObject *QmlMetaProperty::object() const */ QmlMetaProperty &QmlMetaProperty::operator=(const QmlMetaProperty &other) { - d->name = other.d->name; - d->signal = other.d->signal; d->context = other.d->context; - d->coreIdx = other.d->coreIdx; - d->valueTypeIdx = other.d->valueTypeIdx; - d->valueTypeId = other.d->valueTypeId; - d->type = other.d->type; - d->attachedFunc = other.d->attachedFunc; d->object = other.d->object; - d->propType = other.d->propType; - d->category = other.d->category; + + d->isDefaultProperty = other.d->isDefaultProperty; + d->core = other.d->core; + + d->valueTypeCoreIdx = other.d->valueTypeCoreIdx; + d->valueTypePropType = other.d->valueTypePropType; + + d->attachedFunc = other.d->attachedFunc; return *this; } @@ -414,12 +422,14 @@ QmlMetaProperty &QmlMetaProperty::operator=(const QmlMetaProperty &other) */ bool QmlMetaProperty::isWritable() const { - if (propertyCategory() == List || propertyCategory() == QmlList) + QmlMetaProperty::PropertyCategory category = propertyCategory(); + + if (category == List || category == QmlList) return true; else if (type() & SignalProperty) return true; - else if (!d->name.isEmpty() && d->object) - return d->object->metaObject()->property(d->coreIdx).isWritable(); + else if (d->core.isValid() && d->object) + return d->object->metaObject()->property(d->core.coreIndex).isWritable(); else return false; } @@ -429,8 +439,8 @@ bool QmlMetaProperty::isWritable() const */ bool QmlMetaProperty::isDesignable() const { - if (!d->name.isEmpty() && d->object) - return d->object->metaObject()->property(d->coreIdx).isDesignable(); + if (type() & Property && d->core.isValid() && d->object) + return d->object->metaObject()->property(d->core.coreIndex).isDesignable(); else return false; } @@ -449,6 +459,7 @@ bool QmlMetaProperty::isValid() const */ QStringList QmlMetaProperty::properties(QObject *obj) { + // ### What is this used for? if (!obj) return QStringList(); @@ -467,7 +478,23 @@ QStringList QmlMetaProperty::properties(QObject *obj) */ QString QmlMetaProperty::name() const { - return d->name; + if (type() & ValueTypeProperty) { + QString rv = d->core.name + QLatin1String("."); + + QmlEnginePrivate *ep = d->context?QmlEnginePrivate::get(d->context->engine()):0; + QmlValueType *valueType = 0; + if (ep) valueType = ep->valueTypes[d->core.propType]; + else valueType = QmlValueTypeFactory::valueType(d->core.propType); + Q_ASSERT(valueType); + + rv += QLatin1String(valueType->metaObject()->property(d->valueTypeCoreIdx).name()); + + if (!ep) delete valueType; + + return rv; + } else { + return d->core.name; + } } /*! @@ -476,13 +503,26 @@ QString QmlMetaProperty::name() const */ QMetaProperty QmlMetaProperty::property() const { - if (d->object) - return d->object->metaObject()->property(d->coreIdx); + if (type() & Property && d->core.isValid() && d->object) + return d->object->metaObject()->property(d->core.coreIndex); else return QMetaProperty(); } /*! + Return the QMetaMethod for this property if it is a SignalProperty, + otherwise returns an invalid QMetaMethod. +*/ +QMetaMethod QmlMetaProperty::method() const +{ + if (type() & SignalProperty && d->object) + return d->object->metaObject()->method(d->core.coreIndex); + else + return QMetaMethod(); +} + + +/*! Returns the binding associated with this property, or 0 if no binding exists. */ @@ -495,13 +535,13 @@ QmlAbstractBinding *QmlMetaProperty::binding() const if (!data) return 0; - if (!data->hasBindingBit(d->coreIdx)) + if (!data->hasBindingBit(d->core.coreIndex)) return 0; QmlAbstractBinding *binding = data->bindings; while (binding) { // ### This wont work for value types - if (binding->propertyIndex() == d->coreIdx) + if (binding->propertyIndex() == d->core.coreIndex) return binding; binding = binding->m_nextBinding; } @@ -527,11 +567,11 @@ QmlMetaProperty::setBinding(QmlAbstractBinding *newBinding) const QmlDeclarativeData *data = QmlDeclarativeData::get(d->object, 0 != newBinding); - if (data && data->hasBindingBit(d->coreIdx)) { + if (data && data->hasBindingBit(d->core.coreIndex)) { QmlAbstractBinding *binding = data->bindings; while (binding) { // ### This wont work for value types - if (binding->propertyIndex() == d->coreIdx) { + if (binding->propertyIndex() == d->core.coreIndex) { binding->setEnabled(false); if (newBinding) @@ -594,15 +634,14 @@ QmlExpression *QmlMetaProperty::setSignalExpression(QmlExpression *expr) const } if (expr) { - QmlBoundSignal *signal = new QmlBoundSignal(d->object, d->signal, - d->object); + QmlBoundSignal *signal = new QmlBoundSignal(d->object, method(), d->object); return signal->setExpression(expr); } else { return 0; } } -void QmlMetaPropertyPrivate::findSignalInt(QObject *obj, const QString &name) +QMetaMethod QmlMetaPropertyPrivate::findSignal(QObject *obj, const QString &name) { const QMetaObject *mo = obj->metaObject(); @@ -613,12 +652,10 @@ void QmlMetaPropertyPrivate::findSignalInt(QObject *obj, const QString &name) int idx = methodName.indexOf(QLatin1Char('(')); methodName = methodName.left(idx); - if (methodName == name) { - signal = method; - coreIdx = ii; - return; - } + if (methodName == name) + return method; } + return QMetaMethod(); } QObject *QmlMetaPropertyPrivate::attachedObject() const @@ -643,7 +680,7 @@ QVariant QmlMetaProperty::read() const for (int ii = 0; ii < children.count(); ++ii) { QmlBoundSignal *sig = QmlBoundSignal::cast(children.at(ii)); - if (sig && sig->index() == d->coreIdx) + if (sig && sig->index() == d->core.coreIndex) return sig->expression()->expression(); } @@ -662,7 +699,7 @@ void QmlMetaPropertyPrivate::writeSignalProperty(const QVariant &value) for (int ii = 0; ii < children.count(); ++ii) { QmlBoundSignal *sig = QmlBoundSignal::cast(children.at(ii)); - if (sig && sig->index() == coreIdx) { + if (sig && sig->index() == core.coreIndex) { if (expr.isEmpty()) { sig->disconnect(); sig->deleteLater(); @@ -675,12 +712,13 @@ void QmlMetaPropertyPrivate::writeSignalProperty(const QVariant &value) if (!expr.isEmpty()) { // XXX scope - (void *)new QmlBoundSignal(qmlContext(object), expr, object, signal, object); + (void *)new QmlBoundSignal(qmlContext(object), expr, object, q->method(), object); } } QVariant QmlMetaPropertyPrivate::readValueProperty() { + uint type = q->type(); if (type & QmlMetaProperty::Attached) { return QVariant::fromValue(attachedObject()); @@ -689,22 +727,21 @@ QVariant QmlMetaPropertyPrivate::readValueProperty() QmlEnginePrivate *ep = context?QmlEnginePrivate::get(context->engine()):0; QmlValueType *valueType = 0; - if (ep) - valueType = ep->valueTypes[valueTypeId]; - else - valueType = QmlValueTypeFactory::valueType(valueTypeId); + if (ep) valueType = ep->valueTypes[core.propType]; + else valueType = QmlValueTypeFactory::valueType(core.propType); Q_ASSERT(valueType); - valueType->read(object, coreIdx); + valueType->read(object, core.coreIndex); + QVariant rv = - valueType->metaObject()->property(valueTypeIdx).read(valueType); - if (!ep) - delete valueType; + valueType->metaObject()->property(valueTypeCoreIdx).read(valueType); + + if (!ep) delete valueType; return rv; } else { - return object->metaObject()->property(coreIdx).read(object.data()); + return object->metaObject()->property(core.coreIndex).read(object.data()); } } @@ -712,40 +749,49 @@ QVariant QmlMetaPropertyPrivate::readValueProperty() void QmlMetaPropertyPrivate::writeValueProperty(const QVariant &value, QmlMetaProperty::WriteSource source) { - QObject *object = this->object; - int coreIdx = this->coreIdx; - - QmlValueType *writeBack = 0; - QObject *writeBackObj = 0; - int writeBackIdx = -1; - bool deleteWriteBack = false; - // Remove any existing bindings on this property if (source != QmlMetaProperty::Binding) delete q->setBinding(0); + uint type = q->type(); if (type & QmlMetaProperty::ValueTypeProperty) { - QmlEnginePrivate *ep = context?static_cast(QObjectPrivate::get(context->engine())):0; + QmlEnginePrivate *ep = + context?static_cast(QObjectPrivate::get(context->engine())):0; + QmlValueType *writeBack = 0; if (ep) { - writeBack = ep->valueTypes[valueTypeId]; + writeBack = ep->valueTypes[core.propType]; } else { - writeBack = QmlValueTypeFactory::valueType(valueTypeId); - deleteWriteBack = true; + writeBack = QmlValueTypeFactory::valueType(core.propType); } - writeBackObj = this->object; - writeBackIdx = this->coreIdx; - writeBack->read(writeBackObj, writeBackIdx); - object = writeBack; - coreIdx = valueTypeIdx; + writeBack->read(object, core.coreIndex); + + QmlPropertyCache::Data data = core; + data.coreIndex = valueTypeCoreIdx; + data.propType = valueTypePropType; + write(writeBack, data, value, context); + + writeBack->write(object, core.coreIndex); + if (!ep) delete writeBack; + + } else { + + write(object, core, value, context); + } +} - QMetaProperty prop = object->metaObject()->property(coreIdx); +void QmlMetaPropertyPrivate::write(QObject *object, const QmlPropertyCache::Data &property, + const QVariant &value, QmlContext *context) +{ + int coreIdx = property.coreIndex; - if (prop.isEnumType()) { + if (property.flags & QmlPropertyCache::Data::IsEnumType) { + QMetaProperty prop = object->metaObject()->property(property.coreIndex); QVariant v = value; - if (value.type() == QVariant::Double) { //enum values come through the script engine as doubles + // Enum values come through the script engine as doubles + if (value.type() == QVariant::Double) { double integral; double fractional = modf(value.toDouble(), &integral); if (qFuzzyCompare(fractional, (double)0.0)) @@ -753,19 +799,36 @@ void QmlMetaPropertyPrivate::writeValueProperty(const QVariant &value, } prop.write(object, v); - if (writeBack) { - writeBack->write(writeBackObj, writeBackIdx); - if (deleteWriteBack) delete writeBack; - } return; } - int t = propertyType(); + int t = property.propType; int vt = value.userType(); - int category = propertyCategory(); - if (vt == t - && t != QVariant::Url) { // always resolve relative urls + if (t == QVariant::Url) { + + QUrl u; + bool found = false; + if (vt == QVariant::Url) { + u = value.toUrl(); + found = true; + } else if (vt == QVariant::ByteArray) { + u = QUrl(QLatin1String(value.toByteArray())); + found = true; + } else if (vt == QVariant::String) { + u = QUrl(value.toString()); + found = true; + } + + if (found) { + if (context && u.isRelative() && !u.isEmpty()) + u = context->baseUrl().resolved(u); + void *a[1]; + a[0] = &u; + QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, a); + } + + } else if (vt == t) { void *a[1]; a[0] = (void *)value.constData(); @@ -773,9 +836,11 @@ void QmlMetaPropertyPrivate::writeValueProperty(const QVariant &value, } else if (qMetaTypeId() == t) { - prop.write(object, value); + void *a[1]; + a[0] = (void *)&value; + QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, a); - } else if (category == QmlMetaProperty::Object) { + } else if (property.flags & QmlPropertyCache::Data::IsQObjectDerived) { QObject *o = QmlMetaType::toQObject(value); @@ -802,9 +867,10 @@ void QmlMetaPropertyPrivate::writeValueProperty(const QVariant &value, } - } else if (category == QmlMetaProperty::List) { + } else if (property.flags & QmlPropertyCache::Data::IsQList) { int listType = QmlMetaType::listType(t); + QMetaProperty prop = object->metaObject()->property(property.coreIndex); if (value.userType() == qMetaTypeId >()) { const QList &list = @@ -822,9 +888,11 @@ void QmlMetaPropertyPrivate::writeValueProperty(const QVariant &value, QmlMetaType::clear(listVar); QmlMetaType::append(listVar, value); } - } else if (category == QmlMetaProperty::QmlList) { + + } else if (property.flags & QmlPropertyCache::Data::IsQmlList) { // XXX - optimize! + QMetaProperty prop = object->metaObject()->property(property.coreIndex); QVariant list = prop.read(object); QmlPrivate::ListInterface *li = *(QmlPrivate::ListInterface **)list.constData(); @@ -854,118 +922,25 @@ void QmlMetaPropertyPrivate::writeValueProperty(const QVariant &value, void *d = (void *)&obj; li->append(d); } - } else if (category == QmlMetaProperty::Normal) { - - bool found = false; - switch(t) { - case QVariant::Double: - { - double d; - if (vt == QVariant::Int) { - d = value.toInt(); - found = true; - } else if (vt == QVariant::UInt) { - d = value.toUInt(); - found = true; - } - - if (found) { - void *a[1]; - a[0] = &d; - QMetaObject::metacall(object, - QMetaObject::WriteProperty, - coreIdx, a); - } - } - break; - - case QVariant::Int: - { - int i; - if (vt == QVariant::Double) { - i = (int)value.toDouble(); - found = true; - } else if (vt == QVariant::UInt) { - i = (int)value.toUInt(); - found = true; - } - - if (found) { - void *a[1]; - a[0] = &i; - QMetaObject::metacall(object, - QMetaObject::WriteProperty, - coreIdx, a); - } - } - break; - - case QVariant::String: - { - QString s; - if (vt == QVariant::ByteArray) { - s = QLatin1String(value.toByteArray()); - found = true; - } - - if (found) { - void *a[1]; - a[0] = &s; - QMetaObject::metacall(object, - QMetaObject::WriteProperty, - coreIdx, a); - } - } - break; - - case QVariant::Url: - { - QUrl u; - if (vt == QVariant::Url) { - u = value.toUrl(); - found = true; - } else if (vt == QVariant::ByteArray) { - u = QUrl(QLatin1String(value.toByteArray())); - found = true; - } else if (vt == QVariant::String) { - u = QUrl(value.toString()); - found = true; - } + } else { + Q_ASSERT(vt != t); - if (found) { - if (context && u.isRelative() && !u.isEmpty()) - u = context->baseUrl().resolved(u); + QVariant v = value; + if (v.convert((QVariant::Type)t)) { + void *a[1]; + a[0] = (void *)v.constData(); + QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, a); + } else if ((uint)t >= QVariant::UserType && vt == QVariant::String) { + QmlMetaType::StringConverter con = QmlMetaType::customStringConverter(t); + if (con) { + QVariant v = con(value.toString()); + if (v.userType() == t) { void *a[1]; - a[0] = &u; - QMetaObject::metacall(object, - QMetaObject::WriteProperty, - coreIdx, a); + a[0] = (void *)v.constData(); + QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, a); } - } - break; - - - default: - { - if ((uint)t >= QVariant::UserType && vt == QVariant::String) { - QmlMetaType::StringConverter con = QmlMetaType::customStringConverter(t); - if (con) { - QVariant v = con(value.toString()); - prop.write(object, v); - found = true; - } - } - } - break; } - if (!found) - prop.write(object, value); - } - - if (writeBack) { - writeBack->write(writeBackObj, writeBackIdx); - if (deleteWriteBack) delete writeBack; } } @@ -986,7 +961,7 @@ void QmlMetaProperty::write(const QVariant &value, WriteSource source) const d->writeSignalProperty(value); - } else if (d->coreIdx != -1) { + } else if (d->core.isValid()) { d->writeValueProperty(value, source); @@ -999,7 +974,7 @@ void QmlMetaProperty::write(const QVariant &value, WriteSource source) const bool QmlMetaProperty::hasChangedNotifier() const { if (type() & Property && !(type() & Attached) && d->object) { - return d->object->metaObject()->property(d->coreIdx).hasNotifySignal(); + return d->object->metaObject()->property(d->core.coreIndex).hasNotifySignal(); } return false; } @@ -1030,7 +1005,7 @@ bool QmlMetaProperty::connectNotifier(QObject *dest, int method) const if (!(type() & Property) || (type() & Attached) || !d->object) return false; - QMetaProperty prop = d->object->metaObject()->property(d->coreIdx); + QMetaProperty prop = d->object->metaObject()->property(d->core.coreIndex); if (prop.hasNotifySignal()) { return QMetaObject::connect(d->object, prop.notifySignalIndex(), dest, method, Qt::DirectConnection); } else { @@ -1051,7 +1026,7 @@ bool QmlMetaProperty::connectNotifier(QObject *dest, const char *slot) const if (!(type() & Property) || (type() & Attached) || !d->object) return false; - QMetaProperty prop = d->object->metaObject()->property(d->coreIdx); + QMetaProperty prop = d->object->metaObject()->property(d->core.coreIndex); if (prop.hasNotifySignal()) { QByteArray signal(QByteArray("2") + prop.notifySignal().signature()); return QObject::connect(d->object, signal.constData(), dest, slot); @@ -1065,7 +1040,7 @@ bool QmlMetaProperty::connectNotifier(QObject *dest, const char *slot) const */ int QmlMetaProperty::coreIndex() const { - return d->coreIdx; + return d->core.coreIndex; } Q_GLOBAL_STATIC(QmlValueTypeFactory, qmlValueTypes); @@ -1080,17 +1055,17 @@ quint32 QmlMetaProperty::save() const if (type() & Attached) { rv = d->attachedFunc; } else if (type() != Invalid) { - rv = d->coreIdx; + rv = d->core.coreIndex; } Q_ASSERT(rv <= 0x7FF); Q_ASSERT(type() <= 0x3F); - Q_ASSERT(d->valueTypeIdx <= 0x7F); + Q_ASSERT(d->valueTypeCoreIdx <= 0x7F); rv |= (type() << 18); if (type() & ValueTypeProperty) - rv |= (d->valueTypeIdx << 11); + rv |= (d->valueTypeCoreIdx << 11); return rv; } @@ -1131,12 +1106,12 @@ void QmlMetaProperty::restore(quint32 id, QObject *obj, QmlContext *ctxt) d->context = ctxt; id &= 0xFFFFFF; - d->type = id >> 18; + uint type = id >> 18; id &= 0xFFFF; - if (d->type & Attached) { + if (type & Attached) { d->attachedFunc = id; - } else if (d->type & ValueTypeProperty) { + } else if (type & ValueTypeProperty) { int coreIdx = id & 0x7FF; int valueTypeIdx = id >> 11; @@ -1147,46 +1122,31 @@ void QmlMetaProperty::restore(quint32 id, QObject *obj, QmlContext *ctxt) QMetaProperty p2(valueType->metaObject()->property(valueTypeIdx)); - d->name = QLatin1String(p2.name()); - d->propType = p2.userType(); - d->coreIdx = coreIdx; - d->valueTypeIdx = valueTypeIdx; - d->valueTypeId = p.type(); - - } else if (d->type & Property) { + d->core.load(p); + d->valueTypeCoreIdx = valueTypeIdx; + d->valueTypePropType = p.userType(); + } else if (type & Property) { QmlPropertyCache *cache = enginePrivate?enginePrivate->cache(obj):0; - d->coreIdx = id; - if (cache) { QmlPropertyCache::Data *data = cache->property(id); - d->propType = data->propType; - d->name = data->name; + if (data) d->core = *data; } else { QMetaProperty p(obj->metaObject()->property(id)); - d->name = QLatin1String(p.name()); - d->propType = p.userType(); + d->core.load(p); } - } else if (d->type & SignalProperty) { - d->signal = obj->metaObject()->method(id); - d->coreIdx = id; + } else if (type & SignalProperty) { + + QMetaMethod method = obj->metaObject()->method(id); + d->core.load(method); } else { *this = QmlMetaProperty(); } } /*! - Return the QMetaMethod for this property if it is a SignalProperty, - otherwise returns an invalid QMetaMethod. -*/ -QMetaMethod QmlMetaProperty::method() const -{ - return d->signal; -} - -/*! \internal Creates a QmlMetaProperty for the property \a name of \a obj. Unlike @@ -1213,17 +1173,11 @@ QmlMetaProperty QmlMetaProperty::createProperty(QObject *obj, int idx = typeObject->metaObject()->indexOfProperty(path.last().toUtf8().constData()); if (idx == -1) return QmlMetaProperty(); + QMetaProperty vtProp = typeObject->metaObject()->property(idx); - QmlMetaProperty p; - p.d->name = pathName + QLatin1String(".") + path.last(); - p.d->context = 0; - p.d->coreIdx = prop.coreIndex(); - p.d->valueTypeIdx = idx; - p.d->valueTypeId = prop.propertyType(); - p.d->type = QmlMetaProperty::ValueTypeProperty | - QmlMetaProperty::Property; - p.d->object = obj; - p.d->propType = typeObject->metaObject()->property(idx).userType(); + QmlMetaProperty p = prop; + p.d->valueTypeCoreIdx = idx; + p.d->valueTypePropType = vtProp.userType(); return p; } diff --git a/src/declarative/qml/qmlmetaproperty_p.h b/src/declarative/qml/qmlmetaproperty_p.h index 3193aaf..729236b 100644 --- a/src/declarative/qml/qmlmetaproperty_p.h +++ b/src/declarative/qml/qmlmetaproperty_p.h @@ -54,7 +54,8 @@ // #include "qmlmetaproperty.h" -#include "private/qobject_p.h" +#include +#include QT_BEGIN_NAMESPACE @@ -63,36 +64,34 @@ class QmlMetaPropertyPrivate { public: QmlMetaPropertyPrivate() - : q(0), context(0), coreIdx(-1), valueTypeIdx(-1), valueTypeId(0), - type(QmlMetaProperty::Invalid), attachedFunc(-1), - object(0), propType(-1), category(QmlMetaProperty::Unknown) {} + : q(0), context(0), object(0), isDefaultProperty(false), valueTypeCoreIdx(-1), + valueTypePropType(0), attachedFunc(-1) {} + QmlMetaPropertyPrivate(const QmlMetaPropertyPrivate &other) - : q(0), name(other.name), signal(other.signal), context(other.context), - coreIdx(other.coreIdx), valueTypeIdx(other.valueTypeIdx), - valueTypeId(other.valueTypeId), type(other.type), - attachedFunc(other.attachedFunc), object(other.object), - propType(other.propType), category(other.category) {} + : q(0), context(other.context), object(other.object), + isDefaultProperty(other.isDefaultProperty), core(other.core), + valueTypeCoreIdx(other.valueTypeCoreIdx), + valueTypePropType(other.valueTypePropType), attachedFunc(other.attachedFunc) {} QmlMetaProperty *q; - - QString name; - QMetaMethod signal; QmlContext *context; - int coreIdx; - int valueTypeIdx; - int valueTypeId; - uint type; - int attachedFunc; QGuard object; - int propType; - mutable QmlMetaProperty::PropertyCategory category; + bool isDefaultProperty; + QmlPropertyCache::Data core; + + // Describes the "virtual" value-type sub-property. + int valueTypeCoreIdx; // The prop index of the access property on the value type wrapper + int valueTypePropType; // The QVariant::Type of access property on the value type wrapper + + // The attached property accessor + int attachedFunc; void initProperty(QObject *obj, const QString &name); void initDefault(QObject *obj); QObject *attachedObject() const; - void findSignalInt(QObject *, const QString &); + QMetaMethod findSignal(QObject *, const QString &); int propertyType() const; QmlMetaProperty::PropertyCategory propertyCategory() const; @@ -101,6 +100,7 @@ public: QVariant readValueProperty(); void writeValueProperty(const QVariant &, QmlMetaProperty::WriteSource); + static void write(QObject *, const QmlPropertyCache::Data &, const QVariant &, QmlContext *); static quint32 saveValueType(int, int); static quint32 saveProperty(int); diff --git a/src/declarative/qml/qmlpropertycache.cpp b/src/declarative/qml/qmlpropertycache.cpp index 95b819a..7d234fd 100644 --- a/src/declarative/qml/qmlpropertycache.cpp +++ b/src/declarative/qml/qmlpropertycache.cpp @@ -40,10 +40,48 @@ ****************************************************************************/ #include "qmlpropertycache_p.h" -#include "qmlengine_p.h" +#include +#include QT_BEGIN_NAMESPACE +void QmlPropertyCache::Data::load(const QMetaProperty &p) +{ + propType = p.userType(); + coreIndex = p.propertyIndex(); + notifyIndex = p.notifySignalIndex(); + name = QLatin1String(p.name()); + + if (p.isConstant()) + flags |= Data::IsConstant; + + if (propType == qMetaTypeId()) { + flags |= Data::IsQmlBinding; + } else if (p.isEnumType()) { + flags |= Data::IsEnumType; + } else { + QmlMetaType::TypeCategory cat = QmlMetaType::typeCategory(propType); + if (cat == QmlMetaType::Object) + flags |= Data::IsQObjectDerived; + else if (cat == QmlMetaType::List) + flags |= Data::IsQList; + else if (cat == QmlMetaType::QmlList) + flags |= Data::IsQmlList; + } +} + +void QmlPropertyCache::Data::load(const QMetaMethod &m) +{ + name = QLatin1String(m.signature()); + int parenIdx = name.indexOf(QLatin1Char('(')); + Q_ASSERT(parenIdx != -1); + name = name.left(parenIdx); + + coreIndex = m.methodIndex(); + flags |= Data::IsFunction; +} + + QmlPropertyCache::QmlPropertyCache() { } @@ -83,15 +121,7 @@ QmlPropertyCache *QmlPropertyCache::create(QmlEngine *engine, const QMetaObject QScriptDeclarativeClass::PersistentIdentifier *data = enginePriv->objectClass->createPersistentIdentifier(propName); - data->propType = p.userType(); - data->coreIndex = ii; - data->notifyIndex = p.notifySignalIndex(); - data->name = propName; - - if (p.isConstant()) - data->flags |= Data::IsConstant; - if (QmlMetaType::isObject(data->propType)) - data->flags |= Data::IsQObjectDerived; + data->load(p); cache->indexCache[ii] = data; @@ -118,12 +148,13 @@ QmlPropertyCache *QmlPropertyCache::create(QmlEngine *engine, const QMetaObject QScriptDeclarativeClass::PersistentIdentifier *data = enginePriv->objectClass->createPersistentIdentifier(methodName); + + data->load(m); + cache->stringCache.insert(methodName, data); cache->identifierCache.insert(data->identifier, data); data->addref(); data->addref(); - - data->flags |= Data::IsFunction; } return cache; diff --git a/src/declarative/qml/qmlpropertycache_p.h b/src/declarative/qml/qmlpropertycache_p.h index 21c8ef3..149d2a0 100644 --- a/src/declarative/qml/qmlpropertycache_p.h +++ b/src/declarative/qml/qmlpropertycache_p.h @@ -69,18 +69,40 @@ public: struct Data { inline Data(); + inline bool operator==(const Data &); - enum Flag { IsFunction = 0x00000001, + enum Flag { + // Can apply to all properties, except IsFunction + IsConstant = 0x00000004, + + // These are mutually exclusive + IsFunction = 0x00000001, IsQObjectDerived = 0x00000002, - IsConstant = 0x00000004 }; + IsEnumType = 0x00000008, + IsQmlList = 0x00000010, + IsQList = 0x00000020, + IsQmlBinding = 0x00000040 + }; Q_DECLARE_FLAGS(Flags, Flag) + bool isValid() const { return coreIndex != -1; } + Flags flags; int propType; int coreIndex; int notifyIndex; QString name; + + void load(const QMetaProperty &); + void load(const QMetaMethod &); + }; + +#if 0 + struct ValueTypeData { + int valueTypeCoreIdx; // The prop index of the access property on the value type wrapper + int valueTypePropType; // The QVariant::Type of access property on the value type wrapper }; +#endif static QmlPropertyCache *create(QmlEngine *, const QMetaObject *); @@ -106,6 +128,15 @@ QmlPropertyCache::Data::Data() { } +bool QmlPropertyCache::Data::operator==(const QmlPropertyCache::Data::Data &other) +{ + return flags == other.flags && + propType == other.propType && + coreIndex == other.coreIndex && + notifyIndex == other.notifyIndex && + name == other.name; +} + QmlPropertyCache::Data * QmlPropertyCache::property(const QScriptDeclarativeClass::Identifier &id) const { -- cgit v0.12 From 361a605e9269f3072c1f5597a8db0622cf3b116b Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Thu, 1 Oct 2009 17:36:35 +1000 Subject: Read/write property directly from QmlObjectScriptClass --- src/declarative/qml/qmlcontext.cpp | 1 - src/declarative/qml/qmlobjectscriptclass.cpp | 110 +++++++++------------------ src/declarative/qml/qmlobjectscriptclass_p.h | 2 + src/declarative/qml/qmlpropertycache.cpp | 37 +++++++++ src/declarative/qml/qmlpropertycache_p.h | 16 ++-- 5 files changed, 83 insertions(+), 83 deletions(-) diff --git a/src/declarative/qml/qmlcontext.cpp b/src/declarative/qml/qmlcontext.cpp index 1c9d177..5e74d1a 100644 --- a/src/declarative/qml/qmlcontext.cpp +++ b/src/declarative/qml/qmlcontext.cpp @@ -386,7 +386,6 @@ void QmlContextPrivate::setIdProperty(const QString &name, int idx, notifyIndex = q->metaObject()->methodCount(); } - propertyNames->add(name, idx); idValues[idx].priv = this; idValues[idx] = obj; } diff --git a/src/declarative/qml/qmlobjectscriptclass.cpp b/src/declarative/qml/qmlobjectscriptclass.cpp index 0ae1809..28a808a 100644 --- a/src/declarative/qml/qmlobjectscriptclass.cpp +++ b/src/declarative/qml/qmlobjectscriptclass.cpp @@ -149,20 +149,19 @@ QmlObjectScriptClass::queryProperty(QObject *obj, const Identifier &name, } if (cache) { - QmlPropertyCache::Data *property = cache->property(name); - if (!property) return 0; - - if (flags == QScriptClass::HandlesReadAccess) { - lastData = property; - return QScriptClass::HandlesReadAccess; - } else if (property->propType > 0 && property->propType < QVariant::UserType) { - lastData = property; - return flags; - } + lastData = cache->property(name); + } else { + local = QmlPropertyCache::create(obj->metaObject(), toString(name)); + if (local.isValid()) + lastData = &local; } - // Fallback - return QmlEnginePrivate::get(engine)->queryObject(toString(name), &m_id, obj); + if (!lastData) return 0; + + QScriptClass::QueryFlags rv = QScriptClass::HandlesReadAccess; + if (lastData->flags & QmlPropertyCache::Data::IsWritable) + rv |= QScriptClass::HandlesWriteAccess; + return rv; } QScriptValue QmlObjectScriptClass::property(const Object &object, const Identifier &name) @@ -175,35 +174,31 @@ QScriptValue QmlObjectScriptClass::property(QObject *obj, const Identifier &name if (name == m_destroyId->identifier) return m_destroy; + Q_ASSERT(lastData); + Q_ASSERT(obj); + QScriptEngine *scriptEngine = QmlEnginePrivate::getScriptEngine(engine); QmlEnginePrivate *enginePriv = QmlEnginePrivate::get(engine); - if (!obj) { - return QScriptValue(); - } else if (lastData) { + if (lastData->flags & QmlPropertyCache::Data::IsFunction) { + // ### Optimize + QScriptValue sobj = scriptEngine->newQObject(obj); + return sobj.property(toString(name)); + } else { + + QVariant var = obj->metaObject()->property(lastData->coreIndex).read(obj); + if (!(lastData->flags & QmlPropertyCache::Data::IsConstant)) { + enginePriv->capturedProperties << + QmlEnginePrivate::CapturedProperty(obj, lastData->coreIndex, lastData->notifyIndex); + } - if (lastData->flags & QmlPropertyCache::Data::IsFunction) { - // ### Optimize - QScriptValue sobj = scriptEngine->newQObject(obj); - return sobj.property(toString(name)); + if (lastData->flags & QmlPropertyCache::Data::IsQObjectDerived) { + QObject *rv = *(QObject **)var.constData(); + return newQObject(rv); } else { - QVariant var = obj->metaObject()->property(lastData->coreIndex).read(obj); - if (!(lastData->flags & QmlPropertyCache::Data::IsConstant)) { - enginePriv->capturedProperties << - QmlEnginePrivate::CapturedProperty(obj, lastData->coreIndex, - lastData->notifyIndex); - } - - if (lastData->flags & QmlPropertyCache::Data::IsQObjectDerived) { - QObject *rv = *(QObject **)var.constData(); - return newQObject(rv); - } else { - return qScriptValueFromValue(scriptEngine, var); - } + return qScriptValueFromValue(scriptEngine, var); } - } else { - return QmlEnginePrivate::get(engine)->propertyObject(toString(name), obj, m_id); } } @@ -219,51 +214,16 @@ void QmlObjectScriptClass::setProperty(QObject *obj, const QScriptValue &value) { Q_UNUSED(name); - Q_UNUSED(object); + + Q_ASSERT(obj); + Q_ASSERT(lastData); QScriptEngine *scriptEngine = QmlEnginePrivate::getScriptEngine(engine); QmlEnginePrivate *enginePriv = QmlEnginePrivate::get(engine); - if (!obj) { - return; - } else if (lastData) { - switch (lastData->propType) { - case 1: - { - bool b = value.toBoolean(); - void *a[1]; - a[0] = &b; - QMetaObject::metacall(obj, QMetaObject::WriteProperty, lastData->coreIndex, a); - } - break; - - case 2: - { - int b = value.toInteger(); - void *a[1]; - a[0] = &b; - QMetaObject::metacall(obj, QMetaObject::WriteProperty, lastData->coreIndex, a); - } - break; - - case 6: - { - double b = value.toNumber(); - void *a[1]; - a[0] = &b; - QMetaObject::metacall(obj, QMetaObject::WriteProperty, lastData->coreIndex, a); - } - break; - - default: - { - QMetaProperty p = obj->metaObject()->property(lastData->coreIndex); - p.write(obj, value.toVariant()); - } - } - } else { - QmlEnginePrivate::get(engine)->setPropertyObject(value, m_id); - } + // ### Can well known types be optimized? + QVariant v = QmlScriptClass::toVariant(engine, value); + QmlMetaPropertyPrivate::write(obj, *lastData, v, enginePriv->currentExpression->context()); } QObject *QmlObjectScriptClass::toQObject(const Object &object, bool *ok) diff --git a/src/declarative/qml/qmlobjectscriptclass_p.h b/src/declarative/qml/qmlobjectscriptclass_p.h index c25718c..f126192 100644 --- a/src/declarative/qml/qmlobjectscriptclass_p.h +++ b/src/declarative/qml/qmlobjectscriptclass_p.h @@ -86,6 +86,8 @@ protected: private: uint m_id; QmlPropertyCache::Data *lastData; + QmlPropertyCache::Data local; + struct Dummy {}; PersistentIdentifier *m_destroyId; QScriptValue m_destroy; diff --git a/src/declarative/qml/qmlpropertycache.cpp b/src/declarative/qml/qmlpropertycache.cpp index 7d234fd..cc4c2ab 100644 --- a/src/declarative/qml/qmlpropertycache.cpp +++ b/src/declarative/qml/qmlpropertycache.cpp @@ -54,6 +54,8 @@ void QmlPropertyCache::Data::load(const QMetaProperty &p) if (p.isConstant()) flags |= Data::IsConstant; + if (p.isWritable()) + flags |= Data::IsWritable; if (propType == qMetaTypeId()) { flags |= Data::IsQmlBinding; @@ -100,6 +102,41 @@ QmlPropertyCache::~QmlPropertyCache() (*iter)->release(); } +QmlPropertyCache::Data QmlPropertyCache::create(const QMetaObject *metaObject, + const QString &property) +{ + Q_ASSERT(metaObject); + + QmlPropertyCache::Data rv; + + int propCount = metaObject->propertyCount(); + for (int ii = propCount - 1; ii >= 0; --ii) { + QMetaProperty p = metaObject->property(ii); + QString propName = QLatin1String(p.name()); + if (propName == property) { + rv.load(p); + return rv; + } + } + + int methodCount = metaObject->methodCount(); + for (int ii = methodCount - 1; ii >= 0; --ii) { + QMetaMethod m = metaObject->method(ii); + QString methodName = QLatin1String(m.signature()); + + int parenIdx = methodName.indexOf(QLatin1Char('(')); + Q_ASSERT(parenIdx != -1); + methodName = methodName.left(parenIdx); + + if (methodName == property) { + rv.load(m); + return rv; + } + } + + return rv; +} + // ### Optimize - check engine for the parent meta object etc. QmlPropertyCache *QmlPropertyCache::create(QmlEngine *engine, const QMetaObject *metaObject) { diff --git a/src/declarative/qml/qmlpropertycache_p.h b/src/declarative/qml/qmlpropertycache_p.h index 149d2a0..82b8737 100644 --- a/src/declarative/qml/qmlpropertycache_p.h +++ b/src/declarative/qml/qmlpropertycache_p.h @@ -73,15 +73,16 @@ public: enum Flag { // Can apply to all properties, except IsFunction - IsConstant = 0x00000004, + IsConstant = 0x00000001, + IsWritable = 0x00000002, // These are mutually exclusive - IsFunction = 0x00000001, - IsQObjectDerived = 0x00000002, - IsEnumType = 0x00000008, - IsQmlList = 0x00000010, - IsQList = 0x00000020, - IsQmlBinding = 0x00000040 + IsFunction = 0x00000004, + IsQObjectDerived = 0x00000008, + IsEnumType = 0x00000010, + IsQmlList = 0x00000020, + IsQList = 0x00000040, + IsQmlBinding = 0x00000080 }; Q_DECLARE_FLAGS(Flags, Flag) @@ -105,6 +106,7 @@ public: #endif static QmlPropertyCache *create(QmlEngine *, const QMetaObject *); + static Data create(const QMetaObject *, const QString &); inline Data *property(const QScriptDeclarativeClass::Identifier &id) const; Data *property(const QString &) const; -- cgit v0.12 From 02a248c9c57714d4ad1ba775d9e60a7f286f10c6 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Thu, 1 Oct 2009 18:52:53 +1000 Subject: Prevent writes to the global object Also add toString() method to qobjects --- demos/declarative/samegame/content/samegame.js | 28 ++++---- src/declarative/qml/qml.pri | 6 +- src/declarative/qml/qmlengine.cpp | 16 +++-- src/declarative/qml/qmlengine_p.h | 2 + src/declarative/qml/qmlglobalscriptclass.cpp | 94 ++++++++++++++++++++++++++ src/declarative/qml/qmlglobalscriptclass_p.h | 81 ++++++++++++++++++++++ src/declarative/qml/qmlobjectscriptclass.cpp | 83 +++++++++++++---------- src/declarative/qml/qmlobjectscriptclass_p.h | 8 +++ 8 files changed, 260 insertions(+), 58 deletions(-) create mode 100644 src/declarative/qml/qmlglobalscriptclass.cpp create mode 100644 src/declarative/qml/qmlglobalscriptclass_p.h diff --git a/demos/declarative/samegame/content/samegame.js b/demos/declarative/samegame/content/samegame.js index 4a9179b..09057eb 100755 --- a/demos/declarative/samegame/content/samegame.js +++ b/demos/declarative/samegame/content/samegame.js @@ -24,7 +24,7 @@ function timeStr(msecs) { function initBoard() { - for(i = 0; i= maxX || xIdx < 0 || yIdx >= maxY || yIdx < 0) return; if(board[index(xIdx, yIdx)] == null) @@ -105,14 +105,14 @@ function floodFill(xIdx,yIdx,type) function shuffleDown() { //Fall down - for(xIdx=0; xIdx=0; yIdx--){ + for(var xIdx=0; xIdx=0; yIdx--){ if(board[index(xIdx,yIdx)] == null){ fallDist += 1; }else{ if(fallDist > 0){ - obj = board[index(xIdx,yIdx)]; + var obj = board[index(xIdx,yIdx)]; obj.targetY += fallDist * tileSize; board[index(xIdx,yIdx+fallDist)] = obj; board[index(xIdx,yIdx)] = null; @@ -143,8 +143,8 @@ function shuffleDown() function victoryCheck() { //awards bonuses for no tiles left - deservesBonus = true; - for(xIdx=maxX-1; xIdx>=0; xIdx--) + var deservesBonus = true; + for(var xIdx=maxX-1; xIdx>=0; xIdx--) if(board[index(xIdx, maxY - 1)] != null) deservesBonus = false; if(deservesBonus) @@ -166,7 +166,7 @@ function floodMoveCheck(xIdx, yIdx, type) return false; if(board[index(xIdx, yIdx)] == null) return false; - myType = board[index(xIdx, yIdx)].type; + var myType = board[index(xIdx, yIdx)].type; if(type == myType) return true; return floodMoveCheck(xIdx + 1, yIdx, myType) || @@ -174,7 +174,7 @@ function floodMoveCheck(xIdx, yIdx, type) } function createBlock(xIdx,yIdx){ - if(component==null) + if(component==null) component = createComponent(tileSrc); // Note that we don't wait for the component to become ready. This will @@ -182,7 +182,7 @@ function createBlock(xIdx,yIdx){ // not be ready immediately. There is a statusChanged signal on the // component you could use if you want to wait to load remote files. if(component.isReady){ - dynamicObject = component.createObject(); + var dynamicObject = component.createObject(); if(dynamicObject == null){ print("error creating block"); print(component.errorsString()); diff --git a/src/declarative/qml/qml.pri b/src/declarative/qml/qml.pri index 1a6dad3..eb761e3 100644 --- a/src/declarative/qml/qml.pri +++ b/src/declarative/qml/qml.pri @@ -38,7 +38,8 @@ SOURCES += qml/qmlparser.cpp \ qml/qmlpropertycache.cpp \ qml/qmlintegercache.cpp \ qml/qmlobjectscriptclass.cpp \ - qml/qmlcontextscriptclass.cpp + qml/qmlcontextscriptclass.cpp \ + qml/qmlglobalscriptclass.cpp HEADERS += qml/qmlparser_p.h \ qml/qmlinstruction_p.h \ @@ -94,7 +95,8 @@ HEADERS += qml/qmlparser_p.h \ qml/qmlpropertycache_p.h \ qml/qmlintegercache_p.h \ qml/qmlobjectscriptclass_p.h \ - qml/qmlcontextscriptclass_p.h + qml/qmlcontextscriptclass_p.h \ + qml/qmlglobalscriptclass_p.h # for qtscript debugger contains(QT_CONFIG, scripttools):QT += scripttools diff --git a/src/declarative/qml/qmlengine.cpp b/src/declarative/qml/qmlengine.cpp index d680fa1..4afd245 100644 --- a/src/declarative/qml/qmlengine.cpp +++ b/src/declarative/qml/qmlengine.cpp @@ -47,6 +47,7 @@ #include #include #include +#include #ifdef QT_SCRIPTTOOLS_LIB #include @@ -156,7 +157,7 @@ static QString userLocalDataPath(const QString& app) QmlEnginePrivate::QmlEnginePrivate(QmlEngine *e) : rootContext(0), currentExpression(0), - isDebugging(false), contextClass(0), objectClass(0), valueTypeClass(0), + isDebugging(false), contextClass(0), objectClass(0), valueTypeClass(0), globalClass(0), nodeListClass(0), namedNodeMapClass(0), sqlQueryClass(0), scriptEngine(this), rootComponent(0), networkAccessManager(0), typeManager(e), uniqueId(1) { @@ -183,6 +184,14 @@ QmlEnginePrivate::QmlEnginePrivate(QmlEngine *e) qtObject.setProperty(QLatin1String("lighter"), scriptEngine.newFunction(QmlEnginePrivate::lighter, 1)); qtObject.setProperty(QLatin1String("darker"), scriptEngine.newFunction(QmlEnginePrivate::darker, 1)); qtObject.setProperty(QLatin1String("tint"), scriptEngine.newFunction(QmlEnginePrivate::tint, 2)); + + scriptEngine.globalObject().setProperty(QLatin1String("createQmlObject"), + scriptEngine.newFunction(QmlEnginePrivate::createQmlObject, 1)); + scriptEngine.globalObject().setProperty(QLatin1String("createComponent"), + scriptEngine.newFunction(QmlEnginePrivate::createComponent, 1)); + + //scriptEngine.globalObject().setScriptClass(new QmlGlobalScriptClass(&scriptEngine)); + globalClass = new QmlGlobalScriptClass(&scriptEngine); } QmlEnginePrivate::~QmlEnginePrivate() @@ -250,11 +259,6 @@ void QmlEnginePrivate::init() } #endif - scriptEngine.globalObject().setProperty(QLatin1String("createQmlObject"), - scriptEngine.newFunction(QmlEnginePrivate::createQmlObject, 1)); - scriptEngine.globalObject().setProperty(QLatin1String("createComponent"), - scriptEngine.newFunction(QmlEnginePrivate::createComponent, 1)); - if (QCoreApplication::instance()->thread() == q->thread() && QmlEngineDebugServer::isDebuggingEnabled()) { qmlEngineDebugServer(); diff --git a/src/declarative/qml/qmlengine_p.h b/src/declarative/qml/qmlengine_p.h index 764cc6c..231388d 100644 --- a/src/declarative/qml/qmlengine_p.h +++ b/src/declarative/qml/qmlengine_p.h @@ -151,6 +151,8 @@ public: QmlObjectScriptClass *objectClass; QmlValueTypeScriptClass *valueTypeClass; QmlTypeNameScriptClass *typeNameClass; + // Global script class + QScriptClass *globalClass; // Used by DOM Core 3 API QScriptClass *nodeListClass; QScriptClass *namedNodeMapClass; diff --git a/src/declarative/qml/qmlglobalscriptclass.cpp b/src/declarative/qml/qmlglobalscriptclass.cpp new file mode 100644 index 0000000..0ade5ee --- /dev/null +++ b/src/declarative/qml/qmlglobalscriptclass.cpp @@ -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$ +** +****************************************************************************/ + +#include "qmlglobalscriptclass_p.h" +#include +#include +#include + +QT_BEGIN_NAMESPACE + +/* + Used to prevent any writes to the global object. +*/ +QmlGlobalScriptClass::QmlGlobalScriptClass(QScriptEngine *engine) +: QScriptClass(engine) +{ + QScriptValue v = engine->newObject(); + globalObject = engine->globalObject(); + + QScriptValueIterator iter(globalObject); + while (iter.hasNext()) { + iter.next(); + v.setProperty(iter.scriptName(), iter.value()); + } + + v.setScriptClass(this); + engine->setGlobalObject(v); +} + +QScriptClass::QueryFlags +QmlGlobalScriptClass::queryProperty(const QScriptValue &object, + const QScriptString &name, + QueryFlags flags, uint *id) +{ + return HandlesReadAccess | HandlesWriteAccess; +} + +QScriptValue +QmlGlobalScriptClass::property(const QScriptValue &object, + const QScriptString &name, + uint id) +{ + return engine()->undefinedValue(); +} + +void QmlGlobalScriptClass::setProperty(QScriptValue &object, + const QScriptString &name, + uint id, const QScriptValue &value) +{ + QString error = QLatin1String("Invalid write to global property \"") + + name.toString() + QLatin1String("\""); + engine()->currentContext()->throwError(error); +} + +QT_END_NAMESPACE + diff --git a/src/declarative/qml/qmlglobalscriptclass_p.h b/src/declarative/qml/qmlglobalscriptclass_p.h new file mode 100644 index 0000000..1b58f1e --- /dev/null +++ b/src/declarative/qml/qmlglobalscriptclass_p.h @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** 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 QMLGLOBALSCRIPTCLASS_P_H +#define QMLGLOBALSCRIPTCLASS_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include + +QT_BEGIN_NAMESPACE + +class QmlGlobalScriptClass : public QScriptClass +{ +public: + QmlGlobalScriptClass(QScriptEngine *); + + 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); + +private: + QScriptValue globalObject; +}; + +QT_END_NAMESPACE + +#endif // QMLGLOBALSCRIPTCLASS_P_H diff --git a/src/declarative/qml/qmlobjectscriptclass.cpp b/src/declarative/qml/qmlobjectscriptclass.cpp index 28a808a..bb5f191 100644 --- a/src/declarative/qml/qmlobjectscriptclass.cpp +++ b/src/declarative/qml/qmlobjectscriptclass.cpp @@ -51,40 +51,6 @@ struct ObjectData { QGuard object; }; -static QScriptValue QmlObjectToString(QScriptContext *context, QScriptEngine *engine) -{ - QObject* obj = context->thisObject().data().toQObject(); - QString ret = QLatin1String("Qml Object, "); - if(obj){ - //###Should this be designer or developer details? Dev for now. - //TODO: Can we print the id too? - ret += QLatin1String("\""); - ret += obj->objectName(); - ret += QLatin1String("\" "); - ret += QLatin1String(obj->metaObject()->className()); - ret += QLatin1String("(0x"); - ret += QString::number((quintptr)obj,16); - ret += QLatin1String(")"); - }else{ - ret += QLatin1String("null"); - } - return engine->newVariant(ret); -} - -static QScriptValue QmlObjectDestroy(QScriptContext *context, QScriptEngine *engine) -{ - QObject* obj = context->thisObject().toQObject(); - if(obj){ - int delay = 0; - if(context->argumentCount() > 0) - delay = context->argument(0).toInt32(); - obj->deleteLater(); - //### Should this be delayed as well? - context->thisObject().setData(QScriptValue(engine, 0)); - } - return engine->nullValue(); -} - /* The QmlObjectScriptClass handles property access for QObjects via QtScript. It is also used to provide a more useful API in @@ -97,8 +63,10 @@ QmlObjectScriptClass::QmlObjectScriptClass(QmlEngine *bindEngine) engine = bindEngine; QScriptEngine *scriptEngine = QmlEnginePrivate::getScriptEngine(bindEngine); - m_destroy = scriptEngine->newFunction(QmlObjectDestroy); + m_destroy = scriptEngine->newFunction(destroy); m_destroyId = createPersistentIdentifier(QLatin1String("destroy")); + m_toString = scriptEngine->newFunction(tostring); + m_toStringId = createPersistentIdentifier(QLatin1String("toString")); } QmlObjectScriptClass::~QmlObjectScriptClass() @@ -132,7 +100,8 @@ QmlObjectScriptClass::queryProperty(QObject *obj, const Identifier &name, Q_UNUSED(flags); lastData = 0; - if (name == m_destroyId->identifier) + if (name == m_destroyId->identifier || + name == m_toStringId->identifier) return QScriptClass::HandlesReadAccess; if (!obj) @@ -173,6 +142,8 @@ QScriptValue QmlObjectScriptClass::property(QObject *obj, const Identifier &name { if (name == m_destroyId->identifier) return m_destroy; + else if (name == m_toStringId->identifier) + return m_toString; Q_ASSERT(lastData); Q_ASSERT(obj); @@ -240,4 +211,44 @@ void QmlObjectScriptClass::destroyed(const Object &object) delete data; } +QScriptValue QmlObjectScriptClass::tostring(QScriptContext *context, QScriptEngine *engine) +{ + QObject* obj = context->thisObject().toQObject(); + + QString ret; + if(obj){ + QString objectName = obj->objectName(); + + ret += QLatin1String(obj->metaObject()->className()); + ret += QLatin1String("(0x"); + ret += QString::number((quintptr)obj,16); + + if (!objectName.isEmpty()) { + ret += QLatin1String(", \""); + ret += objectName; + ret += QLatin1String("\""); + } + + ret += QLatin1String(")"); + }else{ + ret += QLatin1String("null"); + } + return QScriptValue(ret); +} + +QScriptValue QmlObjectScriptClass::destroy(QScriptContext *context, QScriptEngine *engine) +{ + QObject* obj = context->thisObject().toQObject(); + if(obj){ + int delay = 0; + if(context->argumentCount() > 0) + delay = context->argument(0).toInt32(); + obj->deleteLater(); + //### Should this be delayed as well? + context->thisObject().setData(QScriptValue(engine, 0)); + } + return engine->nullValue(); +} + + QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlobjectscriptclass_p.h b/src/declarative/qml/qmlobjectscriptclass_p.h index f126192..cd67fac 100644 --- a/src/declarative/qml/qmlobjectscriptclass_p.h +++ b/src/declarative/qml/qmlobjectscriptclass_p.h @@ -60,6 +60,8 @@ QT_BEGIN_NAMESPACE class QmlEngine; +class QScriptContext; +class QScriptEngine; class QmlObjectScriptClass : public QScriptDeclarativeClass { public: @@ -90,7 +92,13 @@ private: struct Dummy {}; PersistentIdentifier *m_destroyId; + PersistentIdentifier *m_toStringId; QScriptValue m_destroy; + QScriptValue m_toString; + + static QScriptValue tostring(QScriptContext *context, QScriptEngine *engine); + static QScriptValue destroy(QScriptContext *context, QScriptEngine *engine); + QmlEngine *engine; }; -- cgit v0.12 From 15498e4c5990e934e5f2a3ee27f71c020e277e56 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Fri, 2 Oct 2009 10:04:35 +1000 Subject: Only start timer if it isn't already active --- src/corelib/animation/qabstractanimation.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/corelib/animation/qabstractanimation.cpp b/src/corelib/animation/qabstractanimation.cpp index 6bbd801..4c68ee7 100644 --- a/src/corelib/animation/qabstractanimation.cpp +++ b/src/corelib/animation/qabstractanimation.cpp @@ -231,7 +231,8 @@ void QUnifiedTimer::registerAnimation(QAbstractAnimation *animation) Q_ASSERT(!QAbstractAnimationPrivate::get(animation)->hasRegisteredTimer); QAbstractAnimationPrivate::get(animation)->hasRegisteredTimer = true; animationsToStart << animation; - startStopAnimationTimer.start(STARTSTOP_TIMER_DELAY, this); + if (!startStopAnimationTimer.isActive()) + startStopAnimationTimer.start(STARTSTOP_TIMER_DELAY, this); } void QUnifiedTimer::unregisterAnimation(QAbstractAnimation *animation) @@ -250,7 +251,8 @@ void QUnifiedTimer::unregisterAnimation(QAbstractAnimation *animation) } else { animationsToStart.removeOne(animation); } - QAbstractAnimationPrivate::get(animation)->hasRegisteredTimer = false; + if (!startStopAnimationTimer.isActive()) + startStopAnimationTimer.start(STARTSTOP_TIMER_DELAY, this); } void QAbstractAnimationPrivate::setState(QAbstractAnimation::State newState) -- cgit v0.12 From b3605d7f45c1cdb61bbd2a572e58bd29aaea6956 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Fri, 2 Oct 2009 10:49:14 +1000 Subject: API changes --- src/script/bridge/qscriptdeclarativeclass.cpp | 107 ++++++++++++++++++-------- src/script/bridge/qscriptdeclarativeclass_p.h | 33 ++++---- 2 files changed, 87 insertions(+), 53 deletions(-) diff --git a/src/script/bridge/qscriptdeclarativeclass.cpp b/src/script/bridge/qscriptdeclarativeclass.cpp index c017e13..371a3c3 100644 --- a/src/script/bridge/qscriptdeclarativeclass.cpp +++ b/src/script/bridge/qscriptdeclarativeclass.cpp @@ -51,39 +51,38 @@ QT_BEGIN_NAMESPACE -class QScriptDeclarativeClassPrivate +QScriptDeclarativeClass::PersistentIdentifier::PersistentIdentifier() { -public: - QScriptDeclarativeClassPrivate() {} - - QScriptEngine *engine; - QScriptDeclarativeClass *q_ptr; -}; + new (&d) JSC::Identifier(); +} -void QScriptDeclarativeClass::destroyPersistentIdentifier(void **d) +QScriptDeclarativeClass::PersistentIdentifier::~PersistentIdentifier() { - ((JSC::Identifier *)d)->JSC::Identifier::~Identifier(); + ((JSC::Identifier &)d).JSC::Identifier::~Identifier(); } -void QScriptDeclarativeClass::initPersistentIdentifier(void **d, Identifier *i, const QString &str) +QScriptDeclarativeClass::PersistentIdentifier::PersistentIdentifier(const PersistentIdentifier &other) { - QScriptEnginePrivate *p = - static_cast(QObjectPrivate::get(d_ptr->engine)); - JSC::ExecState* exec = p->currentFrame; + identifier = other.identifier; + new (&d) JSC::Identifier((JSC::Identifier &)(other.d)); +} - new (d) JSC::Identifier(exec, (UChar *)str.constData(), str.size()); - *i = (Identifier)((JSC::Identifier *)d)->ustring().rep(); +QScriptDeclarativeClass::PersistentIdentifier & +QScriptDeclarativeClass::PersistentIdentifier::operator=(const PersistentIdentifier &other) +{ + identifier = other.identifier; + ((JSC::Identifier &)d) = (JSC::Identifier &)(other.d); + return *this; } -void QScriptDeclarativeClass::initPersistentIdentifier(void **d, Identifier *i, const Identifier &id) +class QScriptDeclarativeClassPrivate { - QScriptEnginePrivate *p = - static_cast(QObjectPrivate::get(d_ptr->engine)); - JSC::ExecState* exec = p->currentFrame; +public: + QScriptDeclarativeClassPrivate() {} - new (d) JSC::Identifier(exec, (JSC::UString::Rep *)id); - *i = id; -} + QScriptEngine *engine; + QScriptDeclarativeClass *q_ptr; +}; QScriptDeclarativeClass::QScriptDeclarativeClass(QScriptEngine *engine) : d_ptr(new QScriptDeclarativeClassPrivate) @@ -132,6 +131,51 @@ QScriptDeclarativeClass::Object QScriptDeclarativeClass::object(const QScriptVal return static_cast(delegate)->object(); } +QScriptValue QScriptDeclarativeClass::function(const QScriptValue &v, const Identifier &name) +{ + QScriptValuePrivate *d = QScriptValuePrivate::get(v); + + if (!d->isObject()) + return QScriptValue(); + + JSC::ExecState *exec = d->engine->currentFrame; + JSC::JSObject *object = d->jscValue.getObject(); + JSC::PropertySlot slot(const_cast(object)); + JSC::JSValue result; + + JSC::Identifier id(exec, (JSC::UString::Rep *)name); + + if (const_cast(object)->getOwnPropertySlot(exec, id, slot)) { + result = slot.getValue(exec, id); + if (QScript::isFunction(result)) + return d->engine->scriptValueFromJSCValue(result); + } + + return QScriptValue(); +} + +QScriptValue QScriptDeclarativeClass::property(const QScriptValue &v, const Identifier &name) +{ + QScriptValuePrivate *d = QScriptValuePrivate::get(v); + + if (!d->isObject()) + return QScriptValue(); + + JSC::ExecState *exec = d->engine->currentFrame; + JSC::JSObject *object = d->jscValue.getObject(); + JSC::PropertySlot slot(const_cast(object)); + JSC::JSValue result; + + JSC::Identifier id(exec, (JSC::UString::Rep *)name); + + if (const_cast(object)->getOwnPropertySlot(exec, id, slot)) { + result = slot.getValue(exec, id); + return d->engine->scriptValueFromJSCValue(result); + } + + return QScriptValue(); +} + QScriptDeclarativeClass::~QScriptDeclarativeClass() { } @@ -141,34 +185,31 @@ QScriptEngine *QScriptDeclarativeClass::engine() const return d_ptr->engine; } -/* -QScriptDeclarativeClass::PersistentIdentifier * +QScriptDeclarativeClass::PersistentIdentifier QScriptDeclarativeClass::createPersistentIdentifier(const QString &str) { QScriptEnginePrivate *p = static_cast(QObjectPrivate::get(d_ptr->engine)); JSC::ExecState* exec = p->currentFrame; - PersistentIdentifierPrivate *rv = new PersistentIdentifierPrivate; - rv->identifierValue = JSC::Identifier(exec, (UChar *)str.constData(), str.size()); - rv->identifier = (void *)rv->identifierValue.ustring().rep(); + PersistentIdentifier rv(true); + new (&rv.d) JSC::Identifier(exec, (UChar *)str.constData(), str.size()); + rv.identifier = (void *)((JSC::Identifier &)rv.d).ustring().rep(); return rv; } -QScriptDeclarativeClass::PersistentIdentifier * +QScriptDeclarativeClass::PersistentIdentifier QScriptDeclarativeClass::createPersistentIdentifier(const Identifier &id) { QScriptEnginePrivate *p = static_cast(QObjectPrivate::get(d_ptr->engine)); JSC::ExecState* exec = p->currentFrame; - PersistentIdentifierPrivate *rv = new PersistentIdentifierPrivate; - rv->identifierValue = JSC::Identifier(exec, (JSC::UString::Rep *)id); - rv->identifier = (void *)rv->identifierValue.ustring().rep(); + PersistentIdentifier rv(true); + new (&rv.d) JSC::Identifier(exec, (JSC::UString::Rep *)id); + rv.identifier = (void *)((JSC::Identifier &)rv.d).ustring().rep(); return rv; } -*/ - QString QScriptDeclarativeClass::toString(const Identifier &identifier) { diff --git a/src/script/bridge/qscriptdeclarativeclass_p.h b/src/script/bridge/qscriptdeclarativeclass_p.h index a00a286..16f6942 100644 --- a/src/script/bridge/qscriptdeclarativeclass_p.h +++ b/src/script/bridge/qscriptdeclarativeclass_p.h @@ -71,15 +71,22 @@ public: static QScriptDeclarativeClass *scriptClass(const QScriptValue &); static Object object(const QScriptValue &); - template - class PersistentIdentifier : public T { + static QScriptValue function(const QScriptValue &, const Identifier &); + static QScriptValue property(const QScriptValue &, const Identifier &); + + class Q_SCRIPT_EXPORT PersistentIdentifier + { public: Identifier identifier; - ~PersistentIdentifier() { QScriptDeclarativeClass::destroyPersistentIdentifier(&d); } + PersistentIdentifier(); + ~PersistentIdentifier(); + PersistentIdentifier(const PersistentIdentifier &other); + PersistentIdentifier &operator=(const PersistentIdentifier &other); + private: friend class QScriptDeclarativeClass; - PersistentIdentifier() : identifier(0), d(0) {} + PersistentIdentifier(bool) : identifier(0), d(0) {} void *d; }; @@ -88,18 +95,8 @@ public: QScriptEngine *engine() const; - template - PersistentIdentifier *createPersistentIdentifier(const QString &str) { - PersistentIdentifier *rv = new PersistentIdentifier; - initPersistentIdentifier(&rv->d, &rv->identifier, str); - return rv; - } - template - PersistentIdentifier *createPersistentIdentifier(const Identifier &id) { - PersistentIdentifier *rv = new PersistentIdentifier; - initPersistentIdentifier(&rv->d, &rv->identifier, id); - return rv; - } + PersistentIdentifier createPersistentIdentifier(const QString &); + PersistentIdentifier createPersistentIdentifier(const Identifier &); QString toString(const Identifier &); @@ -116,10 +113,6 @@ public: virtual QVariant toVariant(const Object &, bool *ok = 0); virtual void destroyed(const Object &); - static void destroyPersistentIdentifier(void **); - void initPersistentIdentifier(void **, Identifier *, const QString &); - void initPersistentIdentifier(void **, Identifier *, const Identifier &); - protected: QScopedPointer d_ptr; }; -- cgit v0.12 From 3490b478ed02859f0355438efba900cd853e9c13 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Fri, 2 Oct 2009 17:09:09 +1000 Subject: Reenable types/enums and move scripts into an isolated scope --- demos/declarative/samegame/content/samegame.js | 5 + demos/declarative/samegame/samegame.qml | 4 +- src/declarative/qml/qml.pri | 10 +- src/declarative/qml/qmlcompileddata.cpp | 4 + src/declarative/qml/qmlcompiler.cpp | 1 + src/declarative/qml/qmlcompiler_p.h | 2 + src/declarative/qml/qmlcomponent.cpp | 3 +- src/declarative/qml/qmlcontext.cpp | 5 +- src/declarative/qml/qmlcontext_p.h | 6 +- src/declarative/qml/qmlcontextscriptclass.cpp | 43 ++- src/declarative/qml/qmlcontextscriptclass_p.h | 3 + src/declarative/qml/qmlengine.cpp | 377 +++++++----------------- src/declarative/qml/qmlengine_p.h | 75 +---- src/declarative/qml/qmlintegercache.cpp | 4 +- src/declarative/qml/qmlintegercache_p.h | 9 +- src/declarative/qml/qmlobjectscriptclass.cpp | 22 +- src/declarative/qml/qmlobjectscriptclass_p.h | 6 +- src/declarative/qml/qmlpropertycache.cpp | 12 +- src/declarative/qml/qmlpropertycache_p.h | 10 +- src/declarative/qml/qmltypenamecache.cpp | 93 ++++++ src/declarative/qml/qmltypenamecache_p.h | 113 +++++++ src/declarative/qml/qmltypenamescriptclass.cpp | 159 ++++++++++ src/declarative/qml/qmltypenamescriptclass_p.h | 90 ++++++ src/declarative/qml/qmlvaluetypescriptclass.cpp | 150 ++++++++++ src/declarative/qml/qmlvaluetypescriptclass_p.h | 89 ++++++ src/declarative/util/qmlscript.cpp | 10 +- 26 files changed, 922 insertions(+), 383 deletions(-) create mode 100644 src/declarative/qml/qmltypenamecache.cpp create mode 100644 src/declarative/qml/qmltypenamecache_p.h create mode 100644 src/declarative/qml/qmltypenamescriptclass.cpp create mode 100644 src/declarative/qml/qmltypenamescriptclass_p.h create mode 100644 src/declarative/qml/qmlvaluetypescriptclass.cpp create mode 100644 src/declarative/qml/qmlvaluetypescriptclass_p.h diff --git a/demos/declarative/samegame/content/samegame.js b/demos/declarative/samegame/content/samegame.js index 09057eb..7deafde 100755 --- a/demos/declarative/samegame/content/samegame.js +++ b/demos/declarative/samegame/content/samegame.js @@ -22,6 +22,11 @@ function timeStr(msecs) { return ret; } +function getTileSize() +{ + return tileSize; +} + function initBoard() { for(var i = 0; irelease(); + if (importCache) + importCache->release(); + qDeleteAll(programs); } diff --git a/src/declarative/qml/qmlcompiler.cpp b/src/declarative/qml/qmlcompiler.cpp index 5cb2158..4b5c5bf 100644 --- a/src/declarative/qml/qmlcompiler.cpp +++ b/src/declarative/qml/qmlcompiler.cpp @@ -644,6 +644,7 @@ void QmlCompiler::compileTree(Object *tree) output->bytecode << def; output->imports = unit->imports; + output->importCache = output->imports.cache(engine); Q_ASSERT(tree->metatype); static_cast(output->root) = *tree->metaObject(); diff --git a/src/declarative/qml/qmlcompiler_p.h b/src/declarative/qml/qmlcompiler_p.h index 1cb66c7..fd361fd 100644 --- a/src/declarative/qml/qmlcompiler_p.h +++ b/src/declarative/qml/qmlcompiler_p.h @@ -64,6 +64,7 @@ #include #include #include +#include QT_BEGIN_NAMESPACE @@ -81,6 +82,7 @@ public: QByteArray name; QUrl url; QmlEnginePrivate::Imports imports; + QmlTypeNameCache *importCache; struct TypeReference { diff --git a/src/declarative/qml/qmlcomponent.cpp b/src/declarative/qml/qmlcomponent.cpp index fedc2da..5b1cbeb 100644 --- a/src/declarative/qml/qmlcomponent.cpp +++ b/src/declarative/qml/qmlcomponent.cpp @@ -517,7 +517,8 @@ QmlComponentPrivate::beginCreate(QmlContext *context, const QBitField &bindings) static_cast(QObjectPrivate::get(context)); QmlContext *ctxt = new QmlContext(context, 0, true); static_cast(ctxt->d_func())->url = cc->url; - static_cast(ctxt->d_func())->imports = cc->imports; + static_cast(ctxt->d_func())->imports = cc->importCache; + cc->importCache->addref(); QmlVME vme; QObject *rv = vme.run(ctxt, cc, start, count, bindings); diff --git a/src/declarative/qml/qmlcontext.cpp b/src/declarative/qml/qmlcontext.cpp index 5e74d1a..968597c 100644 --- a/src/declarative/qml/qmlcontext.cpp +++ b/src/declarative/qml/qmlcontext.cpp @@ -56,7 +56,7 @@ QT_BEGIN_NAMESPACE QmlContextPrivate::QmlContextPrivate() : parent(0), engine(0), isInternal(false), propertyNames(0), notifyIndex(-1), - highPriorityCount(0), expressions(0), idValues(0), idValueCount(0) + highPriorityCount(0), imports(0), expressions(0), idValues(0), idValueCount(0) { } @@ -307,6 +307,9 @@ QmlContext::~QmlContext() if (d->propertyNames) d->propertyNames->release(); + + if (d->imports) + d->imports->release(); } void QmlContextPrivate::invalidateEngines() diff --git a/src/declarative/qml/qmlcontext_p.h b/src/declarative/qml/qmlcontext_p.h index 64faa6d..8fd2e92 100644 --- a/src/declarative/qml/qmlcontext_p.h +++ b/src/declarative/qml/qmlcontext_p.h @@ -62,6 +62,7 @@ #include #include #include +#include QT_BEGIN_NAMESPACE @@ -93,8 +94,11 @@ public: QScriptValueList scopeChain; + QList scripts; + QUrl url; - QmlEnginePrivate::Imports imports; + + QmlTypeNameCache *imports; void init(); diff --git a/src/declarative/qml/qmlcontextscriptclass.cpp b/src/declarative/qml/qmlcontextscriptclass.cpp index baea60a..d8ae4f0 100644 --- a/src/declarative/qml/qmlcontextscriptclass.cpp +++ b/src/declarative/qml/qmlcontextscriptclass.cpp @@ -42,6 +42,7 @@ #include "qmlcontextscriptclass_p.h" #include #include +#include QT_BEGIN_NAMESPACE @@ -56,7 +57,7 @@ struct ContextData { */ QmlContextScriptClass::QmlContextScriptClass(QmlEngine *bindEngine) : QScriptDeclarativeClass(QmlEnginePrivate::getScriptEngine(bindEngine)), engine(bindEngine), - lastPropertyIndex(-1), lastDefaultObject(-1) + lastData(0), lastPropertyIndex(-1), lastDefaultObject(-1) { } @@ -76,21 +77,32 @@ QmlContextScriptClass::queryProperty(const Object &object, const Identifier &nam QScriptClass::QueryFlags flags) { Q_UNUSED(flags); + + lastPropertyIndex = -1; + lastDefaultObject = -1; + lastData = 0; + QmlContext *bindContext = ((ContextData *)object)->context.data(); if (!bindContext) return 0; QmlEnginePrivate *ep = QmlEnginePrivate::get(engine); QmlContextPrivate *cp = QmlContextPrivate::get(bindContext); - - lastPropertyIndex = -1; - lastDefaultObject = -1; lastPropertyIndex = cp->propertyNames?cp->propertyNames->value(name):-1; if (lastPropertyIndex != -1) return QScriptClass::HandlesReadAccess; // ### Check for attached properties + if (ep->currentExpression && cp->imports && bindContext == ep->currentExpression->context()) { + QmlTypeNameCache::Data *data = cp->imports->data(name); + + if (data) { + lastData = data; + return QScriptClass::HandlesReadAccess; + } + } + #if 0 QmlType *type = 0; ImportedNamespace *ns = 0; if (currentExpression && bindContext == currentExpression->context() && @@ -117,6 +129,11 @@ QmlContextScriptClass::queryProperty(const Object &object, const Identifier &nam } } + for (int ii = 0; ii < cp->scripts.count(); ++ii) { + lastFunction = QScriptDeclarativeClass::function(cp->scripts.at(ii), name); + if (lastFunction.isValid()) + return QScriptClass::HandlesReadAccess; + } return 0; } @@ -145,7 +162,14 @@ QScriptValue QmlContextScriptClass::property(const Object &object, const Identif } #endif - if (lastPropertyIndex != -1) { + if (lastData) { + + if (lastData->type) + return ep->typeNameClass->newObject(cp->defaultObjects.at(0), lastData->type); + else + return ep->typeNameClass->newObject(cp->defaultObjects.at(0), lastData->typeNamespace); + + } else if (lastPropertyIndex != -1) { QScriptValue rv; if (lastPropertyIndex < cp->idValueCount) { @@ -161,15 +185,18 @@ QScriptValue QmlContextScriptClass::property(const Object &object, const Identif } ep->capturedProperties << - QmlEnginePrivate::CapturedProperty(bindContext, -1, - lastPropertyIndex + cp->notifyIndex); + QmlEnginePrivate::CapturedProperty(bindContext, -1, lastPropertyIndex + cp->notifyIndex); return rv; - } else { + } else if(lastDefaultObject != -1) { // Default object property return ep->objectClass->property(cp->defaultObjects.at(lastDefaultObject), name); + } else { + + return lastFunction; + } } diff --git a/src/declarative/qml/qmlcontextscriptclass_p.h b/src/declarative/qml/qmlcontextscriptclass_p.h index 9ef090d..a00e567 100644 --- a/src/declarative/qml/qmlcontextscriptclass_p.h +++ b/src/declarative/qml/qmlcontextscriptclass_p.h @@ -55,6 +55,7 @@ #include #include +#include QT_BEGIN_NAMESPACE @@ -77,8 +78,10 @@ protected: private: QmlEngine *engine; + QmlTypeNameCache::Data *lastData; int lastPropertyIndex; int lastDefaultObject; + QScriptValue lastFunction; uint m_id; }; diff --git a/src/declarative/qml/qmlengine.cpp b/src/declarative/qml/qmlengine.cpp index 4afd245..e67e42f 100644 --- a/src/declarative/qml/qmlengine.cpp +++ b/src/declarative/qml/qmlengine.cpp @@ -85,6 +85,7 @@ #include #include #include +#include #ifdef Q_OS_WIN // for %APPDATA% #include "qt_windows.h" @@ -274,114 +275,6 @@ QmlEnginePrivate::CapturedProperty::CapturedProperty(const QmlMetaProperty &p) { } -struct QmlTypeNameBridge -{ - QObject *object; - QmlType *type; - QmlEnginePrivate::ImportedNamespace *ns; -}; -Q_DECLARE_METATYPE(QmlTypeNameBridge); - -struct QmlValueTypeReference { - QmlValueType *type; - QGuard object; - int property; -}; -Q_DECLARE_METATYPE(QmlValueTypeReference); - -void QmlEnginePrivate::setPropertyObject(const QScriptValue &value, uint id) -{ - Q_ASSERT(id == resolveData.safetyCheckId); - Q_Q(QmlEngine); - - resolveData.property.write(QmlScriptClass::toVariant(q, value)); -} - -QScriptClass::QueryFlags -QmlEnginePrivate::queryObject(const QString &propName, - uint *id, QObject *obj) -{ - resolveData.safetyCheckId++; - *id = resolveData.safetyCheckId; - resolveData.clear(); - - QScriptClass::QueryFlags rv = 0; - - QmlContext *ctxt = QmlEngine::contextForObject(obj); - if (!ctxt) - ctxt = rootContext; - QmlMetaProperty prop(obj, propName, ctxt); - - if (prop.type() == QmlMetaProperty::Invalid) { - QPair 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) { - resolveData.object = obj; - resolveData.isFunction = true; - rv |= QScriptClass::HandlesReadAccess; - } - } else { - resolveData.object = obj; - resolveData.property = prop; - - rv |= QScriptClass::HandlesReadAccess; - if (prop.isWritable()) - rv |= QScriptClass::HandlesWriteAccess; - } - - return rv; -} - -QScriptValue QmlEnginePrivate::propertyObject(const QString &propName, - QObject *obj, uint id) -{ - Q_ASSERT(id == resolveData.safetyCheckId); - Q_ASSERT(resolveData.object); - - if (resolveData.isFunction) { - // ### Optimize - QScriptValue sobj = scriptEngine.newQObject(obj); - QScriptValue func = sobj.property(propName); - return func; - } else { - const QmlMetaProperty &prop = resolveData.property; - - if (prop.needsChangedNotifier()) - capturedProperties << CapturedProperty(prop); - - int propType = prop.propertyType(); - if (propType < QVariant::UserType && valueTypes[propType]) { - QmlValueTypeReference ref; - ref.type = valueTypes[propType]; - ref.object = obj; - ref.property = prop.coreIndex(); - return scriptEngine.newObject(valueTypeClass, scriptEngine.newVariant(QVariant::fromValue(ref))); - } - - QVariant var = prop.read(); - QObject *varobj = (propType < QVariant::UserType)?0:QmlMetaType::toQObject(var); - if (!varobj) - varobj = qvariant_cast(var); - if (varobj) { - return objectClass->newQObject(varobj); - } else { - return qScriptValueFromValue(&scriptEngine, var); - } - } - - return QScriptValue(); -} - /*! \class QmlEngine \brief The QmlEngine class provides an environment for instantiating QML components. @@ -1039,6 +932,35 @@ QScriptValue QmlEnginePrivate::tint(QScriptContext *ctxt, QScriptEngine *engine) return qScriptValueFromValue(engine, qVariantFromValue(finalColor)); } + +QScriptValue QmlEnginePrivate::scriptValueFromVariant(const QVariant &val) +{ + if (QmlMetaType::isObject(val.userType())) { + QObject *rv = *(QObject **)val.constData(); + return objectClass->newQObject(rv); + } else { + return qScriptValueFromValue(&scriptEngine, val); + } +} + +QVariant QmlEnginePrivate::scriptValueToVariant(const QScriptValue &val) +{ + QScriptDeclarativeClass *dc = QScriptDeclarativeClass::scriptClass(val); + if (dc == objectClass) + return QVariant::fromValue(objectClass->toQObject(val)); + else if (dc == contextClass) + return QVariant(); + + QScriptClass *sc = val.scriptClass(); + if (!sc) { + return val.toVariant(); + } else if (sc == valueTypeClass) { + return valueTypeClass->toVariant(val); + } else { + return QVariant(); + } +} + QmlScriptClass::QmlScriptClass(QmlEngine *bindengine) : QScriptClass(QmlEnginePrivate::getScriptEngine(bindengine)), engine(bindengine) @@ -1060,175 +982,13 @@ QVariant QmlScriptClass::toVariant(QmlEngine *engine, const QScriptValue &val) if (!sc) { return val.toVariant(); } else if (sc == ep->valueTypeClass) { - QmlValueTypeReference ref = - qvariant_cast(val.data().toVariant()); - - if (!ref.object) - return QVariant(); - - QMetaProperty p = ref.object->metaObject()->property(ref.property); - return p.read(ref.object); + return ep->valueTypeClass->toVariant(val); } return QVariant(); } ///////////////////////////////////////////////////////////// -QmlTypeNameScriptClass::QmlTypeNameScriptClass(QmlEngine *engine) -: QmlScriptClass(engine), object(0), type(0) -{ -} - -QmlTypeNameScriptClass::~QmlTypeNameScriptClass() -{ -} - -QmlTypeNameScriptClass::QueryFlags -QmlTypeNameScriptClass::queryProperty(const QScriptValue &scriptObject, - const QScriptString &name, - QueryFlags flags, uint *id) -{ - Q_UNUSED(flags); - - QmlTypeNameBridge bridge = - qvariant_cast(scriptObject.data().toVariant()); - - object = 0; - type = 0; - QmlEnginePrivate *ep = QmlEnginePrivate::get(engine); - - if (bridge.ns) { - QmlType *type = 0; - ep->resolveTypeInNamespace(bridge.ns, name.toString().toUtf8(), - &type, 0, 0, 0); - if (type) { - object = bridge.object; - this->type = type; - return HandlesReadAccess; - } else { - return 0; - } - - } else { - Q_ASSERT(bridge.type); - QString strName = name.toString(); - if (strName.at(0).isUpper()) { - // Must be an enum - // ### Optimize - const char *enumName = strName.toUtf8().constData(); - const QMetaObject *metaObject = bridge.type->baseMetaObject(); - for (int ii = metaObject->enumeratorCount() - 1; ii >= 0; --ii) { - QMetaEnum e = metaObject->enumerator(ii); - int value = e.keyToValue(enumName); - if (value != -1) { - enumValue = value; - return HandlesReadAccess; - } - } - return 0; - } else { - // Must be an attached property - this->object = qmlAttachedPropertiesObjectById(bridge.type->index(), bridge.object); - if (!this->object) - return 0; - return ep->queryObject(strName, id, this->object); - } - } -} - -QScriptValue QmlTypeNameScriptClass::property(const QScriptValue &, - const QScriptString &propName, - uint id) -{ - QmlEnginePrivate *ep = QmlEnginePrivate::get(engine); - if (type) { - QmlTypeNameBridge tnb = { object, type, 0 }; - return ep->scriptEngine.newObject(ep->typeNameClass, ep->scriptEngine.newVariant(qVariantFromValue(tnb))); - } else if (object) { - return ep->propertyObject(propName, object, id); - } else { - return QScriptValue(enumValue); - } -} - -///////////////////////////////////////////////////////////// -QmlValueTypeScriptClass::QmlValueTypeScriptClass(QmlEngine *bindEngine) -: QmlScriptClass(bindEngine) -{ -} - -QmlValueTypeScriptClass::~QmlValueTypeScriptClass() -{ -} - -QmlValueTypeScriptClass::QueryFlags -QmlValueTypeScriptClass::queryProperty(const QScriptValue &object, - const QScriptString &name, - QueryFlags flags, uint *id) -{ - Q_UNUSED(flags); - QmlValueTypeReference ref = - qvariant_cast(object.data().toVariant()); - - if (!ref.object) - return 0; - - QByteArray propName = name.toString().toUtf8(); - - int idx = ref.type->metaObject()->indexOfProperty(propName.constData()); - if (idx == -1) - return 0; - *id = idx; - - QMetaProperty prop = ref.object->metaObject()->property(idx); - - QmlValueTypeScriptClass::QueryFlags rv = - QmlValueTypeScriptClass::HandlesReadAccess; - if (prop.isWritable()) - rv |= QmlValueTypeScriptClass::HandlesWriteAccess; - - return rv; -} - -QScriptValue QmlValueTypeScriptClass::property(const QScriptValue &object, - const QScriptString &name, - uint id) -{ - Q_UNUSED(name); - QmlValueTypeReference ref = - qvariant_cast(object.data().toVariant()); - - if (!ref.object) - return QScriptValue(); - - ref.type->read(ref.object, ref.property); - - QMetaProperty p = ref.type->metaObject()->property(id); - QVariant rv = p.read(ref.type); - - return static_cast(QObjectPrivate::get(engine))->scriptEngine.newVariant(rv); -} - -void QmlValueTypeScriptClass::setProperty(QScriptValue &object, - const QScriptString &name, - uint id, - const QScriptValue &value) -{ - Q_UNUSED(name); - QmlValueTypeReference ref = - qvariant_cast(object.data().toVariant()); - - if (!ref.object) - return; - - QVariant v = QmlScriptClass::toVariant(engine, value); - - ref.type->read(ref.object, ref.property); - QMetaProperty p = ref.type->metaObject()->property(id); - p.write(ref.type, v); - ref.type->write(ref.object, ref.property); -} - struct QmlEnginePrivate::ImportedNamespace { QStringList urls; QList majversions; @@ -1395,6 +1155,7 @@ public: int ref; private: + friend class QmlEnginePrivate::Imports; QmlEnginePrivate::ImportedNamespace unqualifiedset; QHash set; }; @@ -1425,6 +1186,80 @@ QmlEnginePrivate::Imports::~Imports() delete d; } +#include +#include +static QmlTypeNameCache *cacheForNamespace(QmlEngine *engine, const QmlEnginePrivate::ImportedNamespace &set, QmlTypeNameCache *cache) +{ + if (!cache) + cache = new QmlTypeNameCache(engine); + + QList types = QmlMetaType::qmlTypes(); + + for (int ii = 0; ii < set.urls.count(); ++ii) { + if (!set.isBuiltin.at(ii)) + continue; + + QByteArray base = set.urls.at(ii).toUtf8() + "/"; + int major = set.majversions.at(ii); + int minor = set.minversions.at(ii); + + foreach (QmlType *type, types) { + if (type->qmlTypeName().startsWith(base) && + type->qmlTypeName().lastIndexOf('/') == (base.length() - 1) && + type->majorVersion() == major && type->minMinorVersion() <= minor && + type->maxMinorVersion() >= minor) { + + QString name = QString::fromUtf8(type->qmlTypeName().mid(base.length())); + + cache->add(name, type); + } + } + } + + return cache; +} + +QmlTypeNameCache *QmlEnginePrivate::Imports::cache(QmlEngine *engine) const +{ + const QmlEnginePrivate::ImportedNamespace &set = d->unqualifiedset; + + QmlTypeNameCache *cache = new QmlTypeNameCache(engine); + + for (QHash::ConstIterator iter = d->set.begin(); + iter != d->set.end(); ++iter) { + + QmlTypeNameCache::Data *d = cache->data(iter.key()); + if (d) { + if (!d->typeNamespace) + cacheForNamespace(engine, *(*iter), d->typeNamespace); + } else { + QmlTypeNameCache *nc = cacheForNamespace(engine, *(*iter), 0); + cache->add(iter.key(), nc); + nc->release(); + } + } + + cacheForNamespace(engine, set, cache); + + return cache; +} + +/* +QStringList QmlEnginePrivate::Imports::unqualifiedSet() const +{ + QStringList rv; + + const QmlEnginePrivate::ImportedNamespace &set = d->unqualifiedset; + + for (int ii = 0; ii < set.urls.count(); ++ii) { + if (set.isBuiltin.at(ii)) + rv << set.urls.at(ii); + } + + return rv; +} +*/ + /*! Sets the base URL to be used for all relative file imports added. */ diff --git a/src/declarative/qml/qmlengine_p.h b/src/declarative/qml/qmlengine_p.h index 231388d..7978023 100644 --- a/src/declarative/qml/qmlengine_p.h +++ b/src/declarative/qml/qmlengine_p.h @@ -75,6 +75,7 @@ #include #include #include +#include QT_BEGIN_NAMESPACE @@ -92,6 +93,8 @@ class QNetworkReply; class QNetworkAccessManager; class QmlAbstractBinding; class QScriptDeclarativeClass; +class QmlTypeNameScriptClass; +class QmlTypeNameCache; class QmlEnginePrivate : public QObjectPrivate { @@ -102,13 +105,6 @@ public: void init(); - QScriptClass::QueryFlags queryObject(const QString &name, uint *id, - QObject *); - QScriptValue propertyObject(const QString &propName, QObject *, - uint id = 0); - void setPropertyObject(const QScriptValue &, uint id); - - struct CapturedProperty { CapturedProperty(QObject *o, int c, int n) : object(o), coreIndex(c), notifyIndex(n) {} @@ -128,25 +124,6 @@ public: #endif struct ImportedNamespace; - struct ResolveData { - ResolveData() : safetyCheckId(0) {} - int safetyCheckId; - - void clear() { - object = 0; context = 0; - type = 0; ns = 0; - contextIndex = -1; isFunction = false; - } - QObject *object; - QmlContext *context; - - QmlType *type; - QmlEnginePrivate::ImportedNamespace *ns; - - int contextIndex; - bool isFunction; - QmlMetaProperty property; - } resolveData; QmlContextScriptClass *contextClass; QmlObjectScriptClass *objectClass; QmlValueTypeScriptClass *valueTypeClass; @@ -211,9 +188,6 @@ public: } QmlValueTypeFactory valueTypes; - // ### Fixme - typedef QHash, bool> FunctionCache; - FunctionCache functionCache; QHash propertyCache; QmlPropertyCache *cache(QObject *obj) { @@ -228,6 +202,7 @@ public: return rv; } + // ### This whole class is embarrassing struct Imports { Imports(); ~Imports(); @@ -237,6 +212,8 @@ public: void setBaseUrl(const QUrl& url); QUrl baseUrl() const; + QmlTypeNameCache *cache(QmlEngine *) const; + private: friend class QmlEnginePrivate; QmlImportsPrivate *d; @@ -261,6 +238,9 @@ public: QHash m_qmlLists; QHash m_compositeTypes; + QScriptValue scriptValueFromVariant(const QVariant &); + QVariant scriptValueToVariant(const QScriptValue &); + static QScriptValue qmlScriptObject(QObject*, QmlEngine*); static QScriptValue createComponent(QScriptContext*, QScriptEngine*); static QScriptValue createQmlObject(QScriptContext*, QScriptEngine*); @@ -292,43 +272,6 @@ protected: QmlEngine *engine; }; -class QmlTypeNameScriptClass : public QmlScriptClass -{ -public: - QmlTypeNameScriptClass(QmlEngine *); - ~QmlTypeNameScriptClass(); - - virtual QueryFlags queryProperty(const QScriptValue &object, - const QScriptString &name, - QueryFlags flags, uint *id); - virtual QScriptValue property(const QScriptValue &object, - const QScriptString &name, - uint id); - -private: - QObject *object; - QmlType *type; - quint32 enumValue; -}; - -class QmlValueTypeScriptClass : public QmlScriptClass -{ -public: - QmlValueTypeScriptClass(QmlEngine *); - ~QmlValueTypeScriptClass(); - - 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); -}; - QT_END_NAMESPACE #endif // QMLENGINE_P_H diff --git a/src/declarative/qml/qmlintegercache.cpp b/src/declarative/qml/qmlintegercache.cpp index 1bc4086..564faaa 100644 --- a/src/declarative/qml/qmlintegercache.cpp +++ b/src/declarative/qml/qmlintegercache.cpp @@ -62,9 +62,7 @@ void QmlIntegerCache::add(const QString &id, int value) QmlEnginePrivate *enginePriv = QmlEnginePrivate::get(engine); // ### use contextClass - QScriptDeclarativeClass::PersistentIdentifier *d = - enginePriv->objectClass->createPersistentIdentifier(id); - d->value = value; + Data *d = new Data(enginePriv->objectClass->createPersistentIdentifier(id), value); stringCache.insert(id, d); identifierCache.insert(d->identifier, d); diff --git a/src/declarative/qml/qmlintegercache_p.h b/src/declarative/qml/qmlintegercache_p.h index fda80c6..e11e0be 100644 --- a/src/declarative/qml/qmlintegercache_p.h +++ b/src/declarative/qml/qmlintegercache_p.h @@ -74,12 +74,15 @@ public: static QmlIntegerCache *createForEnums(QmlType *, QmlEngine *); private: - struct Data { + struct Data : public QScriptDeclarativeClass::PersistentIdentifier { + Data(const QScriptDeclarativeClass::PersistentIdentifier &i, int v) + : QScriptDeclarativeClass::PersistentIdentifier(i), value(v) {} + int value; }; - typedef QHash *> StringCache; - typedef QHash *> IdentifierCache; + typedef QHash StringCache; + typedef QHash IdentifierCache; StringCache stringCache; IdentifierCache identifierCache; diff --git a/src/declarative/qml/qmlobjectscriptclass.cpp b/src/declarative/qml/qmlobjectscriptclass.cpp index bb5f191..6a34a2f 100644 --- a/src/declarative/qml/qmlobjectscriptclass.cpp +++ b/src/declarative/qml/qmlobjectscriptclass.cpp @@ -64,14 +64,13 @@ QmlObjectScriptClass::QmlObjectScriptClass(QmlEngine *bindEngine) QScriptEngine *scriptEngine = QmlEnginePrivate::getScriptEngine(bindEngine); m_destroy = scriptEngine->newFunction(destroy); - m_destroyId = createPersistentIdentifier(QLatin1String("destroy")); + m_destroyId = createPersistentIdentifier(QLatin1String("destroy")); m_toString = scriptEngine->newFunction(tostring); - m_toStringId = createPersistentIdentifier(QLatin1String("toString")); + m_toStringId = createPersistentIdentifier(QLatin1String("toString")); } QmlObjectScriptClass::~QmlObjectScriptClass() { - delete m_destroyId; } QScriptValue QmlObjectScriptClass::newQObject(QObject *object) @@ -100,8 +99,8 @@ QmlObjectScriptClass::queryProperty(QObject *obj, const Identifier &name, Q_UNUSED(flags); lastData = 0; - if (name == m_destroyId->identifier || - name == m_toStringId->identifier) + if (name == m_destroyId.identifier || + name == m_toStringId.identifier) return QScriptClass::HandlesReadAccess; if (!obj) @@ -140,9 +139,9 @@ QScriptValue QmlObjectScriptClass::property(const Object &object, const Identifi QScriptValue QmlObjectScriptClass::property(QObject *obj, const Identifier &name) { - if (name == m_destroyId->identifier) + if (name == m_destroyId.identifier) return m_destroy; - else if (name == m_toStringId->identifier) + else if (name == m_toStringId.identifier) return m_toString; Q_ASSERT(lastData); @@ -156,6 +155,11 @@ QScriptValue QmlObjectScriptClass::property(QObject *obj, const Identifier &name QScriptValue sobj = scriptEngine->newQObject(obj); return sobj.property(toString(name)); } else { + if (lastData->propType < QVariant::UserType) { + QmlValueType *valueType = enginePriv->valueTypes[lastData->propType]; + if (valueType) + return enginePriv->valueTypeClass->newObject(obj, lastData->coreIndex, valueType); + } QVariant var = obj->metaObject()->property(lastData->coreIndex).read(obj); if (!(lastData->flags & QmlPropertyCache::Data::IsConstant)) { @@ -167,7 +171,7 @@ QScriptValue QmlObjectScriptClass::property(QObject *obj, const Identifier &name QObject *rv = *(QObject **)var.constData(); return newQObject(rv); } else { - return qScriptValueFromValue(scriptEngine, var); + return enginePriv->scriptValueFromVariant(var); } } @@ -250,5 +254,5 @@ QScriptValue QmlObjectScriptClass::destroy(QScriptContext *context, QScriptEngin return engine->nullValue(); } - QT_END_NAMESPACE + diff --git a/src/declarative/qml/qmlobjectscriptclass_p.h b/src/declarative/qml/qmlobjectscriptclass_p.h index cd67fac..c86abdb 100644 --- a/src/declarative/qml/qmlobjectscriptclass_p.h +++ b/src/declarative/qml/qmlobjectscriptclass_p.h @@ -86,13 +86,11 @@ protected: virtual void destroyed(const Object &); private: - uint m_id; QmlPropertyCache::Data *lastData; QmlPropertyCache::Data local; - struct Dummy {}; - PersistentIdentifier *m_destroyId; - PersistentIdentifier *m_toStringId; + PersistentIdentifier m_destroyId; + PersistentIdentifier m_toStringId; QScriptValue m_destroy; QScriptValue m_toString; diff --git a/src/declarative/qml/qmlpropertycache.cpp b/src/declarative/qml/qmlpropertycache.cpp index cc4c2ab..d7b087b 100644 --- a/src/declarative/qml/qmlpropertycache.cpp +++ b/src/declarative/qml/qmlpropertycache.cpp @@ -155,8 +155,8 @@ QmlPropertyCache *QmlPropertyCache::create(QmlEngine *engine, const QMetaObject QMetaProperty p = metaObject->property(ii); QString propName = QLatin1String(p.name()); - QScriptDeclarativeClass::PersistentIdentifier *data = - enginePriv->objectClass->createPersistentIdentifier(propName); + RData *data = new RData; + data->identifier = enginePriv->objectClass->createPersistentIdentifier(propName); data->load(p); @@ -166,7 +166,7 @@ QmlPropertyCache *QmlPropertyCache::create(QmlEngine *engine, const QMetaObject continue; cache->stringCache.insert(propName, data); - cache->identifierCache.insert(data->identifier, data); + cache->identifierCache.insert(data->identifier.identifier, data); data->addref(); data->addref(); } @@ -183,13 +183,13 @@ QmlPropertyCache *QmlPropertyCache::create(QmlEngine *engine, const QMetaObject if (cache->stringCache.contains(methodName)) continue; - QScriptDeclarativeClass::PersistentIdentifier *data = - enginePriv->objectClass->createPersistentIdentifier(methodName); + RData *data = new RData; + data->identifier = enginePriv->objectClass->createPersistentIdentifier(methodName); data->load(m); cache->stringCache.insert(methodName, data); - cache->identifierCache.insert(data->identifier, data); + cache->identifierCache.insert(data->identifier.identifier, data); data->addref(); data->addref(); } diff --git a/src/declarative/qml/qmlpropertycache_p.h b/src/declarative/qml/qmlpropertycache_p.h index 82b8737..f1b1219 100644 --- a/src/declarative/qml/qmlpropertycache_p.h +++ b/src/declarative/qml/qmlpropertycache_p.h @@ -113,11 +113,13 @@ public: Data *property(int) const; private: - struct RData : public Data, public QmlRefCount {}; + struct RData : public Data, public QmlRefCount { + QScriptDeclarativeClass::PersistentIdentifier identifier; + }; - typedef QVector *> IndexCache; - typedef QHash *> StringCache; - typedef QHash *> IdentifierCache; + typedef QVector IndexCache; + typedef QHash StringCache; + typedef QHash IdentifierCache; IndexCache indexCache; StringCache stringCache; diff --git a/src/declarative/qml/qmltypenamecache.cpp b/src/declarative/qml/qmltypenamecache.cpp new file mode 100644 index 0000000..2b0f2c9 --- /dev/null +++ b/src/declarative/qml/qmltypenamecache.cpp @@ -0,0 +1,93 @@ +/**************************************************************************** +** +** 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 "qmltypenamecache_p.h" + +QT_BEGIN_NAMESPACE + +QmlTypeNameCache::QmlTypeNameCache(QmlEngine *e) +: engine(e) +{ +} + +QmlTypeNameCache::~QmlTypeNameCache() +{ + qDeleteAll(stringCache); +} + +void QmlTypeNameCache::add(const QString &name, QmlType *type) +{ + if (stringCache.contains(name)) + return; + + QmlEnginePrivate *ep = QmlEnginePrivate::get(engine); + + RData *data = new RData; + // ### Use typename class + data->identifier = ep->objectClass->createPersistentIdentifier(name); + data->type = type; + stringCache.insert(name, data); + identifierCache.insert(data->identifier.identifier, data); +} + +void QmlTypeNameCache::add(const QString &name, QmlTypeNameCache *typeNamespace) +{ + if (stringCache.contains(name)) + return; + + QmlEnginePrivate *ep = QmlEnginePrivate::get(engine); + + RData *data = new RData; + // ### Use typename class + data->identifier = ep->objectClass->createPersistentIdentifier(name); + data->typeNamespace = typeNamespace; + stringCache.insert(name, data); + identifierCache.insert(data->identifier.identifier, data); + typeNamespace->addref(); +} + +QmlTypeNameCache::Data *QmlTypeNameCache::data(const QString &id) const +{ + return stringCache.value(id); +} + +QT_END_NAMESPACE + diff --git a/src/declarative/qml/qmltypenamecache_p.h b/src/declarative/qml/qmltypenamecache_p.h new file mode 100644 index 0000000..6022b43 --- /dev/null +++ b/src/declarative/qml/qmltypenamecache_p.h @@ -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$ +** +****************************************************************************/ + +#ifndef QMLTYPENAMECACHE_P_H +#define QMLTYPENAMECACHE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QmlType; +class QmlEngine; +class QmlTypeNameCache : public QmlRefCount +{ +public: + QmlTypeNameCache(QmlEngine *); + virtual ~QmlTypeNameCache(); + + struct Data { + inline Data(); + inline ~Data(); + QmlType *type; + QmlTypeNameCache *typeNamespace; + }; + + void add(const QString &, QmlType *); + void add(const QString &, QmlTypeNameCache *); + + Data *data(const QString &) const; + inline Data *data(const QScriptDeclarativeClass::Identifier &id) const; + +private: + struct RData : public Data { + QScriptDeclarativeClass::PersistentIdentifier identifier; + }; + typedef QHash StringCache; + typedef QHash IdentifierCache; + + StringCache stringCache; + IdentifierCache identifierCache; + QmlEngine *engine; +}; + +QmlTypeNameCache::Data::Data() +: type(0), typeNamespace(0) +{ +} + +QmlTypeNameCache::Data::~Data() +{ + if (typeNamespace) typeNamespace->release(); +} + +QmlTypeNameCache::Data *QmlTypeNameCache::data(const QScriptDeclarativeClass::Identifier &id) const +{ + return identifierCache.value(id); +} + +QT_END_NAMESPACE + +#endif // QMLTYPENAMECACHE_P_H + diff --git a/src/declarative/qml/qmltypenamescriptclass.cpp b/src/declarative/qml/qmltypenamescriptclass.cpp new file mode 100644 index 0000000..29e2978 --- /dev/null +++ b/src/declarative/qml/qmltypenamescriptclass.cpp @@ -0,0 +1,159 @@ +/**************************************************************************** +** +** 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 "qmltypenamescriptclass_p.h" +#include +#include + +QT_BEGIN_NAMESPACE + +struct TypeNameData { + TypeNameData(QObject *o, QmlType *t) : object(o), type(t), typeNamespace(0) {} + TypeNameData(QObject *o, QmlTypeNameCache *n) : object(o), type(0), typeNamespace(n) { + if (typeNamespace) typeNamespace->addref(); + } + ~TypeNameData() { + if (typeNamespace) typeNamespace->release(); + } + + QObject *object; + QmlType *type; + QmlTypeNameCache *typeNamespace; +}; + +QmlTypeNameScriptClass::QmlTypeNameScriptClass(QmlEngine *bindEngine) +: QScriptDeclarativeClass(QmlEnginePrivate::getScriptEngine(bindEngine)), + engine(bindEngine), object(0), type(0) +{ +} + +QmlTypeNameScriptClass::~QmlTypeNameScriptClass() +{ +} + +QScriptValue QmlTypeNameScriptClass::newObject(QObject *object, QmlType *type) +{ + QScriptEngine *scriptEngine = QmlEnginePrivate::getScriptEngine(engine); + + return QScriptDeclarativeClass::newObject(scriptEngine, this, (Object)new TypeNameData(object, type)); +} + +QScriptValue QmlTypeNameScriptClass::newObject(QObject *object, QmlTypeNameCache *ns) +{ + QScriptEngine *scriptEngine = QmlEnginePrivate::getScriptEngine(engine); + + return QScriptDeclarativeClass::newObject(scriptEngine, this, (Object)new TypeNameData(object, ns)); +} + + +QScriptClass::QueryFlags +QmlTypeNameScriptClass::queryProperty(const Object &obj, const Identifier &name, + QScriptClass::QueryFlags flags) +{ + Q_UNUSED(flags); + + TypeNameData *data = (TypeNameData *)obj; + + object = 0; + type = 0; + QmlEnginePrivate *ep = QmlEnginePrivate::get(engine); + + if (data->typeNamespace) { + + QmlTypeNameCache::Data *d = data->typeNamespace->data(name); + if (d && d->type) { + type = d->type; + return QScriptClass::HandlesReadAccess; + } else { + return 0; + } + + } else { + Q_ASSERT(data->type); + + QString strName = toString(name); + + if (strName.at(0).isUpper()) { + // Must be an enum + // ### Optimize + const char *enumName = strName.toUtf8().constData(); + const QMetaObject *metaObject = data->type->baseMetaObject(); + for (int ii = metaObject->enumeratorCount() - 1; ii >= 0; --ii) { + QMetaEnum e = metaObject->enumerator(ii); + int value = e.keyToValue(enumName); + if (value != -1) { + enumValue = value; + return QScriptClass::HandlesReadAccess; + } + } + return 0; + } else { + // Must be an attached property + object = qmlAttachedPropertiesObjectById(data->type->index(), data->object); + if (!object) return 0; + return ep->objectClass->queryProperty(object, name, flags); + } + } +} + +QScriptValue QmlTypeNameScriptClass::property(const Object &obj, const Identifier &name) +{ + QmlEnginePrivate *ep = QmlEnginePrivate::get(engine); + if (type) { + return newObject(object, type); + } else if (object) { + return ep->objectClass->property(((TypeNameData *)obj)->object, name); + } else { + return QScriptValue(enumValue); + } +} + +void QmlTypeNameScriptClass::setProperty(const Object &o, const Identifier &n, const QScriptValue &v) +{ + Q_ASSERT(object); + Q_ASSERT(!type); + + QmlEnginePrivate *ep = QmlEnginePrivate::get(engine); + ep->objectClass->setProperty(((TypeNameData *)o)->object, n, v); +} + +QT_END_NAMESPACE + diff --git a/src/declarative/qml/qmltypenamescriptclass_p.h b/src/declarative/qml/qmltypenamescriptclass_p.h new file mode 100644 index 0000000..c642ea4 --- /dev/null +++ b/src/declarative/qml/qmltypenamescriptclass_p.h @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** 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 QMLTYPENAMESCRIPTCLASS_P_H +#define QMLTYPENAMESCRIPTCLASS_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QmlEngine; +class QmlType; +class QmlTypeNameCache; +class QmlTypeNameScriptClass : public QScriptDeclarativeClass +{ +public: + QmlTypeNameScriptClass(QmlEngine *); + ~QmlTypeNameScriptClass(); + + QScriptValue newObject(QObject *, QmlType *); + QScriptValue newObject(QObject *, QmlTypeNameCache *); + +protected: + virtual QScriptClass::QueryFlags queryProperty(const Object &, const Identifier &, + QScriptClass::QueryFlags flags); + + virtual QScriptValue property(const Object &, const Identifier &); + virtual void setProperty(const Object &, const Identifier &name, const QScriptValue &); + +private: + QmlEngine *engine; + QObject *object; + QmlType *type; + quint32 enumValue; +}; + +QT_END_NAMESPACE + +#endif // QMLTYPENAMESCRIPTCLASS_P_H + diff --git a/src/declarative/qml/qmlvaluetypescriptclass.cpp b/src/declarative/qml/qmlvaluetypescriptclass.cpp new file mode 100644 index 0000000..da6c73d --- /dev/null +++ b/src/declarative/qml/qmlvaluetypescriptclass.cpp @@ -0,0 +1,150 @@ +/**************************************************************************** +** +** 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 "qmlvaluetypescriptclass_p.h" +#include + +QT_BEGIN_NAMESPACE + +struct QmlValueTypeReference { + QmlValueType *type; + QGuard object; + int property; +}; +Q_DECLARE_METATYPE(QmlValueTypeReference); + +QmlValueTypeScriptClass::QmlValueTypeScriptClass(QmlEngine *bindEngine) +: QScriptClass(QmlEnginePrivate::getScriptEngine(bindEngine)), engine(bindEngine) +{ +} + +QmlValueTypeScriptClass::~QmlValueTypeScriptClass() +{ +} + +QScriptValue QmlValueTypeScriptClass::newObject(QObject *object, int coreIndex, QmlValueType *type) +{ + QmlValueTypeReference ref = { type, object, coreIndex }; + return QScriptValue(); +} + +QmlValueTypeScriptClass::QueryFlags +QmlValueTypeScriptClass::queryProperty(const QScriptValue &object, + const QScriptString &name, + QueryFlags flags, uint *id) +{ + Q_UNUSED(flags); + QmlValueTypeReference ref = + qvariant_cast(object.data().toVariant()); + + if (!ref.object) + return 0; + + QByteArray propName = name.toString().toUtf8(); + + int idx = ref.type->metaObject()->indexOfProperty(propName.constData()); + if (idx == -1) + return 0; + *id = idx; + + QMetaProperty prop = ref.object->metaObject()->property(idx); + + QmlValueTypeScriptClass::QueryFlags rv = + QmlValueTypeScriptClass::HandlesReadAccess; + if (prop.isWritable()) + rv |= QmlValueTypeScriptClass::HandlesWriteAccess; + + return rv; +} + +QScriptValue QmlValueTypeScriptClass::property(const QScriptValue &object, + const QScriptString &name, + uint id) +{ + Q_UNUSED(name); + QmlValueTypeReference ref = + qvariant_cast(object.data().toVariant()); + + if (!ref.object) + return QScriptValue(); + + ref.type->read(ref.object, ref.property); + + QMetaProperty p = ref.type->metaObject()->property(id); + QVariant rv = p.read(ref.type); + + return static_cast(QObjectPrivate::get(engine))->scriptEngine.newVariant(rv); +} + +void QmlValueTypeScriptClass::setProperty(QScriptValue &object, + const QScriptString &name, + uint id, + const QScriptValue &value) +{ + Q_UNUSED(name); + QmlValueTypeReference ref = + qvariant_cast(object.data().toVariant()); + + if (!ref.object) + return; + + QVariant v = QmlScriptClass::toVariant(engine, value); + + ref.type->read(ref.object, ref.property); + QMetaProperty p = ref.type->metaObject()->property(id); + p.write(ref.type, v); + ref.type->write(ref.object, ref.property); +} + +QVariant QmlValueTypeScriptClass::toVariant(const QScriptValue &val) +{ + QmlValueTypeReference ref = + qvariant_cast(val.data().toVariant()); + + if (!ref.object) + return QVariant(); + + QMetaProperty p = ref.object->metaObject()->property(ref.property); + return p.read(ref.object); +} + +QT_END_NAMESPACE + diff --git a/src/declarative/qml/qmlvaluetypescriptclass_p.h b/src/declarative/qml/qmlvaluetypescriptclass_p.h new file mode 100644 index 0000000..d656a22 --- /dev/null +++ b/src/declarative/qml/qmlvaluetypescriptclass_p.h @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** 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 QMLVALUETYPESCRIPTCLASS_P_H +#define QMLVALUETYPESCRIPTCLASS_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// +#include +#include + +QT_BEGIN_NAMESPACE + +class QmlEngine; +class QmlValueType; +class QmlValueTypeScriptClass : public QScriptClass +{ +public: + QmlValueTypeScriptClass(QmlEngine *); + ~QmlValueTypeScriptClass(); + + QScriptValue newObject(QObject *object, int coreIndex, QmlValueType *); + + 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); + + QVariant toVariant(const QScriptValue &); +private: + QmlEngine *engine; +}; + +QT_END_NAMESPACE + +#endif // QMLVALUETYPESCRIPTCLASS_P_H + diff --git a/src/declarative/util/qmlscript.cpp b/src/declarative/util/qmlscript.cpp index de2128d..2031a54 100644 --- a/src/declarative/util/qmlscript.cpp +++ b/src/declarative/util/qmlscript.cpp @@ -179,10 +179,14 @@ void QmlScriptPrivate::addScriptToEngine(const QString &script, const QString &s QScriptEngine *scriptEngine = QmlEnginePrivate::getScriptEngine(engine); QScriptContext *scriptContext = scriptEngine->pushContext(); - for (int i = context->d_func()->scopeChain.size() - 1; i > -1; --i) { + for (int i = context->d_func()->scopeChain.size() - 1; i >= 0; --i) { scriptContext->pushScope(context->d_func()->scopeChain.at(i)); } - scriptContext->setActivationObject(context->d_func()->scopeChain.at(0)); + + QScriptValue scope = scriptEngine->newObject(); + scriptContext->pushScope(scope); + + scriptContext->setActivationObject(scope); QScriptValue val = scriptEngine->evaluate(script, source); if (scriptEngine->hasUncaughtException()) { @@ -200,6 +204,8 @@ void QmlScriptPrivate::addScriptToEngine(const QString &script, const QString &s } scriptEngine->popContext(); + + context->d_func()->scripts.append(scope); } QT_END_NAMESPACE -- cgit v0.12 From a712a6243be29dbfa49c3d1705c8b1babd8c7a1a Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Fri, 2 Oct 2009 18:01:55 +1000 Subject: Tweak api to improve ownership issues --- src/script/bridge/qscriptdeclarativeclass.cpp | 23 +++++++++-------------- src/script/bridge/qscriptdeclarativeclass_p.h | 22 +++++++++++----------- src/script/bridge/qscriptdeclarativeobject.cpp | 7 ++----- src/script/bridge/qscriptdeclarativeobject_p.h | 6 +++--- 4 files changed, 25 insertions(+), 33 deletions(-) diff --git a/src/script/bridge/qscriptdeclarativeclass.cpp b/src/script/bridge/qscriptdeclarativeclass.cpp index 371a3c3..62c1afc 100644 --- a/src/script/bridge/qscriptdeclarativeclass.cpp +++ b/src/script/bridge/qscriptdeclarativeclass.cpp @@ -94,7 +94,7 @@ QScriptDeclarativeClass::QScriptDeclarativeClass(QScriptEngine *engine) QScriptValue QScriptDeclarativeClass::newObject(QScriptEngine *engine, QScriptDeclarativeClass *scriptClass, - Object object) + Object *object) { Q_ASSERT(engine); Q_ASSERT(scriptClass); @@ -119,7 +119,7 @@ QScriptDeclarativeClass *QScriptDeclarativeClass::scriptClass(const QScriptValue return static_cast(delegate)->scriptClass(); } -QScriptDeclarativeClass::Object QScriptDeclarativeClass::object(const QScriptValue &v) +QScriptDeclarativeClass::Object *QScriptDeclarativeClass::object(const QScriptValue &v) { QScriptValuePrivate *d = QScriptValuePrivate::get(v); if (!d || !d->isJSC() || !d->jscValue.isObject(&QScriptObject::info)) @@ -218,7 +218,7 @@ QString QScriptDeclarativeClass::toString(const Identifier &identifier) } QScriptClass::QueryFlags -QScriptDeclarativeClass::queryProperty(const Object &object, const Identifier &name, +QScriptDeclarativeClass::queryProperty(Object *object, const Identifier &name, QScriptClass::QueryFlags flags) { Q_UNUSED(object); @@ -227,14 +227,14 @@ QScriptDeclarativeClass::queryProperty(const Object &object, const Identifier &n return 0; } -QScriptValue QScriptDeclarativeClass::property(const Object &object, const Identifier &name) +QScriptValue QScriptDeclarativeClass::property(Object *object, const Identifier &name) { Q_UNUSED(object); Q_UNUSED(name); return QScriptValue(); } -void QScriptDeclarativeClass::setProperty(const Object &object, const Identifier &name, +void QScriptDeclarativeClass::setProperty(Object *object, const Identifier &name, const QScriptValue &value) { Q_UNUSED(object); @@ -243,31 +243,26 @@ void QScriptDeclarativeClass::setProperty(const Object &object, const Identifier } QScriptValue::PropertyFlags -QScriptDeclarativeClass::propertyFlags(const Object &object, const Identifier &name) +QScriptDeclarativeClass::propertyFlags(Object *object, const Identifier &name) { Q_UNUSED(object); Q_UNUSED(name); return 0; } -QStringList QScriptDeclarativeClass::propertyNames(const Object &object) +QStringList QScriptDeclarativeClass::propertyNames(Object *object) { Q_UNUSED(object); return QStringList(); } -void QScriptDeclarativeClass::destroyed(const Object &object) -{ - Q_UNUSED(object); -} - -QObject *QScriptDeclarativeClass::toQObject(const Object &, bool *ok) +QObject *QScriptDeclarativeClass::toQObject(Object *, bool *ok) { if (ok) *ok = false; return 0; } -QVariant QScriptDeclarativeClass::toVariant(const Object &, bool *ok) +QVariant QScriptDeclarativeClass::toVariant(Object *, bool *ok) { if (ok) *ok = false; return QVariant(); diff --git a/src/script/bridge/qscriptdeclarativeclass_p.h b/src/script/bridge/qscriptdeclarativeclass_p.h index 16f6942..07cfad1 100644 --- a/src/script/bridge/qscriptdeclarativeclass_p.h +++ b/src/script/bridge/qscriptdeclarativeclass_p.h @@ -65,11 +65,12 @@ class Q_SCRIPT_EXPORT QScriptDeclarativeClass { public: typedef void* Identifier; - typedef void* Object; - static QScriptValue newObject(QScriptEngine *, QScriptDeclarativeClass *, Object); + struct Object { virtual ~Object() {} }; + + static QScriptValue newObject(QScriptEngine *, QScriptDeclarativeClass *, Object *); static QScriptDeclarativeClass *scriptClass(const QScriptValue &); - static Object object(const QScriptValue &); + static Object *object(const QScriptValue &); static QScriptValue function(const QScriptValue &, const Identifier &); static QScriptValue property(const QScriptValue &, const Identifier &); @@ -100,18 +101,17 @@ public: QString toString(const Identifier &); - virtual QScriptClass::QueryFlags queryProperty(const Object &, const Identifier &, + virtual QScriptClass::QueryFlags queryProperty(Object *, const Identifier &, QScriptClass::QueryFlags flags); - virtual QScriptValue property(const Object &, const Identifier &); - virtual void setProperty(const Object &, const Identifier &name, const QScriptValue &); - virtual QScriptValue::PropertyFlags propertyFlags(const Object &, const Identifier &); + virtual QScriptValue property(Object *, const Identifier &); + virtual void setProperty(Object *, const Identifier &name, const QScriptValue &); + virtual QScriptValue::PropertyFlags propertyFlags(Object *, const Identifier &); - virtual QStringList propertyNames(const Object &); + virtual QStringList propertyNames(Object *); - virtual QObject *toQObject(const Object &, bool *ok = 0); - virtual QVariant toVariant(const Object &, bool *ok = 0); - virtual void destroyed(const Object &); + virtual QObject *toQObject(Object *, bool *ok = 0); + virtual QVariant toVariant(Object *, bool *ok = 0); protected: QScopedPointer d_ptr; diff --git a/src/script/bridge/qscriptdeclarativeobject.cpp b/src/script/bridge/qscriptdeclarativeobject.cpp index 62c2686..aa811d1 100644 --- a/src/script/bridge/qscriptdeclarativeobject.cpp +++ b/src/script/bridge/qscriptdeclarativeobject.cpp @@ -64,14 +64,14 @@ namespace QScript { DeclarativeObjectDelegate::DeclarativeObjectDelegate(QScriptDeclarativeClass *c, - QScriptDeclarativeClass::Object &o) + QScriptDeclarativeClass::Object *o) : m_class(c), m_object(o) { } DeclarativeObjectDelegate::~DeclarativeObjectDelegate() { - m_class->destroyed(m_object); + delete m_object; } QScriptObjectDelegate::Type DeclarativeObjectDelegate::type() const @@ -126,7 +126,6 @@ bool DeclarativeObjectDelegate::getPropertyAttributes(const QScriptObject* objec const JSC::Identifier &propertyName, unsigned &attribs) const { - QScriptEnginePrivate *engine = scriptEngineFromExec(exec); QScriptDeclarativeClass::Identifier identifier = (void *)propertyName.ustring().rep(); QScriptClass::QueryFlags flags = @@ -154,8 +153,6 @@ void DeclarativeObjectDelegate::getPropertyNames(QScriptObject* object, JSC::Exe JSC::PropertyNameArray &propertyNames, unsigned listedAttributes) { - QScriptEnginePrivate *engine = scriptEngineFromExec(exec); - QStringList properties = m_class->propertyNames(m_object); for (int ii = 0; ii < properties.count(); ++ii) { const QString &name = properties.at(ii); diff --git a/src/script/bridge/qscriptdeclarativeobject_p.h b/src/script/bridge/qscriptdeclarativeobject_p.h index 87375d8..ccb07bc 100644 --- a/src/script/bridge/qscriptdeclarativeobject_p.h +++ b/src/script/bridge/qscriptdeclarativeobject_p.h @@ -68,13 +68,13 @@ namespace QScript class DeclarativeObjectDelegate : public QScriptObjectDelegate { public: - DeclarativeObjectDelegate(QScriptDeclarativeClass *c, QScriptDeclarativeClass::Object &o); + DeclarativeObjectDelegate(QScriptDeclarativeClass *c, QScriptDeclarativeClass::Object *o); ~DeclarativeObjectDelegate(); virtual Type type() const; QScriptDeclarativeClass *scriptClass() const { return m_class; } - QScriptDeclarativeClass::Object object() const { return m_object; } + QScriptDeclarativeClass::Object *object() const { return m_object; } virtual bool getOwnPropertySlot(QScriptObject*, JSC::ExecState*, const JSC::Identifier& propertyName, @@ -100,7 +100,7 @@ public: private: QScriptDeclarativeClass *m_class; - QScriptDeclarativeClass::Object m_object; + QScriptDeclarativeClass::Object *m_object; }; } // namespace QScript -- cgit v0.12 From 5b37c01aa721057ad0cbef16a79cf179e3c53934 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Fri, 2 Oct 2009 18:02:14 +1000 Subject: Update to new QScriptDeclarativeClass API --- src/declarative/qml/qmlcontextscriptclass.cpp | 48 ++++---------------------- src/declarative/qml/qmlcontextscriptclass_p.h | 6 ++-- src/declarative/qml/qmlobjectscriptclass.cpp | 23 +++++------- src/declarative/qml/qmlobjectscriptclass_p.h | 9 +++-- src/declarative/qml/qmltypenamecache.cpp | 1 + src/declarative/qml/qmltypenamecache_p.h | 1 - src/declarative/qml/qmltypenamescriptclass.cpp | 12 +++---- src/declarative/qml/qmltypenamescriptclass_p.h | 6 ++-- 8 files changed, 31 insertions(+), 75 deletions(-) diff --git a/src/declarative/qml/qmlcontextscriptclass.cpp b/src/declarative/qml/qmlcontextscriptclass.cpp index d8ae4f0..4b149f7 100644 --- a/src/declarative/qml/qmlcontextscriptclass.cpp +++ b/src/declarative/qml/qmlcontextscriptclass.cpp @@ -46,7 +46,7 @@ QT_BEGIN_NAMESPACE -struct ContextData { +struct ContextData : public QScriptDeclarativeClass::Object { ContextData(QmlContext *c) : context(c) {} QGuard context; }; @@ -69,11 +69,11 @@ QScriptValue QmlContextScriptClass::newContext(QmlContext *context) { QScriptEngine *scriptEngine = QmlEnginePrivate::getScriptEngine(engine); - return newObject(scriptEngine, this, (Object)new ContextData(context)); + return newObject(scriptEngine, this, new ContextData(context)); } QScriptClass::QueryFlags -QmlContextScriptClass::queryProperty(const Object &object, const Identifier &name, +QmlContextScriptClass::queryProperty(Object *object, const Identifier &name, QScriptClass::QueryFlags flags) { Q_UNUSED(flags); @@ -93,7 +93,6 @@ QmlContextScriptClass::queryProperty(const Object &object, const Identifier &nam if (lastPropertyIndex != -1) return QScriptClass::HandlesReadAccess; - // ### Check for attached properties if (ep->currentExpression && cp->imports && bindContext == ep->currentExpression->context()) { QmlTypeNameCache::Data *data = cp->imports->data(name); @@ -103,22 +102,6 @@ QmlContextScriptClass::queryProperty(const Object &object, const Identifier &nam } } -#if 0 - QmlType *type = 0; ImportedNamespace *ns = 0; - if (currentExpression && bindContext == currentExpression->context() && - propName.at(0).isUpper() && resolveType(bindContext->d_func()->imports, propName.toUtf8(), &type, 0, 0, 0, &ns)) { - - if (type || ns) { - // Must be either an attached property, or an enum - resolveData.object = bindContext->d_func()->defaultObjects.first(); - resolveData.type = type; - resolveData.ns = ns; - return QScriptClass::HandlesReadAccess; - } - - } -#endif - for (int ii = 0; ii < cp->defaultObjects.count(); ++ii) { QScriptClass::QueryFlags rv = ep->objectClass->queryProperty(cp->defaultObjects.at(ii), name, flags); @@ -137,12 +120,10 @@ QmlContextScriptClass::queryProperty(const Object &object, const Identifier &nam return 0; } -QScriptValue QmlContextScriptClass::property(const Object &object, const Identifier &name) +QScriptValue QmlContextScriptClass::property(Object *object, const Identifier &name) { Q_UNUSED(object); - Q_ASSERT(lastPropertyIndex != -1 || lastDefaultObject != -1); - QmlContext *bindContext = ((ContextData *)object)->context.data(); Q_ASSERT(bindContext); @@ -150,18 +131,6 @@ QScriptValue QmlContextScriptClass::property(const Object &object, const Identif QmlContextPrivate *cp = QmlContextPrivate::get(bindContext); - // ### Check for attached properties -#if 0 - if (resolveData.type || resolveData.ns) { - QmlTypeNameBridge tnb = { - resolveData.object, - resolveData.type, - resolveData.ns - }; - return scriptEngine.newObject(typeNameClass, scriptEngine.newVariant(qVariantFromValue(tnb))); - } -#endif - if (lastData) { if (lastData->type) @@ -176,12 +145,7 @@ QScriptValue QmlContextScriptClass::property(const Object &object, const Identif rv = ep->objectClass->newQObject(cp->idValues[lastPropertyIndex].data()); } else { QVariant value = cp->propertyValues.at(lastPropertyIndex); - if (QmlMetaType::isObject(value.userType())) { - rv = ep->objectClass->newQObject(QmlMetaType::toQObject(value)); - } else { - // ### Shouldn't this be qScriptValueFromValue() - rv = ep->scriptEngine.newVariant(value); - } + return ep->scriptValueFromVariant(value); } ep->capturedProperties << @@ -200,7 +164,7 @@ QScriptValue QmlContextScriptClass::property(const Object &object, const Identif } } -void QmlContextScriptClass::setProperty(const Object &object, const Identifier &name, +void QmlContextScriptClass::setProperty(Object *object, const Identifier &name, const QScriptValue &value) { Q_ASSERT(lastDefaultObject != -1); diff --git a/src/declarative/qml/qmlcontextscriptclass_p.h b/src/declarative/qml/qmlcontextscriptclass_p.h index a00e567..acb8926 100644 --- a/src/declarative/qml/qmlcontextscriptclass_p.h +++ b/src/declarative/qml/qmlcontextscriptclass_p.h @@ -70,10 +70,10 @@ public: QScriptValue newContext(QmlContext *); protected: - virtual QScriptClass::QueryFlags queryProperty(const Object &, const Identifier &, + virtual QScriptClass::QueryFlags queryProperty(Object *, const Identifier &, QScriptClass::QueryFlags flags); - virtual QScriptValue property(const Object &, const Identifier &); - virtual void setProperty(const Object &, const Identifier &name, const QScriptValue &); + virtual QScriptValue property(Object *, const Identifier &); + virtual void setProperty(Object *, const Identifier &name, const QScriptValue &); private: QmlEngine *engine; diff --git a/src/declarative/qml/qmlobjectscriptclass.cpp b/src/declarative/qml/qmlobjectscriptclass.cpp index 6a34a2f..33fd409 100644 --- a/src/declarative/qml/qmlobjectscriptclass.cpp +++ b/src/declarative/qml/qmlobjectscriptclass.cpp @@ -46,7 +46,7 @@ QT_BEGIN_NAMESPACE -struct ObjectData { +struct ObjectData : public QScriptDeclarativeClass::Object { ObjectData(QObject *o) : object(o) {} QGuard object; }; @@ -77,7 +77,7 @@ QScriptValue QmlObjectScriptClass::newQObject(QObject *object) { QScriptEngine *scriptEngine = QmlEnginePrivate::getScriptEngine(engine); - return newObject(scriptEngine, this, (Object)new ObjectData(object)); + return newObject(scriptEngine, this, new ObjectData(object)); } QObject *QmlObjectScriptClass::toQObject(const QScriptValue &value) const @@ -86,7 +86,7 @@ QObject *QmlObjectScriptClass::toQObject(const QScriptValue &value) const } QScriptClass::QueryFlags -QmlObjectScriptClass::queryProperty(const Object &object, const Identifier &name, +QmlObjectScriptClass::queryProperty(Object *object, const Identifier &name, QScriptClass::QueryFlags flags) { return queryProperty(toQObject(object), name, flags); @@ -132,7 +132,7 @@ QmlObjectScriptClass::queryProperty(QObject *obj, const Identifier &name, return rv; } -QScriptValue QmlObjectScriptClass::property(const Object &object, const Identifier &name) +QScriptValue QmlObjectScriptClass::property(Object *object, const Identifier &name) { return property(toQObject(object), name); } @@ -155,7 +155,7 @@ QScriptValue QmlObjectScriptClass::property(QObject *obj, const Identifier &name QScriptValue sobj = scriptEngine->newQObject(obj); return sobj.property(toString(name)); } else { - if (lastData->propType < QVariant::UserType) { + if ((uint)lastData->propType < QVariant::UserType) { QmlValueType *valueType = enginePriv->valueTypes[lastData->propType]; if (valueType) return enginePriv->valueTypeClass->newObject(obj, lastData->coreIndex, valueType); @@ -177,7 +177,7 @@ QScriptValue QmlObjectScriptClass::property(QObject *obj, const Identifier &name } } -void QmlObjectScriptClass::setProperty(const Object &object, +void QmlObjectScriptClass::setProperty(Object *object, const Identifier &name, const QScriptValue &value) { @@ -193,7 +193,6 @@ void QmlObjectScriptClass::setProperty(QObject *obj, Q_ASSERT(obj); Q_ASSERT(lastData); - QScriptEngine *scriptEngine = QmlEnginePrivate::getScriptEngine(engine); QmlEnginePrivate *enginePriv = QmlEnginePrivate::get(engine); // ### Can well known types be optimized? @@ -201,7 +200,7 @@ void QmlObjectScriptClass::setProperty(QObject *obj, QmlMetaPropertyPrivate::write(obj, *lastData, v, enginePriv->currentExpression->context()); } -QObject *QmlObjectScriptClass::toQObject(const Object &object, bool *ok) +QObject *QmlObjectScriptClass::toQObject(Object *object, bool *ok) { if (ok) *ok = true; @@ -209,13 +208,7 @@ QObject *QmlObjectScriptClass::toQObject(const Object &object, bool *ok) return data->object.data(); } -void QmlObjectScriptClass::destroyed(const Object &object) -{ - ObjectData *data = (ObjectData*)object; - delete data; -} - -QScriptValue QmlObjectScriptClass::tostring(QScriptContext *context, QScriptEngine *engine) +QScriptValue QmlObjectScriptClass::tostring(QScriptContext *context, QScriptEngine *) { QObject* obj = context->thisObject().toQObject(); diff --git a/src/declarative/qml/qmlobjectscriptclass_p.h b/src/declarative/qml/qmlobjectscriptclass_p.h index c86abdb..6406f0d 100644 --- a/src/declarative/qml/qmlobjectscriptclass_p.h +++ b/src/declarative/qml/qmlobjectscriptclass_p.h @@ -77,13 +77,12 @@ public: void setProperty(QObject *, const Identifier &name, const QScriptValue &); protected: - virtual QScriptClass::QueryFlags queryProperty(const Object &, const Identifier &, + virtual QScriptClass::QueryFlags queryProperty(Object *, const Identifier &, QScriptClass::QueryFlags flags); - virtual QScriptValue property(const Object &, const Identifier &); - virtual void setProperty(const Object &, const Identifier &name, const QScriptValue &); - virtual QObject *toQObject(const Object &, bool *ok = 0); - virtual void destroyed(const Object &); + virtual QScriptValue property(Object *, const Identifier &); + virtual void setProperty(Object *, const Identifier &name, const QScriptValue &); + virtual QObject *toQObject(Object *, bool *ok = 0); private: QmlPropertyCache::Data *lastData; diff --git a/src/declarative/qml/qmltypenamecache.cpp b/src/declarative/qml/qmltypenamecache.cpp index 2b0f2c9..aa1c938 100644 --- a/src/declarative/qml/qmltypenamecache.cpp +++ b/src/declarative/qml/qmltypenamecache.cpp @@ -40,6 +40,7 @@ ****************************************************************************/ #include "qmltypenamecache_p.h" +#include QT_BEGIN_NAMESPACE diff --git a/src/declarative/qml/qmltypenamecache_p.h b/src/declarative/qml/qmltypenamecache_p.h index 6022b43..f11fe68 100644 --- a/src/declarative/qml/qmltypenamecache_p.h +++ b/src/declarative/qml/qmltypenamecache_p.h @@ -55,7 +55,6 @@ #include #include -#include QT_BEGIN_NAMESPACE diff --git a/src/declarative/qml/qmltypenamescriptclass.cpp b/src/declarative/qml/qmltypenamescriptclass.cpp index 29e2978..7c5e5b0 100644 --- a/src/declarative/qml/qmltypenamescriptclass.cpp +++ b/src/declarative/qml/qmltypenamescriptclass.cpp @@ -45,7 +45,7 @@ QT_BEGIN_NAMESPACE -struct TypeNameData { +struct TypeNameData : public QScriptDeclarativeClass::Object { TypeNameData(QObject *o, QmlType *t) : object(o), type(t), typeNamespace(0) {} TypeNameData(QObject *o, QmlTypeNameCache *n) : object(o), type(0), typeNamespace(n) { if (typeNamespace) typeNamespace->addref(); @@ -73,19 +73,19 @@ QScriptValue QmlTypeNameScriptClass::newObject(QObject *object, QmlType *type) { QScriptEngine *scriptEngine = QmlEnginePrivate::getScriptEngine(engine); - return QScriptDeclarativeClass::newObject(scriptEngine, this, (Object)new TypeNameData(object, type)); + return QScriptDeclarativeClass::newObject(scriptEngine, this, new TypeNameData(object, type)); } QScriptValue QmlTypeNameScriptClass::newObject(QObject *object, QmlTypeNameCache *ns) { QScriptEngine *scriptEngine = QmlEnginePrivate::getScriptEngine(engine); - return QScriptDeclarativeClass::newObject(scriptEngine, this, (Object)new TypeNameData(object, ns)); + return QScriptDeclarativeClass::newObject(scriptEngine, this, new TypeNameData(object, ns)); } QScriptClass::QueryFlags -QmlTypeNameScriptClass::queryProperty(const Object &obj, const Identifier &name, +QmlTypeNameScriptClass::queryProperty(Object *obj, const Identifier &name, QScriptClass::QueryFlags flags) { Q_UNUSED(flags); @@ -134,7 +134,7 @@ QmlTypeNameScriptClass::queryProperty(const Object &obj, const Identifier &name, } } -QScriptValue QmlTypeNameScriptClass::property(const Object &obj, const Identifier &name) +QScriptValue QmlTypeNameScriptClass::property(Object *obj, const Identifier &name) { QmlEnginePrivate *ep = QmlEnginePrivate::get(engine); if (type) { @@ -146,7 +146,7 @@ QScriptValue QmlTypeNameScriptClass::property(const Object &obj, const Identifie } } -void QmlTypeNameScriptClass::setProperty(const Object &o, const Identifier &n, const QScriptValue &v) +void QmlTypeNameScriptClass::setProperty(Object *o, const Identifier &n, const QScriptValue &v) { Q_ASSERT(object); Q_ASSERT(!type); diff --git a/src/declarative/qml/qmltypenamescriptclass_p.h b/src/declarative/qml/qmltypenamescriptclass_p.h index c642ea4..3bd51e6 100644 --- a/src/declarative/qml/qmltypenamescriptclass_p.h +++ b/src/declarative/qml/qmltypenamescriptclass_p.h @@ -71,11 +71,11 @@ public: QScriptValue newObject(QObject *, QmlTypeNameCache *); protected: - virtual QScriptClass::QueryFlags queryProperty(const Object &, const Identifier &, + virtual QScriptClass::QueryFlags queryProperty(Object *, const Identifier &, QScriptClass::QueryFlags flags); - virtual QScriptValue property(const Object &, const Identifier &); - virtual void setProperty(const Object &, const Identifier &name, const QScriptValue &); + virtual QScriptValue property(Object *, const Identifier &); + virtual void setProperty(Object *, const Identifier &name, const QScriptValue &); private: QmlEngine *engine; -- cgit v0.12 From 44638d0f310aad59336ad44f427351a4b9c40f15 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Fri, 2 Oct 2009 18:28:37 +1000 Subject: Implement QmlValueTypeScriptClass::newObject() --- src/declarative/qml/qmlvaluetypescriptclass.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/declarative/qml/qmlvaluetypescriptclass.cpp b/src/declarative/qml/qmlvaluetypescriptclass.cpp index da6c73d..503d64f 100644 --- a/src/declarative/qml/qmlvaluetypescriptclass.cpp +++ b/src/declarative/qml/qmlvaluetypescriptclass.cpp @@ -63,7 +63,8 @@ QmlValueTypeScriptClass::~QmlValueTypeScriptClass() QScriptValue QmlValueTypeScriptClass::newObject(QObject *object, int coreIndex, QmlValueType *type) { QmlValueTypeReference ref = { type, object, coreIndex }; - return QScriptValue(); + QScriptEngine *scriptEngine = QmlEnginePrivate::getScriptEngine(engine); + return scriptEngine->newObject(this, scriptEngine->newVariant(qVariantFromValue(ref))); } QmlValueTypeScriptClass::QueryFlags -- cgit v0.12 From a6a2a2373c63ec3c67be62814bc3391de1338883 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Fri, 2 Oct 2009 18:33:28 +1000 Subject: Crash --- src/declarative/qml/qmltypenamescriptclass.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/declarative/qml/qmltypenamescriptclass.cpp b/src/declarative/qml/qmltypenamescriptclass.cpp index 7c5e5b0..61b57c4 100644 --- a/src/declarative/qml/qmltypenamescriptclass.cpp +++ b/src/declarative/qml/qmltypenamescriptclass.cpp @@ -125,13 +125,15 @@ QmlTypeNameScriptClass::queryProperty(Object *obj, const Identifier &name, } } return 0; - } else { + } else if (data->object) { // Must be an attached property object = qmlAttachedPropertiesObjectById(data->type->index(), data->object); if (!object) return 0; return ep->objectClass->queryProperty(object, name, flags); } } + + return 0; } QScriptValue QmlTypeNameScriptClass::property(Object *obj, const Identifier &name) -- cgit v0.12 From b4001abf71b3335cedfaf72ca3b7f25ea46be35c Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Fri, 2 Oct 2009 18:37:42 +1000 Subject: Add attached property ECMAScript test --- .../declarative/qmlecmascript/data/attachedProperty.qml | 11 +++++++++++ tests/auto/declarative/qmlecmascript/tst_qmlecmascript.cpp | 14 ++++++++++++++ 2 files changed, 25 insertions(+) create mode 100644 tests/auto/declarative/qmlecmascript/data/attachedProperty.qml diff --git a/tests/auto/declarative/qmlecmascript/data/attachedProperty.qml b/tests/auto/declarative/qmlecmascript/data/attachedProperty.qml new file mode 100644 index 0000000..c5088e3 --- /dev/null +++ b/tests/auto/declarative/qmlecmascript/data/attachedProperty.qml @@ -0,0 +1,11 @@ +import Qt.test 1.0 +import Qt.test 1.0 as Namespace + +MyQmlObject { + id: Me + property int a: MyQmlObject.value + property int b: Namespace.MyQmlObject.value + property int c: Me.Namespace.MyQmlObject.value + property int d: Me.Namespace.MyQmlObject.value +} + diff --git a/tests/auto/declarative/qmlecmascript/tst_qmlecmascript.cpp b/tests/auto/declarative/qmlecmascript/tst_qmlecmascript.cpp index d5d20b6..eca4b92 100644 --- a/tests/auto/declarative/qmlecmascript/tst_qmlecmascript.cpp +++ b/tests/auto/declarative/qmlecmascript/tst_qmlecmascript.cpp @@ -44,6 +44,7 @@ private slots: void objectPropertiesTriggerReeval(); void deferredProperties(); void extensionObjects(); + void attachedProperties(); void enums(); void valueTypeFunctions(); void constantsOverrideBindings(); @@ -379,6 +380,19 @@ void tst_qmlecmascript::extensionObjects() QCOMPARE(object->baseProperty(), 92); } +void tst_qmlecmascript::attachedProperties() +{ + QmlComponent component(&engine, TEST_FILE("attachedProperty.qml")); + QObject *object = component.create(); + QVERIFY(object != 0); + QCOMPARE(object->property("a").toInt(), 19); + QCOMPARE(object->property("b").toInt(), 19); + QCOMPARE(object->property("c").toInt(), 19); + QCOMPARE(object->property("d").toInt(), 19); + + // ### Need to test attached property assignment +} + void tst_qmlecmascript::enums() { // Existant enums -- cgit v0.12 From 114adc64fe8deb7d59e608924355f64810f8fe64 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Fri, 2 Oct 2009 19:31:12 +1000 Subject: Fix attached properties/enums from ecmascript --- src/declarative/qml/qmlcontextscriptclass.cpp | 3 +- src/declarative/qml/qmlobjectscriptclass.cpp | 30 +++++++++++++++++-- src/declarative/qml/qmlobjectscriptclass_p.h | 7 ++++- src/declarative/qml/qmltypenamescriptclass.cpp | 41 ++++++++++++++------------ src/declarative/qml/qmltypenamescriptclass_p.h | 5 ++-- 5 files changed, 61 insertions(+), 25 deletions(-) diff --git a/src/declarative/qml/qmlcontextscriptclass.cpp b/src/declarative/qml/qmlcontextscriptclass.cpp index 4b149f7..8f45870 100644 --- a/src/declarative/qml/qmlcontextscriptclass.cpp +++ b/src/declarative/qml/qmlcontextscriptclass.cpp @@ -104,7 +104,8 @@ QmlContextScriptClass::queryProperty(Object *object, const Identifier &name, for (int ii = 0; ii < cp->defaultObjects.count(); ++ii) { QScriptClass::QueryFlags rv = - ep->objectClass->queryProperty(cp->defaultObjects.at(ii), name, flags); + ep->objectClass->queryProperty(cp->defaultObjects.at(ii), name, flags, + QmlObjectScriptClass::SkipAttachedProperties); if (rv) { lastDefaultObject = ii; diff --git a/src/declarative/qml/qmlobjectscriptclass.cpp b/src/declarative/qml/qmlobjectscriptclass.cpp index 33fd409..7c7b13f 100644 --- a/src/declarative/qml/qmlobjectscriptclass.cpp +++ b/src/declarative/qml/qmlobjectscriptclass.cpp @@ -42,7 +42,9 @@ #include "qmlobjectscriptclass_p.h" #include #include +#include #include +#include QT_BEGIN_NAMESPACE @@ -94,10 +96,11 @@ QmlObjectScriptClass::queryProperty(Object *object, const Identifier &name, QScriptClass::QueryFlags QmlObjectScriptClass::queryProperty(QObject *obj, const Identifier &name, - QScriptClass::QueryFlags flags) + QScriptClass::QueryFlags flags, QueryMode mode) { Q_UNUSED(flags); lastData = 0; + lastTNData = 0; if (name == m_destroyId.identifier || name == m_toStringId.identifier) @@ -107,6 +110,22 @@ QmlObjectScriptClass::queryProperty(QObject *obj, const Identifier &name, return 0; QmlEnginePrivate *enginePrivate = QmlEnginePrivate::get(engine); + + if (mode == IncludeAttachedProperties) { + QmlContext *evalContext = enginePrivate->currentExpression->context(); + QmlContextPrivate *cp = QmlContextPrivate::get(evalContext); + // ### Check for attached properties + + if (cp->imports) { + QmlTypeNameCache::Data *data = cp->imports->data(name); + if (data) { + lastTNData = data; + return QScriptClass::HandlesReadAccess; + } + } + + } + QmlPropertyCache *cache = 0; QmlDeclarativeData *ddata = QmlDeclarativeData::get(obj); if (ddata) @@ -150,7 +169,14 @@ QScriptValue QmlObjectScriptClass::property(QObject *obj, const Identifier &name QScriptEngine *scriptEngine = QmlEnginePrivate::getScriptEngine(engine); QmlEnginePrivate *enginePriv = QmlEnginePrivate::get(engine); - if (lastData->flags & QmlPropertyCache::Data::IsFunction) { + if (lastTNData) { + + if (lastTNData->type) + return enginePriv->typeNameClass->newObject(obj, lastTNData->type); + else + return enginePriv->typeNameClass->newObject(obj, lastTNData->typeNamespace); + + } else if (lastData->flags & QmlPropertyCache::Data::IsFunction) { // ### Optimize QScriptValue sobj = scriptEngine->newQObject(obj); return sobj.property(toString(name)); diff --git a/src/declarative/qml/qmlobjectscriptclass_p.h b/src/declarative/qml/qmlobjectscriptclass_p.h index 6406f0d..6de63ca 100644 --- a/src/declarative/qml/qmlobjectscriptclass_p.h +++ b/src/declarative/qml/qmlobjectscriptclass_p.h @@ -56,6 +56,7 @@ #include #include #include +#include QT_BEGIN_NAMESPACE @@ -71,8 +72,11 @@ public: QScriptValue newQObject(QObject *); QObject *toQObject(const QScriptValue &) const; + enum QueryMode { IncludeAttachedProperties, SkipAttachedProperties }; + QScriptClass::QueryFlags queryProperty(QObject *, const Identifier &, - QScriptClass::QueryFlags flags); + QScriptClass::QueryFlags flags, + QueryMode = IncludeAttachedProperties); QScriptValue property(QObject *, const Identifier &); void setProperty(QObject *, const Identifier &name, const QScriptValue &); @@ -85,6 +89,7 @@ protected: virtual QObject *toQObject(Object *, bool *ok = 0); private: + QmlTypeNameCache::Data *lastTNData; QmlPropertyCache::Data *lastData; QmlPropertyCache::Data local; diff --git a/src/declarative/qml/qmltypenamescriptclass.cpp b/src/declarative/qml/qmltypenamescriptclass.cpp index 61b57c4..4e1ac4b 100644 --- a/src/declarative/qml/qmltypenamescriptclass.cpp +++ b/src/declarative/qml/qmltypenamescriptclass.cpp @@ -46,8 +46,8 @@ QT_BEGIN_NAMESPACE struct TypeNameData : public QScriptDeclarativeClass::Object { - TypeNameData(QObject *o, QmlType *t) : object(o), type(t), typeNamespace(0) {} - TypeNameData(QObject *o, QmlTypeNameCache *n) : object(o), type(0), typeNamespace(n) { + TypeNameData(QObject *o, QmlType *t, QmlTypeNameScriptClass::TypeNameMode m) : object(o), type(t), typeNamespace(0), mode(m) {} + TypeNameData(QObject *o, QmlTypeNameCache *n, QmlTypeNameScriptClass::TypeNameMode m) : object(o), type(0), typeNamespace(n), mode(m) { if (typeNamespace) typeNamespace->addref(); } ~TypeNameData() { @@ -57,6 +57,7 @@ struct TypeNameData : public QScriptDeclarativeClass::Object { QObject *object; QmlType *type; QmlTypeNameCache *typeNamespace; + QmlTypeNameScriptClass::TypeNameMode mode; }; QmlTypeNameScriptClass::QmlTypeNameScriptClass(QmlEngine *bindEngine) @@ -69,21 +70,20 @@ QmlTypeNameScriptClass::~QmlTypeNameScriptClass() { } -QScriptValue QmlTypeNameScriptClass::newObject(QObject *object, QmlType *type) +QScriptValue QmlTypeNameScriptClass::newObject(QObject *object, QmlType *type, TypeNameMode mode) { QScriptEngine *scriptEngine = QmlEnginePrivate::getScriptEngine(engine); - return QScriptDeclarativeClass::newObject(scriptEngine, this, new TypeNameData(object, type)); + return QScriptDeclarativeClass::newObject(scriptEngine, this, new TypeNameData(object, type, mode)); } -QScriptValue QmlTypeNameScriptClass::newObject(QObject *object, QmlTypeNameCache *ns) +QScriptValue QmlTypeNameScriptClass::newObject(QObject *object, QmlTypeNameCache *ns, TypeNameMode mode) { QScriptEngine *scriptEngine = QmlEnginePrivate::getScriptEngine(engine); - return QScriptDeclarativeClass::newObject(scriptEngine, this, new TypeNameData(object, ns)); + return QScriptDeclarativeClass::newObject(scriptEngine, this, new TypeNameData(object, ns, mode)); } - QScriptClass::QueryFlags QmlTypeNameScriptClass::queryProperty(Object *obj, const Identifier &name, QScriptClass::QueryFlags flags) @@ -113,15 +113,17 @@ QmlTypeNameScriptClass::queryProperty(Object *obj, const Identifier &name, if (strName.at(0).isUpper()) { // Must be an enum - // ### Optimize - const char *enumName = strName.toUtf8().constData(); - const QMetaObject *metaObject = data->type->baseMetaObject(); - for (int ii = metaObject->enumeratorCount() - 1; ii >= 0; --ii) { - QMetaEnum e = metaObject->enumerator(ii); - int value = e.keyToValue(enumName); - if (value != -1) { - enumValue = value; - return QScriptClass::HandlesReadAccess; + if (data->mode == IncludeEnums) { + // ### Optimize + const char *enumName = strName.toUtf8().constData(); + const QMetaObject *metaObject = data->type->baseMetaObject(); + for (int ii = metaObject->enumeratorCount() - 1; ii >= 0; --ii) { + QMetaEnum e = metaObject->enumerator(ii); + int value = e.keyToValue(enumName); + if (value != -1) { + enumValue = value; + return QScriptClass::HandlesReadAccess; + } } } return 0; @@ -129,7 +131,8 @@ QmlTypeNameScriptClass::queryProperty(Object *obj, const Identifier &name, // Must be an attached property object = qmlAttachedPropertiesObjectById(data->type->index(), data->object); if (!object) return 0; - return ep->objectClass->queryProperty(object, name, flags); + return ep->objectClass->queryProperty(object, name, flags, + QmlObjectScriptClass::SkipAttachedProperties); } } @@ -140,9 +143,9 @@ QScriptValue QmlTypeNameScriptClass::property(Object *obj, const Identifier &nam { QmlEnginePrivate *ep = QmlEnginePrivate::get(engine); if (type) { - return newObject(object, type); + return newObject(((TypeNameData *)obj)->object, type, ((TypeNameData *)obj)->mode); } else if (object) { - return ep->objectClass->property(((TypeNameData *)obj)->object, name); + return ep->objectClass->property(object, name); } else { return QScriptValue(enumValue); } diff --git a/src/declarative/qml/qmltypenamescriptclass_p.h b/src/declarative/qml/qmltypenamescriptclass_p.h index 3bd51e6..d8112d2 100644 --- a/src/declarative/qml/qmltypenamescriptclass_p.h +++ b/src/declarative/qml/qmltypenamescriptclass_p.h @@ -67,8 +67,9 @@ public: QmlTypeNameScriptClass(QmlEngine *); ~QmlTypeNameScriptClass(); - QScriptValue newObject(QObject *, QmlType *); - QScriptValue newObject(QObject *, QmlTypeNameCache *); + enum TypeNameMode { IncludeEnums, ExcludeEnums }; + QScriptValue newObject(QObject *, QmlType *, TypeNameMode = IncludeEnums); + QScriptValue newObject(QObject *, QmlTypeNameCache *, TypeNameMode = IncludeEnums); protected: virtual QScriptClass::QueryFlags queryProperty(Object *, const Identifier &, -- cgit v0.12 From 43d3c9127e36b8f3134a173736d63140b381899f Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Fri, 2 Oct 2009 23:51:09 +1000 Subject: Fix test failures --- src/declarative/qml/qmlbinding.h | 1 + src/declarative/qml/qmlcontextscriptclass.cpp | 2 +- src/declarative/qml/qmlexpression.cpp | 20 ++++++-------------- src/declarative/qml/qmlmetaproperty.cpp | 16 +++++++++++----- src/declarative/qml/qmlmetaproperty_p.h | 1 + src/declarative/qml/qmlobjectscriptclass.cpp | 11 +++++++---- src/declarative/qml/qmlpropertycache.cpp | 2 ++ src/declarative/qml/qmlvaluetypescriptclass.cpp | 2 +- 8 files changed, 30 insertions(+), 25 deletions(-) diff --git a/src/declarative/qml/qmlbinding.h b/src/declarative/qml/qmlbinding.h index 675917d..e3a297c 100644 --- a/src/declarative/qml/qmlbinding.h +++ b/src/declarative/qml/qmlbinding.h @@ -73,6 +73,7 @@ public: private: friend class QmlDeclarativeData; friend class QmlMetaProperty; + friend class QmlMetaPropertyPrivate; friend class QmlVME; QObject *m_object; diff --git a/src/declarative/qml/qmlcontextscriptclass.cpp b/src/declarative/qml/qmlcontextscriptclass.cpp index 8f45870..226c34c 100644 --- a/src/declarative/qml/qmlcontextscriptclass.cpp +++ b/src/declarative/qml/qmlcontextscriptclass.cpp @@ -146,7 +146,7 @@ QScriptValue QmlContextScriptClass::property(Object *object, const Identifier &n rv = ep->objectClass->newQObject(cp->idValues[lastPropertyIndex].data()); } else { QVariant value = cp->propertyValues.at(lastPropertyIndex); - return ep->scriptValueFromVariant(value); + rv = ep->scriptValueFromVariant(value); } ep->capturedProperties << diff --git a/src/declarative/qml/qmlexpression.cpp b/src/declarative/qml/qmlexpression.cpp index adf5261..61c14a9 100644 --- a/src/declarative/qml/qmlexpression.cpp +++ b/src/declarative/qml/qmlexpression.cpp @@ -296,13 +296,8 @@ QVariant QmlExpressionPrivate::evalQtScript(QObject *secondaryScope) QList list; for (int ii = 0; ii < length; ++ii) { QScriptValue arrayItem = svalue.property(ii); - QObject *d = - qvariant_cast(arrayItem.data().toVariant()); - if (d) { - list << d; - } else { - list << 0; - } + QObject *d = arrayItem.toQObject(); + list << d; } rv = QVariant::fromValue(list); } @@ -316,13 +311,10 @@ QVariant QmlExpressionPrivate::evalQtScript(QObject *secondaryScope) !svalue.isQMetaObject() && !svalue.isQObject() && !svalue.isRegExp()) { - QScriptValue objValue = svalue.data(); - if (objValue.isValid()) { - QVariant var = objValue.toVariant(); - if (var.userType() >= (int)QVariant::UserType && - QmlMetaType::isObject(var.userType())) - rv = var; - } + + QObject *o = svalue.toQObject(); + if (o) + return qVariantFromValue(o); } if (rv.isNull()) rv = svalue.toVariant(); diff --git a/src/declarative/qml/qmlmetaproperty.cpp b/src/declarative/qml/qmlmetaproperty.cpp index 477377e..155b34a 100644 --- a/src/declarative/qml/qmlmetaproperty.cpp +++ b/src/declarative/qml/qmlmetaproperty.cpp @@ -564,14 +564,20 @@ QmlMetaProperty::setBinding(QmlAbstractBinding *newBinding) const if (!isProperty() || (type() & Attached) || !d->object) return 0; - QmlDeclarativeData *data = - QmlDeclarativeData::get(d->object, 0 != newBinding); + d->setBinding(d->object, d->core, newBinding); +} + +QmlAbstractBinding * +QmlMetaPropertyPrivate::setBinding(QObject *object, const QmlPropertyCache::Data &core, + QmlAbstractBinding *newBinding) +{ + QmlDeclarativeData *data = QmlDeclarativeData::get(object, 0 != newBinding); - if (data && data->hasBindingBit(d->core.coreIndex)) { + if (data && data->hasBindingBit(core.coreIndex)) { QmlAbstractBinding *binding = data->bindings; while (binding) { // ### This wont work for value types - if (binding->propertyIndex() == d->core.coreIndex) { + if (binding->propertyIndex() == core.coreIndex) { binding->setEnabled(false); if (newBinding) @@ -1124,7 +1130,7 @@ void QmlMetaProperty::restore(quint32 id, QObject *obj, QmlContext *ctxt) d->core.load(p); d->valueTypeCoreIdx = valueTypeIdx; - d->valueTypePropType = p.userType(); + d->valueTypePropType = p2.userType(); } else if (type & Property) { QmlPropertyCache *cache = enginePrivate?enginePrivate->cache(obj):0; diff --git a/src/declarative/qml/qmlmetaproperty_p.h b/src/declarative/qml/qmlmetaproperty_p.h index 729236b..00b9c3a 100644 --- a/src/declarative/qml/qmlmetaproperty_p.h +++ b/src/declarative/qml/qmlmetaproperty_p.h @@ -101,6 +101,7 @@ public: QVariant readValueProperty(); void writeValueProperty(const QVariant &, QmlMetaProperty::WriteSource); static void write(QObject *, const QmlPropertyCache::Data &, const QVariant &, QmlContext *); + static QmlAbstractBinding *setBinding(QObject *, const QmlPropertyCache::Data &, QmlAbstractBinding *); static quint32 saveValueType(int, int); static quint32 saveProperty(int); diff --git a/src/declarative/qml/qmlobjectscriptclass.cpp b/src/declarative/qml/qmlobjectscriptclass.cpp index 7c7b13f..2d5991c 100644 --- a/src/declarative/qml/qmlobjectscriptclass.cpp +++ b/src/declarative/qml/qmlobjectscriptclass.cpp @@ -45,6 +45,7 @@ #include #include #include +#include QT_BEGIN_NAMESPACE @@ -181,6 +182,11 @@ QScriptValue QmlObjectScriptClass::property(QObject *obj, const Identifier &name QScriptValue sobj = scriptEngine->newQObject(obj); return sobj.property(toString(name)); } else { + if (!(lastData->flags & QmlPropertyCache::Data::IsConstant)) { + enginePriv->capturedProperties << + QmlEnginePrivate::CapturedProperty(obj, lastData->coreIndex, lastData->notifyIndex); + } + if ((uint)lastData->propType < QVariant::UserType) { QmlValueType *valueType = enginePriv->valueTypes[lastData->propType]; if (valueType) @@ -188,10 +194,6 @@ QScriptValue QmlObjectScriptClass::property(QObject *obj, const Identifier &name } QVariant var = obj->metaObject()->property(lastData->coreIndex).read(obj); - if (!(lastData->flags & QmlPropertyCache::Data::IsConstant)) { - enginePriv->capturedProperties << - QmlEnginePrivate::CapturedProperty(obj, lastData->coreIndex, lastData->notifyIndex); - } if (lastData->flags & QmlPropertyCache::Data::IsQObjectDerived) { QObject *rv = *(QObject **)var.constData(); @@ -223,6 +225,7 @@ void QmlObjectScriptClass::setProperty(QObject *obj, // ### Can well known types be optimized? QVariant v = QmlScriptClass::toVariant(engine, value); + delete QmlMetaPropertyPrivate::setBinding(obj, *lastData, 0); QmlMetaPropertyPrivate::write(obj, *lastData, v, enginePriv->currentExpression->context()); } diff --git a/src/declarative/qml/qmlpropertycache.cpp b/src/declarative/qml/qmlpropertycache.cpp index d7b087b..300bbf6 100644 --- a/src/declarative/qml/qmlpropertycache.cpp +++ b/src/declarative/qml/qmlpropertycache.cpp @@ -48,6 +48,8 @@ QT_BEGIN_NAMESPACE void QmlPropertyCache::Data::load(const QMetaProperty &p) { propType = p.userType(); + if (propType == QVariant::LastType) + propType = qMetaTypeId(); coreIndex = p.propertyIndex(); notifyIndex = p.notifySignalIndex(); name = QLatin1String(p.name()); diff --git a/src/declarative/qml/qmlvaluetypescriptclass.cpp b/src/declarative/qml/qmlvaluetypescriptclass.cpp index 503d64f..6fd674a 100644 --- a/src/declarative/qml/qmlvaluetypescriptclass.cpp +++ b/src/declarative/qml/qmlvaluetypescriptclass.cpp @@ -112,7 +112,7 @@ QScriptValue QmlValueTypeScriptClass::property(const QScriptValue &object, QMetaProperty p = ref.type->metaObject()->property(id); QVariant rv = p.read(ref.type); - return static_cast(QObjectPrivate::get(engine))->scriptEngine.newVariant(rv); + return static_cast(QObjectPrivate::get(engine))->scriptValueFromVariant(rv); } void QmlValueTypeScriptClass::setProperty(QScriptValue &object, -- cgit v0.12 From b2c1ddf00ba2c3395dbfca417540153ea173a870 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Sat, 3 Oct 2009 00:08:03 +1000 Subject: Use QMetaObject::indexOfProperty() This is both more efficient, and allows the creation of dynamic properties. --- src/declarative/qml/qmlpropertycache.cpp | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/declarative/qml/qmlpropertycache.cpp b/src/declarative/qml/qmlpropertycache.cpp index 300bbf6..63ce00c 100644 --- a/src/declarative/qml/qmlpropertycache.cpp +++ b/src/declarative/qml/qmlpropertycache.cpp @@ -111,14 +111,10 @@ QmlPropertyCache::Data QmlPropertyCache::create(const QMetaObject *metaObject, QmlPropertyCache::Data rv; - int propCount = metaObject->propertyCount(); - for (int ii = propCount - 1; ii >= 0; --ii) { - QMetaProperty p = metaObject->property(ii); - QString propName = QLatin1String(p.name()); - if (propName == property) { - rv.load(p); - return rv; - } + int idx = metaObject->indexOfProperty(property.toUtf8()); + if (idx != -1) { + rv.load(metaObject->property(idx)); + return rv; } int methodCount = metaObject->methodCount(); -- cgit v0.12 From ff93f4ef4a0effef760964e32cdb77049f19f8ad Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Mon, 5 Oct 2009 15:12:21 +1100 Subject: Compile against updated JSC --- .../JavaScriptCore/runtime/Executable.cpp | 20 +++++++++++------ .../JavaScriptCore/runtime/Executable.h | 1 + src/script/api/qscriptengine.cpp | 26 +++++++++++++++------- src/script/bridge/qscriptdeclarativeclass.cpp | 4 ++-- src/script/bridge/qscriptdeclarativeobject.cpp | 8 +++---- src/script/bridge/qscriptdeclarativeobject_p.h | 7 +++--- 6 files changed, 42 insertions(+), 24 deletions(-) diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Executable.cpp b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Executable.cpp index 5e79794..3df5a84 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Executable.cpp +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Executable.cpp @@ -59,13 +59,8 @@ FunctionExecutable::~FunctionExecutable() delete m_codeBlock; } -JSObject* EvalExecutable::compile(ExecState* exec, ScopeChainNode* scopeChainNode) +void EvalExecutable::compile(ExecState*exec, RefPtr &evalNode, ScopeChainNode* scopeChainNode) { - int errLine; - UString errMsg; - RefPtr evalNode = exec->globalData().parser->parse(&exec->globalData(), exec->lexicalGlobalObject()->debugger(), exec, m_source, &errLine, &errMsg); - if (!evalNode) - return Error::create(exec, SyntaxError, errMsg, errLine, m_source.provider()->asID(), m_source.provider()->url()); recordParse(evalNode->features(), evalNode->lineNo(), evalNode->lastLine()); ScopeChain scopeChain(scopeChainNode); @@ -75,7 +70,18 @@ JSObject* EvalExecutable::compile(ExecState* exec, ScopeChainNode* scopeChainNod m_evalCodeBlock = new EvalCodeBlock(this, globalObject, source().provider(), scopeChain.localDepth()); OwnPtr generator(new BytecodeGenerator(evalNode.get(), globalObject->debugger(), scopeChain, m_evalCodeBlock->symbolTable(), m_evalCodeBlock)); generator->generate(); - +} + +JSObject* EvalExecutable::compile(ExecState* exec, ScopeChainNode* scopeChainNode) +{ + int errLine; + UString errMsg; + RefPtr evalNode = exec->globalData().parser->parse(&exec->globalData(), exec->lexicalGlobalObject()->debugger(), exec, m_source, &errLine, &errMsg); + if (!evalNode) + return Error::create(exec, SyntaxError, errMsg, errLine, m_source.provider()->asID(), m_source.provider()->url()); + + compile(exec, evalNode, scopeChainNode); + evalNode->destroyData(); return 0; } diff --git a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Executable.h b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Executable.h index f3003dd..8d6a668 100644 --- a/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Executable.h +++ b/src/3rdparty/javascriptcore/JavaScriptCore/runtime/Executable.h @@ -155,6 +155,7 @@ namespace JSC { } JSObject* compile(ExecState*, ScopeChainNode*); + void compile(ExecState*, RefPtr &, ScopeChainNode*); ExceptionInfo* reparseExceptionInfo(JSGlobalData*, ScopeChainNode*, CodeBlock*); static PassRefPtr create(const SourceCode& source) { return adoptRef(new EvalExecutable(source)); } diff --git a/src/script/api/qscriptengine.cpp b/src/script/api/qscriptengine.cpp index 7256f27..2bb6eae 100644 --- a/src/script/api/qscriptengine.cpp +++ b/src/script/api/qscriptengine.cpp @@ -344,6 +344,7 @@ class QScriptProgramPrivate { public: QScriptProgramPrivate() : refcount(1), hasException(false) { } + ~QScriptProgramPrivate() { if (evalNode) evalNode->destroyData(); } void addref() { ++refcount; } void release() { if (--refcount) delete this; } @@ -2143,15 +2144,17 @@ QScriptProgram QScriptEngine::compile(const QString &program, const QString &fil QBoolBlocker inEval(d->inEval, true); currentContext()->activationObject(); //force the creation of a context for native function; + JSC::Debugger* debugger = d->originalGlobalObject()->debugger(); + JSC::UString jscProgram = program; JSC::UString jscFileName = fileName; JSC::ExecState* exec = d->currentFrame; - + WTF::PassRefPtr provider + = QScript::UStringSourceProviderWithFeedback::create(jscProgram, jscFileName, lineNumber, d); + intptr_t sourceId = provider->asID(); JSC::SourceCode &source = rv.d->source; - source = JSC::makeSource(jscProgram, jscFileName, lineNumber); + source = JSC::SourceCode(provider, lineNumber); //after construction of SourceCode provider variable will be null. - intptr_t sourceId = source.provider()->asID(); - JSC::Debugger* debugger = d->originalGlobalObject()->debugger(); if (debugger) debugger->evaluateStart(sourceId); @@ -2161,9 +2164,9 @@ QScriptProgram QScriptEngine::compile(const QString &program, const QString &fil int errorLine; JSC::UString errorMessage; WTF::RefPtr &evalNode = rv.d->evalNode; - evalNode = exec->globalData().parser->parse(exec, exec->dynamicGlobalObject()->debugger(), source, &errorLine, &errorMessage); + evalNode = exec->globalData().parser->parse(&exec->globalData(), exec->lexicalGlobalObject()->debugger(), exec, source, &errorLine, &errorMessage); if (!evalNode) { - JSC::JSValue exceptionValue = JSC::Error::create(exec, JSC::SyntaxError, errorMessage, errorLine, source.provider()->asID(), 0); + JSC::JSValue exceptionValue = JSC::Error::create(exec, JSC::SyntaxError, errorMessage, errorLine, source.provider()->asID(), source.provider()->url()); exec->setException(exceptionValue); if (debugger) { @@ -2195,10 +2198,12 @@ QScriptValue QScriptEngine::evaluate(const QScriptProgram &program) QBoolBlocker inEval(d->inEval, true); currentContext()->activationObject(); //force the creation of a context for native function; + JSC::Debugger* debugger = d->originalGlobalObject()->debugger(); + JSC::ExecState* exec = d->currentFrame; intptr_t sourceId = program.d->source.provider()->asID(); - JSC::Debugger* debugger = d->originalGlobalObject()->debugger(); + if (debugger) debugger->evaluateStart(sourceId); @@ -2207,11 +2212,16 @@ QScriptValue QScriptEngine::evaluate(const QScriptProgram &program) WTF::RefPtr &evalNode = program.d->evalNode; + JSC::EvalExecutable executable(program.d->source); + executable.compile(exec, evalNode, exec->scopeChain()); + JSC::JSValue thisValue = d->thisForContext(exec); JSC::JSObject* thisObject = (!thisValue || thisValue.isUndefinedOrNull()) ? exec->dynamicGlobalObject() : thisValue.toObject(exec); JSC::JSValue exceptionValue; d->timeoutChecker()->setShouldAbort(false); - JSC::JSValue result = exec->interpreter()->execute(evalNode.get(), exec, thisObject, exec->scopeChain(), &exceptionValue); + if (d->processEventsInterval > 0) + d->timeoutChecker()->reset(); + JSC::JSValue result = exec->interpreter()->execute(&executable, exec, thisObject, exec->scopeChain(), &exceptionValue); if (d->timeoutChecker()->shouldAbort()) { if (d->abortResult.isError()) diff --git a/src/script/bridge/qscriptdeclarativeclass.cpp b/src/script/bridge/qscriptdeclarativeclass.cpp index 62c1afc..b990e33 100644 --- a/src/script/bridge/qscriptdeclarativeclass.cpp +++ b/src/script/bridge/qscriptdeclarativeclass.cpp @@ -110,7 +110,7 @@ QScriptValue QScriptDeclarativeClass::newObject(QScriptEngine *engine, QScriptDeclarativeClass *QScriptDeclarativeClass::scriptClass(const QScriptValue &v) { QScriptValuePrivate *d = QScriptValuePrivate::get(v); - if (!d || !d->isJSC() || !d->jscValue.isObject(&QScriptObject::info)) + if (!d || !d->isJSC() || !d->jscValue.inherits(&QScriptObject::info)) return 0; QScriptObject *scriptObject = static_cast(JSC::asObject(d->jscValue)); QScriptObjectDelegate *delegate = scriptObject->delegate(); @@ -122,7 +122,7 @@ QScriptDeclarativeClass *QScriptDeclarativeClass::scriptClass(const QScriptValue QScriptDeclarativeClass::Object *QScriptDeclarativeClass::object(const QScriptValue &v) { QScriptValuePrivate *d = QScriptValuePrivate::get(v); - if (!d || !d->isJSC() || !d->jscValue.isObject(&QScriptObject::info)) + if (!d || !d->isJSC() || !d->jscValue.inherits(&QScriptObject::info)) return 0; QScriptObject *scriptObject = static_cast(JSC::asObject(d->jscValue)); QScriptObjectDelegate *delegate = scriptObject->delegate(); diff --git a/src/script/bridge/qscriptdeclarativeobject.cpp b/src/script/bridge/qscriptdeclarativeobject.cpp index aa811d1..ef77de0 100644 --- a/src/script/bridge/qscriptdeclarativeobject.cpp +++ b/src/script/bridge/qscriptdeclarativeobject.cpp @@ -149,9 +149,9 @@ bool DeclarativeObjectDelegate::getPropertyAttributes(const QScriptObject* objec return QScriptObjectDelegate::getPropertyAttributes(object, exec, propertyName, attribs); } -void DeclarativeObjectDelegate::getPropertyNames(QScriptObject* object, JSC::ExecState *exec, - JSC::PropertyNameArray &propertyNames, - unsigned listedAttributes) +void DeclarativeObjectDelegate::getOwnPropertyNames(QScriptObject* object, JSC::ExecState *exec, + JSC::PropertyNameArray &propertyNames, + bool includeNonEnumerable) { QStringList properties = m_class->propertyNames(m_object); for (int ii = 0; ii < properties.count(); ++ii) { @@ -159,7 +159,7 @@ void DeclarativeObjectDelegate::getPropertyNames(QScriptObject* object, JSC::Exe propertyNames.add(JSC::Identifier(exec, name)); } - QScriptObjectDelegate::getPropertyNames(object, exec, propertyNames, listedAttributes); + QScriptObjectDelegate::getOwnPropertyNames(object, exec, propertyNames, includeNonEnumerable); } JSC::CallType DeclarativeObjectDelegate::getCallData(QScriptObject *object, JSC::CallData &callData) diff --git a/src/script/bridge/qscriptdeclarativeobject_p.h b/src/script/bridge/qscriptdeclarativeobject_p.h index ccb07bc..9c14774 100644 --- a/src/script/bridge/qscriptdeclarativeobject_p.h +++ b/src/script/bridge/qscriptdeclarativeobject_p.h @@ -55,6 +55,7 @@ #include +#include "config.h" #include "qscriptobject_p.h" #include "qscriptdeclarativeclass_p.h" @@ -88,9 +89,9 @@ public: virtual bool getPropertyAttributes(const QScriptObject*, JSC::ExecState*, const JSC::Identifier&, unsigned&) const; - virtual void getPropertyNames(QScriptObject*, JSC::ExecState*, - JSC::PropertyNameArray&, - unsigned listedAttributes = JSC::Structure::Prototype); + virtual void getOwnPropertyNames(QScriptObject*, JSC::ExecState*, + JSC::PropertyNameArray&, + bool includeNonEnumerable = false); virtual JSC::CallType getCallData(QScriptObject*, JSC::CallData&); virtual JSC::ConstructType getConstructData(QScriptObject*, JSC::ConstructData&); -- cgit v0.12 From c4a7ff8d05c157c9ad628554b94d62a03b69f584 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Mon, 5 Oct 2009 16:05:42 +1000 Subject: Add scope auto test --- .../auto/declarative/qmlecmascript/data/scope.qml | 42 ++++++++++++++++++++++ .../qmlecmascript/tst_qmlecmascript.cpp | 18 ++++++++++ 2 files changed, 60 insertions(+) create mode 100644 tests/auto/declarative/qmlecmascript/data/scope.qml diff --git a/tests/auto/declarative/qmlecmascript/data/scope.qml b/tests/auto/declarative/qmlecmascript/data/scope.qml new file mode 100644 index 0000000..87155d1 --- /dev/null +++ b/tests/auto/declarative/qmlecmascript/data/scope.qml @@ -0,0 +1,42 @@ +import Qt 4.6 + +Item { + id: Root + + property int a: 1 + property int binding: a + property string binding2: a + "Test" + property int binding3: myFunction() + property int binding4: myNestedFunction() + + Script { + function myFunction() { + return a; + } + } + + Item { + id: NestedObject + + Script { + function myNestedFunction() { + return a; + } + } + + property int a: 2 + property int binding: a + property string binding2: a + "Test" + property int binding3: myFunction() + property int binding4: myNestedFunction() + } + + property alias test1: Root.binding + property alias test2: NestedObject.binding + property alias test3: Root.binding2 + property alias test4: NestedObject.binding2 + property alias test5: Root.binding3 + property alias test6: NestedObject.binding3 + property alias test7: Root.binding4 + property alias test8: NestedObject.binding4 +} diff --git a/tests/auto/declarative/qmlecmascript/tst_qmlecmascript.cpp b/tests/auto/declarative/qmlecmascript/tst_qmlecmascript.cpp index eca4b92..00c3475 100644 --- a/tests/auto/declarative/qmlecmascript/tst_qmlecmascript.cpp +++ b/tests/auto/declarative/qmlecmascript/tst_qmlecmascript.cpp @@ -51,6 +51,7 @@ private slots: void outerBindingOverridesInnerBinding(); void aliasPropertyAndBinding(); void nonExistantAttachedObject(); + void scope(); private: QmlEngine engine; @@ -525,6 +526,23 @@ void tst_qmlecmascript::nonExistantAttachedObject() QVERIFY(object != 0); } +void tst_qmlecmascript::scope() +{ + QmlComponent component(&engine, TEST_FILE("scope.qml")); + qWarning() << component.errors(); + QObject *object = component.create(); + QVERIFY(object != 0); + + QCOMPARE(object->property("test1").toInt(), 1); + QCOMPARE(object->property("test2").toInt(), 2); + QCOMPARE(object->property("test3").toString(), QString("1Test")); + QCOMPARE(object->property("test4").toString(), QString("2Test")); + QCOMPARE(object->property("test5").toInt(), 1); + QCOMPARE(object->property("test6").toInt(), 1); + QCOMPARE(object->property("test7").toInt(), 2); + QCOMPARE(object->property("test8").toInt(), 2); +} + /* Confirm bindings and alias properties can coexist. -- cgit v0.12 From b411c4db37bcbb5152bf8e8b225e259c05c46b59 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Mon, 5 Oct 2009 18:37:48 +1000 Subject: Support all variant types as signal parameters --- src/declarative/qml/qmlmetatype.cpp | 206 +++++++++++++++++++-- .../qmlecmascript/data/signalParameterTypes.qml | 16 ++ .../qmlecmascript/tst_qmlecmascript.cpp | 16 +- 3 files changed, 219 insertions(+), 19 deletions(-) create mode 100644 tests/auto/declarative/qmlecmascript/data/signalParameterTypes.qml diff --git a/src/declarative/qml/qmlmetatype.cpp b/src/declarative/qml/qmlmetatype.cpp index 14d85ff..663e8e0 100644 --- a/src/declarative/qml/qmlmetatype.cpp +++ b/src/declarative/qml/qmlmetatype.cpp @@ -929,6 +929,30 @@ QList QmlMetaType::qmlTypes() return data->nameToType.values(); } +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//#include +#include +#include +#include +#include +#include +#include +#include +#include + /*! 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 @@ -988,7 +1012,6 @@ bool QmlMetaType::copy(int type, void *data, const void *copy) case QMetaType::QChar: *static_cast(data) = *static_cast(copy); return true; -#ifndef QT_BOOTSTRAPPED case QMetaType::QVariantMap: *static_cast(data) = *static_cast(copy); return true; @@ -998,7 +1021,6 @@ bool QmlMetaType::copy(int type, void *data, const void *copy) case QMetaType::QVariantList: *static_cast(data) = *static_cast(copy); return true; -#endif case QMetaType::QByteArray: *static_cast(data) = *static_cast(copy); return true; @@ -1008,11 +1030,9 @@ bool QmlMetaType::copy(int type, void *data, const void *copy) case QMetaType::QStringList: *static_cast(data) = *static_cast(copy); return true; -#ifndef QT_BOOTSTRAPPED case QMetaType::QBitArray: *static_cast(data) = *static_cast(copy); return true; -#endif case QMetaType::QDate: *static_cast(data) = *static_cast(copy); return true; @@ -1022,15 +1042,12 @@ bool QmlMetaType::copy(int type, void *data, const void *copy) case QMetaType::QDateTime: *static_cast(data) = *static_cast(copy); return true; -#ifndef QT_BOOTSTRAPPED case QMetaType::QUrl: *static_cast(data) = *static_cast(copy); return true; -#endif case QMetaType::QLocale: *static_cast(data) = *static_cast(copy); return true; -#ifndef QT_NO_GEOM_VARIANT case QMetaType::QRect: *static_cast(data) = *static_cast(copy); return true; @@ -1058,7 +1075,6 @@ bool QmlMetaType::copy(int type, void *data, const void *copy) case QMetaType::QVector3D: *static_cast(data) = *static_cast(copy); return true; -#endif #ifndef QT_NO_REGEXP case QMetaType::QRegExp: *static_cast(data) = *static_cast(copy); @@ -1066,8 +1082,90 @@ bool QmlMetaType::copy(int type, void *data, const void *copy) #endif case QMetaType::Void: return true; + + +#ifdef QT3_SUPPORT + case QMetaType::QColorGroup: + *static_cast(data) = *static_cast(copy); + return true; +#endif + + case QMetaType::QFont: + *static_cast(data) = *static_cast(copy); + return true; + case QMetaType::QPixmap: + *static_cast(data) = *static_cast(copy); + return true; + case QMetaType::QBrush: + *static_cast(data) = *static_cast(copy); + return true; + case QMetaType::QColor: + *static_cast(data) = *static_cast(copy); + return true; + case QMetaType::QPalette: + *static_cast(data) = *static_cast(copy); + return true; + case QMetaType::QIcon: + *static_cast(data) = *static_cast(copy); + return true; + case QMetaType::QImage: + *static_cast(data) = *static_cast(copy); + return true; + case QMetaType::QPolygon: + *static_cast(data) = *static_cast(copy); + return true; + case QMetaType::QRegion: + *static_cast(data) = *static_cast(copy); + return true; + case QMetaType::QBitmap: + *static_cast(data) = *static_cast(copy); + return true; + case QMetaType::QCursor: + *static_cast(data) = *static_cast(copy); + return true; + case QMetaType::QSizePolicy: + *static_cast(data) = *static_cast(copy); + return true; + case QMetaType::QKeySequence: + *static_cast(data) = *static_cast(copy); + return true; + case QMetaType::QPen: + *static_cast(data) = *static_cast(copy); + return true; + case QMetaType::QTextLength: + *static_cast(data) = *static_cast(copy); + return true; + case QMetaType::QTextFormat: + *static_cast(data) = *static_cast(copy); + return true; + case QMetaType::QMatrix: + *static_cast(data) = *static_cast(copy); + return true; + case QMetaType::QTransform: + *static_cast(data) = *static_cast(copy); + return true; + case QMetaType::QMatrix4x4: + *static_cast(data) = *static_cast(copy); + return true; + case QMetaType::QVector2D: + *static_cast(data) = *static_cast(copy); + return true; + case QMetaType::QVector4D: + *static_cast(data) = *static_cast(copy); + return true; + case QMetaType::QQuaternion: + *static_cast(data) = *static_cast(copy); + return true; + default: - ; + if (type == qMetaTypeId()) { + *static_cast(data) = *static_cast(copy); + return true; + } else if (typeCategory(type) != Unknown) { + *static_cast(data) = *static_cast(copy); + return true; + } + break; } } else { switch(type) { @@ -1118,7 +1216,6 @@ bool QmlMetaType::copy(int type, void *data, const void *copy) case QMetaType::QChar: *static_cast(data) = NS(QChar)(); return true; -#ifndef QT_BOOTSTRAPPED case QMetaType::QVariantMap: *static_cast(data) = NS(QVariantMap)(); return true; @@ -1128,7 +1225,6 @@ bool QmlMetaType::copy(int type, void *data, const void *copy) case QMetaType::QVariantList: *static_cast(data) = NS(QVariantList)(); return true; -#endif case QMetaType::QByteArray: *static_cast(data) = NS(QByteArray)(); return true; @@ -1138,11 +1234,9 @@ bool QmlMetaType::copy(int type, void *data, const void *copy) case QMetaType::QStringList: *static_cast(data) = NS(QStringList)(); return true; -#ifndef QT_BOOTSTRAPPED case QMetaType::QBitArray: *static_cast(data) = NS(QBitArray)(); return true; -#endif case QMetaType::QDate: *static_cast(data) = NS(QDate)(); return true; @@ -1152,15 +1246,12 @@ bool QmlMetaType::copy(int type, void *data, const void *copy) case QMetaType::QDateTime: *static_cast(data) = NS(QDateTime)(); return true; -#ifndef QT_BOOTSTRAPPED case QMetaType::QUrl: *static_cast(data) = NS(QUrl)(); return true; -#endif case QMetaType::QLocale: *static_cast(data) = NS(QLocale)(); return true; -#ifndef QT_NO_GEOM_VARIANT case QMetaType::QRect: *static_cast(data) = NS(QRect)(); return true; @@ -1188,7 +1279,6 @@ bool QmlMetaType::copy(int type, void *data, const void *copy) case QMetaType::QVector3D: *static_cast(data) = NS(QVector3D)(); return true; -#endif #ifndef QT_NO_REGEXP case QMetaType::QRegExp: *static_cast(data) = NS(QRegExp)(); @@ -1196,8 +1286,88 @@ bool QmlMetaType::copy(int type, void *data, const void *copy) #endif case QMetaType::Void: return true; + +#ifdef QT3_SUPPORT + case QMetaType::QColorGroup: + *static_cast(data) = NS(QColorGroup)(); + return true; +#endif + + case QMetaType::QFont: + *static_cast(data) = NS(QFont)(); + return true; + case QMetaType::QPixmap: + *static_cast(data) = NS(QPixmap)(); + return true; + case QMetaType::QBrush: + *static_cast(data) = NS(QBrush)(); + return true; + case QMetaType::QColor: + *static_cast(data) = NS(QColor)(); + return true; + case QMetaType::QPalette: + *static_cast(data) = NS(QPalette)(); + return true; + case QMetaType::QIcon: + *static_cast(data) = NS(QIcon)(); + return true; + case QMetaType::QImage: + *static_cast(data) = NS(QImage)(); + return true; + case QMetaType::QPolygon: + *static_cast(data) = NS(QPolygon)(); + return true; + case QMetaType::QRegion: + *static_cast(data) = NS(QRegion)(); + return true; + case QMetaType::QBitmap: + *static_cast(data) = NS(QBitmap)(); + return true; + case QMetaType::QCursor: + *static_cast(data) = NS(QCursor)(); + return true; + case QMetaType::QSizePolicy: + *static_cast(data) = NS(QSizePolicy)(); + return true; + case QMetaType::QKeySequence: + *static_cast(data) = NS(QKeySequence)(); + return true; + case QMetaType::QPen: + *static_cast(data) = NS(QPen)(); + return true; + case QMetaType::QTextLength: + *static_cast(data) = NS(QTextLength)(); + return true; + case QMetaType::QTextFormat: + *static_cast(data) = NS(QTextFormat)(); + return true; + case QMetaType::QMatrix: + *static_cast(data) = NS(QMatrix)(); + return true; + case QMetaType::QTransform: + *static_cast(data) = NS(QTransform)(); + return true; + case QMetaType::QMatrix4x4: + *static_cast(data) = NS(QMatrix4x4)(); + return true; + case QMetaType::QVector2D: + *static_cast(data) = NS(QVector2D)(); + return true; + case QMetaType::QVector4D: + *static_cast(data) = NS(QVector4D)(); + return true; + case QMetaType::QQuaternion: + *static_cast(data) = NS(QQuaternion)(); + return true; default: - ; + if (type == qMetaTypeId()) { + *static_cast(data) = NS(QVariant)(); + return true; + } else if (typeCategory(type) != Unknown) { + *static_cast(data) = 0; + return true; + } + break; } } diff --git a/tests/auto/declarative/qmlecmascript/data/signalParameterTypes.qml b/tests/auto/declarative/qmlecmascript/data/signalParameterTypes.qml new file mode 100644 index 0000000..42d26a1 --- /dev/null +++ b/tests/auto/declarative/qmlecmascript/data/signalParameterTypes.qml @@ -0,0 +1,16 @@ +import Qt.test 1.0 + +MyQmlObject +{ + id: Root + property int intProperty + property real realProperty + property color colorProperty + property var variantProperty + + signal mySignal(int a, real b, color c, var d) + + onMySignal: { intProperty = a; realProperty = b; colorProperty = c; variantProperty = d; } + + onBasicSignal: Root.mySignal(10, 19.2, Qt.rgba(1, 1, 0, 1), Qt.rgba(1, 0, 1, 1)) +} diff --git a/tests/auto/declarative/qmlecmascript/tst_qmlecmascript.cpp b/tests/auto/declarative/qmlecmascript/tst_qmlecmascript.cpp index 00c3475..65f7021 100644 --- a/tests/auto/declarative/qmlecmascript/tst_qmlecmascript.cpp +++ b/tests/auto/declarative/qmlecmascript/tst_qmlecmascript.cpp @@ -52,6 +52,7 @@ private slots: void aliasPropertyAndBinding(); void nonExistantAttachedObject(); void scope(); + void signalParameterTypes(); private: QmlEngine engine; @@ -529,7 +530,6 @@ void tst_qmlecmascript::nonExistantAttachedObject() void tst_qmlecmascript::scope() { QmlComponent component(&engine, TEST_FILE("scope.qml")); - qWarning() << component.errors(); QObject *object = component.create(); QVERIFY(object != 0); @@ -543,6 +543,20 @@ void tst_qmlecmascript::scope() QCOMPARE(object->property("test8").toInt(), 2); } +void tst_qmlecmascript::signalParameterTypes() +{ + QmlComponent component(&engine, TEST_FILE("signalParameterTypes.qml")); + MyQmlObject *object = qobject_cast(component.create()); + QVERIFY(object != 0); + + emit object->basicSignal(); + + QCOMPARE(object->property("intProperty").toInt(), 10); + QCOMPARE(object->property("realProperty").toReal(), 19.2); + QVERIFY(object->property("colorProperty").value() == QColor(255, 255, 0, 255)); + QVERIFY(object->property("variantProperty") == QVariant::fromValue(QColor(255, 0, 255, 255))); +} + /* Confirm bindings and alias properties can coexist. -- cgit v0.12 From 54e8e22a49148b089fd02895ead5c27aaf62e18e Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Tue, 6 Oct 2009 10:36:07 +1000 Subject: Share QScriptValue's where possible Also add an autotest for object comparisons --- src/declarative/qml/qmldeclarativedata_p.h | 2 ++ src/declarative/qml/qmlobjectscriptclass.cpp | 11 ++++++++++- .../qmlecmascript/data/objectsCompareAsEqual.qml | 15 +++++++++++++++ .../declarative/qmlecmascript/tst_qmlecmascript.cpp | 21 +++++++++++++++++++++ 4 files changed, 48 insertions(+), 1 deletion(-) create mode 100644 tests/auto/declarative/qmlecmascript/data/objectsCompareAsEqual.qml diff --git a/src/declarative/qml/qmldeclarativedata_p.h b/src/declarative/qml/qmldeclarativedata_p.h index b4c87b8..f6ecc3d 100644 --- a/src/declarative/qml/qmldeclarativedata_p.h +++ b/src/declarative/qml/qmldeclarativedata_p.h @@ -54,6 +54,7 @@ // #include +#include QT_BEGIN_NAMESPACE @@ -86,6 +87,7 @@ public: QHash *attachedProperties; + QScriptValue scriptValue; QmlPropertyCache *propertyCache; static QmlDeclarativeData *get(const QObject *object, bool create = false) { diff --git a/src/declarative/qml/qmlobjectscriptclass.cpp b/src/declarative/qml/qmlobjectscriptclass.cpp index 2d5991c..330eddd 100644 --- a/src/declarative/qml/qmlobjectscriptclass.cpp +++ b/src/declarative/qml/qmlobjectscriptclass.cpp @@ -80,7 +80,16 @@ QScriptValue QmlObjectScriptClass::newQObject(QObject *object) { QScriptEngine *scriptEngine = QmlEnginePrivate::getScriptEngine(engine); - return newObject(scriptEngine, this, new ObjectData(object)); + QmlDeclarativeData *ddata = QmlDeclarativeData::get(object, true); + + if (!ddata->scriptValue.isValid()) { + ddata->scriptValue = newObject(scriptEngine, this, new ObjectData(object)); + return ddata->scriptValue; + } else if (ddata->scriptValue.engine() == QmlEnginePrivate::getScriptEngine(engine)) { + return ddata->scriptValue; + } else { + return newObject(scriptEngine, this, new ObjectData(object)); + } } QObject *QmlObjectScriptClass::toQObject(const QScriptValue &value) const diff --git a/tests/auto/declarative/qmlecmascript/data/objectsCompareAsEqual.qml b/tests/auto/declarative/qmlecmascript/data/objectsCompareAsEqual.qml new file mode 100644 index 0000000..2526576 --- /dev/null +++ b/tests/auto/declarative/qmlecmascript/data/objectsCompareAsEqual.qml @@ -0,0 +1,15 @@ +import Qt 4.6 + +Item { + id: Root + + property var item: Child + Item { id: Child } + + property bool test1: Child == Child + property bool test2: Child.parent == Root + property bool test3: Root != Child + property bool test4: item == Child + property bool test5: item != Root +} + diff --git a/tests/auto/declarative/qmlecmascript/tst_qmlecmascript.cpp b/tests/auto/declarative/qmlecmascript/tst_qmlecmascript.cpp index 65f7021..15bfe24 100644 --- a/tests/auto/declarative/qmlecmascript/tst_qmlecmascript.cpp +++ b/tests/auto/declarative/qmlecmascript/tst_qmlecmascript.cpp @@ -53,6 +53,7 @@ private slots: void nonExistantAttachedObject(); void scope(); void signalParameterTypes(); + void objectsCompareAsEqual(); private: QmlEngine engine; @@ -543,6 +544,10 @@ void tst_qmlecmascript::scope() QCOMPARE(object->property("test8").toInt(), 2); } +/* +Tests that "any" type passes through a synthesized signal parameter. This +is essentially a test of QmlMetaType::copy() +*/ void tst_qmlecmascript::signalParameterTypes() { QmlComponent component(&engine, TEST_FILE("signalParameterTypes.qml")); @@ -558,6 +563,22 @@ void tst_qmlecmascript::signalParameterTypes() } /* +Test that two JS objects for the same QObject compare as equal. +*/ +void tst_qmlecmascript::objectsCompareAsEqual() +{ + QmlComponent component(&engine, TEST_FILE("objectsCompareAsEqual.qml")); + QObject *object = component.create(); + QVERIFY(object != 0); + + QCOMPARE(object->property("test1").toBool(), true); + QCOMPARE(object->property("test2").toBool(), true); + QCOMPARE(object->property("test3").toBool(), true); + QCOMPARE(object->property("test4").toBool(), true); + QCOMPARE(object->property("test5").toBool(), true); +} + +/* Confirm bindings and alias properties can coexist. Tests for a regression where the binding would not reevaluate. -- cgit v0.12 From 51e9a75d2d26f2f7ad4cf11a730c8d6e12dc3886 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Tue, 6 Oct 2009 15:01:28 +1000 Subject: Improve scope autotest --- tests/auto/declarative/qmlecmascript/data/ScopeObject.qml | 14 ++++++++++++++ tests/auto/declarative/qmlecmascript/data/scope.qml | 6 ++++++ tests/auto/declarative/qmlecmascript/tst_qmlecmascript.cpp | 2 ++ 3 files changed, 22 insertions(+) create mode 100644 tests/auto/declarative/qmlecmascript/data/ScopeObject.qml diff --git a/tests/auto/declarative/qmlecmascript/data/ScopeObject.qml b/tests/auto/declarative/qmlecmascript/data/ScopeObject.qml new file mode 100644 index 0000000..b7bec63 --- /dev/null +++ b/tests/auto/declarative/qmlecmascript/data/ScopeObject.qml @@ -0,0 +1,14 @@ +import Qt 4.6 + +Item { + property int a: 3 + property int binding: myFunction(); + property int binding2: myCompFunction(); + + Script { + function myCompFunction() { + return a; + } + } +} + diff --git a/tests/auto/declarative/qmlecmascript/data/scope.qml b/tests/auto/declarative/qmlecmascript/data/scope.qml index 87155d1..80222c8 100644 --- a/tests/auto/declarative/qmlecmascript/data/scope.qml +++ b/tests/auto/declarative/qmlecmascript/data/scope.qml @@ -31,6 +31,10 @@ Item { property int binding4: myNestedFunction() } + ScopeObject { + id: CompObject + } + property alias test1: Root.binding property alias test2: NestedObject.binding property alias test3: Root.binding2 @@ -39,4 +43,6 @@ Item { property alias test6: NestedObject.binding3 property alias test7: Root.binding4 property alias test8: NestedObject.binding4 + property alias test9: CompObject.binding + property alias test10: CompObject.binding2 } diff --git a/tests/auto/declarative/qmlecmascript/tst_qmlecmascript.cpp b/tests/auto/declarative/qmlecmascript/tst_qmlecmascript.cpp index 15bfe24..c69528a 100644 --- a/tests/auto/declarative/qmlecmascript/tst_qmlecmascript.cpp +++ b/tests/auto/declarative/qmlecmascript/tst_qmlecmascript.cpp @@ -542,6 +542,8 @@ void tst_qmlecmascript::scope() QCOMPARE(object->property("test6").toInt(), 1); QCOMPARE(object->property("test7").toInt(), 2); QCOMPARE(object->property("test8").toInt(), 2); + QCOMPARE(object->property("test9").toInt(), 1); + QCOMPARE(object->property("test10").toInt(), 3); } /* -- cgit v0.12 From 00da55bcd3ab574073b34ae4b558a40722a94c47 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Tue, 6 Oct 2009 15:02:13 +1000 Subject: Add a QScriptEngine::pushCleanContext() method --- src/script/api/qscriptengine.cpp | 41 ++++++++++++++++++++++++++++++++++++++-- src/script/api/qscriptengine.h | 1 + src/script/api/qscriptengine_p.h | 2 +- 3 files changed, 41 insertions(+), 3 deletions(-) diff --git a/src/script/api/qscriptengine.cpp b/src/script/api/qscriptengine.cpp index 2bb6eae..785d80f 100644 --- a/src/script/api/qscriptengine.cpp +++ b/src/script/api/qscriptengine.cpp @@ -2400,6 +2400,35 @@ QScriptContext *QScriptEngine::pushContext() return d->contextForFrame(newFrame); } +/*! + Enters a new execution context and returns the associated + QScriptContext object. + + Once you are done with the context, you should call popContext() to + restore the old context. + + By default, the `this' object of the new context is the Global Object. + The context's \l{QScriptContext::callee()}{callee}() will be invalid. + + Unlike pushContext(), the default scope chain is reset to include + only the global object and the QScriptContext's activation object. + + \sa popContext() +*/ +QScriptContext *QScriptEngine::pushCleanContext() +{ + Q_D(QScriptEngine); + + JSC::CallFrame* newFrame = d->pushContext(d->currentFrame, d->currentFrame->globalData().dynamicGlobalObject, + JSC::ArgList(), /*callee = */0, false, true); + + if (agent()) + agent()->contextPush(); + + return d->contextForFrame(newFrame); +} + + /*! \internal push a context for a native function. JSC native function doesn't have different stackframe or context. so we need to create one. @@ -2411,7 +2440,8 @@ QScriptContext *QScriptEngine::pushContext() return the new top frame. (might be the same as exec if a new stackframe was not needed) or 0 if stack overflow */ JSC::CallFrame *QScriptEnginePrivate::pushContext(JSC::CallFrame *exec, JSC::JSValue _thisObject, - const JSC::ArgList& args, JSC::JSObject *callee, bool calledAsConstructor) + const JSC::ArgList& args, JSC::JSObject *callee, bool calledAsConstructor, + bool clearScopeChain) { JSC::JSValue thisObject = _thisObject; if (calledAsConstructor) { @@ -2445,7 +2475,14 @@ JSC::CallFrame *QScriptEnginePrivate::pushContext(JSC::CallFrame *exec, JSC::JSV for (it = args.begin(); it != args.end(); ++it) newCallFrame[++dst] = *it; newCallFrame += argc + JSC::RegisterFile::CallFrameHeaderSize; - newCallFrame->init(0, /*vPC=*/0, exec->scopeChain(), exec, flags | ShouldRestoreCallFrame, argc, callee); + + if (!clearScopeChain) { + newCallFrame->init(0, /*vPC=*/0, exec->scopeChain(), exec, flags | ShouldRestoreCallFrame, argc, callee); + } else { + JSC::JSObject *jscObject = originalGlobalObject(); + JSC::ScopeChainNode *scn = new JSC::ScopeChainNode(0, jscObject, &exec->globalData(), jscObject); + newCallFrame->init(0, /*vPC=*/0, scn, exec, flags | ShouldRestoreCallFrame, argc, callee); + } } else { setContextFlags(newCallFrame, flags); #if ENABLE(JIT) diff --git a/src/script/api/qscriptengine.h b/src/script/api/qscriptengine.h index 71266cc..cd86aca 100644 --- a/src/script/api/qscriptengine.h +++ b/src/script/api/qscriptengine.h @@ -182,6 +182,7 @@ public: QScriptContext *currentContext() const; QScriptContext *pushContext(); + QScriptContext *pushCleanContext(); void popContext(); bool canEvaluate(const QString &program) const; diff --git a/src/script/api/qscriptengine_p.h b/src/script/api/qscriptengine_p.h index 5f31054..7218ee1 100644 --- a/src/script/api/qscriptengine_p.h +++ b/src/script/api/qscriptengine_p.h @@ -162,7 +162,7 @@ public: static JSC::Register *thisRegisterForFrame(JSC::ExecState *frame); JSC::CallFrame *pushContext(JSC::CallFrame *exec, JSC::JSValue thisObject, const JSC::ArgList& args, - JSC::JSObject *callee, bool calledAsConstructor = false); + JSC::JSObject *callee, bool calledAsConstructor = false, bool clearScopeChain = false); void popContext(); void mark(JSC::MarkStack& markStack); -- cgit v0.12 From 9e4b877430a6811079d209656587ea228334ed34 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Tue, 6 Oct 2009 15:30:59 +1000 Subject: Export the active QScriptContext during a callback Clearly the API needs work :) --- src/script/bridge/qscriptdeclarativeclass.cpp | 50 ++++++++++++++++++++++++-- src/script/bridge/qscriptdeclarativeclass_p.h | 4 +++ src/script/bridge/qscriptdeclarativeobject.cpp | 7 ++++ 3 files changed, 59 insertions(+), 2 deletions(-) diff --git a/src/script/bridge/qscriptdeclarativeclass.cpp b/src/script/bridge/qscriptdeclarativeclass.cpp index b990e33..a7667cb 100644 --- a/src/script/bridge/qscriptdeclarativeclass.cpp +++ b/src/script/bridge/qscriptdeclarativeclass.cpp @@ -47,6 +47,7 @@ #include #include #include +#include #include QT_BEGIN_NAMESPACE @@ -78,14 +79,14 @@ QScriptDeclarativeClass::PersistentIdentifier::operator=(const PersistentIdentif class QScriptDeclarativeClassPrivate { public: - QScriptDeclarativeClassPrivate() {} + QScriptDeclarativeClassPrivate() : engine(0), q_ptr(0) {} QScriptEngine *engine; QScriptDeclarativeClass *q_ptr; }; QScriptDeclarativeClass::QScriptDeclarativeClass(QScriptEngine *engine) -: d_ptr(new QScriptDeclarativeClassPrivate) +: context(0), d_ptr(new QScriptDeclarativeClassPrivate) { Q_ASSERT(sizeof(void*) == sizeof(JSC::Identifier)); d_ptr->q_ptr = this; @@ -176,6 +177,51 @@ QScriptValue QScriptDeclarativeClass::property(const QScriptValue &v, const Iden return QScriptValue(); } +/* +Returns the scope chain entry \a index from the end. This is equivalent to: + context->scopeChain().at(context->scopeChain.length() - 1 - index) +*/ +QScriptValue QScriptDeclarativeClass::scopeChainValue(QScriptContext *context, int index) +{ + context->activationObject(); //ensure the creation of the normal scope for native context + const JSC::CallFrame *frame = QScriptEnginePrivate::frameForContext(context); + QScriptEnginePrivate *engine = QScript::scriptEngineFromExec(frame); + + JSC::ScopeChainNode *node = frame->scopeChain(); + JSC::ScopeChainIterator it(node); + + int count = 0; + for (it = node->begin(); it != node->end(); ++it) + ++count; + + if (count < index) + return QScriptValue(); + + count -= index; + + for (it = node->begin(); it != node->end(); ++it) { + + if (count == 0) { + + JSC::JSObject *object = *it; + if (!object) return QScriptValue(); + + if (object->inherits(&QScript::QScriptActivationObject::info) + && (static_cast(object)->delegate() != 0)) { + // Return the object that property access is being delegated to + object = static_cast(object)->delegate(); + } + return engine->scriptValueFromJSCValue(object); + + } else { + --count; + } + + } + + return QScriptValue(); +} + QScriptDeclarativeClass::~QScriptDeclarativeClass() { } diff --git a/src/script/bridge/qscriptdeclarativeclass_p.h b/src/script/bridge/qscriptdeclarativeclass_p.h index 07cfad1..0d05ec5 100644 --- a/src/script/bridge/qscriptdeclarativeclass_p.h +++ b/src/script/bridge/qscriptdeclarativeclass_p.h @@ -61,6 +61,7 @@ QT_BEGIN_NAMESPACE class QScriptDeclarativeClassPrivate; class PersistentIdentifierPrivate; +class QScriptContext; class Q_SCRIPT_EXPORT QScriptDeclarativeClass { public: @@ -75,6 +76,8 @@ public: static QScriptValue function(const QScriptValue &, const Identifier &); static QScriptValue property(const QScriptValue &, const Identifier &); + static QScriptValue scopeChainValue(QScriptContext *, int index); + class Q_SCRIPT_EXPORT PersistentIdentifier { public: @@ -113,6 +116,7 @@ public: virtual QObject *toQObject(Object *, bool *ok = 0); virtual QVariant toVariant(Object *, bool *ok = 0); + QScriptContext *context; protected: QScopedPointer d_ptr; }; diff --git a/src/script/bridge/qscriptdeclarativeobject.cpp b/src/script/bridge/qscriptdeclarativeobject.cpp index ef77de0..ffdebb0 100644 --- a/src/script/bridge/qscriptdeclarativeobject.cpp +++ b/src/script/bridge/qscriptdeclarativeobject.cpp @@ -87,13 +87,16 @@ bool DeclarativeObjectDelegate::getOwnPropertySlot(QScriptObject* object, QScriptEnginePrivate *engine = scriptEngineFromExec(exec); QScriptDeclarativeClass::Identifier identifier = (void *)propertyName.ustring().rep(); + m_class->context = reinterpret_cast(exec); QScriptClass::QueryFlags flags = m_class->queryProperty(m_object, identifier, QScriptClass::HandlesReadAccess); if (flags & QScriptClass::HandlesReadAccess) { QScriptValue value = m_class->property(m_object, identifier); + m_class->context = 0; slot.setValue(engine->scriptValueToJSCValue(value)); return true; } + m_class->context = 0; return QScriptObjectDelegate::getOwnPropertySlot(object, exec, propertyName, slot); } @@ -105,12 +108,16 @@ void DeclarativeObjectDelegate::put(QScriptObject* object, JSC::ExecState *exec, QScriptEnginePrivate *engine = scriptEngineFromExec(exec); QScriptDeclarativeClass::Identifier identifier = (void *)propertyName.ustring().rep(); + m_class->context = reinterpret_cast(exec); QScriptClass::QueryFlags flags = m_class->queryProperty(m_object, identifier, QScriptClass::HandlesWriteAccess); if (flags & QScriptClass::HandlesWriteAccess) { m_class->setProperty(m_object, identifier, engine->scriptValueFromJSCValue(value)); + m_class->context = 0; return; } + m_class->context = 0; + QScriptObjectDelegate::put(object, exec, propertyName, value, slot); } -- cgit v0.12 From 067b419199b369b6c81fa1ae387257aa87cab20c Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Tue, 6 Oct 2009 15:31:56 +1000 Subject: Improve scope handling --- src/declarative/qml/qmlcontext.cpp | 11 +---- src/declarative/qml/qmlcontext_p.h | 3 +- src/declarative/qml/qmlcontextscriptclass.cpp | 45 +++++++++++++++++---- src/declarative/qml/qmlcontextscriptclass_p.h | 6 +++ src/declarative/qml/qmlexpression.cpp | 22 +++++----- src/declarative/qml/qmlobjectscriptclass.cpp | 56 ++++++++++++++++---------- src/declarative/qml/qmlobjectscriptclass_p.h | 3 +- src/declarative/qml/qmltypenamescriptclass.cpp | 3 +- src/declarative/util/qmlscript.cpp | 6 +-- 9 files changed, 96 insertions(+), 59 deletions(-) diff --git a/src/declarative/qml/qmlcontext.cpp b/src/declarative/qml/qmlcontext.cpp index 968597c..a1eb5de 100644 --- a/src/declarative/qml/qmlcontext.cpp +++ b/src/declarative/qml/qmlcontext.cpp @@ -103,16 +103,7 @@ void QmlContextPrivate::init() //set scope chain QScriptEngine *scriptEngine = QmlEnginePrivate::getScriptEngine(engine); - QScriptValue scopeObj = QmlEnginePrivate::get(engine)->contextClass->newContext(q); - - //### no longer need to push global object once we switch to JSC (test with objects added to globalObject) - //if (parent) - // scopeChain = parent->d_func()->scopeChain; - if (!parent) - scopeChain.append(scriptEngine->globalObject()); - else - scopeChain = parent->d_func()->scopeChain; - scopeChain.prepend(scopeObj); + scriptValue = QmlEnginePrivate::get(engine)->contextClass->newContext(q); } void QmlContextPrivate::addDefaultObject(QObject *object, Priority priority) diff --git a/src/declarative/qml/qmlcontext_p.h b/src/declarative/qml/qmlcontext_p.h index 8fd2e92..22e5895 100644 --- a/src/declarative/qml/qmlcontext_p.h +++ b/src/declarative/qml/qmlcontext_p.h @@ -85,14 +85,13 @@ public: bool isInternal; QmlIntegerCache *propertyNames; -// QHash propertyNames; QList propertyValues; int notifyIndex; QObjectList defaultObjects; int highPriorityCount; - QScriptValueList scopeChain; + QScriptValue scriptValue; QList scripts; diff --git a/src/declarative/qml/qmlcontextscriptclass.cpp b/src/declarative/qml/qmlcontextscriptclass.cpp index 226c34c..6d2c58c 100644 --- a/src/declarative/qml/qmlcontextscriptclass.cpp +++ b/src/declarative/qml/qmlcontextscriptclass.cpp @@ -72,51 +72,80 @@ QScriptValue QmlContextScriptClass::newContext(QmlContext *context) return newObject(scriptEngine, this, new ContextData(context)); } +QmlContext *QmlContextScriptClass::contextFromValue(const QScriptValue &v) +{ + if (scriptClass(v) != this) + return 0; + + ContextData *data = (ContextData *)object(v); + return data->context; +} + +#include QScriptClass::QueryFlags QmlContextScriptClass::queryProperty(Object *object, const Identifier &name, QScriptClass::QueryFlags flags) { Q_UNUSED(flags); + lastContext = 0; + lastData = 0; lastPropertyIndex = -1; lastDefaultObject = -1; - lastData = 0; QmlContext *bindContext = ((ContextData *)object)->context.data(); if (!bindContext) return 0; + while (bindContext) { + QScriptClass::QueryFlags rv = queryProperty(bindContext, name, flags); + if (rv) return rv; + bindContext = bindContext->parentContext(); + } + + return 0; +} + +QScriptClass::QueryFlags +QmlContextScriptClass::queryProperty(QmlContext *bindContext, const Identifier &name, + QScriptClass::QueryFlags flags) +{ QmlEnginePrivate *ep = QmlEnginePrivate::get(engine); QmlContextPrivate *cp = QmlContextPrivate::get(bindContext); lastPropertyIndex = cp->propertyNames?cp->propertyNames->value(name):-1; - if (lastPropertyIndex != -1) + if (lastPropertyIndex != -1) { + lastContext = bindContext; return QScriptClass::HandlesReadAccess; + } - if (ep->currentExpression && cp->imports && bindContext == ep->currentExpression->context()) { + if (cp->imports) { QmlTypeNameCache::Data *data = cp->imports->data(name); if (data) { lastData = data; + lastContext = bindContext; return QScriptClass::HandlesReadAccess; } } for (int ii = 0; ii < cp->defaultObjects.count(); ++ii) { QScriptClass::QueryFlags rv = - ep->objectClass->queryProperty(cp->defaultObjects.at(ii), name, flags, - QmlObjectScriptClass::SkipAttachedProperties); + ep->objectClass->queryProperty(cp->defaultObjects.at(ii), name, flags, 0); if (rv) { lastDefaultObject = ii; + lastContext = bindContext; return rv; } } for (int ii = 0; ii < cp->scripts.count(); ++ii) { lastFunction = QScriptDeclarativeClass::function(cp->scripts.at(ii), name); - if (lastFunction.isValid()) + if (lastFunction.isValid()) { + lastContext = bindContext; return QScriptClass::HandlesReadAccess; + } } return 0; } @@ -125,7 +154,7 @@ QScriptValue QmlContextScriptClass::property(Object *object, const Identifier &n { Q_UNUSED(object); - QmlContext *bindContext = ((ContextData *)object)->context.data(); + QmlContext *bindContext = lastContext; Q_ASSERT(bindContext); QmlEnginePrivate *ep = QmlEnginePrivate::get(engine); @@ -170,7 +199,7 @@ void QmlContextScriptClass::setProperty(Object *object, const Identifier &name, { Q_ASSERT(lastDefaultObject != -1); - QmlContext *bindContext = ((ContextData *)object)->context.data(); + QmlContext *bindContext = lastContext; Q_ASSERT(bindContext); QmlEnginePrivate *ep = QmlEnginePrivate::get(engine); diff --git a/src/declarative/qml/qmlcontextscriptclass_p.h b/src/declarative/qml/qmlcontextscriptclass_p.h index acb8926..761a115 100644 --- a/src/declarative/qml/qmlcontextscriptclass_p.h +++ b/src/declarative/qml/qmlcontextscriptclass_p.h @@ -69,6 +69,8 @@ public: QScriptValue newContext(QmlContext *); + QmlContext *contextFromValue(const QScriptValue &); + protected: virtual QScriptClass::QueryFlags queryProperty(Object *, const Identifier &, QScriptClass::QueryFlags flags); @@ -76,8 +78,12 @@ protected: virtual void setProperty(Object *, const Identifier &name, const QScriptValue &); private: + QScriptClass::QueryFlags queryProperty(QmlContext *, const Identifier &, + QScriptClass::QueryFlags flags); + QmlEngine *engine; + QmlContext *lastContext; QmlTypeNameCache::Data *lastData; int lastPropertyIndex; int lastDefaultObject; diff --git a/src/declarative/qml/qmlexpression.cpp b/src/declarative/qml/qmlexpression.cpp index 61c14a9..e1c7afe 100644 --- a/src/declarative/qml/qmlexpression.cpp +++ b/src/declarative/qml/qmlexpression.cpp @@ -82,17 +82,20 @@ void QmlExpressionPrivate::init(QmlContext *ctxt, void *expr, QmlRefCount *rc, int progIdx = *(data + 1); QmlEngine *engine = ctxt->engine(); + QmlEnginePrivate *ep = QmlEnginePrivate::get(engine); QScriptEngine *scriptEngine = QmlEnginePrivate::getScriptEngine(engine); if (!dd->programs.at(progIdx)) { dd->programs[progIdx] = new QScriptProgram(scriptEngine->compile(expression)); } QmlContextPrivate *ctxtPriv = ctxt->d_func(); - QScriptContext *scriptContext = scriptEngine->pushContext(); - for (int i = ctxtPriv->scopeChain.size() - 1; i > -1; --i) - scriptContext->pushScope(ctxtPriv->scopeChain.at(i)); + QScriptContext *scriptContext = scriptEngine->pushCleanContext(); + scriptContext->pushScope(ctxtPriv->scriptValue); + if (me) + scriptContext->pushScope(ep->objectClass->newQObject(me)); expressionFunction = scriptEngine->evaluate(*dd->programs[progIdx]); + expressionFunctionValid = true; scriptEngine->popContext(); } @@ -239,9 +242,8 @@ QVariant QmlExpressionPrivate::evalQtScript(QObject *secondaryScope) QmlContextPrivate *ctxtPriv = context()->d_func(); QmlEngine *engine = context()->engine(); + QmlEnginePrivate *ep = QmlEnginePrivate::get(engine); - if (me) - ctxtPriv->defaultObjects.insert(ctxtPriv->highPriorityCount, me); if (secondaryScope) ctxtPriv->defaultObjects.insert(ctxtPriv->highPriorityCount, secondaryScope); @@ -250,9 +252,11 @@ QVariant QmlExpressionPrivate::evalQtScript(QObject *secondaryScope) if (!expressionFunctionValid) { - QScriptContext *scriptContext = scriptEngine->pushContext(); - for (int i = ctxtPriv->scopeChain.size() - 1; i > -1; --i) - scriptContext->pushScope(ctxtPriv->scopeChain.at(i)); + QScriptContext *scriptContext = scriptEngine->pushCleanContext(); + scriptContext->pushScope(ctxtPriv->scriptValue); + + if (me) + scriptContext->pushScope(ep->objectClass->newQObject(me)); if (expressionRewritten) { expressionFunction = scriptEngine->evaluate(expression, fileName, line); @@ -283,8 +287,6 @@ QVariant QmlExpressionPrivate::evalQtScript(QObject *secondaryScope) } } - if (me) - ctxtPriv->defaultObjects.removeAt(ctxtPriv->highPriorityCount); if (secondaryScope) ctxtPriv->defaultObjects.removeAt(ctxtPriv->highPriorityCount); diff --git a/src/declarative/qml/qmlobjectscriptclass.cpp b/src/declarative/qml/qmlobjectscriptclass.cpp index 330eddd..2d69590 100644 --- a/src/declarative/qml/qmlobjectscriptclass.cpp +++ b/src/declarative/qml/qmlobjectscriptclass.cpp @@ -80,6 +80,9 @@ QScriptValue QmlObjectScriptClass::newQObject(QObject *object) { QScriptEngine *scriptEngine = QmlEnginePrivate::getScriptEngine(engine); + if (!object) + return newObject(scriptEngine, this, new ObjectData(object)); + QmlDeclarativeData *ddata = QmlDeclarativeData::get(object, true); if (!ddata->scriptValue.isValid()) { @@ -101,12 +104,12 @@ QScriptClass::QueryFlags QmlObjectScriptClass::queryProperty(Object *object, const Identifier &name, QScriptClass::QueryFlags flags) { - return queryProperty(toQObject(object), name, flags); + return queryProperty(toQObject(object), name, flags, 0); } QScriptClass::QueryFlags QmlObjectScriptClass::queryProperty(QObject *obj, const Identifier &name, - QScriptClass::QueryFlags flags, QueryMode mode) + QScriptClass::QueryFlags flags, QmlContext *evalContext) { Q_UNUSED(flags); lastData = 0; @@ -120,21 +123,7 @@ QmlObjectScriptClass::queryProperty(QObject *obj, const Identifier &name, return 0; QmlEnginePrivate *enginePrivate = QmlEnginePrivate::get(engine); - - if (mode == IncludeAttachedProperties) { - QmlContext *evalContext = enginePrivate->currentExpression->context(); - QmlContextPrivate *cp = QmlContextPrivate::get(evalContext); - // ### Check for attached properties - - if (cp->imports) { - QmlTypeNameCache::Data *data = cp->imports->data(name); - if (data) { - lastTNData = data; - return QScriptClass::HandlesReadAccess; - } - } - - } + QScriptEngine *scriptEngine = QmlEnginePrivate::getScriptEngine(engine); QmlPropertyCache *cache = 0; QmlDeclarativeData *ddata = QmlDeclarativeData::get(obj); @@ -153,12 +142,35 @@ QmlObjectScriptClass::queryProperty(QObject *obj, const Identifier &name, lastData = &local; } - if (!lastData) return 0; + if (lastData) { + QScriptClass::QueryFlags rv = QScriptClass::HandlesReadAccess; + if (lastData->flags & QmlPropertyCache::Data::IsWritable) + rv |= QScriptClass::HandlesWriteAccess; + return rv; + } + + if (!evalContext && context) { + // Global object, QScriptContext activation object, QmlContext object + QScriptValue scopeNode = scopeChainValue(context, 3); + Q_ASSERT(scopeNode.isValid()); + Q_ASSERT(scriptClass(scopeNode) == enginePrivate->contextClass); + + evalContext = enginePrivate->contextClass->contextFromValue(scopeNode); + } + + if (evalContext) { + QmlContextPrivate *cp = QmlContextPrivate::get(evalContext); + + if (cp->imports) { + QmlTypeNameCache::Data *data = cp->imports->data(name); + if (data) { + lastTNData = data; + return QScriptClass::HandlesReadAccess; + } + } + } - QScriptClass::QueryFlags rv = QScriptClass::HandlesReadAccess; - if (lastData->flags & QmlPropertyCache::Data::IsWritable) - rv |= QScriptClass::HandlesWriteAccess; - return rv; + return 0; } QScriptValue QmlObjectScriptClass::property(Object *object, const Identifier &name) diff --git a/src/declarative/qml/qmlobjectscriptclass_p.h b/src/declarative/qml/qmlobjectscriptclass_p.h index 6de63ca..3fcf009 100644 --- a/src/declarative/qml/qmlobjectscriptclass_p.h +++ b/src/declarative/qml/qmlobjectscriptclass_p.h @@ -63,6 +63,7 @@ QT_BEGIN_NAMESPACE class QmlEngine; class QScriptContext; class QScriptEngine; +class QmlContext; class QmlObjectScriptClass : public QScriptDeclarativeClass { public: @@ -76,7 +77,7 @@ public: QScriptClass::QueryFlags queryProperty(QObject *, const Identifier &, QScriptClass::QueryFlags flags, - QueryMode = IncludeAttachedProperties); + QmlContext *evalContext); QScriptValue property(QObject *, const Identifier &); void setProperty(QObject *, const Identifier &name, const QScriptValue &); diff --git a/src/declarative/qml/qmltypenamescriptclass.cpp b/src/declarative/qml/qmltypenamescriptclass.cpp index 4e1ac4b..c0613d1 100644 --- a/src/declarative/qml/qmltypenamescriptclass.cpp +++ b/src/declarative/qml/qmltypenamescriptclass.cpp @@ -131,8 +131,7 @@ QmlTypeNameScriptClass::queryProperty(Object *obj, const Identifier &name, // Must be an attached property object = qmlAttachedPropertiesObjectById(data->type->index(), data->object); if (!object) return 0; - return ep->objectClass->queryProperty(object, name, flags, - QmlObjectScriptClass::SkipAttachedProperties); + return ep->objectClass->queryProperty(object, name, flags, 0); } } diff --git a/src/declarative/util/qmlscript.cpp b/src/declarative/util/qmlscript.cpp index 2031a54..5d58f64 100644 --- a/src/declarative/util/qmlscript.cpp +++ b/src/declarative/util/qmlscript.cpp @@ -178,10 +178,8 @@ void QmlScriptPrivate::addScriptToEngine(const QString &script, const QString &s QmlContext *context = qmlContext(q); QScriptEngine *scriptEngine = QmlEnginePrivate::getScriptEngine(engine); - QScriptContext *scriptContext = scriptEngine->pushContext(); - for (int i = context->d_func()->scopeChain.size() - 1; i >= 0; --i) { - scriptContext->pushScope(context->d_func()->scopeChain.at(i)); - } + QScriptContext *scriptContext = scriptEngine->pushCleanContext(); + scriptContext->pushScope(QmlContextPrivate::get(context)->scriptValue); QScriptValue scope = scriptEngine->newObject(); scriptContext->pushScope(scope); -- cgit v0.12 From 3184fbcd858244b5cd171fd0ab32c3ff565e579e Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Tue, 6 Oct 2009 15:48:32 +1000 Subject: Add tst_qmlecmascript::scriptAccess testcase --- .../auto/declarative/qmlecmascript/data/scriptAccess.js | 7 +++++++ .../declarative/qmlecmascript/data/scriptAccess.qml | 17 +++++++++++++++++ .../declarative/qmlecmascript/tst_qmlecmascript.cpp | 15 +++++++++++++++ 3 files changed, 39 insertions(+) create mode 100644 tests/auto/declarative/qmlecmascript/data/scriptAccess.js create mode 100644 tests/auto/declarative/qmlecmascript/data/scriptAccess.qml diff --git a/tests/auto/declarative/qmlecmascript/data/scriptAccess.js b/tests/auto/declarative/qmlecmascript/data/scriptAccess.js new file mode 100644 index 0000000..c00d285 --- /dev/null +++ b/tests/auto/declarative/qmlecmascript/data/scriptAccess.js @@ -0,0 +1,7 @@ +var extVariable = 19; + +function extMethod() +{ + return extVariable; +} + diff --git a/tests/auto/declarative/qmlecmascript/data/scriptAccess.qml b/tests/auto/declarative/qmlecmascript/data/scriptAccess.qml new file mode 100644 index 0000000..feb6d16 --- /dev/null +++ b/tests/auto/declarative/qmlecmascript/data/scriptAccess.qml @@ -0,0 +1,17 @@ +import Qt 4.6 + +Item { + Script { + function method() { + return 10; + } + } + + Script { + source: "scriptAccess.js" + } + + property int test1: method() + property int test2: extMethod() + property int test3: extVariable +} diff --git a/tests/auto/declarative/qmlecmascript/tst_qmlecmascript.cpp b/tests/auto/declarative/qmlecmascript/tst_qmlecmascript.cpp index c69528a..15a7860 100644 --- a/tests/auto/declarative/qmlecmascript/tst_qmlecmascript.cpp +++ b/tests/auto/declarative/qmlecmascript/tst_qmlecmascript.cpp @@ -54,6 +54,7 @@ private slots: void scope(); void signalParameterTypes(); void objectsCompareAsEqual(); + void scriptAccess(); private: QmlEngine engine; @@ -600,6 +601,20 @@ void tst_qmlecmascript::aliasPropertyAndBinding() QCOMPARE(object->property("c3").toInt(), 19); } +/* +Tests that only methods of Script {} blocks are exposed. +*/ +void tst_qmlecmascript::scriptAccess() +{ + QmlComponent component(&engine, TEST_FILE("scriptAccess.qml")); + QObject *object = component.create(); + QVERIFY(object != 0); + + QCOMPARE(object->property("test1").toInt(), 10); + QCOMPARE(object->property("test2").toInt(), 19); + QCOMPARE(object->property("test3").toInt(), 0); +} + QTEST_MAIN(tst_qmlecmascript) #include "tst_qmlecmascript.moc" -- cgit v0.12 From 50a4a8ec76b98cc860de9b6e6aaf25c87e690eed Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Tue, 6 Oct 2009 17:47:14 +1000 Subject: Another test --- .../qmllanguage/data/dynamicObjectProperties.qml | 13 +++++++++++++ tests/auto/declarative/qmllanguage/tst_qmllanguage.cpp | 14 ++++++++++++++ 2 files changed, 27 insertions(+) create mode 100644 tests/auto/declarative/qmllanguage/data/dynamicObjectProperties.qml diff --git a/tests/auto/declarative/qmllanguage/data/dynamicObjectProperties.qml b/tests/auto/declarative/qmllanguage/data/dynamicObjectProperties.qml new file mode 100644 index 0000000..e69ccee --- /dev/null +++ b/tests/auto/declarative/qmllanguage/data/dynamicObjectProperties.qml @@ -0,0 +1,13 @@ +import Test 1.0 +import Qt 4.6 +import Qt 4.6 as Qt + +Object { + property Object objectProperty + property Object objectProperty2 + objectProperty2: Object {} + + property MyComponent myComponentProperty + property MyComponent myComponentProperty2 + myComponentProperty2: MyComponent {} +} diff --git a/tests/auto/declarative/qmllanguage/tst_qmllanguage.cpp b/tests/auto/declarative/qmllanguage/tst_qmllanguage.cpp index 1bf98df..3825b62 100644 --- a/tests/auto/declarative/qmllanguage/tst_qmllanguage.cpp +++ b/tests/auto/declarative/qmllanguage/tst_qmllanguage.cpp @@ -45,6 +45,7 @@ private slots: void idProperty(); void assignSignal(); void dynamicProperties(); + void dynamicObjectProperties(); void dynamicSignalsAndSlots(); void simpleBindings(); void autoComponentCreation(); @@ -404,6 +405,19 @@ void tst_qmllanguage::dynamicProperties() QCOMPARE(object->property("variantProperty"), QVariant(12)); } +// Tests the creation and assignment of dynamic object properties +// ### Not complete +void tst_qmllanguage::dynamicObjectProperties() +{ + QmlComponent component(&engine, TEST_FILE("dynamicObjectProperties.qml")); + VERIFY_ERRORS(0); + QObject *object = component.create(); + QVERIFY(object != 0); + + QVERIFY(object->property("objectProperty") == qVariantFromValue((QObject*)0)); + QVERIFY(object->property("objectProperty2") != qVariantFromValue((QObject*)0)); +} + // Tests the declaration of dynamic signals and slots void tst_qmllanguage::dynamicSignalsAndSlots() { -- cgit v0.12 From e79cf93c8b724c8eac042e68ba8dee0b9f2feee3 Mon Sep 17 00:00:00 2001 From: Bea Lam Date: Wed, 7 Oct 2009 15:02:04 +1000 Subject: Remove redundant QFxItem::activeFocusChanged(); is not used anywhere, presumedly replaced by QFxItem::focusChanged(). --- doc/src/declarative/focus.qdoc | 6 +++--- doc/src/tutorials/declarative.qdoc | 2 +- examples/examples.pro | 1 - src/declarative/fx/qfxitem.cpp | 16 ---------------- src/declarative/fx/qfxitem.h | 2 -- src/declarative/fx/qfxtextedit.cpp | 2 +- 6 files changed, 5 insertions(+), 24 deletions(-) diff --git a/doc/src/declarative/focus.qdoc b/doc/src/declarative/focus.qdoc index 028b5f0..dd5dcaf 100644 --- a/doc/src/declarative/focus.qdoc +++ b/doc/src/declarative/focus.qdoc @@ -35,12 +35,12 @@ Item { \section1 Querying the Active Focus Item Whether or not an \l Item has \e {active focus} can be queried through the -read-only property \c {Item::activeFocus}. For example, here we have a \l Text +read-only property \c {Item::focus}. For example, here we have a \l Text element whose text is determined by whether or not it has \e {active focus}. \code Text { - text: activeFocus ? "I have active focus!" : "I do not have active focus" + text: focus ? "I have active focus!" : "I do not have active focus" } \endcode @@ -167,7 +167,7 @@ Conceptually \e {focus scopes} are quite simple. \o Within each \e {focus scope} one element may have \c {Item::focus} set to true. If more than one \l Item has the \c {Item::focus} property set, the first is selected and the others are unset, just like when there are no \e {focus scopes}. \o When a \e {focus scope} receives \e {active focus}, the contained element with \c {Item::focus} set (if any) also gets \e {active focus}. If this element is also a \l FocusScope, the proxying behaviour continues. Both the -\e {focus scope} and the sub-focused item will have \c {Item::activeFocus} set. +\e {focus scope} and the sub-focused item will have \c {Item::focus} set. \endlist So far the example has the second component statically selected. It is trivial diff --git a/doc/src/tutorials/declarative.qdoc b/doc/src/tutorials/declarative.qdoc index 48beabd..bbc3d15 100644 --- a/doc/src/tutorials/declarative.qdoc +++ b/doc/src/tutorials/declarative.qdoc @@ -500,7 +500,7 @@ to receive focus \endlist - The read-only property activeFocus can be used to determine whether a + The read-only property focus can be used to determine whether a component will receive key input. Any un-handled keys will be passed to the components parent, which in turn will pass keys it doesn't handle up to its own ancestors. diff --git a/examples/examples.pro b/examples/examples.pro index 7acd67b..c53bc7d 100644 --- a/examples/examples.pro +++ b/examples/examples.pro @@ -46,7 +46,6 @@ contains(QT_CONFIG, multimedia) { contains(QT_CONFIG, script): SUBDIRS += script contains(QT_CONFIG, phonon):!static: SUBDIRS += phonon -contains(QT_CONFIG, webkit): SUBDIRS += webkit embedded:SUBDIRS += qws !wince*:!symbian: { !contains(QT_EDITION, Console):contains(QT_BUILD_PARTS, tools):SUBDIRS += designer diff --git a/src/declarative/fx/qfxitem.cpp b/src/declarative/fx/qfxitem.cpp index 4d31aaa..6a9af1b 100644 --- a/src/declarative/fx/qfxitem.cpp +++ b/src/declarative/fx/qfxitem.cpp @@ -1257,12 +1257,6 @@ QFxKeysAttached *QFxKeysAttached::qmlAttachedProperties(QObject *obj) */ /*! - \fn void QFxItem::activeFocusChanged() - - This signal is emitted when this item gains active focus. -*/ - -/*! \fn void QFxItem::baselineOffsetChanged() This signal is emitted when the baseline offset of the item @@ -2260,16 +2254,6 @@ void QFxItem::setKeepMouseGrab(bool keep) } /*! - This function emits the \e activeFocusChanged signal. - \a flag is not used. - */ -void QFxItem::activeFocusChanged(bool flag) -{ - Q_UNUSED(flag); - emit activeFocusChanged(); -} - -/*! This function emits the \e focusChanged signal. Subclasses overriding this function should call up diff --git a/src/declarative/fx/qfxitem.h b/src/declarative/fx/qfxitem.h index 30c522f..674940d 100644 --- a/src/declarative/fx/qfxitem.h +++ b/src/declarative/fx/qfxitem.h @@ -166,7 +166,6 @@ Q_SIGNALS: void stateChanged(const QString &); void focusChanged(); void wantsFocusChanged(); - void activeFocusChanged(); void parentChanged(); protected: @@ -183,7 +182,6 @@ protected: virtual void classBegin(); virtual void componentComplete(); virtual void focusChanged(bool); - virtual void activeFocusChanged(bool); virtual void keyPressEvent(QKeyEvent *event); virtual void keyReleaseEvent(QKeyEvent *event); virtual void inputMethodEvent(QInputMethodEvent *); diff --git a/src/declarative/fx/qfxtextedit.cpp b/src/declarative/fx/qfxtextedit.cpp index f4c2e4c..7eb25a8 100644 --- a/src/declarative/fx/qfxtextedit.cpp +++ b/src/declarative/fx/qfxtextedit.cpp @@ -822,7 +822,7 @@ void QFxTextEdit::keyReleaseEvent(QKeyEvent *event) \overload Handles changing of the focus property. Focus is applied to the control even if the edit does not have active focus. This is because things - like KeyProxy can give the behavior of focus even when activeFocus isn't + like KeyProxy can give the behavior of focus even when hasFocus() isn't true. */ void QFxTextEdit::focusChanged(bool hasFocus) -- cgit v0.12 From 99573a8e81fcea38c5f68b340068fff266315c03 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Wed, 7 Oct 2009 15:37:44 +1000 Subject: Make Script an instrinsic type This allows us to delay the QML load until external script files have been loaded from the network, and to correctly scope these scripts. --- src/declarative/qml/qml.pri | 1 + src/declarative/qml/qmlcompiler.cpp | 78 ++++++++- src/declarative/qml/qmlcompiler_p.h | 1 + src/declarative/qml/qmlcompositetypedata_p.h | 22 +++ src/declarative/qml/qmlcompositetypemanager.cpp | 152 ++++++++++++++++- src/declarative/qml/qmlcompositetypemanager_p.h | 6 + src/declarative/qml/qmlcontext.cpp | 39 +++++ src/declarative/qml/qmlcontext_p.h | 1 + src/declarative/qml/qmlinstruction_p.h | 4 + src/declarative/qml/qmlmetaproperty.cpp | 2 +- src/declarative/qml/qmlparser.cpp | 2 + src/declarative/qml/qmlparser_p.h | 5 + src/declarative/qml/qmlscript.cpp | 82 ++++++++++ src/declarative/qml/qmlscriptparser.cpp | 51 +++++- src/declarative/qml/qmlscriptparser_p.h | 2 + src/declarative/qml/qmlvme.cpp | 7 + src/declarative/util/qmlscript.cpp | 209 ------------------------ src/declarative/util/qmlscript.h | 84 ---------- src/declarative/util/util.pri | 2 - 19 files changed, 441 insertions(+), 309 deletions(-) create mode 100644 src/declarative/qml/qmlscript.cpp delete mode 100644 src/declarative/util/qmlscript.cpp delete mode 100644 src/declarative/util/qmlscript.h diff --git a/src/declarative/qml/qml.pri b/src/declarative/qml/qml.pri index e46dd3f..a2e2050 100644 --- a/src/declarative/qml/qml.pri +++ b/src/declarative/qml/qml.pri @@ -35,6 +35,7 @@ SOURCES += qml/qmlparser.cpp \ qml/qmlsqldatabase.cpp \ qml/qmetaobjectbuilder.cpp \ qml/qmlwatcher.cpp \ + qml/qmlscript.cpp \ qml/qmlpropertycache.cpp \ qml/qmlintegercache.cpp \ qml/qmltypenamecache.cpp \ diff --git a/src/declarative/qml/qmlcompiler.cpp b/src/declarative/qml/qmlcompiler.cpp index 4b5c5bf..12e8101 100644 --- a/src/declarative/qml/qmlcompiler.cpp +++ b/src/declarative/qml/qmlcompiler.cpp @@ -669,7 +669,11 @@ bool QmlCompiler::buildObject(Object *obj, const BindingContext &ctxt) if (obj->metatype == &QmlComponent::staticMetaObject) { COMPILE_CHECK(buildComponent(obj, ctxt)); return true; - } + } + + // Build any script blocks for this type + for (int ii = 0; ii < obj->scriptBlockObjects.count(); ++ii) + COMPILE_CHECK(buildScript(obj, obj->scriptBlockObjects.at(ii))); // Object instantiations reset the binding context BindingContext objCtxt(obj); @@ -824,6 +828,15 @@ void QmlCompiler::genObject(QmlParser::Object *obj) output->bytecode << id; } + // Set any script blocks + for (int ii = 0; ii < obj->scriptBlocks.count(); ++ii) { + QmlInstruction script; + script.type = QmlInstruction::StoreScript; + script.line = -1; // ### + script.storeScript.value = output->indexForString(obj->scriptBlocks.at(ii)); + output->bytecode << script; + } + // Begin the class if (obj->parserStatusCast != -1) { QmlInstruction begin; @@ -1000,7 +1013,8 @@ bool QmlCompiler::buildComponent(QmlParser::Object *obj, // Find, check and set the "id" property (if any) Property *idProp = 0; if (obj->properties.count() > 1 || - (obj->properties.count() == 1 && obj->properties.begin().key() != "id")) + (obj->properties.count() == 1 && obj->properties.begin().key() != "id") || + !obj->scriptBlockObjects.isEmpty()) COMPILE_EXCEPTION(obj, "Invalid component specification"); if (obj->properties.count()) @@ -1037,6 +1051,66 @@ bool QmlCompiler::buildComponent(QmlParser::Object *obj, return true; } +bool QmlCompiler::buildScript(QmlParser::Object *obj, QmlParser::Object *script) +{ + QString scriptCode; + + if (script->properties.count() == 1 && + script->properties.begin().key() == QByteArray("source")) { + + Property *source = *script->properties.begin(); + if (script->defaultProperty) + COMPILE_EXCEPTION(source, "Invalid Script block. Specify either the source property or inline script."); + + if (source->value || source->values.count() != 1 || + source->values.at(0)->object || !source->values.at(0)->value.isString()) + COMPILE_EXCEPTION(source, "Invalid Script source value"); + + QString sourceUrl = + output->url.resolved(QUrl(source->values.at(0)->value.asString())).toString(); + + for (int ii = 0; ii < unit->resources.count(); ++ii) { + if (unit->resources.at(ii)->url == sourceUrl) { + scriptCode = QString::fromUtf8(unit->resources.at(ii)->data); + break; + } + } + + } else if (!script->properties.isEmpty()) { + COMPILE_EXCEPTION(*script->properties.begin(), "Properties cannot be set on Script block"); + } else if (script->defaultProperty) { + QmlParser::Location currentLocation; + + for (int ii = 0; ii < script->defaultProperty->values.count(); ++ii) { + Value *v = script->defaultProperty->values.at(ii); + if (v->object || !v->value.isString()) + COMPILE_EXCEPTION(v, "Invalid Script block"); + + if (ii == 0) { + currentLocation = v->location.start; + scriptCode.append(QString(currentLocation.column, QLatin1Char(' '))); + } + + while (currentLocation.line < v->location.start.line) { + scriptCode.append(QLatin1String("\n")); + currentLocation.line++; + currentLocation.column = 0; + } + + scriptCode.append(QString(v->location.start.column - currentLocation.column, QLatin1Char(' '))); + + scriptCode += v->value.asString(); + currentLocation = v->location.end; + currentLocation.column++; + } + } + + if (!scriptCode.isEmpty()) + obj->scriptBlocks.append(scriptCode); + + return true; +} + bool QmlCompiler::buildComponentFromRoot(QmlParser::Object *obj, const BindingContext &ctxt) { diff --git a/src/declarative/qml/qmlcompiler_p.h b/src/declarative/qml/qmlcompiler_p.h index fd361fd..1d27342 100644 --- a/src/declarative/qml/qmlcompiler_p.h +++ b/src/declarative/qml/qmlcompiler_p.h @@ -171,6 +171,7 @@ private: bool buildObject(QmlParser::Object *obj, const BindingContext &); + bool buildScript(QmlParser::Object *obj, QmlParser::Object *script); bool buildComponent(QmlParser::Object *obj, const BindingContext &); bool buildSubObject(QmlParser::Object *obj, const BindingContext &); bool buildSignal(QmlParser::Property *prop, QmlParser::Object *obj, diff --git a/src/declarative/qml/qmlcompositetypedata_p.h b/src/declarative/qml/qmlcompositetypedata_p.h index 48c6c2b..fa11137 100644 --- a/src/declarative/qml/qmlcompositetypedata_p.h +++ b/src/declarative/qml/qmlcompositetypedata_p.h @@ -58,6 +58,7 @@ QT_BEGIN_NAMESPACE +class QmlCompositeTypeResource; class QmlCompositeTypeData : public QmlRefCount { public: @@ -101,6 +102,7 @@ public: }; QList types; + QList resources; // Add or remove p as a waiter. When the QmlCompositeTypeData becomes // ready, the QmlComponentPrivate::typeDataReady() method will be invoked on @@ -122,5 +124,25 @@ private: QmlCompiledData *compiledComponent; }; +class QmlCompositeTypeResource : public QmlRefCount +{ +public: + QmlCompositeTypeResource(); + virtual ~QmlCompositeTypeResource(); + + enum Status { + Invalid, + Complete, + Error, + Waiting + }; + Status status; + + QList dependants; + + QString url; + QByteArray data; +}; + #endif // QMLCOMPOSITETYPEDATA_P_H diff --git a/src/declarative/qml/qmlcompositetypemanager.cpp b/src/declarative/qml/qmlcompositetypemanager.cpp index a99cff0..71b4ef0 100644 --- a/src/declarative/qml/qmlcompositetypemanager.cpp +++ b/src/declarative/qml/qmlcompositetypemanager.cpp @@ -63,6 +63,9 @@ QmlCompositeTypeData::~QmlCompositeTypeData() for (int ii = 0; ii < dependants.count(); ++ii) dependants.at(ii)->release(); + for (int ii = 0; ii < resources.count(); ++ii) + resources.at(ii)->release(); + if (compiledComponent) compiledComponent->release(); @@ -70,6 +73,16 @@ QmlCompositeTypeData::~QmlCompositeTypeData() delete component; } +QmlCompositeTypeResource::QmlCompositeTypeResource() +{ +} + +QmlCompositeTypeResource::~QmlCompositeTypeResource() +{ + for (int ii = 0; ii < dependants.count(); ++ii) + dependants.at(ii)->release(); +} + void QmlCompositeTypeData::addWaiter(QmlComponentPrivate *p) { waiters << p; @@ -142,6 +155,10 @@ QmlCompositeTypeManager::~QmlCompositeTypeManager() (*iter)->release(); iter = components.erase(iter); } + for (Resources::Iterator iter = resources.begin(); iter != resources.end();) { + (*iter)->release(); + iter = resources.erase(iter); + } } QmlCompositeTypeData *QmlCompositeTypeManager::get(const QUrl &url) @@ -181,8 +198,16 @@ void QmlCompositeTypeManager::clearCache() ++iter; } } -} + for (Resources::Iterator iter = resources.begin(); iter != resources.end();) { + if ((*iter)->status != QmlCompositeTypeResource::Waiting) { + (*iter)->release(); + iter = resources.erase(iter); + } else { + ++iter; + } + } +} void QmlCompositeTypeManager::replyFinished() { @@ -215,6 +240,52 @@ void QmlCompositeTypeManager::replyFinished() reply->deleteLater(); } +void QmlCompositeTypeManager::resourceReplyFinished() +{ + QNetworkReply *reply = static_cast(sender()); + + QmlCompositeTypeResource *resource = resources.value(reply->url().toString()); + Q_ASSERT(resource); + + if (reply->error() != QNetworkReply::NoError) { + + resource->status = QmlCompositeTypeResource::Error; + + } else { + + resource->status = QmlCompositeTypeResource::Complete; + resource->data = reply->readAll(); + + } + + doComplete(resource); + reply->deleteLater(); +} + +void QmlCompositeTypeManager::loadResource(QmlCompositeTypeResource *resource) +{ + QUrl url(resource->url); + + if (url.scheme() == QLatin1String("file")) { + + QFile file(url.toLocalFile()); + if (file.open(QFile::ReadOnly)) { + resource->data = file.readAll(); + resource->status = QmlCompositeTypeResource::Complete; + } else { + resource->status = QmlCompositeTypeResource::Error; + } + + } else { + + QNetworkReply *reply = + engine->networkAccessManager()->get(QNetworkRequest(url)); + QObject::connect(reply, SIGNAL(finished()), + this, SLOT(resourceReplyFinished())); + + } +} + void QmlCompositeTypeManager::loadSource(QmlCompositeTypeData *unit) { QUrl url(unit->imports.baseUrl()); @@ -308,6 +379,15 @@ void QmlCompositeTypeManager::doComplete(QmlCompositeTypeData *unit) } } +void QmlCompositeTypeManager::doComplete(QmlCompositeTypeResource *resource) +{ + for (int ii = 0; ii < resource->dependants.count(); ++ii) { + checkComplete(resource->dependants.at(ii)); + resource->dependants.at(ii)->release(); + } + resource->dependants.clear(); +} + void QmlCompositeTypeManager::checkComplete(QmlCompositeTypeData *unit) { if (unit->status != QmlCompositeTypeData::Waiting) @@ -329,12 +409,33 @@ void QmlCompositeTypeManager::checkComplete(QmlCompositeTypeData *unit) waiting++; } } + for (int ii = 0; ii < unit->resources.count(); ++ii) { + QmlCompositeTypeResource *r = unit->resources.at(ii); + + if (!r) + continue; + + if (r->status == QmlCompositeTypeResource::Error) { + unit->status = QmlCompositeTypeData::Error; + QmlError error; + error.setUrl(unit->imports.baseUrl()); + error.setDescription(QLatin1String("Resource ") + r->url + + QLatin1String(" unavailable")); + unit->errors << error; + doComplete(unit); + return; + } else if (r->status == QmlCompositeTypeData::Waiting) { + waiting++; + } + } + if (!waiting) { unit->status = QmlCompositeTypeData::Complete; doComplete(unit); } } +// ### Check ref counting in here void QmlCompositeTypeManager::compile(QmlCompositeTypeData *unit) { QList types = unit->data.referencedTypes(); @@ -346,12 +447,6 @@ void QmlCompositeTypeManager::compile(QmlCompositeTypeData *unit) QmlCompositeTypeData::TypeReference ref; - if (typeName == QByteArray("Property") || - typeName == QByteArray("Signal")) { - unit->types << ref; - continue; - } - QUrl url; int majorVersion; int minorVersion; @@ -431,6 +526,49 @@ void QmlCompositeTypeManager::compile(QmlCompositeTypeData *unit) unit->types << ref; } + QList resourceList = unit->data.referencedResources(); + for (int ii = 0; ii < resourceList.count(); ++ii) { + QUrl url = unit->imports.baseUrl().resolved(resourceList.at(ii)); + + QmlCompositeTypeResource *resource = resources.value(url.toString()); + + if (!resource) { + resource = new QmlCompositeTypeResource; + resource->status = QmlCompositeTypeResource::Waiting; + resource->url = url.toString(); + resources.insert(resource->url, resource); + + loadResource(resource); + } + + switch(resource->status) { + case QmlCompositeTypeResource::Invalid: + case QmlCompositeTypeResource::Error: + unit->status = QmlCompositeTypeData::Error; + { + QmlError error; + error.setUrl(unit->imports.baseUrl()); + error.setDescription(QLatin1String("Resource ") + resource->url + + QLatin1String(" unavailable")); + unit->errors << error; + } + doComplete(unit); + return; + + case QmlCompositeTypeData::Complete: + break; + + case QmlCompositeTypeData::Waiting: + unit->addref(); + resource->dependants << unit; + waiting++; + break; + } + + resource->addref(); + unit->resources << resource; + } + if (waiting) { unit->status = QmlCompositeTypeData::Waiting; } else { diff --git a/src/declarative/qml/qmlcompositetypemanager_p.h b/src/declarative/qml/qmlcompositetypemanager_p.h index 8f16998..843a9cf 100644 --- a/src/declarative/qml/qmlcompositetypemanager_p.h +++ b/src/declarative/qml/qmlcompositetypemanager_p.h @@ -67,6 +67,7 @@ class QmlComponent; class QmlDomDocument; class QmlCompositeTypeData; +class QmlCompositeTypeResource; class QmlCompositeTypeManager : public QObject { @@ -88,19 +89,24 @@ public: private Q_SLOTS: void replyFinished(); + void resourceReplyFinished(); void requestProgress(qint64 received, qint64 total); private: void loadSource(QmlCompositeTypeData *); + void loadResource(QmlCompositeTypeResource *); void compile(QmlCompositeTypeData *); void setData(QmlCompositeTypeData *, const QByteArray &, const QUrl &); void doComplete(QmlCompositeTypeData *); + void doComplete(QmlCompositeTypeResource *); void checkComplete(QmlCompositeTypeData *); QmlEngine *engine; typedef QHash Components; Components components; + typedef QHash Resources; + Resources resources; }; QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlcontext.cpp b/src/declarative/qml/qmlcontext.cpp index a1eb5de..549925f 100644 --- a/src/declarative/qml/qmlcontext.cpp +++ b/src/declarative/qml/qmlcontext.cpp @@ -48,6 +48,7 @@ #include #include #include +#include // 6-bits #define MAXIMUM_DEFAULT_OBJECTS 63 @@ -60,6 +61,44 @@ QmlContextPrivate::QmlContextPrivate() { } +void QmlContextPrivate::addScript(const QString &script, QObject *scopeObject) +{ + if (!engine) + return; + + QmlEnginePrivate *enginePriv = QmlEnginePrivate::get(engine); + QScriptEngine *scriptEngine = QmlEnginePrivate::getScriptEngine(engine); + + QScriptContext *scriptContext = scriptEngine->pushCleanContext(); + scriptContext->pushScope(scriptValue); + + if (scopeObject) + scriptContext->pushScope(enginePriv->objectClass->newQObject(scopeObject)); + + QScriptValue scope = scriptEngine->newObject(); + scriptContext->setActivationObject(scope); + + QScriptValue val = scriptEngine->evaluate(script); + + if (scriptEngine->hasUncaughtException()) { + if (scriptEngine->uncaughtException().isError()){ + QScriptValue exception = scriptEngine->uncaughtException(); + if (!exception.property(QLatin1String("fileName")).toString().isEmpty()){ + qWarning() << exception.property(QLatin1String("fileName")).toString() + << scriptEngine->uncaughtExceptionLineNumber() + << exception.toString(); + + } else { + qmlInfo(scopeObject) << exception.toString(); + } + } + } + + scriptEngine->popContext(); + + scripts.append(scope); +} + void QmlContextPrivate::dump() { dump(0); diff --git a/src/declarative/qml/qmlcontext_p.h b/src/declarative/qml/qmlcontext_p.h index 22e5895..d18bfda 100644 --- a/src/declarative/qml/qmlcontext_p.h +++ b/src/declarative/qml/qmlcontext_p.h @@ -94,6 +94,7 @@ public: QScriptValue scriptValue; QList scripts; + void addScript(const QString &script, QObject *scope); QUrl url; diff --git a/src/declarative/qml/qmlinstruction_p.h b/src/declarative/qml/qmlinstruction_p.h index 38b3191..1dcdace 100644 --- a/src/declarative/qml/qmlinstruction_p.h +++ b/src/declarative/qml/qmlinstruction_p.h @@ -118,6 +118,7 @@ public: StoreInterface, /* storeObject */ StoreSignal, /* storeSignal */ + StoreScript, /* storeScript */ // // Unresolved single assignment @@ -238,6 +239,9 @@ public: int value; } storeString; struct { + int value; + } storeScript; + struct { int propertyIndex; int value; } storeUrl; diff --git a/src/declarative/qml/qmlmetaproperty.cpp b/src/declarative/qml/qmlmetaproperty.cpp index 155b34a..302ce8c 100644 --- a/src/declarative/qml/qmlmetaproperty.cpp +++ b/src/declarative/qml/qmlmetaproperty.cpp @@ -564,7 +564,7 @@ QmlMetaProperty::setBinding(QmlAbstractBinding *newBinding) const if (!isProperty() || (type() & Attached) || !d->object) return 0; - d->setBinding(d->object, d->core, newBinding); + return d->setBinding(d->object, d->core, newBinding); } QmlAbstractBinding * diff --git a/src/declarative/qml/qmlparser.cpp b/src/declarative/qml/qmlparser.cpp index 39fe1e2..8c46939 100644 --- a/src/declarative/qml/qmlparser.cpp +++ b/src/declarative/qml/qmlparser.cpp @@ -82,6 +82,8 @@ QmlParser::Object::~Object() prop->release(); foreach(const DynamicProperty &prop, dynamicProperties) if (prop.defaultValue) prop.defaultValue->release(); + foreach(Object *obj, scriptBlockObjects) + obj->release(); } void Object::setBindingBit(int b) diff --git a/src/declarative/qml/qmlparser_p.h b/src/declarative/qml/qmlparser_p.h index e0579b0..16862eb 100644 --- a/src/declarative/qml/qmlparser_p.h +++ b/src/declarative/qml/qmlparser_p.h @@ -151,6 +151,8 @@ namespace QmlParser Property *defaultProperty; QHash properties; + QList scriptBlockObjects; + // Output of the compilation phase (these properties continue to exist // in either the defaultProperty or properties members too) void addValueProperty(Property *); @@ -164,6 +166,9 @@ namespace QmlParser QList groupedProperties; QList valueTypeProperties; + // Script blocks that were nested under this object + QStringList scriptBlocks; + // The bytes to cast instances by to get to the QmlParserStatus // interface. -1 indicates the type doesn't support this interface. // Set by the QmlCompiler. diff --git a/src/declarative/qml/qmlscript.cpp b/src/declarative/qml/qmlscript.cpp new file mode 100644 index 0000000..307d72f --- /dev/null +++ b/src/declarative/qml/qmlscript.cpp @@ -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$ +** +****************************************************************************/ + +// This is just a dummy file to include the documentation + +/*! + \qmlclass Script QmlScript + \brief The Script element adds JavaScript snippets. + \ingroup group_utility + + QmlScript is used to add convenient JavaScript "glue" methods to + your Qt Declarative application or component. While you can have any JavaScript code + within a QmlScript, it is best to limit yourself to defining functions. + + \qml + Script { + function debugMyComponent() { + print(text.text); + print(otherinterestingitem.property); + } + } + MouseRegion { onClicked: debugMyComponent() } + \endqml + + \note QmlScript executes JavaScript as soon as it is specified. + When defining a component, this may be before the execution context is + fully specified. As a result some properties or items may not be + accessible. By limiting your JavaScript to defining functions that are + only executed later once the context is fully defined, this problem is + avoided. +*/ + +/*! + \qmlproperty string Script::script + \default + JavaScript code to execute. +*/ + +/*! + \qmlproperty url Script::source + + Setting this property causes the Script element to read JavaScript code from + the file specified. +*/ diff --git a/src/declarative/qml/qmlscriptparser.cpp b/src/declarative/qml/qmlscriptparser.cpp index c126830..1c7bf83 100644 --- a/src/declarative/qml/qmlscriptparser.cpp +++ b/src/declarative/qml/qmlscriptparser.cpp @@ -289,12 +289,26 @@ ProcessAST::defineObjectBinding_helper(AST::UiQualifiedId *propertyName, if (lastTypeDot >= 0) resolvableObjectType.replace(QLatin1Char('.'),QLatin1Char('/')); - QmlScriptParser::TypeReference *typeRef = _parser->findOrCreateType(resolvableObjectType); + bool isScript = resolvableObjectType == QLatin1String("Script"); + + if (isScript) { + if (_stateStack.isEmpty() || _stateStack.top().property) { + QmlError error; + error.setDescription(QLatin1String("Invalid use of Script block")); + error.setLine(typeLocation.startLine); + error.setColumn(typeLocation.startColumn); + _parser->_errors << error; + } + } Object *obj = new Object; - obj->type = typeRef->id; - typeRef->refObjects.append(obj); + if (!isScript) { + QmlScriptParser::TypeReference *typeRef = _parser->findOrCreateType(resolvableObjectType); + obj->type = typeRef->id; + + typeRef->refObjects.append(obj); + } // XXX this doesn't do anything (_scope never builds up) _scope.append(resolvableObjectType); @@ -303,7 +317,11 @@ ProcessAST::defineObjectBinding_helper(AST::UiQualifiedId *propertyName, obj->location = location; - if (propertyCount) { + if (isScript) { + + _stateStack.top().object->scriptBlockObjects.append(obj); + + } else if (propertyCount) { Property *prop = currentProperty(); Value *v = new Value; @@ -385,6 +403,26 @@ Object *ProcessAST::defineObjectBinding(AST::UiQualifiedId *qualifiedId, _stateStack.pop(); // object return obj; + } else if (objectType == QLatin1String("Script")) { + + AST::UiObjectMemberList *it = initializer->members; + for (; it; it = it->next) { + AST::UiScriptBinding *scriptBinding = AST::cast(it->member); + if (! scriptBinding) + continue; + + QString propertyName = asString(scriptBinding->qualifiedId); + if (propertyName == QLatin1String("source")) { + if (AST::ExpressionStatement *stmt = AST::cast(scriptBinding->statement)) { + AST::StringLiteral *string = AST::cast(stmt->expression); + if (string) { + // We need to add this as a resource + _parser->_refUrls << QUrl(string->value->asString()); + } + } + } + } + } return defineObjectBinding_helper(qualifiedId, objectType, typeLocation, location, initializer); @@ -867,6 +905,11 @@ QList QmlScriptParser::referencedTypes() const return _refTypes; } +QList QmlScriptParser::referencedResources() const +{ + return _refUrls; +} + Object *QmlScriptParser::tree() const { return root; diff --git a/src/declarative/qml/qmlscriptparser_p.h b/src/declarative/qml/qmlscriptparser_p.h index d489610..b25d6bf 100644 --- a/src/declarative/qml/qmlscriptparser_p.h +++ b/src/declarative/qml/qmlscriptparser_p.h @@ -102,6 +102,7 @@ public: bool parse(const QByteArray &data, const QUrl &url = QUrl()); QList referencedTypes() const; + QList referencedResources() const; QmlParser::Object *tree() const; QList imports() const; @@ -123,6 +124,7 @@ public: QmlParser::Object *root; QList _imports; QList _refTypes; + QList _refUrls; QString _scriptFile; QmlScriptParserJsASTData *data; }; diff --git a/src/declarative/qml/qmlvme.cpp b/src/declarative/qml/qmlvme.cpp index 4ba412b..e4eef64 100644 --- a/src/declarative/qml/qmlvme.cpp +++ b/src/declarative/qml/qmlvme.cpp @@ -564,6 +564,13 @@ QObject *QmlVME::run(QStack &stack, QmlContext *ctxt, } break; + case QmlInstruction::StoreScript: + { + QObject *target = stack.top(); + cp->addScript(primitives.at(instr.storeScript.value), target); + } + break; + case QmlInstruction::BeginObject: { QObject *target = stack.top(); diff --git a/src/declarative/util/qmlscript.cpp b/src/declarative/util/qmlscript.cpp deleted file mode 100644 index 5d58f64..0000000 --- a/src/declarative/util/qmlscript.cpp +++ /dev/null @@ -1,209 +0,0 @@ -/**************************************************************************** -** -** 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "qmlscript.h" -#include -#include -#include -#include - -QT_BEGIN_NAMESPACE - -class QmlScriptPrivate : public QObjectPrivate -{ - Q_DECLARE_PUBLIC(QmlScript); - -public: - QmlScriptPrivate() : reply(0) {} - - void addScriptToEngine(const QString &, const QString &source=QString()); - - QString script; - QNetworkReply *reply; - QUrl url; -}; - -/*! - \qmlclass Script QmlScript - \brief The Script element adds JavaScript snippets. - \ingroup group_utility - - QmlScript is used to add convenient JavaScript "glue" methods to - your Qt Declarative application or component. While you can have any JavaScript code - within a QmlScript, it is best to limit yourself to defining functions. - - \qml - Script { - function debugMyComponent() { - print(text.text); - print(otherinterestingitem.property); - } - } - MouseRegion { onClicked: debugMyComponent() } - \endqml - - \note QmlScript executes JavaScript as soon as it is specified. - When defining a component, this may be before the execution context is - fully specified. As a result some properties or items may not be - accessible. By limiting your JavaScript to defining functions that are - only executed later once the context is fully defined, this problem is - avoided. -*/ - -QML_DEFINE_TYPE(Qt,4,6,(QT_VERSION&0x00ff00)>>8,Script,QmlScript) -QmlScript::QmlScript(QObject *parent) : QObject(*(new QmlScriptPrivate), parent) -{ -} - -/*! - \qmlproperty string Script::script - \default - JavaScript code to execute. -*/ -QString QmlScript::script() const -{ - Q_D(const QmlScript); - return d->script; -} - -void QmlScript::setScript(const QString &script) -{ - Q_D(QmlScript); - d->script = script; - d->addScriptToEngine(d->script); -} - -/*! - \qmlproperty url Script::source - - Setting this property causes the Script element to read JavaScript code from - the file specified. -*/ -QUrl QmlScript::source() const -{ - Q_D(const QmlScript); - return d->url; -} - -void QmlScript::setSource(const QUrl &source) -{ - Q_D(QmlScript); - if (d->url == source) - return; - d->url = qmlContext(this)->resolvedUrl(source); - -#ifndef QT_NO_LOCALFILE_OPTIMIZED_QML - if (d->url.scheme() == QLatin1String("file")) { - QFile file(d->url.toLocalFile()); - file.open(QIODevice::ReadOnly); - QByteArray ba = file.readAll(); - d->addScriptToEngine(QString::fromUtf8(ba), file.fileName()); - } else -#endif - { - QNetworkRequest req(d->url); - d->reply = qmlEngine(this)->networkAccessManager()->get(req); - QObject::connect(d->reply, SIGNAL(finished()), - this, SLOT(replyFinished())); - } -} - -void QmlScript::replyFinished() -{ - Q_D(QmlScript); - if (!d->reply->error()) { - QByteArray ba = d->reply->readAll(); - d->addScriptToEngine(QString::fromUtf8(ba), d->url.toString()); - } - d->reply->deleteLater(); - d->reply = 0; -} - -void QmlScriptPrivate::addScriptToEngine(const QString &script, const QString &source) -{ -#ifdef Q_ENABLE_PERFORMANCE_LOG - QFxPerfTimer pt; -#endif - Q_Q(QmlScript); - QmlEngine *engine = qmlEngine(q); - QmlContext *context = qmlContext(q); - QScriptEngine *scriptEngine = QmlEnginePrivate::getScriptEngine(engine); - - QScriptContext *scriptContext = scriptEngine->pushCleanContext(); - scriptContext->pushScope(QmlContextPrivate::get(context)->scriptValue); - - QScriptValue scope = scriptEngine->newObject(); - scriptContext->pushScope(scope); - - scriptContext->setActivationObject(scope); - - QScriptValue val = scriptEngine->evaluate(script, source); - if (scriptEngine->hasUncaughtException()) { - if (scriptEngine->uncaughtException().isError()){ - QScriptValue exception = scriptEngine->uncaughtException(); - if (!exception.property(QLatin1String("fileName")).toString().isEmpty()){ - qWarning() << exception.property(QLatin1String("fileName")).toString() - << scriptEngine->uncaughtExceptionLineNumber() - << exception.toString(); - - } else { - qmlInfo(q) << exception.toString(); - } - } - } - - scriptEngine->popContext(); - - context->d_func()->scripts.append(scope); -} - -QT_END_NAMESPACE diff --git a/src/declarative/util/qmlscript.h b/src/declarative/util/qmlscript.h deleted file mode 100644 index 4ba4f6b..0000000 --- a/src/declarative/util/qmlscript.h +++ /dev/null @@ -1,84 +0,0 @@ -/**************************************************************************** -** -** 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 QMLSCRIPT_H -#define QMLSCRIPT_H - -#include -#include -#include - -QT_BEGIN_HEADER - -QT_BEGIN_NAMESPACE - -QT_MODULE(Declarative) - -class QmlScriptPrivate; -class Q_DECLARATIVE_EXPORT QmlScript : public QObject -{ - Q_OBJECT - Q_DECLARE_PRIVATE(QmlScript) - - Q_PROPERTY(QString script READ script WRITE setScript) - Q_PROPERTY(QUrl source READ source WRITE setSource) - Q_CLASSINFO("DefaultProperty", "script") - -public: - QmlScript(QObject *parent=0); - - QString script() const; - void setScript(const QString &); - - QUrl source() const; - void setSource(const QUrl &); - -private Q_SLOTS: - void replyFinished(); -}; - -QT_END_NAMESPACE - -QML_DECLARE_TYPE(QmlScript) - -QT_END_HEADER - -#endif diff --git a/src/declarative/util/util.pri b/src/declarative/util/util.pri index 41c9019..ec9967c 100644 --- a/src/declarative/util/util.pri +++ b/src/declarative/util/util.pri @@ -4,7 +4,6 @@ SOURCES += \ util/qperformancelog.cpp \ util/qmlconnection.cpp \ util/qmlpackage.cpp \ - util/qmlscript.cpp \ util/qmlanimation.cpp \ util/qmlsystempalette.cpp \ util/qmlspringfollow.cpp \ @@ -29,7 +28,6 @@ HEADERS += \ util/qperformancelog_p.h \ util/qmlconnection.h \ util/qmlpackage.h \ - util/qmlscript.h \ util/qmlanimation.h \ util/qmlanimation_p.h \ util/qmlsystempalette.h \ -- cgit v0.12 From c164ba0b9486e0a559ed4daa076416cd9f81962f Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Wed, 7 Oct 2009 17:02:55 +1000 Subject: Fix test --- tests/auto/declarative/qmlecmascript/tst_qmlecmascript.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/auto/declarative/qmlecmascript/tst_qmlecmascript.cpp b/tests/auto/declarative/qmlecmascript/tst_qmlecmascript.cpp index c7f0424..34fa5e9 100644 --- a/tests/auto/declarative/qmlecmascript/tst_qmlecmascript.cpp +++ b/tests/auto/declarative/qmlecmascript/tst_qmlecmascript.cpp @@ -679,7 +679,8 @@ void tst_qmlecmascript::objectToString() MyQmlObject *object = qobject_cast(component.create()); QVERIFY(object != 0); QMetaObject::invokeMethod(object, "testToString"); - QVERIFY(object->stringProperty().startsWith("Qml Object, \"objName\" MyQmlObject_QML_15")); + QVERIFY(object->stringProperty().startsWith("MyQmlObject_QML_")); + QVERIFY(object->stringProperty().endsWith(", \"objName\")")); } QTEST_MAIN(tst_qmlecmascript) -- cgit v0.12 From 26fc680ab4344d1c14756459ab92c0413aebf99c Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Wed, 7 Oct 2009 17:43:07 +1000 Subject: Add Object.destroy(int delay) parameter --- src/declarative/qml/qmlobjectscriptclass.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/declarative/qml/qmlobjectscriptclass.cpp b/src/declarative/qml/qmlobjectscriptclass.cpp index 2d69590..ce74aef 100644 --- a/src/declarative/qml/qmlobjectscriptclass.cpp +++ b/src/declarative/qml/qmlobjectscriptclass.cpp @@ -46,6 +46,7 @@ #include #include #include +#include QT_BEGIN_NAMESPACE @@ -290,9 +291,10 @@ QScriptValue QmlObjectScriptClass::destroy(QScriptContext *context, QScriptEngin int delay = 0; if(context->argumentCount() > 0) delay = context->argument(0).toInt32(); - obj->deleteLater(); - //### Should this be delayed as well? - context->thisObject().setData(QScriptValue(engine, 0)); + if (delay > 0) + QTimer::singleShot(delay, obj, SLOT(deleteLater())); + else + obj->deleteLater(); } return engine->nullValue(); } -- cgit v0.12 From 5bc98da76b7d6ab4d175ac75e539d7f887c2c080 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Wed, 7 Oct 2009 18:15:15 +1000 Subject: Fix test case qWait() enters a nested event loop, so delete laters weren't being processed. --- tests/auto/declarative/qmlecmascript/tst_qmlecmascript.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/auto/declarative/qmlecmascript/tst_qmlecmascript.cpp b/tests/auto/declarative/qmlecmascript/tst_qmlecmascript.cpp index 34fa5e9..4ed12f7 100644 --- a/tests/auto/declarative/qmlecmascript/tst_qmlecmascript.cpp +++ b/tests/auto/declarative/qmlecmascript/tst_qmlecmascript.cpp @@ -667,6 +667,7 @@ void tst_qmlecmascript::dynamicDestruction() QMetaObject::invokeMethod(object, "killMe"); QVERIFY(object); QTest::qWait(0); + QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion); QVERIFY(!object); } -- cgit v0.12 From 12f272ce159853329a26fc82dfb55b930a97a2a9 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Wed, 7 Oct 2009 18:20:40 +1000 Subject: Remove bogus assert --- src/declarative/qml/qmlobjectscriptclass.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/declarative/qml/qmlobjectscriptclass.cpp b/src/declarative/qml/qmlobjectscriptclass.cpp index ce74aef..9448dcc 100644 --- a/src/declarative/qml/qmlobjectscriptclass.cpp +++ b/src/declarative/qml/qmlobjectscriptclass.cpp @@ -186,7 +186,6 @@ QScriptValue QmlObjectScriptClass::property(QObject *obj, const Identifier &name else if (name == m_toStringId.identifier) return m_toString; - Q_ASSERT(lastData); Q_ASSERT(obj); QScriptEngine *scriptEngine = QmlEnginePrivate::getScriptEngine(engine); -- cgit v0.12 From d07270161ef3d1c4b3ed29110a16eaff54333fd5 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Wed, 7 Oct 2009 22:07:06 +1000 Subject: Fix test case qWait() enters a nested event loop, so delete laters weren't being processed. --- tests/auto/declarative/qmlecmascript/tst_qmlecmascript.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/auto/declarative/qmlecmascript/tst_qmlecmascript.cpp b/tests/auto/declarative/qmlecmascript/tst_qmlecmascript.cpp index 4ed12f7..51f1ce7 100644 --- a/tests/auto/declarative/qmlecmascript/tst_qmlecmascript.cpp +++ b/tests/auto/declarative/qmlecmascript/tst_qmlecmascript.cpp @@ -660,8 +660,10 @@ void tst_qmlecmascript::dynamicDestruction() QMetaObject::invokeMethod(object, "killOther"); QVERIFY(createdQmlObject); QTest::qWait(0); + QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion); QVERIFY(createdQmlObject); QTest::qWait(100); + QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion); QVERIFY(!createdQmlObject); QMetaObject::invokeMethod(object, "killMe"); -- cgit v0.12 From 60a5afb67efcefa74cf452379dcef46b83daa265 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Wed, 7 Oct 2009 23:33:32 +1000 Subject: Self deleting binding test --- .../qmlecmascript/data/selfDeletingBinding.2.qml | 17 ++++++++++++++++ .../qmlecmascript/data/selfDeletingBinding.qml | 18 +++++++++++++++++ tests/auto/declarative/qmlecmascript/testtypes.h | 5 +++++ .../qmlecmascript/tst_qmlecmascript.cpp | 23 ++++++++++++++++++++++ 4 files changed, 63 insertions(+) create mode 100644 tests/auto/declarative/qmlecmascript/data/selfDeletingBinding.2.qml create mode 100644 tests/auto/declarative/qmlecmascript/data/selfDeletingBinding.qml diff --git a/tests/auto/declarative/qmlecmascript/data/selfDeletingBinding.2.qml b/tests/auto/declarative/qmlecmascript/data/selfDeletingBinding.2.qml new file mode 100644 index 0000000..58cf805 --- /dev/null +++ b/tests/auto/declarative/qmlecmascript/data/selfDeletingBinding.2.qml @@ -0,0 +1,17 @@ +import Qt.test 1.0 + +MyQmlContainer { + property bool triggerDelete: false + + children: [ + MyQmlObject { + // Will trigger deletion on binding assignment + deleteOnSet: Math.max(0, 1) + }, + + MyQmlObject { + // Will trigger deletion on binding assignment, but after component creation + deleteOnSet: if (triggerDelete) 1; else 0; + } + ] +} diff --git a/tests/auto/declarative/qmlecmascript/data/selfDeletingBinding.qml b/tests/auto/declarative/qmlecmascript/data/selfDeletingBinding.qml new file mode 100644 index 0000000..074851a --- /dev/null +++ b/tests/auto/declarative/qmlecmascript/data/selfDeletingBinding.qml @@ -0,0 +1,18 @@ +import Qt.test 1.0 + +MyQmlContainer { + property bool triggerDelete: false + + children: [ + MyQmlObject { + // Will trigger deletion during binding evaluation + stringProperty: {deleteMe(), "Hello"} + }, + + MyQmlObject { + // Will trigger deletion during binding evaluation, but after component creation + stringProperty: if (triggerDelete) { deleteMe(), "Hello" } else { "World" } + } + + ] +} diff --git a/tests/auto/declarative/qmlecmascript/testtypes.h b/tests/auto/declarative/qmlecmascript/testtypes.h index ffc8fec..e6c2c20 100644 --- a/tests/auto/declarative/qmlecmascript/testtypes.h +++ b/tests/auto/declarative/qmlecmascript/testtypes.h @@ -23,6 +23,7 @@ class MyQmlObject : public QObject Q_OBJECT Q_ENUMS(MyEnum) Q_ENUMS(MyEnum2) + Q_PROPERTY(int deleteOnSet READ deleteOnSet WRITE setDeleteOnSet); Q_PROPERTY(bool trueProperty READ trueProperty CONSTANT) Q_PROPERTY(bool falseProperty READ falseProperty CONSTANT) Q_PROPERTY(QString stringProperty READ stringProperty WRITE setStringProperty NOTIFY stringChanged) @@ -61,6 +62,9 @@ public: static MyQmlAttachedObject *qmlAttachedProperties(QObject *o) { return new MyQmlAttachedObject(o); } + + int deleteOnSet() const { return 1; } + void setDeleteOnSet(int v) { if(v) delete this; } signals: void basicSignal(); void argumentSignal(int a, QString b, qreal c); @@ -68,6 +72,7 @@ signals: void objectChanged(); public slots: + void deleteMe() { delete this; } void method() { m_methodCalled = true; } void method(int a) { if(a == 163) m_methodIntCalled = true; } void setString(const QString &s) { m_string = s; } diff --git a/tests/auto/declarative/qmlecmascript/tst_qmlecmascript.cpp b/tests/auto/declarative/qmlecmascript/tst_qmlecmascript.cpp index 51f1ce7..6bc88c0 100644 --- a/tests/auto/declarative/qmlecmascript/tst_qmlecmascript.cpp +++ b/tests/auto/declarative/qmlecmascript/tst_qmlecmascript.cpp @@ -59,6 +59,7 @@ private slots: void dynamicCreation(); void dynamicDestruction(); void objectToString(); + void selfDeletingBinding(); private: QmlEngine engine; @@ -686,6 +687,28 @@ void tst_qmlecmascript::objectToString() QVERIFY(object->stringProperty().endsWith(", \"objName\")")); } +/* +Tests bindings that indirectly cause their own deletion work. + +This test is best run under valgrind to ensure no invalid memory access occur. +*/ +void tst_qmlecmascript::selfDeletingBinding() +{ + { + QmlComponent component(&engine, TEST_FILE("selfDeletingBinding.qml")); + QObject *object = component.create(); + QVERIFY(object != 0); + object->setProperty("triggerDelete", true); + } + + { + QmlComponent component(&engine, TEST_FILE("selfDeletingBinding.2.qml")); + QObject *object = component.create(); + QVERIFY(object != 0); + object->setProperty("triggerDelete", true); + } +} + QTEST_MAIN(tst_qmlecmascript) #include "tst_qmlecmascript.moc" -- cgit v0.12 From 41ec742f6713f5b3b4da853f514d685c35c3f31f Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Thu, 8 Oct 2009 13:25:56 +1000 Subject: Make qmlecmascript:selfDeletingBinding pass Expressions and bindings must not reference data following their evalutation incase their object has been deleted. To solve this, the needed data is separated into a reference counted QmlExpressionData and QmlBindingData object. --- src/declarative/qml/qmlbinding.cpp | 59 ++++++----- src/declarative/qml/qmlbinding_p.h | 15 ++- src/declarative/qml/qmlexpression.cpp | 193 +++++++++++++++++++--------------- src/declarative/qml/qmlexpression_p.h | 48 +++++---- 4 files changed, 182 insertions(+), 133 deletions(-) diff --git a/src/declarative/qml/qmlbinding.cpp b/src/declarative/qml/qmlbinding.cpp index 454369b..3a34f46 100644 --- a/src/declarative/qml/qmlbinding.cpp +++ b/src/declarative/qml/qmlbinding.cpp @@ -57,11 +57,16 @@ QT_BEGIN_NAMESPACE QML_DEFINE_NOCREATE_TYPE(QmlBinding); -QmlBindingPrivate::QmlBindingPrivate() +QmlBindingData::QmlBindingData() : updating(false), enabled(false) { } +QmlBindingPrivate::QmlBindingPrivate() +: QmlExpressionPrivate(new QmlBindingData) +{ +} + QmlBinding::QmlBinding(void *data, QmlRefCount *rc, QObject *obj, QmlContext *ctxt, QObject *parent) : QmlExpression(ctxt, data, rc, obj, *new QmlBindingPrivate) { @@ -81,7 +86,7 @@ QmlBinding::~QmlBinding() void QmlBinding::setTarget(const QmlMetaProperty &prop) { Q_D(QmlBinding); - d->property = prop; + d->bindingData()->property = prop; update(); } @@ -89,7 +94,7 @@ void QmlBinding::setTarget(const QmlMetaProperty &prop) QmlMetaProperty QmlBinding::property() const { Q_D(const QmlBinding); - return d->property; + return d->bindingData()->property; } void QmlBinding::update() @@ -99,45 +104,41 @@ void QmlBinding::update() #ifdef Q_ENABLE_PERFORMANCE_LOG QFxPerfTimer bu; #endif - if (!d->enabled) + QmlBindingData *data = d->bindingData(); + + if (!data->enabled) return; - if (!d->updating) { - d->updating = true; + data->addref(); - if (d->property.propertyCategory() == QmlMetaProperty::Bindable) { + if (!data->updating) { + data->updating = true; - int idx = d->property.coreIndex(); + if (data->property.propertyCategory() == QmlMetaProperty::Bindable) { + + int idx = data->property.coreIndex(); Q_ASSERT(idx != -1); void *a[1]; QmlBinding *t = this; a[0] = (void *)&t; - QMetaObject::metacall(d->property.object(), + QMetaObject::metacall(data->property.object(), QMetaObject::WriteProperty, idx, a); } else { QVariant value = this->value(); - if (value.type() == QVariant::String) { - QmlMetaType::StringConverter con = QmlMetaType::customStringConverter(d->property.propertyType()); - if (con) - value = con(value.toString()); - } - - if (d->property.propertyType() == QVariant::Vector3D && - value.type() == QVariant::String) { - value = qVariantFromValue(QmlStringConverters::vector3DFromString(value.toString())); - } - - d->property.write(value, QmlMetaProperty::Binding); + data->property.write(value, QmlMetaProperty::Binding); } - d->updating = false; + data->updating = false; } else { - qmlInfo(d->property.object()) << "Binding loop detected for property" << d->property.name(); + qmlInfo(data->property.object()) << "Binding loop detected for property" + << data->property.name(); } + + data->release(); } void QmlBinding::valueChanged() @@ -148,30 +149,30 @@ void QmlBinding::valueChanged() void QmlBinding::setEnabled(bool e) { Q_D(QmlBinding); - d->enabled = e; + d->bindingData()->enabled = e; setTrackChange(e); + QmlAbstractBinding::setEnabled(e); + if (e) { - addToObject(d->property.object()); + addToObject(d->bindingData()->property.object()); update(); } else { removeFromObject(); } - - QmlAbstractBinding::setEnabled(e); } int QmlBinding::propertyIndex() { Q_D(QmlBinding); - return d->property.coreIndex(); + return d->bindingData()->property.coreIndex(); } bool QmlBinding::enabled() const { Q_D(const QmlBinding); - return d->enabled; + return d->bindingData()->enabled; } QString QmlBinding::expression() const diff --git a/src/declarative/qml/qmlbinding_p.h b/src/declarative/qml/qmlbinding_p.h index 963e2c1..2c0c6b9 100644 --- a/src/declarative/qml/qmlbinding_p.h +++ b/src/declarative/qml/qmlbinding_p.h @@ -59,11 +59,10 @@ QT_BEGIN_NAMESPACE -class QmlBindingPrivate : public QmlExpressionPrivate +class QmlBindingData : public QmlExpressionData { - Q_DECLARE_PUBLIC(QmlBinding) public: - QmlBindingPrivate(); + QmlBindingData(); bool updating:1; bool enabled:1; @@ -71,6 +70,16 @@ public: QmlMetaProperty property; }; +class QmlBindingPrivate : public QmlExpressionPrivate +{ + Q_DECLARE_PUBLIC(QmlBinding) +public: + QmlBindingPrivate(); + + QmlBindingData *bindingData() { return static_cast(data); } + const QmlBindingData *bindingData() const { return static_cast(data); } +}; + QT_END_NAMESPACE #endif // QMLBINDING_P_H diff --git a/src/declarative/qml/qmlexpression.cpp b/src/declarative/qml/qmlexpression.cpp index e1c7afe..23e1700 100644 --- a/src/declarative/qml/qmlexpression.cpp +++ b/src/declarative/qml/qmlexpression.cpp @@ -51,41 +51,63 @@ Q_DECLARE_METATYPE(QList); QT_BEGIN_NAMESPACE -QmlExpressionPrivate::QmlExpressionPrivate() +QmlExpressionData::QmlExpressionData() : expressionFunctionValid(false), expressionRewritten(false), me(0), trackChange(true), line(-1), guardList(0), guardListLength(0) { } +QmlExpressionData::~QmlExpressionData() +{ + if (guardList) { delete [] guardList; guardList = 0; } +} + +QmlExpressionPrivate::QmlExpressionPrivate() +: data(new QmlExpressionData) +{ + data->q = this; +} + +QmlExpressionPrivate::QmlExpressionPrivate(QmlExpressionData *d) +: data(d) +{ + data->q = this; +} + +QmlExpressionPrivate::~QmlExpressionPrivate() +{ + if (data) { data->q = 0; data->release(); data = 0; } +} + void QmlExpressionPrivate::init(QmlContext *ctxt, const QString &expr, QObject *me) { - expression = expr; + data->expression = expr; - QmlAbstractExpression::setContext(ctxt); - this->me = me; + data->QmlAbstractExpression::setContext(ctxt); + data->me = me; } void QmlExpressionPrivate::init(QmlContext *ctxt, void *expr, QmlRefCount *rc, QObject *me) { - quint32 *data = (quint32 *)expr; - Q_ASSERT(*data == BasicScriptEngineData || - *data == PreTransformedQtScriptData); - if (*data == BasicScriptEngineData) { - sse.load((const char *)(data + 1), rc); + quint32 *exprData = (quint32 *)expr; + Q_ASSERT(*exprData == BasicScriptEngineData || + *exprData == PreTransformedQtScriptData); + if (*exprData == BasicScriptEngineData) { + data->sse.load((const char *)(exprData + 1), rc); } else { QmlCompiledData *dd = (QmlCompiledData *)rc; - expressionRewritten = true; - expression = QString::fromRawData((QChar *)(data + 3), data[2]); + data->expressionRewritten = true; + data->expression = QString::fromRawData((QChar *)(exprData + 3), exprData[2]); - int progIdx = *(data + 1); + int progIdx = *(exprData + 1); QmlEngine *engine = ctxt->engine(); QmlEnginePrivate *ep = QmlEnginePrivate::get(engine); QScriptEngine *scriptEngine = QmlEnginePrivate::getScriptEngine(engine); if (!dd->programs.at(progIdx)) { - dd->programs[progIdx] = new QScriptProgram(scriptEngine->compile(expression)); + dd->programs[progIdx] = new QScriptProgram(scriptEngine->compile(data->expression)); } QmlContextPrivate *ctxtPriv = ctxt->d_func(); @@ -94,19 +116,14 @@ void QmlExpressionPrivate::init(QmlContext *ctxt, void *expr, QmlRefCount *rc, if (me) scriptContext->pushScope(ep->objectClass->newQObject(me)); - expressionFunction = scriptEngine->evaluate(*dd->programs[progIdx]); + data->expressionFunction = scriptEngine->evaluate(*dd->programs[progIdx]); - expressionFunctionValid = true; + data->expressionFunctionValid = true; scriptEngine->popContext(); } - QmlAbstractExpression::setContext(ctxt); - this->me = me; -} - -QmlExpressionPrivate::~QmlExpressionPrivate() -{ - if (guardList) { delete [] guardList; guardList = 0; } + data->QmlAbstractExpression::setContext(ctxt); + data->me = me; } /*! @@ -173,7 +190,7 @@ QmlExpression::~QmlExpression() QmlEngine *QmlExpression::engine() const { Q_D(const QmlExpression); - return d->context()?d->context()->engine():0; + return d->data->context()?d->data->context()->engine():0; } /*! @@ -183,7 +200,7 @@ QmlEngine *QmlExpression::engine() const QmlContext *QmlExpression::context() const { Q_D(const QmlExpression); - return d->context(); + return d->data->context(); } /*! @@ -192,10 +209,10 @@ QmlContext *QmlExpression::context() const QString QmlExpression::expression() const { Q_D(const QmlExpression); - if (d->sse.isValid()) - return QLatin1String(d->sse.expression()); + if (d->data->sse.isValid()) + return QLatin1String(d->data->sse.expression()); else - return d->expression; + return d->data->expression; } /*! @@ -215,12 +232,12 @@ void QmlExpression::setExpression(const QString &expression) d->clearGuards(); - d->expression = expression; - d->expressionFunctionValid = false; - d->expressionRewritten = false; - d->expressionFunction = QScriptValue(); + d->data->expression = expression; + d->data->expressionFunctionValid = false; + d->data->expressionRewritten = false; + d->data->expressionFunction = QScriptValue(); - d->sse.clear(); + d->data->sse.clear(); } QVariant QmlExpressionPrivate::evalSSE() @@ -229,7 +246,7 @@ QVariant QmlExpressionPrivate::evalSSE() QFxPerfTimer perfsse; #endif - QVariant rv = sse.run(context(), me); + QVariant rv = data->sse.run(data->context(), data->me); return rv; } @@ -240,8 +257,8 @@ QVariant QmlExpressionPrivate::evalQtScript(QObject *secondaryScope) QFxPerfTimer perfqt; #endif - QmlContextPrivate *ctxtPriv = context()->d_func(); - QmlEngine *engine = context()->engine(); + QmlContextPrivate *ctxtPriv = data->context()->d_func(); + QmlEngine *engine = data->context()->engine(); QmlEnginePrivate *ep = QmlEnginePrivate::get(engine); if (secondaryScope) @@ -250,28 +267,29 @@ QVariant QmlExpressionPrivate::evalQtScript(QObject *secondaryScope) QScriptEngine *scriptEngine = QmlEnginePrivate::getScriptEngine(engine); - if (!expressionFunctionValid) { + if (!data->expressionFunctionValid) { QScriptContext *scriptContext = scriptEngine->pushCleanContext(); scriptContext->pushScope(ctxtPriv->scriptValue); - if (me) - scriptContext->pushScope(ep->objectClass->newQObject(me)); + if (data->me) + scriptContext->pushScope(ep->objectClass->newQObject(data->me)); - if (expressionRewritten) { - expressionFunction = scriptEngine->evaluate(expression, fileName, line); + if (data->expressionRewritten) { + data->expressionFunction = scriptEngine->evaluate(data->expression, + data->fileName, data->line); } else { QmlRewrite::RewriteBinding rewriteBinding; - const QString code = rewriteBinding(expression); - expressionFunction = scriptEngine->evaluate(code, fileName, line); + const QString code = rewriteBinding(data->expression); + data->expressionFunction = scriptEngine->evaluate(code, data->fileName, data->line); } scriptEngine->popContext(); - expressionFunctionValid = true; + data->expressionFunctionValid = true; } - QScriptValue svalue = expressionFunction.call(); + QScriptValue svalue = data->expressionFunction.call(); if (scriptEngine->hasUncaughtException()) { if (scriptEngine->uncaughtException().isError()){ @@ -329,7 +347,7 @@ QVariant QmlExpressionPrivate::value(QObject *secondaryScope) Q_Q(QmlExpression); QVariant rv; - if (!q->engine() || (!sse.isValid() && expression.isEmpty())) + if (!q->engine() || (!data->sse.isValid() && data->expression.isEmpty())) return rv; #ifdef Q_ENABLE_PERFORMANCE_LOG @@ -344,7 +362,11 @@ QVariant QmlExpressionPrivate::value(QObject *secondaryScope) ep->currentExpression = q; - if (sse.isValid()) { + // This object might be deleted during the eval + QmlExpressionData *localData = data; + localData->addref(); + + if (data->sse.isValid()) { rv = evalSSE(); } else { rv = evalQtScript(secondaryScope); @@ -352,12 +374,17 @@ QVariant QmlExpressionPrivate::value(QObject *secondaryScope) ep->currentExpression = lastCurrentExpression; - if ((!q->trackChange() || !ep->capturedProperties.count()) && guardList) { - clearGuards(); - } else if(q->trackChange()) { - updateGuards(ep->capturedProperties); + // Check if we were deleted + if (localData->q) { + if ((!data->trackChange || !ep->capturedProperties.count()) && data->guardList) { + clearGuards(); + } else if(data->trackChange) { + updateGuards(ep->capturedProperties); + } } + localData->release(); + lastCapturedProperties.copyAndClear(ep->capturedProperties); return rv; @@ -381,7 +408,7 @@ QVariant QmlExpression::value() bool QmlExpression::isConstant() const { Q_D(const QmlExpression); - return !d->guardList; + return !d->data->guardList; } /*! @@ -390,7 +417,7 @@ bool QmlExpression::isConstant() const bool QmlExpression::trackChange() const { Q_D(const QmlExpression); - return d->trackChange; + return d->data->trackChange; } /*! @@ -411,7 +438,7 @@ bool QmlExpression::trackChange() const void QmlExpression::setTrackChange(bool trackChange) { Q_D(QmlExpression); - d->trackChange = trackChange; + d->data->trackChange = trackChange; } /*! @@ -421,8 +448,8 @@ void QmlExpression::setTrackChange(bool trackChange) void QmlExpression::setSourceLocation(const QUrl &fileName, int line) { Q_D(QmlExpression); - d->fileName = fileName.toString(); - d->line = line; + d->data->fileName = fileName.toString(); + d->data->line = line; } /*! @@ -434,7 +461,7 @@ void QmlExpression::setSourceLocation(const QUrl &fileName, int line) QObject *QmlExpression::scopeObject() const { Q_D(const QmlExpression); - return d->me; + return d->data->me; } /*! \internal */ @@ -452,16 +479,16 @@ void QmlExpressionPrivate::clearGuards() notifyIdx = QmlExpression::staticMetaObject.indexOfMethod("__q_notify()"); - for (int ii = 0; ii < guardListLength; ++ii) { - if (guardList[ii].data()) { - QMetaObject::disconnect(guardList[ii].data(), - guardList[ii].notifyIndex, + for (int ii = 0; ii < data->guardListLength; ++ii) { + if (data->guardList[ii].data()) { + QMetaObject::disconnect(data->guardList[ii].data(), + data->guardList[ii].notifyIndex, q, notifyIdx); } } - delete [] guardList; guardList = 0; - guardListLength = 0; + delete [] data->guardList; data->guardList = 0; + data->guardListLength = 0; } void QmlExpressionPrivate::updateGuards(const QPODVector &properties) @@ -474,10 +501,10 @@ void QmlExpressionPrivate::updateGuards(const QPODVectorguardListLength) + newGuardList = new QmlExpressionData::SignalGuard[properties.count()]; bool outputWarningHeader = false; int hit = 0; @@ -485,20 +512,20 @@ void QmlExpressionPrivate::updateGuards(const QPODVector= guardListLength) { + if (ii >= data->guardListLength) { // New guard - } else if(guardList[ii].data() == property.object && - guardList[ii].notifyIndex == property.notifyIndex) { + } else if(data->guardList[ii].data() == property.object && + data->guardList[ii].notifyIndex == property.notifyIndex) { // Cache hit - if (!guardList[ii].isDuplicate || - (guardList[ii].isDuplicate && hit == ii)) { + if (!data->guardList[ii].isDuplicate || + (data->guardList[ii].isDuplicate && hit == ii)) { needGuard = false; ++hit; } - } else if(guardList[ii].data() && !guardList[ii].isDuplicate) { + } else if(data->guardList[ii].data() && !data->guardList[ii].isDuplicate) { // Cache miss - QMetaObject::disconnect(guardList[ii].data(), - guardList[ii].notifyIndex, + QMetaObject::disconnect(data->guardList[ii].data(), + data->guardList[ii].notifyIndex, q, notifyIdx); } /* else { @@ -507,9 +534,9 @@ void QmlExpressionPrivate::updateGuards(const QPODVectorguardList[jj]; } if (property.notifyIndex != -1) { @@ -539,22 +566,22 @@ void QmlExpressionPrivate::updateGuards(const QPODVectorguardList[ii]; } } - for (int ii = properties.count(); ii < guardListLength; ++ii) { - if (guardList[ii].data() && !guardList[ii].isDuplicate) { - QMetaObject::disconnect(guardList[ii].data(), - guardList[ii].notifyIndex, + for (int ii = properties.count(); ii < data->guardListLength; ++ii) { + if (data->guardList[ii].data() && !data->guardList[ii].isDuplicate) { + QMetaObject::disconnect(data->guardList[ii].data(), + data->guardList[ii].notifyIndex, q, notifyIdx); } } if (newGuardList) { - if (guardList) delete [] guardList; - guardList = newGuardList; - guardListLength = properties.count(); + if (data->guardList) delete [] data->guardList; + data->guardList = newGuardList; + data->guardListLength = properties.count(); } } diff --git a/src/declarative/qml/qmlexpression_p.h b/src/declarative/qml/qmlexpression_p.h index 501e5d8..33016e6 100644 --- a/src/declarative/qml/qmlexpression_p.h +++ b/src/declarative/qml/qmlexpression_p.h @@ -79,23 +79,13 @@ private: QmlAbstractExpression *m_nextExpression; }; -class QmlExpression; -class QString; -class QmlExpressionPrivate : public QObjectPrivate, public QmlAbstractExpression +class QmlExpressionData : public QmlAbstractExpression, public QmlRefCount { - Q_DECLARE_PUBLIC(QmlExpression) public: - QmlExpressionPrivate(); - ~QmlExpressionPrivate(); - - enum CompiledDataType { - BasicScriptEngineData = 1, - PreTransformedQtScriptData = 2 - }; + QmlExpressionData(); + ~QmlExpressionData(); - - void init(QmlContext *, const QString &, QObject *); - void init(QmlContext *, void *, QmlRefCount *, QObject *); + QmlExpressionPrivate *q; QString expression; bool expressionFunctionValid:1; @@ -109,10 +99,6 @@ public: QString fileName; int line; - QVariant value(QObject *secondaryScope = 0); - QVariant evalSSE(); - QVariant evalQtScript(QObject *secondaryScope); - struct SignalGuard : public QGuard { SignalGuard() : isDuplicate(false), notifyIndex(-1) {} @@ -132,6 +118,32 @@ public: }; SignalGuard *guardList; int guardListLength; +}; + +class QmlExpression; +class QString; +class QmlExpressionPrivate : public QObjectPrivate +{ + Q_DECLARE_PUBLIC(QmlExpression) +public: + QmlExpressionPrivate(); + QmlExpressionPrivate(QmlExpressionData *); + ~QmlExpressionPrivate(); + + enum CompiledDataType { + BasicScriptEngineData = 1, + PreTransformedQtScriptData = 2 + }; + + void init(QmlContext *, const QString &, QObject *); + void init(QmlContext *, void *, QmlRefCount *, QObject *); + + QmlExpressionData *data; + + QVariant value(QObject *secondaryScope = 0); + QVariant evalSSE(); + QVariant evalQtScript(QObject *secondaryScope); + void updateGuards(const QPODVector &properties); void clearGuards(); -- cgit v0.12 From 16cf54b2a1f8631c59950989691f6384c0550040 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Thu, 8 Oct 2009 13:54:28 +1000 Subject: Tweak QScriptDeclarativeClass API to not be so silly --- src/script/bridge/qscriptdeclarativeclass.cpp | 42 +++++++++++++------------- src/script/bridge/qscriptdeclarativeclass_p.h | 3 +- src/script/bridge/qscriptdeclarativeobject.cpp | 14 +++++---- src/script/bridge/qscriptdeclarativeobject_p.h | 14 +++++++++ 4 files changed, 45 insertions(+), 28 deletions(-) diff --git a/src/script/bridge/qscriptdeclarativeclass.cpp b/src/script/bridge/qscriptdeclarativeclass.cpp index a7667cb..d019839 100644 --- a/src/script/bridge/qscriptdeclarativeclass.cpp +++ b/src/script/bridge/qscriptdeclarativeclass.cpp @@ -76,17 +76,8 @@ QScriptDeclarativeClass::PersistentIdentifier::operator=(const PersistentIdentif return *this; } -class QScriptDeclarativeClassPrivate -{ -public: - QScriptDeclarativeClassPrivate() : engine(0), q_ptr(0) {} - - QScriptEngine *engine; - QScriptDeclarativeClass *q_ptr; -}; - QScriptDeclarativeClass::QScriptDeclarativeClass(QScriptEngine *engine) -: context(0), d_ptr(new QScriptDeclarativeClassPrivate) +: d_ptr(new QScriptDeclarativeClassPrivate) { Q_ASSERT(sizeof(void*) == sizeof(JSC::Identifier)); d_ptr->q_ptr = this; @@ -178,8 +169,9 @@ QScriptValue QScriptDeclarativeClass::property(const QScriptValue &v, const Iden } /* -Returns the scope chain entry \a index from the end. This is equivalent to: - context->scopeChain().at(context->scopeChain.length() - 1 - index) +Returns the scope chain entry at \a index. If index is less than 0, returns +entries starting at the end. For example, scopeChainValue(context, -1) will return +the value last in the scope chain. */ QScriptValue QScriptDeclarativeClass::scopeChainValue(QScriptContext *context, int index) { @@ -190,18 +182,21 @@ QScriptValue QScriptDeclarativeClass::scopeChainValue(QScriptContext *context, i JSC::ScopeChainNode *node = frame->scopeChain(); JSC::ScopeChainIterator it(node); - int count = 0; - for (it = node->begin(); it != node->end(); ++it) - ++count; - - if (count < index) - return QScriptValue(); + if (index < 0) { + int count = 0; + for (it = node->begin(); it != node->end(); ++it) + ++count; - count -= index; + index = qAbs(index); + if (index > count) + return QScriptValue(); + else + index = count - index; + } for (it = node->begin(); it != node->end(); ++it) { - if (count == 0) { + if (index == 0) { JSC::JSObject *object = *it; if (!object) return QScriptValue(); @@ -214,7 +209,7 @@ QScriptValue QScriptDeclarativeClass::scopeChainValue(QScriptContext *context, i return engine->scriptValueFromJSCValue(object); } else { - --count; + --index; } } @@ -314,3 +309,8 @@ QVariant QScriptDeclarativeClass::toVariant(Object *, bool *ok) return QVariant(); } +QScriptContext *QScriptDeclarativeClass::context() const +{ + return d_ptr->context; +} + diff --git a/src/script/bridge/qscriptdeclarativeclass_p.h b/src/script/bridge/qscriptdeclarativeclass_p.h index 0d05ec5..b28209a 100644 --- a/src/script/bridge/qscriptdeclarativeclass_p.h +++ b/src/script/bridge/qscriptdeclarativeclass_p.h @@ -116,8 +116,9 @@ public: virtual QObject *toQObject(Object *, bool *ok = 0); virtual QVariant toVariant(Object *, bool *ok = 0); - QScriptContext *context; + QScriptContext *context() const; protected: + friend class QScriptDeclarativeClassPrivate; QScopedPointer d_ptr; }; diff --git a/src/script/bridge/qscriptdeclarativeobject.cpp b/src/script/bridge/qscriptdeclarativeobject.cpp index ffdebb0..76c2eb0 100644 --- a/src/script/bridge/qscriptdeclarativeobject.cpp +++ b/src/script/bridge/qscriptdeclarativeobject.cpp @@ -87,16 +87,17 @@ bool DeclarativeObjectDelegate::getOwnPropertySlot(QScriptObject* object, QScriptEnginePrivate *engine = scriptEngineFromExec(exec); QScriptDeclarativeClass::Identifier identifier = (void *)propertyName.ustring().rep(); - m_class->context = reinterpret_cast(exec); + QScriptDeclarativeClassPrivate *p = QScriptDeclarativeClassPrivate::get(m_class); + p->context = reinterpret_cast(exec); QScriptClass::QueryFlags flags = m_class->queryProperty(m_object, identifier, QScriptClass::HandlesReadAccess); if (flags & QScriptClass::HandlesReadAccess) { QScriptValue value = m_class->property(m_object, identifier); - m_class->context = 0; + p->context = 0; slot.setValue(engine->scriptValueToJSCValue(value)); return true; } - m_class->context = 0; + p->context = 0; return QScriptObjectDelegate::getOwnPropertySlot(object, exec, propertyName, slot); } @@ -108,15 +109,16 @@ void DeclarativeObjectDelegate::put(QScriptObject* object, JSC::ExecState *exec, QScriptEnginePrivate *engine = scriptEngineFromExec(exec); QScriptDeclarativeClass::Identifier identifier = (void *)propertyName.ustring().rep(); - m_class->context = reinterpret_cast(exec); + QScriptDeclarativeClassPrivate *p = QScriptDeclarativeClassPrivate::get(m_class); + p->context = reinterpret_cast(exec); QScriptClass::QueryFlags flags = m_class->queryProperty(m_object, identifier, QScriptClass::HandlesWriteAccess); if (flags & QScriptClass::HandlesWriteAccess) { m_class->setProperty(m_object, identifier, engine->scriptValueFromJSCValue(value)); - m_class->context = 0; + p->context = 0; return; } - m_class->context = 0; + p->context = 0; QScriptObjectDelegate::put(object, exec, propertyName, value, slot); } diff --git a/src/script/bridge/qscriptdeclarativeobject_p.h b/src/script/bridge/qscriptdeclarativeobject_p.h index 9c14774..c6dfb83 100644 --- a/src/script/bridge/qscriptdeclarativeobject_p.h +++ b/src/script/bridge/qscriptdeclarativeobject_p.h @@ -63,6 +63,20 @@ QT_BEGIN_NAMESPACE class QScriptClass; +class QScriptDeclarativeClassPrivate +{ +public: + QScriptDeclarativeClassPrivate() : engine(0), q_ptr(0), context(0) {} + + QScriptEngine *engine; + QScriptDeclarativeClass *q_ptr; + QScriptContext *context; + + static QScriptDeclarativeClassPrivate *get(QScriptDeclarativeClass *c) { + return c->d_ptr.data(); + } +}; + namespace QScript { -- cgit v0.12 From f5d0eed0973ff6e9054dfa2003d553117a5e272d Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Thu, 8 Oct 2009 13:54:42 +1000 Subject: Update to use new QScriptDeclarativeClass API --- src/declarative/qml/qmlobjectscriptclass.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/declarative/qml/qmlobjectscriptclass.cpp b/src/declarative/qml/qmlobjectscriptclass.cpp index 9448dcc..84470fc 100644 --- a/src/declarative/qml/qmlobjectscriptclass.cpp +++ b/src/declarative/qml/qmlobjectscriptclass.cpp @@ -150,9 +150,9 @@ QmlObjectScriptClass::queryProperty(QObject *obj, const Identifier &name, return rv; } - if (!evalContext && context) { + if (!evalContext && context()) { // Global object, QScriptContext activation object, QmlContext object - QScriptValue scopeNode = scopeChainValue(context, 3); + QScriptValue scopeNode = scopeChainValue(context(), -3); Q_ASSERT(scopeNode.isValid()); Q_ASSERT(scriptClass(scopeNode) == enginePrivate->contextClass); -- cgit v0.12 From 3215a23a399d881afafcf3cb9524124d452c669b Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Thu, 8 Oct 2009 13:55:24 +1000 Subject: Use correct file case --- src/declarative/qml/qmlmetatype.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/declarative/qml/qmlmetatype.cpp b/src/declarative/qml/qmlmetatype.cpp index 663e8e0..c40232f 100644 --- a/src/declarative/qml/qmlmetatype.cpp +++ b/src/declarative/qml/qmlmetatype.cpp @@ -948,9 +948,9 @@ QList QmlMetaType::qmlTypes() #include #include #include -#include -#include -#include +#include +#include +#include #include /*! -- cgit v0.12 From 0bb82245f83b47adf654d34d3e273dad1e39bd27 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Thu, 8 Oct 2009 14:12:52 +1000 Subject: Call QApplication::exit() repeatedly This is necessary incase we want to exit before we've entered the event loop. --- tools/qmlviewer/qfxtester.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tools/qmlviewer/qfxtester.cpp b/tools/qmlviewer/qfxtester.cpp index 87ab43b..216685c 100644 --- a/tools/qmlviewer/qfxtester.cpp +++ b/tools/qmlviewer/qfxtester.cpp @@ -118,12 +118,14 @@ void QFxTester::imagefailure() void QFxTester::complete() { + if (options & QmlViewer::ExitOnComplete) + QApplication::exit(hasFailed?-1:0); + if (hasCompleted) return; hasCompleted = true; - if (options & QmlViewer::ExitOnComplete) - QApplication::exit(hasFailed?-1:0); - else if (options & QmlViewer::Play) + + if (options & QmlViewer::Play) qWarning("Script playback complete"); } -- cgit v0.12 From d265b449325ef60624640f80f9438ac63547c1a8 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Thu, 8 Oct 2009 14:26:18 +1000 Subject: Fix crash --- src/declarative/qml/qmlobjectscriptclass.cpp | 2 +- .../qmlecmascript/data/extendedObjectPropertyLookup.qml | 8 ++++++++ .../auto/declarative/qmlecmascript/tst_qmlecmascript.cpp | 15 +++++++++++++++ 3 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 tests/auto/declarative/qmlecmascript/data/extendedObjectPropertyLookup.qml diff --git a/src/declarative/qml/qmlobjectscriptclass.cpp b/src/declarative/qml/qmlobjectscriptclass.cpp index 84470fc..d3a2a22 100644 --- a/src/declarative/qml/qmlobjectscriptclass.cpp +++ b/src/declarative/qml/qmlobjectscriptclass.cpp @@ -132,7 +132,7 @@ QmlObjectScriptClass::queryProperty(QObject *obj, const Identifier &name, cache = ddata->propertyCache; if (!cache) { cache = enginePrivate->cache(obj); - if (ddata) { cache->addref(); ddata->propertyCache = cache; } + if (cache && ddata) { cache->addref(); ddata->propertyCache = cache; } } if (cache) { diff --git a/tests/auto/declarative/qmlecmascript/data/extendedObjectPropertyLookup.qml b/tests/auto/declarative/qmlecmascript/data/extendedObjectPropertyLookup.qml new file mode 100644 index 0000000..8ff3aeb --- /dev/null +++ b/tests/auto/declarative/qmlecmascript/data/extendedObjectPropertyLookup.qml @@ -0,0 +1,8 @@ +import Qt.test 1.0 +import Qt 4.6 + +Object { + property MyExtendedObject a; + a: MyExtendedObject { id: Root } + property int b: Math.max(Root.extendedProperty, 0) +} diff --git a/tests/auto/declarative/qmlecmascript/tst_qmlecmascript.cpp b/tests/auto/declarative/qmlecmascript/tst_qmlecmascript.cpp index 6bc88c0..dde3bb7 100644 --- a/tests/auto/declarative/qmlecmascript/tst_qmlecmascript.cpp +++ b/tests/auto/declarative/qmlecmascript/tst_qmlecmascript.cpp @@ -60,6 +60,7 @@ private slots: void dynamicDestruction(); void objectToString(); void selfDeletingBinding(); + void extendedObjectPropertyLookup(); private: QmlEngine engine; @@ -709,6 +710,20 @@ void tst_qmlecmascript::selfDeletingBinding() } } +/* +Test that extended object properties can be accessed. + +This test a regression where this used to crash. The issue was specificially +for extended objects that did not include a synthesized meta object (so non-root +and no synthesiszed properties). +*/ +void tst_qmlecmascript::extendedObjectPropertyLookup() +{ + QmlComponent component(&engine, TEST_FILE("extendedObjectPropertyLookup.qml")); + QObject *object = component.create(); + QVERIFY(object != 0); +} + QTEST_MAIN(tst_qmlecmascript) #include "tst_qmlecmascript.moc" -- cgit v0.12 From f149107f3281fd537c98aaac5cba5934d55aa78a Mon Sep 17 00:00:00 2001 From: Bea Lam Date: Thu, 8 Oct 2009 15:08:40 +1000 Subject: Clean up --- examples/declarative/animation/animation.qml | 8 ++ examples/declarative/connections/connections.qml | 11 +- examples/declarative/dynamic/dynamic.js | 26 ++-- examples/declarative/dynamic/dynamic.qml | 66 +++++++++-- examples/declarative/effects/test.qml | 73 +++++++----- examples/declarative/layouts/Button.qml | 27 ++++- examples/declarative/layouts/layouts.qml | 19 +-- examples/declarative/layouts/positioners.qml | 145 ++++++++++++++++++----- 8 files changed, 277 insertions(+), 98 deletions(-) diff --git a/examples/declarative/animation/animation.qml b/examples/declarative/animation/animation.qml index ccfe164..31c75e1 100644 --- a/examples/declarative/animation/animation.qml +++ b/examples/declarative/animation/animation.qml @@ -4,17 +4,20 @@ Rectangle { width: 400 height: 200 color: "white" + Rectangle { width: 40 height: 40 y: 80 color: "#FF0000" radius: 10 + // Animate the x property. Setting repeat to true makes the // animation repeat indefinitely, otherwise it would only run once. x: SequentialAnimation { running: true repeat: true + // Move from 0 to 360 in 500ms, using the easeInOutQuad easing function NumberAnimation { from: 0 @@ -22,10 +25,12 @@ Rectangle { easing: "easeInOutQuad" duration: 500 } + // Then pause for 200ms PauseAnimation { duration: 200 } + // Then move back to 0 in 2 seconds, using the easeInOutElastic easing function NumberAnimation { from: 360 @@ -34,16 +39,19 @@ Rectangle { duration: 2000 } } + // Alternate color between red and green color: SequentialAnimation { running: true repeat: true + ColorAnimation { property: "color" from: "#FF0000" to: "#00FF00" duration: 5000 } + ColorAnimation { property: "color" from: "#00FF00" diff --git a/examples/declarative/connections/connections.qml b/examples/declarative/connections/connections.qml index 521cc01..b693b7e 100644 --- a/examples/declarative/connections/connections.qml +++ b/examples/declarative/connections/connections.qml @@ -5,6 +5,7 @@ Rectangle { color: "blue" width: 40 height: 30 + Rectangle { id: dot color: "red" @@ -13,19 +14,19 @@ Rectangle { x: rect.width/2 y: rect.height/2 } + MouseRegion { id: mr anchors.fill: rect } + Connection { sender: mr signal: "clicked(mouse)" script: { - - color="green"; - dot.x = mouse.x-1; - dot.y = mouse.y-1; - + color = "green"; + dot.x = mouse.x-1; + dot.y = mouse.y-1; } } } diff --git a/examples/declarative/dynamic/dynamic.js b/examples/declarative/dynamic/dynamic.js index 8f1e138..8bfdba3 100644 --- a/examples/declarative/dynamic/dynamic.js +++ b/examples/declarative/dynamic/dynamic.js @@ -2,54 +2,56 @@ var dynamicObject = null; var fourthBox = null; var component = null; var started = false; + function createQml(p) { - return createQmlObject('DynRect {}',p,'DynPart.qml'); + return createQmlObject('DynRect {}', p, 'DynPart.qml'); } function destroyDynamicObject() { - if(!(dynamicObject==null)){ + if (!(dynamicObject == null)) { dynamicObject.destroy(); dynamicObject = null; } } function instantCreateWithComponent() {//Like create, but assumes instant readyness - if(dynamicObject!=null)//Already made + if (dynamicObject != null)//Already made return null; component = createComponent("dynamic.qml"); dynamicObject = component.createObject(); - if(dynamicObject == null){ + + if (dynamicObject == null) { print("error creating component"); - }else{ + } else { dynamicObject.parent = targetItem; return dynamicObject; } return null; } -function finishCreation(){ - if(component.isReady && dynamicObject == null){ +function finishCreation() { + if (component.isReady && dynamicObject == null) { dynamicObject = component.createObject(); dynamicObject.parent = targetItem; - }else if(component.isError){ + } else if (component.isError) { dynamicObject = null; print("error creating component"); print(component.errorsString()); } } -function createWithComponent(){ - if(component!=null){ +function createWithComponent() { + if (component != null) { return finishCreation(); } - if(started!=false){ + if (started != false) { finishCreation();//Remakes if destroyed return dynamicObject; } started = true; component = createComponent("dynamic.qml"); finishCreation(); - if(dynamicObject != null){ + if (dynamicObject != null) { return dynamicObject; } component.statusChanged.connect(finishCreation); diff --git a/examples/declarative/dynamic/dynamic.qml b/examples/declarative/dynamic/dynamic.qml index 6ea7ab8..66fdf87 100644 --- a/examples/declarative/dynamic/dynamic.qml +++ b/examples/declarative/dynamic/dynamic.qml @@ -1,22 +1,55 @@ import Qt 4.6 -Rectangle { id: page; width: 800; height: 800; color:"black" +Rectangle { + id: page + width: 800 + height: 800 + color: "black" Script { source: "dynamic.js" } - property bool extendStars: false; + + property bool extendStars: false + Item { id: targetItem; x: 100; y: 100; } Item { id: targetItem2; x: 0; y: 300; } - Rectangle { width: 100; height: 100; color: "green"; id: rect - MouseRegion { anchors.fill:parent; onClicked: {a = createWithComponent();}} + + Rectangle { + id: rect + width: 100 + height: 100 + color: "green" + + MouseRegion { + anchors.fill: parent + onClicked: { a = createWithComponent(); } + } } - Rectangle { width: 100; height: 100; color: "red"; id: rect2; y:100; - MouseRegion { anchors.fill:parent; onClicked: {destroyDynamicObject();}} + + Rectangle { + id: rect2 + width: 100 + height: 100 + y: 100 + color: "red" + + MouseRegion { + anchors.fill:parent + onClicked: { destroyDynamicObject(); } + } } - Rectangle { width: 100; height: 100; color: "blue"; id: rect3; y:200; - MouseRegion { anchors.fill:parent; onClicked: - { - if(fourthBox == null) { + + Rectangle { + id: rect3 + width: 100 + height: 100 + y: 200 + color: "blue" + + MouseRegion { + anchors.fill: parent + onClicked: { + if (fourthBox == null) { a = createQml(targetItem2); - if(a!=null) { + if (a != null) { a.parent = targetItem2;//BUG: this should happen automatically fourthBox = a; print(a.toStr()); @@ -31,5 +64,14 @@ Rectangle { id: page; width: 800; height: 800; color:"black" } } } - Particles { x:0; y:0; count:20; lifeSpan:500; width:100; height: if(extendStars){400;}else{300;} source:"star.png"} + + Particles { + x: 0 + y: 0 + count: 20 + lifeSpan: 500 + width: 100 + height: if (extendStars) { 400; } else { 300; } + source: "star.png" + } } diff --git a/examples/declarative/effects/test.qml b/examples/declarative/effects/test.qml index 83bfde2..73c6839 100644 --- a/examples/declarative/effects/test.qml +++ b/examples/declarative/effects/test.qml @@ -2,89 +2,108 @@ import Qt 4.6 Rectangle { color: "white" - width: 800 + width: 600 height: 600 Image { + id: blur source: "pic.jpg" effect: Blur { - blurRadius: NumberAnimation { id: blur; from: 0; to: 10; duration: 200; repeat: true } + blurRadius: NumberAnimation { + id: blurEffect + from: 0; to: 10 + duration: 200 + repeat: true + } } - MouseRegion { anchors.fill: parent; onClicked: blur.running = !blur.running } - - Text { color: "white"; text: "Blur" } + MouseRegion { anchors.fill: parent; onClicked: blurEffect.running = !blurEffect.running } } + Text { text: "Blur"; anchors.top: blur.bottom; anchors.horizontalCenter: blur.horizontalCenter } + Image { + id: grayscale source: "pic.jpg" - x: 200 - effect: Grayscale {} - Text { color: "white"; text: "Grayscale" } + effect: Grayscale {} } + Text { text: "Grayscale"; anchors.top: grayscale.bottom; anchors.horizontalCenter: grayscale.horizontalCenter } + Image { + id: colorize source: "pic.jpg" - x: 400 - effect: Colorize { color: "blue" } - Text { color: "white"; text: "Colorize" } + effect: Colorize { color: "blue" } } + Text { text: "Colorize"; anchors.top: colorize.bottom; anchors.horizontalCenter: colorize.horizontalCenter } + Image { + id: pixelize source: "pic.jpg" - y: 300 + effect: Pixelize { - pixelSize: NumberAnimation { id: pixelize; from: 0; to: 10; duration: 200; repeat: true } + pixelSize: NumberAnimation { + id: pixelizeEffect + from: 0; to: 10 + duration: 200 + repeat: true + } } - MouseRegion { anchors.fill: parent; onClicked: pixelize.running = !pixelize.running } - - Text { color: "white"; text: "Pixelize" } + MouseRegion { anchors.fill: parent; onClicked: pixelizeEffect.running = !pixelizeEffect.running } } + Text { text: "Pixelize"; anchors.top: pixelize.bottom; anchors.horizontalCenter: pixelize.horizontalCenter } Image { + id: dropShadow source: "pic.jpg" - x: 200 y: 300 + effect: DropShadow { blurRadius: 3 offset.x: 3 - offset.y: NumberAnimation { id: dropShadow; from: 0; to: 10; duration: 200; repeat: true; } + offset.y: NumberAnimation { id: dropShadowEffect; from: 0; to: 10; duration: 200; repeat: true; } } - MouseRegion { anchors.fill: parent; onClicked: dropShadow.running = !dropShadow.running } - - Text { color: "white"; text: "DropShadow" } + MouseRegion { anchors.fill: parent; onClicked: dropShadowEffect.running = !dropShadowEffect.running } } + Text { text: "Drop Shadow"; anchors.top: dropShadow.bottom; anchors.horizontalCenter: dropShadow.horizontalCenter } Image { + id: bloom source: "pic.jpg" - x: 400 y: 300 + effect: Bloom { blurRadius: 3 brightness: 128 - strength: NumberAnimation { id: bloom; from: 0; to: 1; duration: 200; repeat: true; } + strength: NumberAnimation { + id: bloomEffect + from: 0; to: 1 + duration: 200 + repeat: true + } } - MouseRegion { anchors.fill: parent; onClicked: bloom.running = !bloom.running } - - Text { color: "white"; text: "Bloom" } + MouseRegion { anchors.fill: parent; onClicked: bloomEffect.running = !bloomEffect.running } } + Text { text: "Bloom"; anchors.top: bloom.bottom; anchors.horizontalCenter: bloom.horizontalCenter } + Text { x: 100; y: 250 - text: "Clicking Blur, Pixelize or DropShadow will \ntoggle animation." + text: "Clicking Blur, Pixelize, Drop Shadow or Bloom will \ntoggle animation." color: "black" } diff --git a/examples/declarative/layouts/Button.qml b/examples/declarative/layouts/Button.qml index 6c2fd8d..186512b 100644 --- a/examples/declarative/layouts/Button.qml +++ b/examples/declarative/layouts/Button.qml @@ -1,20 +1,35 @@ import Qt 4.6 -Rectangle { border.color: "black"; color: "steelblue"; radius: 5; width: pix.width + text.width + 13; height: pix.height + 10; id: page +Rectangle { + id: page + border.color: "black" + color: "steelblue" + radius: 5 + width: pix.width + text.width + 13 + height: pix.height + 10 + property string text property string icon signal clicked + Image { id: pix; x: 5; y:5; source: parent.icon} + Text { id: text; text: page.text; color: "white"; x:pix.width+pix.x+3; anchors.verticalCenter: pix.verticalCenter;} - MouseRegion{ id:mr; anchors.fill: parent; onClicked: {parent.focus = true; page.clicked()}} + + MouseRegion { + id: mr + anchors.fill: parent + onClicked: { parent.focus = true; page.clicked() } + } states: - State{ name:"pressed"; when:mr.pressed - PropertyChanges {target:text; x: 5} - PropertyChanges {target:pix; x:text.x+text.width + 3} + State { + name: "pressed"; when: mr.pressed + PropertyChanges { target:text; x: 5 } + PropertyChanges { target:pix; x:text.x+text.width + 3 } } transitions: Transition{ - NumberAnimation{ properties:"x,left"; easing:"easeInOutQuad"; duration:200 } + NumberAnimation { properties:"x,left"; easing:"easeInOutQuad"; duration:200 } } } diff --git a/examples/declarative/layouts/layouts.qml b/examples/declarative/layouts/layouts.qml index b54a7f3..accd969 100644 --- a/examples/declarative/layouts/layouts.qml +++ b/examples/declarative/layouts/layouts.qml @@ -1,20 +1,25 @@ import Qt 4.6 -Item { id: resizable - width:400; height:400; - GraphicsObjectContainer{ +Item { + id: resizable + width:400 + height:400 + + GraphicsObjectContainer { anchors.fill:parent - QGraphicsWidget{ + + QGraphicsWidget { size.width:parent.width size.height:parent.height - layout: QGraphicsLinearLayout{ - LayoutItem{ + + layout: QGraphicsLinearLayout { + LayoutItem { minimumSize: "100x100" maximumSize: "300x300" preferredSize: "100x100" Rectangle { color: "yellow"; anchors.fill: parent } } - LayoutItem{ + LayoutItem { minimumSize: "100x100" maximumSize: "400x400" preferredSize: "200x200" diff --git a/examples/declarative/layouts/positioners.qml b/examples/declarative/layouts/positioners.qml index fe28105..90efde2 100644 --- a/examples/declarative/layouts/positioners.qml +++ b/examples/declarative/layouts/positioners.qml @@ -1,43 +1,130 @@ import Qt 4.6 -Rectangle { width: 420; height: 420; id:page; color:"white" - Column { id: layout1; y:0; //width: 100; height:250; - move: Transition{ NumberAnimation {properties: "y"; easing: "easeOutBounce" }} - add: Transition{ NumberAnimation { properties: "y"; from: 500; duration:500; easing: "easeOutQuad"}} - remove: Transition { NumberAnimation { properties:"y"; to: 500; duration:500; easing: "easeInQuad"}} - Rectangle { color: "red"; width: 100; height: 50; border.color: "black"; radius: 15 } - Rectangle { id: blueV1; color: "lightsteelblue"; width: 100; height: 50; border.color: "black"; radius: 15 - //opacity: Behavior{ NumberAnimation {}} + +Rectangle { + id: page + width: 420 + height: 420 + color: "white" + + Column { + id: layout1 + y: 0 + move: Transition { + NumberAnimation { + properties: "y"; easing: "easeOutBounce" + } } - Rectangle { color: "green"; width: 100; height: 50; border.color: "black"; radius: 15 } - Rectangle { id: blueV2; color: "lightsteelblue"; width: 100; height: 50; border.color: "black"; radius: 15 - //opacity: Behavior{ NumberAnimation {}} + add: Transition { + NumberAnimation { + properties: "y"; from: 500; duration:500; easing: "easeOutQuad" + } } + remove: Transition { + NumberAnimation { + properties:"y"; to: 500; duration:500; easing: "easeInQuad" + } + } + Rectangle { color: "red"; width: 100; height: 50; border.color: "black"; radius: 15 } + Rectangle { id: blueV1; color: "lightsteelblue"; width: 100; height: 50; border.color: "black"; radius: 15 } + Rectangle { color: "green"; width: 100; height: 50; border.color: "black"; radius: 15 } + Rectangle { id: blueV2; color: "lightsteelblue"; width: 100; height: 50; border.color: "black"; radius: 15 } Rectangle { color: "orange"; width: 100; height: 50; border.color: "black"; radius: 15 } } - Row { id: layout2; y:300; - move: Transition{ NumberAnimation {properties: "x"; easing: "easeOutBounce" }} - add: Transition{ NumberAnimation { properties: "x"; from: 500; duration:500; easing: "easeOutQuad"} - NumberAnimation { properties: "opacity"; from: 0; duration: 500;}} - remove: Transition { NumberAnimation { properties: "x"; to: 500; duration:500; easing: "easeInQuad"} - NumberAnimation { properties: "opacity"; from: 1; duration: 500}} + + Row { + id: layout2 + y: 300 + move: Transition { + NumberAnimation { + properties: "x"; easing: "easeOutBounce" + } + } + add: Transition { + NumberAnimation { + properties: "x"; from: 500; duration:500; easing: "easeOutQuad" + } + NumberAnimation { + properties: "opacity"; from: 0; duration: 500; + } + } + remove: Transition { + NumberAnimation { + properties: "x"; to: 500; duration:500; easing: "easeInQuad" + } + NumberAnimation { + properties: "opacity"; from: 1; duration: 500 + } + } Rectangle { color: "red"; width: 50; height: 100; border.color: "black"; radius: 15 } Rectangle { id: blueH1; color: "lightsteelblue"; width: 50; height: 100; border.color: "black"; radius: 15 } Rectangle { color: "green"; width: 50; height: 100; border.color: "black"; radius: 15 } Rectangle { id: blueH2; color: "lightsteelblue"; width: 50; height: 100; border.color: "black"; radius: 15 } Rectangle { color: "orange"; width: 50; height: 100; border.color: "black"; radius: 15 } } - Button { text: "Remove"; icon: "del.png"; x: 135; y:90; - onClicked: {blueH2.opacity=0; blueH1.opacity=0; blueV1.opacity=0; blueV2.opacity=0; blueG1.opacity=0; blueG2.opacity=0; blueG3.opacity=0;} - } - Button { text: "Add"; icon: "add.png"; x: 145; y:140; - onClicked: {blueH2.opacity=1; blueH1.opacity=1; blueV1.opacity=1; blueV2.opacity=1; blueG1.opacity=1; blueG2.opacity=1; blueG3.opacity=1;} - } - Grid { x:260; y:0; columns:3 - remove: Transition { NumberAnimation{ properties: "opacity"; from: 1; to: 0; duration: 500} - NumberAnimation{properties: "x,y"; easing: "easeOutBounce"} } - move: Transition { NumberAnimation{ properties: "x,y"; easing: "easeOutBounce" }} - add: Transition { NumberAnimation{ properties: "opacity"; from: 0; to: 1; duration: 500} - NumberAnimation{properties: "x,y"; easing: "easeOutBounce"} } + + Button { + text: "Remove" + icon: "del.png" + x: 135 + y: 90 + + onClicked: { + blueH2.opacity = 0 + blueH1.opacity = 0 + blueV1.opacity = 0 + blueV2.opacity = 0 + blueG1.opacity = 0 + blueG2.opacity = 0 + blueG3.opacity = 0 + } + } + + Button { + text: "Add" + icon: "add.png" + x: 145 + y: 140 + + onClicked: { + blueH2.opacity = 1 + blueH1.opacity = 1 + blueV1.opacity = 1 + blueV2.opacity = 1 + blueG1.opacity = 1 + blueG2.opacity = 1 + blueG3.opacity = 1 + } + } + + Grid { + x: 260 + y: 0 + columns: 3 + + remove: Transition { + NumberAnimation { + properties: "opacity"; from: 1; to: 0; duration: 500 + } + NumberAnimation { + properties: "x,y"; easing: "easeOutBounce" + } + } + + move: Transition { + NumberAnimation { + properties: "x,y"; easing: "easeOutBounce" + } + } + + add: Transition { + NumberAnimation { + properties: "opacity"; from: 0; to: 1; duration: 500 + } + NumberAnimation { + properties: "x,y"; easing: "easeOutBounce" + } + } + Rectangle { color: "red"; width: 50; height: 100; border.color: "black"; radius: 15 } Rectangle { id: blueG1; color: "lightsteelblue"; width: 50; height: 100; border.color: "black"; radius: 15 } Rectangle { color: "green"; width: 50; height: 100; border.color: "black"; radius: 15 } -- cgit v0.12 From e795864872095d2179a3639403343ade3daf61c7 Mon Sep 17 00:00:00 2001 From: Bea Lam Date: Thu, 8 Oct 2009 15:09:39 +1000 Subject: Add command line options. --- tools/qmldebugger/main.cpp | 49 ++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 43 insertions(+), 6 deletions(-) diff --git a/tools/qmldebugger/main.cpp b/tools/qmldebugger/main.cpp index 7fabfb7..ccd3761 100644 --- a/tools/qmldebugger/main.cpp +++ b/tools/qmldebugger/main.cpp @@ -23,9 +23,15 @@ Q_OBJECT public: Shell(QWidget * = 0); -private slots: + void setHost(const QString &host); + void setPort(quint16 port); + void showEngineTab(); + +public slots: void connectToHost(); void disconnectFromHost(); + +private slots: void connectionStateChanged(); private: @@ -38,6 +44,7 @@ private: QPushButton *m_disconnectButton; EnginePane *m_enginePane; + QTabWidget *m_tabs; }; Shell::Shell(QWidget *parent) @@ -71,19 +78,34 @@ Shell::Shell(QWidget *parent) m_disconnectButton->setEnabled(false); connectLayout->addWidget(m_disconnectButton); - QTabWidget *tabs = new QTabWidget(this); - layout->addWidget(tabs); + m_tabs = new QTabWidget(this); + layout->addWidget(m_tabs); CanvasFrameRate *cfr = new CanvasFrameRate(&client, this); - tabs->addTab(cfr, tr("Frame Rate")); + m_tabs->addTab(cfr, tr("Frame Rate")); m_enginePane = new EnginePane(&client, this); - tabs->addTab(m_enginePane, tr("QML Engine")); + m_tabs->addTab(m_enginePane, tr("QML Engine")); QObject::connect(&client, SIGNAL(stateChanged(QAbstractSocket::SocketState)), this, SLOT(connectionStateChanged())); connectionStateChanged(); } +void Shell::setHost(const QString &host) +{ + m_host->setText(host); +} + +void Shell::setPort(quint16 port) +{ + m_port->setValue(port); +} + +void Shell::showEngineTab() +{ + m_tabs->setCurrentWidget(m_enginePane); +} + void Shell::connectionStateChanged() { switch (client.state()) { @@ -132,9 +154,24 @@ int main(int argc, char ** argv) { QApplication app(argc, argv); + QStringList args = app.arguments(); + Shell shell; - shell.show(); + if (args.contains("--engine")) + shell.showEngineTab(); + + if (args.count() > 1 && args.at(1).contains(':')) { + QStringList hostAndPort = args.at(1).split(':'); + bool ok = false; + quint16 port = hostAndPort[1].toInt(&ok); + if (ok) { + shell.setHost(hostAndPort[0]); + shell.setPort(port); + shell.connectToHost(); + } + } + shell.show(); return app.exec(); } -- cgit v0.12 From 05e4f1eaeb3f916bcf845ae0d7e85d283e9ca1bd Mon Sep 17 00:00:00 2001 From: Bea Lam Date: Thu, 8 Oct 2009 16:09:16 +1000 Subject: Remove redundant support/ files. --- examples/declarative/support/contact.cpp | 81 ------------- examples/declarative/support/contact.h | 140 ----------------------- examples/declarative/support/contactmodel.cpp | 158 -------------------------- examples/declarative/support/contactmodel.h | 55 --------- examples/declarative/support/support.pro | 12 -- 5 files changed, 446 deletions(-) delete mode 100644 examples/declarative/support/contact.cpp delete mode 100644 examples/declarative/support/contact.h delete mode 100644 examples/declarative/support/contactmodel.cpp delete mode 100644 examples/declarative/support/contactmodel.h delete mode 100644 examples/declarative/support/support.pro diff --git a/examples/declarative/support/contact.cpp b/examples/declarative/support/contact.cpp deleted file mode 100644 index 9ffeb97..0000000 --- a/examples/declarative/support/contact.cpp +++ /dev/null @@ -1,81 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 1992-$THISYEAR$ $TROLLTECH$. All rights reserved. -** -** This file is part of the $MODULE$ of the Qt Toolkit. -** -** $TROLLTECH_DUAL_LICENSE$ -** -** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE -** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. -** -****************************************************************************/ - -#include "contact.h" - -QML_DEFINE_TYPE(0,0,0,0,Contact,Contact); -Contact::Contact() : QObject(0) -{ - m_firstName = "John"; - m_lastName = "Smith"; - m_portraitFile = "contact.png"; - m_company = "Trollkia"; - m_emails << "smith@trollkia.com" << "john45@gmail.com"; - - m_numbers << new PhoneNumber; - m_numbers << new PhoneNumber; - m_numbers << new PhoneNumber; - - m_numbers.at(0)->setType(PhoneNumber::HomePhone); - m_numbers.at(0)->setNumber("35412451"); - - m_numbers.at(1)->setType(PhoneNumber::BusinessPhone); - m_numbers.at(1)->setNumber("33424994"); - - m_numbers.at(2)->setType(PhoneNumber::MobilePhone); - m_numbers.at(2)->setNumber("0424655137"); - - m_addresses << new Address; - m_addresses << new Address; - m_addresses << new Address; - m_addresses.at(0)->setNumber(13); - m_addresses.at(0)->setStreet("Blackhill Cr"); - m_addresses.at(0)->setCountry("Australia"); - m_addresses.at(1)->setNumber(116); - m_addresses.at(1)->setStreet("Sandankerveien"); - m_addresses.at(1)->setCountry("Norway"); - m_addresses.at(2)->setNumber(92); - m_addresses.at(2)->setStreet("Elizibeth St"); - m_addresses.at(2)->setCountry("Australia"); -} - -void Contact::addNumber(PhoneNumber *newNumber) -{ - m_numbers << newNumber; - emit numbersChanged(); -} - -void Contact::addAddress(Address *newAddress) -{ - m_addresses << newAddress; - emit addressesChanged(); -} - -void Contact::addEmail(QString &newEmail) -{ - - m_emails << newEmail; - emit emailsChanged(); -} - -QML_DEFINE_TYPE(0,0,0,0,Address,Address); -Address::Address() -: _number(0) -{ -} - -QML_DEFINE_TYPE(0,0,0,0,PhoneNumber, PhoneNumber); -PhoneNumber::PhoneNumber() -: _type(HomePhone) -{ -} diff --git a/examples/declarative/support/contact.h b/examples/declarative/support/contact.h deleted file mode 100644 index 7b25869..0000000 --- a/examples/declarative/support/contact.h +++ /dev/null @@ -1,140 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 1992-$THISYEAR$ $TROLLTECH$. All rights reserved. -** -** This file is part of the $MODULE$ of the Qt Toolkit. -** -** $TROLLTECH_DUAL_LICENSE$ -** -** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE -** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. -** -****************************************************************************/ - -#ifndef CONTACT_H -#define CONTACT_H - -#include -#include - -class Address : public QObject -{ - Q_OBJECT -public: - Address(); - - Q_PROPERTY(int number READ number WRITE setNumber NOTIFY changed); - Q_PROPERTY(QString street READ street WRITE setStreet NOTIFY changed); - Q_PROPERTY(QString country READ country WRITE setCountry NOTIFY changed); - - int number() const { return _number; } - void setNumber(int n) { _number = n; emit changed(); } - - QString street() const { return _street; } - void setStreet(const QString &s) { _street = s; emit changed(); } - - QString country() const { return _country; } - void setCountry(const QString &c) { _country = c; emit changed(); } - -signals: - void changed(); - -private: - int _number; - QString _street; - QString _country; -}; -QML_DECLARE_TYPE(Address); - -class PhoneNumber : public QObject -{ - Q_OBJECT - Q_ENUMS(PhoneType) -public: - PhoneNumber(); - - enum PhoneType { - HomePhone, - BusinessPhone, - MobilePhone - }; - - Q_PROPERTY(QString number READ number WRITE setNumber NOTIFY changed); - Q_PROPERTY(PhoneType type READ type WRITE setType NOTIFY changed); - - QString number() const { return _number; } - void setNumber(QString n) { _number = n; emit changed(); } - - PhoneType type() const { return _type; } - void setType(PhoneType type) { _type = type; emit changed(); } - -signals: - void changed(); - -private: - QString _number; - PhoneType _type; -}; -QML_DECLARE_TYPE(PhoneNumber); - -class Contact : public QObject -{ - Q_OBJECT -public: - Contact(); - - Q_PROPERTY(QString firstName READ firstName WRITE setFirstName NOTIFY nameChanged); - QString firstName() const { return m_firstName; } - - Q_PROPERTY(QString lastName READ lastName WRITE setLastName NOTIFY nameChanged); - QString lastName() const { return m_lastName; } - - Q_PROPERTY(QString portraitFile READ portraitFile WRITE setPortraitFile NOTIFY portraitChanged); - QString portraitFile() const { return m_portraitFile; } - - Q_PROPERTY(QString company READ company WRITE setCompany NOTIFY companyChanged); - QString company() const { return m_company; } - - Q_PROPERTY(QStringList emails READ emails WRITE setEmails NOTIFY emailsChanged); - QStringList emails() const { return m_emails; } - - Q_PROPERTY(QList
* addresses READ addresses); - QList
* addresses() { return &m_addresses; } - - Q_PROPERTY(QList* numbers READ numbers); - QList* numbers() { return &m_numbers; } - - - void addEmail(QString&); - void addAddress(Address*); - void addNumber(PhoneNumber*); - -public slots: - void setFirstName(const QString &name) { m_firstName = name; emit nameChanged(); } - void setLastName(const QString &name) { m_lastName = name; emit nameChanged(); } - void setPortraitFile(const QString &portraitFile) { m_portraitFile = portraitFile; emit portraitChanged(); } - void setCompany(const QString &company) { m_company = company; emit companyChanged(); } - void setEmails(const QStringList &emails) { m_emails = emails; emit emailsChanged(); } - -signals: - void nameChanged(); - void portraitChanged(); - void companyChanged(); - void emailsChanged(); - void numbersChanged(); - void addressesChanged(); - -private: - QString m_firstName; - QString m_lastName; - QString m_portraitFile; - - QString m_company; - - QList
m_addresses; - QListm_numbers; - QStringList m_emails; -}; -QML_DECLARE_TYPE(Contact); - -#endif diff --git a/examples/declarative/support/contactmodel.cpp b/examples/declarative/support/contactmodel.cpp deleted file mode 100644 index ff71b9c..0000000 --- a/examples/declarative/support/contactmodel.cpp +++ /dev/null @@ -1,158 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 1992-$THISYEAR$ $TROLLTECH$. All rights reserved. -** -** This file is part of the $MODULE$ of the Qt Toolkit. -** -** $TROLLTECH_DUAL_LICENSE$ -** -** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE -** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. -** -****************************************************************************/ - -#include "contactmodel.h" - -ContactModel::ContactModel(QObject *parent) : QListModelInterface(parent) -{ - QFile f("../contacts/contacts.txt"); - f.open(QIODevice::ReadOnly); - QTextStream ts(&f); - QString text = ts.readLine(); - while(!text.isEmpty()) { - Contact *c = new Contact; - QStringList list = text.split(" "); - c->setFirstName(list[0]); - c->setLastName(list[1]); - for (int i = 2; i < list.count(); ++i) - c->addEmail(list[i]); - //contactList.append(c); - insertContact(c); - - text = ts.readLine(); - } - f.close(); -} - -ContactModel::~ContactModel() -{ - while (!contactList.isEmpty()) { - Contact *c = contactList.takeFirst(); - delete c; - } -} - -int ContactModel::count() const -{ - return contactList.count(); -} - -QHash ContactModel::data(int index, const QList &roles) const -{ - QHash returnHash; - - for (int i = 0; i < roles.size(); ++i) { - int role = roles.at(i); - QVariant info; - switch(role) { - case PortraitRole: - info = "contact.png"; - break; - case FirstNameRole: - info = contactList.at(index)->firstName(); - break; - case LastNameRole: - info = contactList.at(index)->lastName(); - break; - case CompanyRole: - info = contactList.at(index)->company(); - break; - case EmailsRole: - info = contactList.at(index)->emails(); - break; - case AddressesRole: - //returns QVariant BOOL - info = QVariant::fromValue(contactList.at(index)->addresses()); - break; - case NumbersRole: - info = QVariant::fromValue(contactList.at(index)->numbers()); - break; - default: - break; - } - returnHash.insert(role, info); - } - - return returnHash; -} - -QString ContactModel::toString(int role) const -{ - switch(role) { - case PortraitRole: - return "portrait"; - case FirstNameRole: - return "firstName"; - case LastNameRole: - return "lastName"; - case CompanyRole: - return "company"; - case EmailsRole: - return "emails"; - case AddressesRole: - return "addresses"; - case NumbersRole: - return "numbers"; - default: - return ""; - } -} - -QList ContactModel::roles() const -{ - return QList() << PortraitRole << FirstNameRole << LastNameRole << CompanyRole << EmailsRole << AddressesRole << NumbersRole; -} - -void ContactModel::deleteContact(int index) -{ - delete contactList.takeAt(index); - emit itemsRemoved(index, 1); -} - -int ContactModel::insertContact(Contact *contact) -{ - int index = 0; - QString fullName = contact->lastName(); - index = findIndex(fullName); - contactList.insert(index, contact); - emit itemsInserted(index, 1); - return index; -} - - -//search - binary search algorithm lastname only - -int ContactModel::findIndex(QString &searchName) const -{ - int start = 0; - int end = contactList.size()-1; - int middle = 0; - QString middleString; - - while (start <= end) - { - middle = (start+end)/2; - middleString = contactList.at(middle)->lastName(); - if (isAfter(searchName, middleString) < 0) start = middle+1; - else if( isAfter(middleString, searchName) < 0) end = middle-1; - else return middle; - } - return start; -} - -int ContactModel::isAfter(QString &name1, QString &name2) const -{ - //if c1 is after c2 alphabetically, return positive - int compString = QString::compare(name1, name2, Qt::CaseInsensitive); - return -compString; -} diff --git a/examples/declarative/support/contactmodel.h b/examples/declarative/support/contactmodel.h deleted file mode 100644 index e262358..0000000 --- a/examples/declarative/support/contactmodel.h +++ /dev/null @@ -1,55 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 1992-$THISYEAR$ $TROLLTECH$. All rights reserved. -** -** This file is part of the $MODULE$ of the Qt Toolkit. -** -** $TROLLTECH_DUAL_LICENSE$ -** -** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE -** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. -** -****************************************************************************/ - -#ifndef _CONTACTMODEL_H_ -#define _CONTACTMODEL_H_ - -#include -#include "contact.h" - -class ContactModel : public QListModelInterface -{ - Q_OBJECT -public: - ContactModel(QObject *parent = 0); - ~ContactModel(); - - enum Roles { - PortraitRole, - FirstNameRole, - LastNameRole, - CompanyRole, - EmailsRole, - AddressesRole, - NumbersRole - }; - - int count() const; - - QHash data(int index, const QList &roles) const; - QList roles() const; - - - QString toString(int role) const; - - void deleteContact(int index); - int insertContact(Contact *contact); - - int isAfter(QString &name1, QString &name2) const; - int findIndex(QString &searchName) const; - -private: - QList contactList; -}; - -#endif diff --git a/examples/declarative/support/support.pro b/examples/declarative/support/support.pro deleted file mode 100644 index 1da1a28..0000000 --- a/examples/declarative/support/support.pro +++ /dev/null @@ -1,12 +0,0 @@ -TEMPLATE = lib -TARGET = QtFxSupport -DEPENDPATH += . -INCLUDEPATH += . -MOC_DIR = .moc -OBJECTS_DIR = .obj -DESTDIR = ../../lib -QT += script declarative - -HEADERS += contact.h contactmodel.h -SOURCES += contact.cpp contactmodel.cpp - -- cgit v0.12 From e08c4d393cbef8aa526328678ef4d71642b32f84 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Thu, 8 Oct 2009 18:01:00 +1000 Subject: Rename label to labeltext Resolves scope collision between label property and label id --- demos/declarative/flickr/common/MediaLineEdit.qml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/demos/declarative/flickr/common/MediaLineEdit.qml b/demos/declarative/flickr/common/MediaLineEdit.qml index 4b21f66..f959bc5 100644 --- a/demos/declarative/flickr/common/MediaLineEdit.qml +++ b/demos/declarative/flickr/common/MediaLineEdit.qml @@ -6,18 +6,18 @@ Item { property string label property string text - width: Math.max(94,label.width + editor.width + 20) + width: Math.max(94,labeltext.width + editor.width + 20) height: buttonImage.height states: [ State { name: "Edit" PropertyChanges { - target: label + target: labeltext text: container.label + ": " } PropertyChanges { - target: label + target: labeltext x: 10 } PropertyChanges { @@ -78,7 +78,7 @@ Item { } Text { - id: label + id: labeltext font.bold: true color: "white" anchors.verticalCenter: container.verticalCenter @@ -93,7 +93,7 @@ Item { selectionColor: "green" width: 0 clip: true - anchors.left: label.right + anchors.left: labeltext.right anchors.verticalCenter: container.verticalCenter } Keys.forwardTo: [(returnKey), (editor)] -- cgit v0.12 From 5537833ea06a60a5ed6027c9d3d707291b2673ee Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Thu, 8 Oct 2009 19:45:44 +1000 Subject: Fix messed up merge --- src/corelib/animation/qabstractanimation.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/corelib/animation/qabstractanimation.cpp b/src/corelib/animation/qabstractanimation.cpp index a45f60b..a8c3504 100644 --- a/src/corelib/animation/qabstractanimation.cpp +++ b/src/corelib/animation/qabstractanimation.cpp @@ -246,13 +246,13 @@ void QUnifiedTimer::unregisterAnimation(QAbstractAnimation *animation) // this is needed if we unregister an animation while its running if (idx <= currentAnimationIdx) --currentAnimationIdx; - if (animations.isEmpty()) + if (animations.isEmpty() && !startStopAnimationTimer.isActive()) startStopAnimationTimer.start(STARTSTOP_TIMER_DELAY, this); } else { animationsToStart.removeOne(animation); } - if (!startStopAnimationTimer.isActive()) - startStopAnimationTimer.start(STARTSTOP_TIMER_DELAY, this); + + QAbstractAnimationPrivate::get(animation)->hasRegisteredTimer = false; } void QAbstractAnimationPrivate::setState(QAbstractAnimation::State newState) -- cgit v0.12 From f41e84f6ce70e8b05f6cfcadc6780dc5ecc2f8b0 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Thu, 8 Oct 2009 19:51:51 +1000 Subject: Zero bindingBits correctly --- src/declarative/qml/qmlengine.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/declarative/qml/qmlengine.cpp b/src/declarative/qml/qmlengine.cpp index 9ee0d1b..ccdf6cf 100644 --- a/src/declarative/qml/qmlengine.cpp +++ b/src/declarative/qml/qmlengine.cpp @@ -534,9 +534,10 @@ void QmlDeclarativeData::setBindingBit(QObject *obj, int bit) bindingBits = (quint32 *)realloc(bindingBits, arraySize * sizeof(quint32)); + memset(bindingBits + oldArraySize, - sizeof(quint32) * (arraySize - oldArraySize), - 0x00); + 0x00, + sizeof(quint32) * (arraySize - oldArraySize)); bindingBitsSize = arraySize * 32; } -- cgit v0.12 From d9f715adfbd0483f113f3108d5285c31833763c1 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Thu, 8 Oct 2009 19:52:18 +1000 Subject: Small optimization --- src/declarative/qml/qmlobjectscriptclass.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/declarative/qml/qmlobjectscriptclass.cpp b/src/declarative/qml/qmlobjectscriptclass.cpp index d3a2a22..41573a2 100644 --- a/src/declarative/qml/qmlobjectscriptclass.cpp +++ b/src/declarative/qml/qmlobjectscriptclass.cpp @@ -214,12 +214,13 @@ QScriptValue QmlObjectScriptClass::property(QObject *obj, const Identifier &name return enginePriv->valueTypeClass->newObject(obj, lastData->coreIndex, valueType); } - QVariant var = obj->metaObject()->property(lastData->coreIndex).read(obj); - if (lastData->flags & QmlPropertyCache::Data::IsQObjectDerived) { - QObject *rv = *(QObject **)var.constData(); + QObject *rv = 0; + void *args[] = { &rv, 0 }; + QMetaObject::metacall(obj, QMetaObject::ReadProperty, lastData->coreIndex, args); return newQObject(rv); } else { + QVariant var = obj->metaObject()->property(lastData->coreIndex).read(obj); return enginePriv->scriptValueFromVariant(var); } -- cgit v0.12 From 0fcc46e34c7feedfa1758ead64b09be59813f7d1 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Thu, 8 Oct 2009 19:52:32 +1000 Subject: Fix visual model crash at shutdown due to dangling pointer --- src/declarative/fx/qfxvisualitemmodel.cpp | 76 +++++++++++++++++++------------ 1 file changed, 46 insertions(+), 30 deletions(-) diff --git a/src/declarative/fx/qfxvisualitemmodel.cpp b/src/declarative/fx/qfxvisualitemmodel.cpp index b7248ea..943f909 100644 --- a/src/declarative/fx/qfxvisualitemmodel.cpp +++ b/src/declarative/fx/qfxvisualitemmodel.cpp @@ -239,6 +239,10 @@ class QFxVisualDataModelPrivate : public QObjectPrivate public: QFxVisualDataModelPrivate(QmlContext *); + static QFxVisualDataModelPrivate *get(QFxVisualDataModel *m) { + return static_cast(QObjectPrivate::get(m)); + } + QGuard m_listModelInterface; QGuard m_abstractItemModel; QGuard m_visualItemModel; @@ -363,7 +367,8 @@ class QFxVisualDataModelData : public QObject { Q_OBJECT public: - QFxVisualDataModelData(int index, QFxVisualDataModelPrivate *model); + QFxVisualDataModelData(int index, QFxVisualDataModel *model); + ~QFxVisualDataModelData(); Q_PROPERTY(int index READ index NOTIFY indexChanged) int index() const; @@ -379,7 +384,7 @@ Q_SIGNALS: private: friend class QFxVisualDataModelDataMetaObject; int m_index; - QFxVisualDataModelPrivate *m_model; + QGuard m_model; QFxVisualDataModelDataMetaObject *m_meta; }; @@ -404,15 +409,19 @@ int QFxVisualDataModelDataMetaObject::createProperty(const char *name, const cha QFxVisualDataModelData *data = static_cast(object()); - if ((!data->m_model->m_listModelInterface || !data->m_model->m_abstractItemModel) - && data->m_model->m_listAccessor) { - data->m_model->ensureRoles(); - if (data->m_model->m_roleNames.contains(QLatin1String(name))) + if (!data->m_model) + return -1; + + QFxVisualDataModelPrivate *model = QFxVisualDataModelPrivate::get(data->m_model); + + if ((!model->m_listModelInterface || !model->m_abstractItemModel) && model->m_listAccessor) { + model->ensureRoles(); + if (model->m_roleNames.contains(QLatin1String(name))) return QmlOpenMetaObject::createProperty(name, type); } else { - data->m_model->ensureRoles(); + model->ensureRoles(); const QLatin1String sname(name); - if (data->m_model->m_roleNames.contains(sname)) + if (model->m_roleNames.contains(sname)) return QmlOpenMetaObject::createProperty(name, type); } return -1; @@ -425,45 +434,48 @@ QFxVisualDataModelDataMetaObject::propertyCreated(int, QMetaPropertyBuilder &pro QFxVisualDataModelData *data = static_cast(object()); + + Q_ASSERT(data->m_model); + QFxVisualDataModelPrivate *model = QFxVisualDataModelPrivate::get(data->m_model); + QString name = QLatin1String(prop.name()); - if ((!data->m_model->m_listModelInterface || !data->m_model->m_abstractItemModel) - && data->m_model->m_listAccessor) { + if ((!model->m_listModelInterface || !model->m_abstractItemModel) && model->m_listAccessor) { if (name == QLatin1String("modelData")) { - if (data->m_model->m_listAccessor->type() == QmlListAccessor::Instance) { - QObject *object = data->m_model->m_listAccessor->at(0).value(); + if (model->m_listAccessor->type() == QmlListAccessor::Instance) { + QObject *object = model->m_listAccessor->at(0).value(); return object->metaObject()->property(1).read(object); // the first property after objectName } - return data->m_model->m_listAccessor->at(data->m_index); + return model->m_listAccessor->at(data->m_index); } else { // return any property of a single object instance. - QObject *object = data->m_model->m_listAccessor->at(0).value(); + QObject *object = model->m_listAccessor->at(0).value(); return object->property(prop.name()); } - } else if (data->m_model->m_listModelInterface) { - data->m_model->ensureRoles(); - QHash::const_iterator it = data->m_model->m_roleNames.find(name); - if (it != data->m_model->m_roleNames.end()) { + } else if (model->m_listModelInterface) { + model->ensureRoles(); + QHash::const_iterator it = model->m_roleNames.find(name); + if (it != model->m_roleNames.end()) { roles.append(*it); - QHash values = data->m_model->m_listModelInterface->data(data->m_index, QList() << *it); + QHash values = model->m_listModelInterface->data(data->m_index, QList() << *it); if (values.isEmpty()) return QVariant(); else return values.value(*it); - } else if (data->m_model->m_roles.count() == 1 && name == QLatin1String("modelData")) { + } else if (model->m_roles.count() == 1 && name == QLatin1String("modelData")) { //for compatability with other lists, assign modelData if there is only a single role - QHash values = data->m_model->m_listModelInterface->data(data->m_index, QList() << data->m_model->m_roles.first()); + QHash values = model->m_listModelInterface->data(data->m_index, QList() << model->m_roles.first()); if (values.isEmpty()) return QVariant(); else return *values.begin(); } - } else if (data->m_model->m_abstractItemModel) { - data->m_model->ensureRoles(); - QHash::const_iterator it = data->m_model->m_roleNames.find(name); - if (it != data->m_model->m_roleNames.end()) { + } else if (model->m_abstractItemModel) { + model->ensureRoles(); + QHash::const_iterator it = model->m_roleNames.find(name); + if (it != model->m_roleNames.end()) { roles.append(*it); - QModelIndex index = data->m_model->m_abstractItemModel->index(data->m_index, 0); - return data->m_model->m_abstractItemModel->data(index, *it); + QModelIndex index = model->m_abstractItemModel->index(data->m_index, 0); + return model->m_abstractItemModel->data(index, *it); } } Q_ASSERT(!"Can never be reached"); @@ -471,12 +483,16 @@ QFxVisualDataModelDataMetaObject::propertyCreated(int, QMetaPropertyBuilder &pro } QFxVisualDataModelData::QFxVisualDataModelData(int index, - QFxVisualDataModelPrivate *model) + QFxVisualDataModel *model) : m_index(index), m_model(model), m_meta(new QFxVisualDataModelDataMetaObject(this)) { } +QFxVisualDataModelData::~QFxVisualDataModelData() +{ +} + int QFxVisualDataModelData::index() const { return m_index; @@ -752,7 +768,7 @@ QFxItem *QFxVisualDataModel::item(int index, const QByteArray &viewId, bool comp QmlContext *ccontext = d->m_context; if (!ccontext) ccontext = qmlContext(this); QmlContext *ctxt = new QmlContext(ccontext); - QFxVisualDataModelData *data = new QFxVisualDataModelData(index, d); + QFxVisualDataModelData *data = new QFxVisualDataModelData(index, this); ctxt->setContextProperty(QLatin1String("model"), data); ctxt->addDefaultObject(data); nobj = d->m_delegate->beginCreate(ctxt); @@ -821,7 +837,7 @@ QVariant QFxVisualDataModel::evaluate(int index, const QString &expression, QObj QmlContext *ccontext = d->m_context; if (!ccontext) ccontext = qmlContext(this); QmlContext *ctxt = new QmlContext(ccontext); - QFxVisualDataModelData *data = new QFxVisualDataModelData(index, d); + QFxVisualDataModelData *data = new QFxVisualDataModelData(index, this); ctxt->addDefaultObject(data); QmlExpression e(ctxt, expression, objectContext); e.setTrackChange(false); -- cgit v0.12 From 7a5659038c6b558f4edc49150126787a3930102b Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Thu, 8 Oct 2009 20:05:18 +1000 Subject: Incorrect use of Script {} --- demos/declarative/contacts/FieldText.qml | 40 +++++++++++----------- demos/declarative/contacts/RemoveButton.qml | 23 ++++++------- .../declarative/webbrowser/fieldtext/FieldText.qml | 2 -- 3 files changed, 31 insertions(+), 34 deletions(-) diff --git a/demos/declarative/contacts/FieldText.qml b/demos/declarative/contacts/FieldText.qml index d30d4d8..2e8b60d 100644 --- a/demos/declarative/contacts/FieldText.qml +++ b/demos/declarative/contacts/FieldText.qml @@ -9,29 +9,29 @@ Rectangle { property var label: "" onTextChanged: { reset() } signal confirmed - resources: [ - Script { - function edit() { - if (!contacts.mouseGrabbed) { - fieldText.state='editing'; - contacts.mouseGrabbed=true; - } - } - function confirm() { - fieldText.text = textEdit.text; - fieldText.state=''; - contacts.mouseGrabbed=false; - fieldText.confirmed(); - } - function reset() { - textEdit.text = fieldText.text; - fieldText.state=''; - contacts.mouseGrabbed=false; + Script { + + function edit() { + if (!contacts.mouseGrabbed) { + fieldText.state='editing'; + contacts.mouseGrabbed=true; } - } - ] + function confirm() { + fieldText.text = textEdit.text; + fieldText.state=''; + contacts.mouseGrabbed=false; + fieldText.confirmed(); + } + function reset() { + textEdit.text = fieldText.text; + fieldText.state=''; + contacts.mouseGrabbed=false; + } + + } + Image { id: cancelIcon width: 22 diff --git a/demos/declarative/contacts/RemoveButton.qml b/demos/declarative/contacts/RemoveButton.qml index cc858c3..2c3cc9e 100644 --- a/demos/declarative/contacts/RemoveButton.qml +++ b/demos/declarative/contacts/RemoveButton.qml @@ -8,21 +8,20 @@ Rectangle { radius: 5 property var expandedWidth: 230 signal confirmed - resources: [ - Script { - function toggle() { - if (removeButton.state == 'opened') { - removeButton.state = ''; - contacts.mouseGrabbed=false; - } else { - if (!contacts.mouseGrabbed) { - removeButton.state = 'opened'; - contacts.mouseGrabbed=true; - } + Script { + function toggle() { + if (removeButton.state == 'opened') { + removeButton.state = ''; + contacts.mouseGrabbed=false; + } else { + if (!contacts.mouseGrabbed) { + removeButton.state = 'opened'; + contacts.mouseGrabbed=true; } } } - ] + } + Image { id: trashIcon width: 22 diff --git a/demos/declarative/webbrowser/fieldtext/FieldText.qml b/demos/declarative/webbrowser/fieldtext/FieldText.qml index fe55185..2adfbbf 100644 --- a/demos/declarative/webbrowser/fieldtext/FieldText.qml +++ b/demos/declarative/webbrowser/fieldtext/FieldText.qml @@ -10,7 +10,6 @@ Item { signal cancelled signal startEdit - resources: [ Script { function edit() { @@ -36,7 +35,6 @@ Item { } } - ] Image { id: cancelIcon -- cgit v0.12 From 931350a9cb24f30e6fd6c227dbdc40937d59a705 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Thu, 8 Oct 2009 22:46:57 +1000 Subject: Move Q_PROPERTY()'s to top of object Q_PROPERTY() macros without a semicolon inside a class access block (public:) confuses moc into ignoring Q_INVOKABLES --- src/declarative/qml/qmlcomponentjs_p.h | 8 ++++---- src/declarative/util/qmlpackage.cpp | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/declarative/qml/qmlcomponentjs_p.h b/src/declarative/qml/qmlcomponentjs_p.h index 0f56766..3213929 100644 --- a/src/declarative/qml/qmlcomponentjs_p.h +++ b/src/declarative/qml/qmlcomponentjs_p.h @@ -69,14 +69,14 @@ class Q_DECLARATIVE_EXPORT QmlComponentJS : public QmlComponent { Q_OBJECT Q_DECLARE_PRIVATE(QmlComponentJS) - friend class QmlEngine; -public: - QmlComponentJS(QmlEngine *, const QUrl &url, QObject *parent = 0); - QmlComponentJS(QmlEngine *, QObject *parent=0); Q_PROPERTY(bool isNull READ isNull NOTIFY isNullChanged) Q_PROPERTY(bool isReady READ isReady NOTIFY isReadyChanged) Q_PROPERTY(bool isError READ isError NOTIFY isErrorChanged) Q_PROPERTY(bool isLoading READ isLoading NOTIFY isLoadingChanged) + friend class QmlEngine; +public: + QmlComponentJS(QmlEngine *, const QUrl &url, QObject *parent = 0); + QmlComponentJS(QmlEngine *, QObject *parent=0); Q_INVOKABLE QScriptValue createObject(); Q_INVOKABLE QString errorsString() const; diff --git a/src/declarative/util/qmlpackage.cpp b/src/declarative/util/qmlpackage.cpp index 912bb6b..7df8453 100644 --- a/src/declarative/util/qmlpackage.cpp +++ b/src/declarative/util/qmlpackage.cpp @@ -55,11 +55,11 @@ public: class QmlPackageAttached : public QObject { Q_OBJECT +Q_PROPERTY(QString name READ name WRITE setName) public: QmlPackageAttached(QObject *parent); virtual ~QmlPackageAttached(); - Q_PROPERTY(QString name READ name WRITE setName) QString name() const; void setName(const QString &n); -- cgit v0.12 From 3d6132ae9224b9374285d9eda062a815c4582f7c Mon Sep 17 00:00:00 2001 From: Martin Jones Date: Fri, 9 Oct 2009 10:45:00 +1000 Subject: No need for temporary currentItem --- src/declarative/fx/qfxgridview.cpp | 15 +++------------ src/declarative/fx/qfxlistview.cpp | 19 ++++--------------- 2 files changed, 7 insertions(+), 27 deletions(-) diff --git a/src/declarative/fx/qfxgridview.cpp b/src/declarative/fx/qfxgridview.cpp index a8b27f4..2d25d56 100644 --- a/src/declarative/fx/qfxgridview.cpp +++ b/src/declarative/fx/qfxgridview.cpp @@ -149,7 +149,7 @@ class QFxGridViewPrivate : public QFxFlickablePrivate public: QFxGridViewPrivate() - : model(0), currentItem(0), tmpCurrent(0), flow(QFxGridView::LeftToRight) + : model(0), currentItem(0), flow(QFxGridView::LeftToRight) , visiblePos(0), visibleIndex(0) , currentIndex(-1) , cellWidth(100), cellHeight(100), columns(1), requestedIndex(-1) , highlightComponent(0), highlight(0), trackedItem(0) @@ -298,7 +298,6 @@ public: QList visibleItems; QHash unrequestedItems; FxGridItem *currentItem; - QFxItem *tmpCurrent; QFxGridView::Flow flow; int visiblePos; int visibleIndex; @@ -640,10 +639,6 @@ void QFxGridViewPrivate::updateCurrent(int modelIndex) return; } - if (tmpCurrent) { - delete tmpCurrent; - tmpCurrent = 0; - } FxGridItem *oldCurrentItem = currentItem; currentIndex = modelIndex; currentItem = createItem(modelIndex); @@ -821,12 +816,8 @@ void QFxGridView::setCurrentIndex(int index) QFxItem *QFxGridView::currentItem() { Q_D(QFxGridView); - if (!d->currentItem) { - // Always return something valid - if (!d->tmpCurrent) - d->tmpCurrent = new QFxItem(viewport()); - return d->tmpCurrent; - } + if (!d->currentItem) + return 0; return d->currentItem->item; } diff --git a/src/declarative/fx/qfxlistview.cpp b/src/declarative/fx/qfxlistview.cpp index 1247021..5afd881 100644 --- a/src/declarative/fx/qfxlistview.cpp +++ b/src/declarative/fx/qfxlistview.cpp @@ -170,15 +170,15 @@ class QFxListViewPrivate : public QFxFlickablePrivate public: QFxListViewPrivate() - : model(0), currentItem(0), tmpCurrent(0), orient(Qt::Vertical) + : model(0), currentItem(0), orient(Qt::Vertical) , visiblePos(0), visibleIndex(0) , averageSize(100.0), currentIndex(-1), requestedIndex(-1) , highlightRangeStart(0), highlightRangeEnd(0) , highlightComponent(0), highlight(0), trackedItem(0) , moveReason(Other), buffer(0), highlightPosAnimator(0), highlightSizeAnimator(0), spacing(0.0) + , highlightMoveSpeed(400), highlightResizeSpeed(400) , ownModel(false), wrap(false), autoHighlight(true) , haveHighlightRange(false), strictHighlightRange(false) - , highlightMoveSpeed(400), highlightResizeSpeed(400) {} void init(); @@ -371,7 +371,6 @@ public: QList visibleItems; QHash unrequestedItems; FxListItem *currentItem; - QFxItem *tmpCurrent; Qt::Orientation orient; int visiblePos; int visibleIndex; @@ -752,10 +751,6 @@ void QFxListViewPrivate::updateCurrent(int modelIndex) return; } - if (tmpCurrent) { - delete tmpCurrent; - tmpCurrent = 0; - } FxListItem *oldCurrentItem = currentItem; currentIndex = modelIndex; currentItem = createItem(modelIndex); @@ -991,14 +986,8 @@ void QFxListView::setCurrentIndex(int index) QFxItem *QFxListView::currentItem() { Q_D(QFxListView); - if (!d->currentItem) { - // Always return something valid - if (!d->tmpCurrent) { - d->tmpCurrent = new QFxItem; - d->tmpCurrent->setParent(viewport()); - } - return d->tmpCurrent; - } + if (!d->currentItem) + return 0; return d->currentItem->item; } -- cgit v0.12 From b957118a2d2f44cec5f1a0709da26a5c685cc344 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Fri, 9 Oct 2009 11:10:43 +1000 Subject: Fix example errors --- examples/declarative/layouts/Button.qml | 8 ++++---- examples/declarative/webview/content/FieldText.qml | 2 -- examples/declarative/xmldata/yahoonews.qml | 2 +- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/examples/declarative/layouts/Button.qml b/examples/declarative/layouts/Button.qml index 6c2fd8d..1fa0dee 100644 --- a/examples/declarative/layouts/Button.qml +++ b/examples/declarative/layouts/Button.qml @@ -1,16 +1,16 @@ import Qt 4.6 -Rectangle { border.color: "black"; color: "steelblue"; radius: 5; width: pix.width + text.width + 13; height: pix.height + 10; id: page +Rectangle { border.color: "black"; color: "steelblue"; radius: 5; width: pix.width + textelement.width + 13; height: pix.height + 10; id: page property string text property string icon signal clicked Image { id: pix; x: 5; y:5; source: parent.icon} - Text { id: text; text: page.text; color: "white"; x:pix.width+pix.x+3; anchors.verticalCenter: pix.verticalCenter;} + Text { id: textelement; text: page.text; color: "white"; x:pix.width+pix.x+3; anchors.verticalCenter: pix.verticalCenter;} MouseRegion{ id:mr; anchors.fill: parent; onClicked: {parent.focus = true; page.clicked()}} states: State{ name:"pressed"; when:mr.pressed - PropertyChanges {target:text; x: 5} - PropertyChanges {target:pix; x:text.x+text.width + 3} + PropertyChanges {target:textelement; x: 5} + PropertyChanges {target:pix; x:textelement.x+textelement.width + 3} } transitions: diff --git a/examples/declarative/webview/content/FieldText.qml b/examples/declarative/webview/content/FieldText.qml index fe55185..2adfbbf 100644 --- a/examples/declarative/webview/content/FieldText.qml +++ b/examples/declarative/webview/content/FieldText.qml @@ -10,7 +10,6 @@ Item { signal cancelled signal startEdit - resources: [ Script { function edit() { @@ -36,7 +35,6 @@ Item { } } - ] Image { id: cancelIcon diff --git a/examples/declarative/xmldata/yahoonews.qml b/examples/declarative/xmldata/yahoonews.qml index bad1d88..6d43f46 100644 --- a/examples/declarative/xmldata/yahoonews.qml +++ b/examples/declarative/xmldata/yahoonews.qml @@ -32,7 +32,7 @@ Rectangle { height: wrapper.height + 10 MouseRegion { anchors.fill: wrapper - onPressed: { delegate.ListView.list.currentIndex = index; } + onPressed: { delegate.ListView.view.currentIndex = index; } onClicked: { if (wrapper.state == 'Details') { wrapper.state = '';} else {wrapper.state = 'Details';} } } Rectangle { -- cgit v0.12 From 8e56f62a7155ec8f8e8af07100675fd6185bf481 Mon Sep 17 00:00:00 2001 From: Martin Jones Date: Fri, 9 Oct 2009 11:25:28 +1000 Subject: Remove some warnings. --- src/declarative/qml/qmlxmlhttprequest.cpp | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/declarative/qml/qmlxmlhttprequest.cpp b/src/declarative/qml/qmlxmlhttprequest.cpp index 65c5b16..0bc927c 100644 --- a/src/declarative/qml/qmlxmlhttprequest.cpp +++ b/src/declarative/qml/qmlxmlhttprequest.cpp @@ -1190,7 +1190,7 @@ static QScriptValue qmlxmlhttprequest_open(QScriptContext *context, QScriptEngin if (!request) return context->throwError(QScriptContext::ReferenceError, QLatin1String("Not an XMLHttpRequest object")); if (context->argumentCount() < 2 || context->argumentCount() > 5) - return context->throwError(QScriptContext::SyntaxError, "Incorrect argument count"); + return context->throwError(QScriptContext::SyntaxError, QLatin1String("Incorrect argument count")); // Argument 0 - Method QString method = context->argument(0).toString().toUpper(); @@ -1198,7 +1198,7 @@ static QScriptValue qmlxmlhttprequest_open(QScriptContext *context, QScriptEngin method != QLatin1String("PUT") && method != QLatin1String("HEAD") && method != QLatin1String("POST")) - return context->throwError(QScriptContext::SyntaxError, "Unsupported method"); + return context->throwError(QScriptContext::SyntaxError, QLatin1String("Unsupported method")); // Argument 1 - URL @@ -1209,12 +1209,12 @@ static QScriptValue qmlxmlhttprequest_open(QScriptContext *context, QScriptEngin if (ctxt) url = ctxt->resolvedUrl(url); else - return context->throwError(QScriptContext::SyntaxError, "Relative URLs not supported"); + return context->throwError(QScriptContext::SyntaxError, QLatin1String("Relative URLs not supported")); } // Argument 2 - async (optional) if (context->argumentCount() > 2 && !context->argument(2).toBoolean()) - return context->throwError(QScriptContext::SyntaxError, "Synchronous call not supported"); + return context->throwError(QScriptContext::SyntaxError, QLatin1String("Synchronous call not supported")); // Argument 3/4 - user/pass (optional) @@ -1242,12 +1242,12 @@ static QScriptValue qmlxmlhttprequest_setRequestHeader(QScriptContext *context, if (!request) return context->throwError(QScriptContext::ReferenceError, QLatin1String("Not an XMLHttpRequest object")); if (context->argumentCount() != 2) - return context->throwError(QScriptContext::SyntaxError, "Incorrect argument count"); + return context->throwError(QScriptContext::SyntaxError, QLatin1String("Incorrect argument count")); if (request->readyState() != QmlXMLHttpRequest::Opened || request->sendFlag()) - return context->throwError(INVALID_STATE_ERR, "Invalid state"); + return context->throwError(INVALID_STATE_ERR, QLatin1String("Invalid state")); QString name = context->argument(0).toString(); @@ -1289,10 +1289,10 @@ static QScriptValue qmlxmlhttprequest_send(QScriptContext *context, QScriptEngin if (!request) return context->throwError(QScriptContext::ReferenceError, QLatin1String("Not an XMLHttpRequest object")); if (request->readyState() != QmlXMLHttpRequest::Opened) - return context->throwError(INVALID_STATE_ERR, "Invalid state"); + return context->throwError(INVALID_STATE_ERR, QLatin1String("Invalid state")); if (request->sendFlag()) - return context->throwError(INVALID_STATE_ERR, "Invalid state"); + return context->throwError(INVALID_STATE_ERR, QLatin1String("Invalid state")); QByteArray data; if (context->argumentCount() > 0) @@ -1324,7 +1324,7 @@ static QScriptValue qmlxmlhttprequest_getResponseHeader(QScriptContext *context, if (request->readyState() != QmlXMLHttpRequest::Loading && request->readyState() != QmlXMLHttpRequest::Done && request->readyState() != QmlXMLHttpRequest::HeadersReceived) - return context->throwError(INVALID_STATE_ERR, "Invalid state"); + return context->throwError(INVALID_STATE_ERR, QLatin1String("Invalid state")); QString headerName = context->argument(0).toString(); @@ -1342,7 +1342,7 @@ static QScriptValue qmlxmlhttprequest_getAllResponseHeaders(QScriptContext *cont if (request->readyState() != QmlXMLHttpRequest::Loading && request->readyState() != QmlXMLHttpRequest::Done && request->readyState() != QmlXMLHttpRequest::HeadersReceived) - return context->throwError(INVALID_STATE_ERR, "Invalid state"); + return context->throwError(INVALID_STATE_ERR, QLatin1String("Invalid state")); return QScriptValue(request->headers()); } @@ -1363,7 +1363,7 @@ static QScriptValue qmlxmlhttprequest_status(QScriptContext *context, QScriptEng if (request->readyState() == QmlXMLHttpRequest::Unsent || request->readyState() == QmlXMLHttpRequest::Opened) - return context->throwError(INVALID_STATE_ERR, "Invalid state"); + return context->throwError(INVALID_STATE_ERR, QLatin1String("Invalid state")); if (request->errorFlag()) return QScriptValue(0); @@ -1378,7 +1378,7 @@ static QScriptValue qmlxmlhttprequest_statusText(QScriptContext *context, QScrip if (request->readyState() == QmlXMLHttpRequest::Unsent || request->readyState() == QmlXMLHttpRequest::Opened) - return context->throwError(INVALID_STATE_ERR, "Invalid state"); + return context->throwError(INVALID_STATE_ERR, QLatin1String("Invalid state")); if (request->errorFlag()) return QScriptValue(0); -- cgit v0.12