diff options
Diffstat (limited to 'src/declarative')
23 files changed, 615 insertions, 561 deletions
diff --git a/src/declarative/graphicsitems/qmlgraphicsitem.cpp b/src/declarative/graphicsitems/qmlgraphicsitem.cpp index dd685d4..bd3c1ea 100644 --- a/src/declarative/graphicsitems/qmlgraphicsitem.cpp +++ b/src/declarative/graphicsitems/qmlgraphicsitem.cpp @@ -1533,8 +1533,12 @@ void QmlGraphicsItem::setParentItem(QmlGraphicsItem *parent) QmlGraphicsItem *oldParent = parentItem(); if (parent == oldParent || !parent) return; + Q_D(QmlGraphicsItem); QObject::setParent(parent); - QGraphicsObject::setParentItem(parent); + d->setParentItemHelper(parent, /*newParentVariant=*/0, /*thisPointerVariant=*/0); + if (oldParent) + emit oldParent->childrenChanged(); + emit parentChanged(); } /*! diff --git a/src/declarative/qml/qml.pri b/src/declarative/qml/qml.pri index 9268545..6f2f57f 100644 --- a/src/declarative/qml/qml.pri +++ b/src/declarative/qml/qml.pri @@ -32,9 +32,8 @@ SOURCES += \ $$PWD/qmlscriptparser.cpp \ $$PWD/qmlenginedebug.cpp \ $$PWD/qmlrewrite.cpp \ - $$PWD/qmlbindingvme.cpp \ $$PWD/qmlvaluetype.cpp \ - $$PWD/qmlbindingoptimizations.cpp \ + $$PWD/qmlcompiledbindings.cpp \ $$PWD/qmlxmlhttprequest.cpp \ $$PWD/qmlsqldatabase.cpp \ $$PWD/qmetaobjectbuilder.cpp \ @@ -95,13 +94,12 @@ HEADERS += \ $$PWD/qmldeclarativedata_p.h \ $$PWD/qmlerror.h \ $$PWD/qmlscriptparser_p.h \ - $$PWD/qmlbindingvme_p.h \ $$PWD/qmlenginedebug_p.h \ $$PWD/qmlrewrite_p.h \ $$PWD/qpodvector_p.h \ $$PWD/qbitfield_p.h \ $$PWD/qmlvaluetype_p.h \ - $$PWD/qmlbindingoptimizations_p.h \ + $$PWD/qmlcompiledbindings_p.h \ $$PWD/qmlxmlhttprequest_p.h \ $$PWD/qmlsqldatabase_p.h \ $$PWD/qmetaobjectbuilder_p.h \ diff --git a/src/declarative/qml/qmlbinding.cpp b/src/declarative/qml/qmlbinding.cpp index c0389a8..3e29a3c 100644 --- a/src/declarative/qml/qmlbinding.cpp +++ b/src/declarative/qml/qmlbinding.cpp @@ -147,7 +147,11 @@ void QmlBinding::update(QmlMetaProperty::WriteFlags flags) bool isUndefined = false; QVariant value = this->value(&isUndefined); - if (isUndefined && !data->error.isValid()) { + if (isUndefined && !data->error.isValid() && data->property.isResettable()) { + + data->property.reset(); + + } else if (isUndefined && !data->error.isValid()) { QUrl url = QUrl(data->url); int line = data->line; @@ -159,7 +163,7 @@ void QmlBinding::update(QmlMetaProperty::WriteFlags flags) data->error.setDescription(QLatin1String("Unable to assign [undefined] to ") + QLatin1String(QMetaType::typeName(data->property.propertyType()))); } else if (!isUndefined && data->property.object() && - !data->property.write(value, flags)) { + !data->property.write(value, flags)) { QUrl url = QUrl(data->url); int line = data->line; diff --git a/src/declarative/qml/qmlbindingoptimizations.cpp b/src/declarative/qml/qmlbindingoptimizations.cpp deleted file mode 100644 index 1e49636..0000000 --- a/src/declarative/qml/qmlbindingoptimizations.cpp +++ /dev/null @@ -1,173 +0,0 @@ -/**************************************************************************** -** -** 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 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 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 "qmlbindingoptimizations_p.h" - -#include "qmlcontext_p.h" -#include <QtDeclarative/qmlinfo.h> -#include "qmlbindingvme_p.h" - -QT_BEGIN_NAMESPACE - -int QmlOptimizedBindings::methodCount = -1; - -QmlOptimizedBindings::QmlOptimizedBindings(const char *program, QmlContext *context) -: m_program(program) -{ - if (methodCount == -1) - methodCount = QmlOptimizedBindings::staticMetaObject.methodCount(); - - m_config.target = this; - m_config.targetSlot = metaObject()->methodCount(); - - quint32 bindings = 0; - QmlBindingVME::init(m_program, &m_config, &m_signalTable, &bindings); - - m_bindings = new Binding[bindings]; - - QmlAbstractExpression::setContext(context); -} - -QmlOptimizedBindings::~QmlOptimizedBindings() -{ - delete [] m_bindings; -} - -QmlAbstractBinding *QmlOptimizedBindings::configBinding(int index, QObject *target, - QObject *scope, int property) -{ - Binding *rv = m_bindings + index; - - rv->index = index; - rv->property = property; - rv->target = target; - rv->scope = scope; - rv->parent = this; - - addref(); // This is decremented in Binding::destroy() - - return rv; -} - -void QmlOptimizedBindings::Binding::setEnabled(bool e, QmlMetaProperty::WriteFlags flags) -{ - if (e) { - addToObject(target); - update(flags); - } else { - removeFromObject(); - } - - QmlAbstractBinding::setEnabled(e, flags); - - if (enabled != e) { - enabled = e; - - if (e) update(flags); - } -} - -int QmlOptimizedBindings::Binding::propertyIndex() -{ - return property & 0xFFFF; -} - -void QmlOptimizedBindings::Binding::update(QmlMetaProperty::WriteFlags) -{ - parent->run(this); -} - -void QmlOptimizedBindings::Binding::destroy() -{ - enabled = false; - removeFromObject(); - parent->release(); -} - -int QmlOptimizedBindings::qt_metacall(QMetaObject::Call c, int id, void **) -{ - if (c == QMetaObject::InvokeMetaMethod && id >= methodCount) { - id -= methodCount; - - quint32 *reeval = m_signalTable + m_signalTable[id]; - quint32 count = *reeval; - ++reeval; - for (quint32 ii = 0; ii < count; ++ii) { - run(m_bindings + reeval[ii]); - } - } - return -1; -} - -void QmlOptimizedBindings::run(Binding *binding) -{ - if (!binding->enabled) - return; - if (binding->updating) - qWarning("ERROR: Circular binding"); - - QmlContext *context = QmlAbstractExpression::context(); - if (!context) { - qWarning("QmlOptimizedBindings: Attempted to evaluate an expression in an invalid context"); - return; - } - QmlContextPrivate *cp = QmlContextPrivate::get(context); - - if (binding->property & 0xFFFF0000) { - QmlEnginePrivate *ep = QmlEnginePrivate::get(cp->engine); - - QmlValueType *vt = ep->valueTypes[(binding->property >> 16) & 0xFF]; - Q_ASSERT(vt); - vt->read(binding->target, binding->property & 0xFFFF); - - QObject *target = vt; - QmlBindingVME::run(m_program, binding->index, &m_config, cp, binding, - binding->scope, target); - - vt->write(binding->target, binding->property & 0xFFFF, - QmlMetaProperty::DontRemoveBinding); - } else { - QmlBindingVME::run(m_program, binding->index, &m_config, cp, binding, - binding->scope, binding->target); - } -} - -QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlbindingvme_p.h b/src/declarative/qml/qmlbindingvme_p.h deleted file mode 100644 index 01280f0..0000000 --- a/src/declarative/qml/qmlbindingvme_p.h +++ /dev/null @@ -1,182 +0,0 @@ -/**************************************************************************** -** -** 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 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 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 QMLBINDINGVME_P_H -#define QMLBINDINGVME_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 <QtCore/qglobal.h> -#include <private/qscriptdeclarativeclass_p.h> -#include "qmlexpression_p.h" -#include "qmlguard_p.h" - -QT_BEGIN_HEADER - -QT_BEGIN_NAMESPACE - -class QObject; -class QmlContextPrivate; -class QmlBindingVME -{ -public: - struct Config { - Config() : target(0), targetSlot(-1), subscriptions(0), identifiers(0) {} - ~Config() { delete [] subscriptions; delete [] identifiers; } - QObject *target; - int targetSlot; - - struct Subscription { - struct Signal { - QmlGuard<QObject> source; - int notifyIndex; - }; - - struct Id { - inline Id(); - inline ~Id(); - inline void reset(); - Id *next; - Id**prev; - QObject *target; - int methodIndex; - }; - - enum { InvalidType, SignalType, IdType } type; - inline Subscription(); - inline ~Subscription(); - bool isSignal() const { return type == SignalType; } - bool isId() const { return type == IdType; } - inline Signal *signal(); - inline Id *id(); - union { - char signalData[sizeof(Signal)]; - char idData[sizeof(Id)]; - }; - }; - Subscription *subscriptions; - QScriptDeclarativeClass::PersistentIdentifier *identifiers; - }; - - static void init(const char *program, Config *config, - quint32 **sigTable, quint32 *bindingCount); - static void run(const char *program, int instr, - Config *config, QmlContextPrivate *context, QmlDelayedError *error, - QObject *scope, QObject *output); - static void dump(const char *); -}; - -QmlBindingVME::Config::Subscription::Subscription() -: type(InvalidType) -{ -} - -QmlBindingVME::Config::Subscription::~Subscription() -{ - if (type == SignalType) ((Signal *)signalData)->~Signal(); - else if (type == IdType) ((Id *)idData)->~Id(); -} - -QmlBindingVME::Config::Subscription::Id::Id() -: next(0), prev(0), target(0), methodIndex(-1) -{ -} - -QmlBindingVME::Config::Subscription::Id::~Id() -{ - reset(); -} - -void QmlBindingVME::Config::Subscription::Id::reset() -{ - if (next) next->prev = prev; - if (prev) *prev = next; - next = 0; - prev = 0; - target = 0; - methodIndex = -1; -} - -class QmlBindingCompilerPrivate; -class QmlBindingCompiler -{ -public: - QmlBindingCompiler(); - ~QmlBindingCompiler(); - - // Returns true if bindings were compiled - bool isValid() const; - - struct Expression - { - QmlParser::Object *component; - QmlParser::Object *context; - QmlParser::Property *property; - QmlParser::Variant expression; - QHash<QString, QmlParser::Object *> ids; - QmlEnginePrivate::Imports imports; - }; - - // -1 on failure, otherwise the binding index to use - int compile(const Expression &, QmlEnginePrivate *); - - // Returns the compiled program - QByteArray program() const; - -private: - QmlBindingCompilerPrivate *d; -}; - -QT_END_NAMESPACE - -QT_END_HEADER - -#endif // QMLBINDINGVME_P_H - diff --git a/src/declarative/qml/qmlbindingvme.cpp b/src/declarative/qml/qmlcompiledbindings.cpp index 47f02b2..d09f7eb 100644 --- a/src/declarative/qml/qmlbindingvme.cpp +++ b/src/declarative/qml/qmlcompiledbindings.cpp @@ -39,7 +39,9 @@ ** ****************************************************************************/ -#include "qmlbindingvme_p.h" +#include "qmlcompiledbindings_p.h" + +#include <QtDeclarative/qmlinfo.h> #include <private/qmlcontext_p.h> #include <private/qmljsast_p.h> #include <private/qmljsengine_p.h> @@ -52,22 +54,6 @@ QT_BEGIN_NAMESPACE using namespace QmlJS; -QmlBindingVME::Config::Subscription::Signal *QmlBindingVME::Config::Subscription::signal() -{ - if (type == IdType) ((Id *)idData)->~Id(); - if (type != SignalType) new (signalData) Signal; - type = SignalType; - return (Signal *)signalData; -} - -QmlBindingVME::Config::Subscription::Id *QmlBindingVME::Config::Subscription::id() -{ - if (type == SignalType) ((Signal *)signalData)->~Signal(); - if (type != IdType) new (idData) Id; - type = IdType; - return (Id *)idData; -} - namespace { // Supported types: int, qreal, QString (needs constr/destr), QObject*, bool struct Register { @@ -106,7 +92,258 @@ struct Register { int type; // Optional type void *data[2]; // Object stored here }; +} + +class QmlCompiledBindingsPrivate : public QObjectPrivate +{ + Q_DECLARE_PUBLIC(QmlCompiledBindings) + +public: + QmlCompiledBindingsPrivate(); + virtual ~QmlCompiledBindingsPrivate(); + + struct Binding : public QmlAbstractBinding, public QmlDelayedError { + Binding() : enabled(false), updating(0), property(0), + scope(0), target(0), parent(0) {} + + // Inherited from QmlAbstractBinding + virtual void setEnabled(bool, QmlMetaProperty::WriteFlags flags); + virtual int propertyIndex(); + virtual void update(QmlMetaProperty::WriteFlags flags); + virtual void destroy(); + + int index:30; + bool enabled:1; + bool updating:1; + int property; + QObject *scope; + QObject *target; + + QmlCompiledBindingsPrivate *parent; + }; + + struct Subscription { + struct Signal { + QmlGuard<QObject> source; + int notifyIndex; + }; + + enum { InvalidType, SignalType, IdType } type; + inline Subscription(); + inline ~Subscription(); + bool isSignal() const { return type == SignalType; } + bool isId() const { return type == IdType; } + inline Signal *signal(); + inline QmlContextPrivate::IdNotifier *id(); + union { + char signalData[sizeof(Signal)]; + char idData[sizeof(QmlContextPrivate::IdNotifier)]; + }; + }; + Subscription *subscriptions; + QScriptDeclarativeClass::PersistentIdentifier *identifiers; + + void run(Binding *); + + const char *programData; + Binding *m_bindings; + quint32 *m_signalTable; + + static int methodCount; + + void init(); + void run(int instr, QmlContextPrivate *context, + QmlDelayedError *error, QObject *scope, QObject *output); + + + inline void unsubscribe(int subIndex); + inline void subscribeId(QmlContextPrivate *p, int idIndex, int subIndex); + inline void subscribe(QObject *o, int notifyIndex, int subIndex); + + QmlPropertyCache::Data *findproperty(QObject *obj, + const QScriptDeclarativeClass::Identifier &name, + QmlEnginePrivate *enginePriv, + QmlPropertyCache::Data &local); + bool findproperty(QObject *obj, + Register *output, + QmlEnginePrivate *enginePriv, + int subIdx, + const QScriptDeclarativeClass::Identifier &name, + bool isTerminal); + void findgeneric(Register *output, // value output + int subIdx, // Subscription index in config + QmlContextPrivate *context, // Context to search in + const QScriptDeclarativeClass::Identifier &name, + bool isTerminal); +}; + +QmlCompiledBindingsPrivate::QmlCompiledBindingsPrivate() +: subscriptions(0), identifiers(0) +{ +} + +QmlCompiledBindingsPrivate::~QmlCompiledBindingsPrivate() +{ + delete [] subscriptions; subscriptions = 0; + delete [] identifiers; identifiers = 0; +} + +QmlCompiledBindingsPrivate::Subscription::Subscription() +: type(InvalidType) +{ +} + +QmlCompiledBindingsPrivate::Subscription::~Subscription() +{ + if (type == SignalType) ((Signal *)signalData)->~Signal(); + else if (type == IdType) ((QmlContextPrivate::IdNotifier *)idData)->~IdNotifier(); +} + + +int QmlCompiledBindingsPrivate::methodCount = -1; + +QmlCompiledBindings::QmlCompiledBindings(const char *program, QmlContext *context) +: QObject(*(new QmlCompiledBindingsPrivate)) +{ + Q_D(QmlCompiledBindings); + + if (d->methodCount == -1) + d->methodCount = QmlCompiledBindings::staticMetaObject.methodCount(); + + d->programData = program; + + d->init(); + + QmlAbstractExpression::setContext(context); +} + +QmlCompiledBindings::~QmlCompiledBindings() +{ + Q_D(QmlCompiledBindings); + + delete [] d->m_bindings; +} + +QmlAbstractBinding *QmlCompiledBindings::configBinding(int index, QObject *target, + QObject *scope, int property) +{ + Q_D(QmlCompiledBindings); + + QmlCompiledBindingsPrivate::Binding *rv = d->m_bindings + index; + + rv->index = index; + rv->property = property; + rv->target = target; + rv->scope = scope; + rv->parent = d; + + addref(); // This is decremented in Binding::destroy() + + return rv; +} + +void QmlCompiledBindingsPrivate::Binding::setEnabled(bool e, QmlMetaProperty::WriteFlags flags) +{ + if (e) { + addToObject(target); + update(flags); + } else { + removeFromObject(); + } + QmlAbstractBinding::setEnabled(e, flags); + + if (enabled != e) { + enabled = e; + + if (e) update(flags); + } +} + +int QmlCompiledBindingsPrivate::Binding::propertyIndex() +{ + return property & 0xFFFF; +} + +void QmlCompiledBindingsPrivate::Binding::update(QmlMetaProperty::WriteFlags) +{ + parent->run(this); +} + +void QmlCompiledBindingsPrivate::Binding::destroy() +{ + enabled = false; + removeFromObject(); + parent->q_func()->release(); +} + +int QmlCompiledBindings::qt_metacall(QMetaObject::Call c, int id, void **) +{ + Q_D(QmlCompiledBindings); + + if (c == QMetaObject::InvokeMetaMethod && id >= d->methodCount) { + id -= d->methodCount; + + quint32 *reeval = d->m_signalTable + d->m_signalTable[id]; + quint32 count = *reeval; + ++reeval; + for (quint32 ii = 0; ii < count; ++ii) { + d->run(d->m_bindings + reeval[ii]); + } + } + return -1; +} + +void QmlCompiledBindingsPrivate::run(Binding *binding) +{ + Q_Q(QmlCompiledBindings); + + if (!binding->enabled) + return; + if (binding->updating) + qWarning("ERROR: Circular binding"); + + QmlContext *context = q->QmlAbstractExpression::context(); + if (!context) { + qWarning("QmlCompiledBindings: Attempted to evaluate an expression in an invalid context"); + return; + } + QmlContextPrivate *cp = QmlContextPrivate::get(context); + + if (binding->property & 0xFFFF0000) { + QmlEnginePrivate *ep = QmlEnginePrivate::get(cp->engine); + + QmlValueType *vt = ep->valueTypes[(binding->property >> 16) & 0xFF]; + Q_ASSERT(vt); + vt->read(binding->target, binding->property & 0xFFFF); + + QObject *target = vt; + run(binding->index, cp, binding, binding->scope, target); + + vt->write(binding->target, binding->property & 0xFFFF, + QmlMetaProperty::DontRemoveBinding); + } else { + run(binding->index, cp, binding, binding->scope, binding->target); + } +} + +QmlCompiledBindingsPrivate::Subscription::Signal *QmlCompiledBindingsPrivate::Subscription::signal() +{ + if (type == IdType) ((QmlContextPrivate::IdNotifier *)idData)->~IdNotifier(); + if (type != SignalType) new (signalData) Signal; + type = SignalType; + return (Signal *)signalData; +} + +QmlContextPrivate::IdNotifier *QmlCompiledBindingsPrivate::Subscription::id() +{ + if (type == SignalType) ((Signal *)signalData)->~Signal(); + if (type != IdType) new (idData) QmlContextPrivate::IdNotifier; + type = IdType; + return (QmlContextPrivate::IdNotifier *)idData; +} + +namespace { // This structure is exactly 8-bytes in size struct Instr { enum { @@ -411,68 +648,72 @@ struct QmlBindingCompilerPrivate QByteArray buildExceptionData() const; }; -inline void unsubscribe(int subIndex, QmlBindingVME::Config *config) +void QmlCompiledBindingsPrivate::unsubscribe(int subIndex) { - QmlBindingVME::Config::Subscription *sub = (config->subscriptions + subIndex); + Q_Q(QmlCompiledBindings); + + QmlCompiledBindingsPrivate::Subscription *sub = (subscriptions + subIndex); if (sub->isSignal()) { - QmlBindingVME::Config::Subscription::Signal *s = sub->signal(); + QmlCompiledBindingsPrivate::Subscription::Signal *s = sub->signal(); if (s->source) #if (QT_VERSION >= QT_VERSION_CHECK(4, 6, 2)) QMetaObject::disconnectOne(s->source, s->notifyIndex, - config->target, config->targetSlot + subIndex); + q, methodCount + subIndex); #else // QTBUG-6781 QMetaObject::disconnect(s->source, s->notifyIndex, - config->target, config->targetSlot + subIndex); + q, methodCount + subIndex); #endif } else if (sub->isId()) { - sub->id()->reset(); + sub->id()->clear(); } } -inline void subscribeId(QmlContextPrivate *p, int idIndex, - int subIndex, QmlBindingVME::Config *config) +void QmlCompiledBindingsPrivate::subscribeId(QmlContextPrivate *p, int idIndex, int subIndex) { - unsubscribe(subIndex, config); + Q_Q(QmlCompiledBindings); + + unsubscribe(subIndex); if (p->idValues[idIndex]) { - QmlBindingVME::Config::Subscription *sub = (config->subscriptions + subIndex); - QmlBindingVME::Config::Subscription::Id *i = sub->id(); + QmlCompiledBindingsPrivate::Subscription *sub = (subscriptions + subIndex); + QmlContextPrivate::IdNotifier *i = sub->id(); i->next = p->idValues[idIndex].bindings; i->prev = &p->idValues[idIndex].bindings; p->idValues[idIndex].bindings = i; if (i->next) i->next->prev = &i->next; - i->target = config->target; - i->methodIndex = config->targetSlot + subIndex; + i->target = q; + i->methodIndex = methodCount + subIndex; } } -inline void subscribe(QObject *o, int notifyIndex, - int subIndex, QmlBindingVME::Config *config) +void QmlCompiledBindingsPrivate::subscribe(QObject *o, int notifyIndex, int subIndex) { - QmlBindingVME::Config::Subscription *sub = (config->subscriptions + subIndex); + Q_Q(QmlCompiledBindings); + + QmlCompiledBindingsPrivate::Subscription *sub = (subscriptions + subIndex); if (sub->isId()) - unsubscribe(subIndex, config); + unsubscribe(subIndex); - QmlBindingVME::Config::Subscription::Signal *s = sub->signal(); + QmlCompiledBindingsPrivate::Subscription::Signal *s = sub->signal(); if (o != s->source || notifyIndex != s->notifyIndex) { if (s->source) #if (QT_VERSION >= QT_VERSION_CHECK(4, 6, 2)) QMetaObject::disconnectOne(s->source, s->notifyIndex, - config->target, config->targetSlot + subIndex); + q, methodCount + subIndex); #else // QTBUG-6781 QMetaObject::disconnect(s->source, s->notifyIndex, - config->target, config->targetSlot + subIndex); + q, methodCount + subIndex); #endif s->source = o; s->notifyIndex = notifyIndex; if (s->source && s->notifyIndex != -1) - QMetaObject::connect(s->source, s->notifyIndex, config->target, - config->targetSlot + subIndex, Qt::DirectConnection); + QMetaObject::connect(s->source, s->notifyIndex, q, + methodCount + subIndex, Qt::DirectConnection); } } @@ -566,10 +807,11 @@ static QObject *variantToQObject(const QVariant &value, bool *ok) } } -static QmlPropertyCache::Data *findproperty(QObject *obj, - const QScriptDeclarativeClass::Identifier &name, - QmlEnginePrivate *enginePriv, - QmlPropertyCache::Data &local) +QmlPropertyCache::Data * +QmlCompiledBindingsPrivate::findproperty(QObject *obj, + const QScriptDeclarativeClass::Identifier &name, + QmlEnginePrivate *enginePriv, + QmlPropertyCache::Data &local) { QmlPropertyCache *cache = 0; QmlDeclarativeData *ddata = QmlDeclarativeData::get(obj); @@ -595,11 +837,10 @@ static QmlPropertyCache::Data *findproperty(QObject *obj, return property; } -static bool findproperty(QObject *obj, Register *output, - QmlEnginePrivate *enginePriv, - QmlBindingVME::Config *config, int subIdx, - const QScriptDeclarativeClass::Identifier &name, - bool isTerminal) +bool QmlCompiledBindingsPrivate::findproperty(QObject *obj, Register *output, + QmlEnginePrivate *enginePriv, + int subIdx, const QScriptDeclarativeClass::Identifier &name, + bool isTerminal) { if (!obj) { output->setUndefined(); @@ -611,7 +852,7 @@ static bool findproperty(QObject *obj, Register *output, if (property) { if (subIdx != -1) - subscribe(obj, property->notifyIndex, subIdx, config); + subscribe(obj, property->notifyIndex, subIdx); if (property->flags & QmlPropertyCache::Data::IsQObjectDerived) { void *args[] = { output->typeDataPtr(), 0 }; @@ -668,12 +909,11 @@ static bool findproperty(QObject *obj, Register *output, } } -static void findgeneric(Register *output, // value output - QmlBindingVME::Config *config, - int subIdx, // Subscription index in config - QmlContextPrivate *context, // Context to search in - const QScriptDeclarativeClass::Identifier &name, - bool isTerminal) +void QmlCompiledBindingsPrivate::findgeneric(Register *output, + int subIdx, + QmlContextPrivate *context, + const QScriptDeclarativeClass::Identifier &name, + bool isTerminal) { QmlEnginePrivate *enginePriv = QmlEnginePrivate::get(context->engine); @@ -685,8 +925,7 @@ static void findgeneric(Register *output, // val if (contextPropertyIndex != -1) { if (subIdx != -1) - subscribe(QmlContextPrivate::get(context), contextPropertyIndex + context->notifyIndex, - subIdx, config); + subscribe(QmlContextPrivate::get(context), contextPropertyIndex + context->notifyIndex, subIdx); if (contextPropertyIndex < context->idValueCount) { output->setQObject(context->idValues[contextPropertyIndex]); @@ -717,7 +956,7 @@ static void findgeneric(Register *output, // val if (QObject *root = context->defaultObjects.isEmpty()?0:context->defaultObjects.first()) { - if (findproperty(root, output, enginePriv, config, subIdx, name, isTerminal)) + if (findproperty(root, output, enginePriv, subIdx, name, isTerminal)) return; } @@ -732,20 +971,16 @@ static void findgeneric(Register *output, // val output->setUndefined(); } -/*! -Returns the signal/binding table. -*/ -void QmlBindingVME::init(const char *programData, Config *config, - quint32 **sigTable, quint32 *bindingCount) +void QmlCompiledBindingsPrivate::init() { Program *program = (Program *)programData; if (program->subscriptions) - config->subscriptions = new Config::Subscription[program->subscriptions]; + subscriptions = new QmlCompiledBindingsPrivate::Subscription[program->subscriptions]; if (program->identifiers) - config->identifiers = new QScriptDeclarativeClass::PersistentIdentifier[program->identifiers]; + identifiers = new QScriptDeclarativeClass::PersistentIdentifier[program->identifiers]; - *sigTable = (quint32 *)(program->data() + program->signalTableOffset); - *bindingCount = program->bindings; + m_signalTable = (quint32 *)(program->data() + program->signalTableOffset); + m_bindings = new QmlCompiledBindingsPrivate::Binding[program->bindings]; } static void throwException(int id, QmlDelayedError *error, @@ -769,9 +1004,9 @@ static void throwException(int id, QmlDelayedError *error, qWarning() << error->error; } -void QmlBindingVME::run(const char *programData, int instrIndex, - Config *config, QmlContextPrivate *context, QmlDelayedError *error, - QObject *scope, QObject *output) +void QmlCompiledBindingsPrivate::run(int instrIndex, + QmlContextPrivate *context, QmlDelayedError *error, + QObject *scope, QObject *output) { error->removeError(); @@ -791,17 +1026,15 @@ void QmlBindingVME::run(const char *programData, int instrIndex, break; case Instr::SubscribeId: - subscribeId(context, instr->subscribe.index, instr->subscribe.offset, config); + subscribeId(context, instr->subscribe.index, instr->subscribe.offset); break; case Instr::Subscribe: { QObject *o = 0; - int notifyIndex = instr->subscribe.index; - const Register &object = registers[instr->subscribe.reg]; if (!object.isUndefined()) o = object.getQObject(); - subscribe(o, instr->subscribe.index, instr->subscribe.offset, config); + subscribe(o, instr->subscribe.index, instr->subscribe.offset); } break; @@ -1084,14 +1317,13 @@ void QmlBindingVME::run(const char *programData, int instrIndex, return; case Instr::InitString: - if (!config->identifiers[instr->initstring.offset].identifier) { + if (!identifiers[instr->initstring.offset].identifier) { quint32 len = *(quint32 *)(data + instr->initstring.dataIdx); QChar *strdata = (QChar *)(data + instr->initstring.dataIdx + sizeof(quint32)); QString str = QString::fromRawData(strdata, len); - config->identifiers[instr->initstring.offset] = - engine->objectClass->createPersistentIdentifier(str); + identifiers[instr->initstring.offset] = engine->objectClass->createPersistentIdentifier(str); } break; @@ -1100,9 +1332,9 @@ void QmlBindingVME::run(const char *programData, int instrIndex, // We start the search in the parent context, as we know that the // name is not present in the current context or it would have been // found during the static compile - findgeneric(registers + instr->find.reg, config, instr->find.subscribeIndex, + findgeneric(registers + instr->find.reg, instr->find.subscribeIndex, QmlContextPrivate::get(context->parent), - config->identifiers[instr->find.name].identifier, + identifiers[instr->find.name].identifier, instr->common.type == Instr::FindGenericTerminal); break; @@ -1116,8 +1348,8 @@ void QmlBindingVME::run(const char *programData, int instrIndex, } findproperty(object.getQObject(), registers + instr->find.reg, - QmlEnginePrivate::get(context->engine), config, - instr->find.subscribeIndex, config->identifiers[instr->find.name].identifier, + QmlEnginePrivate::get(context->engine), + instr->find.subscribeIndex, identifiers[instr->find.name].identifier, instr->common.type == Instr::FindPropertyTerminal); } break; @@ -1186,9 +1418,9 @@ void QmlBindingVME::run(const char *programData, int instrIndex, } } -void QmlBindingVME::dump(const char *programData) +void QmlBindingCompiler::dump(const QByteArray &programData) { - const Program *program = (const Program *)programData; + const Program *program = (const Program *)programData.constData(); qWarning() << "Program.bindings:" << program->bindings; qWarning() << "Program.dataLength:" << program->dataLength; @@ -2513,5 +2745,5 @@ QByteArray QmlBindingCompiler::program() const } -QT_END_NAMESPACE +QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlbindingoptimizations_p.h b/src/declarative/qml/qmlcompiledbindings_p.h index 42b7d17..1d8fac4 100644 --- a/src/declarative/qml/qmlbindingoptimizations_p.h +++ b/src/declarative/qml/qmlcompiledbindings_p.h @@ -55,50 +55,57 @@ #include "qmlexpression_p.h" #include "qmlbinding.h" -#include "qmlbindingvme_p.h" QT_BEGIN_HEADER QT_BEGIN_NAMESPACE -class QmlOptimizedBindings : public QObject, public QmlAbstractExpression, public QmlRefCount +class QmlBindingCompilerPrivate; +class QmlBindingCompiler { public: - QmlOptimizedBindings(const char *program, QmlContext *context); - virtual ~QmlOptimizedBindings(); + QmlBindingCompiler(); + ~QmlBindingCompiler(); + + // Returns true if bindings were compiled + bool isValid() const; + + struct Expression + { + QmlParser::Object *component; + QmlParser::Object *context; + QmlParser::Property *property; + QmlParser::Variant expression; + QHash<QString, QmlParser::Object *> ids; + QmlEnginePrivate::Imports imports; + }; + + // -1 on failure, otherwise the binding index to use + int compile(const Expression &, QmlEnginePrivate *); + + // Returns the compiled program + QByteArray program() const; + + static void dump(const QByteArray &); +private: + QmlBindingCompilerPrivate *d; +}; + +class QmlCompiledBindingsPrivate; +class QmlCompiledBindings : public QObject, public QmlAbstractExpression, public QmlRefCount +{ +public: + QmlCompiledBindings(const char *program, QmlContext *context); + virtual ~QmlCompiledBindings(); + QmlAbstractBinding *configBinding(int index, QObject *target, QObject *scope, int property); protected: int qt_metacall(QMetaObject::Call, int, void **); private: - struct Binding : public QmlAbstractBinding, public QmlDelayedError { - Binding() : enabled(false), updating(0), property(0), - scope(0), target(0), parent(0) {} - - // Inherited from QmlAbstractBinding - virtual void setEnabled(bool, QmlMetaProperty::WriteFlags flags); - virtual int propertyIndex(); - virtual void update(QmlMetaProperty::WriteFlags flags); - virtual void destroy(); - - int index:30; - bool enabled:1; - bool updating:1; - int property; - QObject *scope; - QObject *target; - - QmlOptimizedBindings *parent; - }; - void run(Binding *); - - QmlBindingVME::Config m_config; - const char *m_program; - Binding *m_bindings; - quint32 *m_signalTable; - - static int methodCount; + Q_DISABLE_COPY(QmlCompiledBindings); + Q_DECLARE_PRIVATE(QmlCompiledBindings); }; QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlcompiler.cpp b/src/declarative/qml/qmlcompiler.cpp index 5937734..bb7abf3 100644 --- a/src/declarative/qml/qmlcompiler.cpp +++ b/src/declarative/qml/qmlcompiler.cpp @@ -64,7 +64,7 @@ #include "qmlglobal_p.h" #include "qmlscriptparser_p.h" #include "qmlbinding.h" -#include "qmlbindingvme_p.h" +#include "qmlcompiledbindings_p.h" #include <qfxperf_p_p.h> @@ -257,26 +257,30 @@ bool QmlCompiler::testLiteralAssignment(const QMetaProperty &prop, break; case QVariant::Color: { - QColor c = QmlStringConverters::colorFromString(string); - if (!c.isValid()) COMPILE_EXCEPTION(v, QCoreApplication::translate("QmlCompiler","Invalid property assignment: color expected")); + bool ok; + QmlStringConverters::colorFromString(string, &ok); + if (!ok) COMPILE_EXCEPTION(v, QCoreApplication::translate("QmlCompiler","Invalid property assignment: color expected")); } break; case QVariant::Date: { - QDate d = QDate::fromString(string, Qt::ISODate); - if (!d.isValid()) COMPILE_EXCEPTION(v, QCoreApplication::translate("QmlCompiler","Invalid property assignment: date expected")); + bool ok; + QmlStringConverters::dateFromString(string, &ok); + if (!ok) COMPILE_EXCEPTION(v, QCoreApplication::translate("QmlCompiler","Invalid property assignment: date expected")); } break; case QVariant::Time: { - QTime time = QTime::fromString(string, Qt::ISODate); - if (!time.isValid()) COMPILE_EXCEPTION(v, QCoreApplication::translate("QmlCompiler","Invalid property assignment: time expected")); + bool ok; + QmlStringConverters::timeFromString(string, &ok); + if (!ok) COMPILE_EXCEPTION(v, QCoreApplication::translate("QmlCompiler","Invalid property assignment: time expected")); } break; case QVariant::DateTime: { - QDateTime dateTime = QDateTime::fromString(string, Qt::ISODate); - if (!dateTime.isValid()) COMPILE_EXCEPTION(v, QCoreApplication::translate("QmlCompiler","Invalid property assignment: datetime expected")); + bool ok; + QmlStringConverters::dateTimeFromString(string, &ok); + if (!ok) COMPILE_EXCEPTION(v, QCoreApplication::translate("QmlCompiler","Invalid property assignment: datetime expected")); } break; case QVariant::Point: @@ -311,7 +315,7 @@ bool QmlCompiler::testLiteralAssignment(const QMetaProperty &prop, case QVariant::Vector3D: { bool ok; - QVector3D point = QmlStringConverters::vector3DFromString(string, &ok); + QmlStringConverters::vector3DFromString(string, &ok); if (!ok) COMPILE_EXCEPTION(v, QCoreApplication::translate("QmlCompiler","Invalid property assignment: 3D vector expected")); } break; @@ -417,7 +421,7 @@ void QmlCompiler::genLiteralAssignment(const QMetaProperty &prop, break; case QVariant::Date: { - QDate d = QDate::fromString(string, Qt::ISODate); + QDate d = QmlStringConverters::dateFromString(string); instr.type = QmlInstruction::StoreDate; instr.storeDate.propertyIndex = prop.propertyIndex(); instr.storeDate.value = d.toJulianDay(); @@ -425,7 +429,7 @@ void QmlCompiler::genLiteralAssignment(const QMetaProperty &prop, break; case QVariant::Time: { - QTime time = QTime::fromString(string, Qt::ISODate); + QTime time = QmlStringConverters::timeFromString(string); int data[] = { time.hour(), time.minute(), time.second(), time.msec() }; int index = output->indexForInt(data, 4); @@ -436,7 +440,7 @@ void QmlCompiler::genLiteralAssignment(const QMetaProperty &prop, break; case QVariant::DateTime: { - QDateTime dateTime = QDateTime::fromString(string, Qt::ISODate); + QDateTime dateTime = QmlStringConverters::dateTimeFromString(string); int data[] = { dateTime.date().toJulianDay(), dateTime.time().hour(), dateTime.time().minute(), @@ -2672,7 +2676,7 @@ bool QmlCompiler::completeComponentBuild() if (bindingCompiler.isValid()) { compileState.compiledBindingData = bindingCompiler.program(); - QmlBindingVME::dump(compileState.compiledBindingData); + QmlBindingCompiler::dump(compileState.compiledBindingData); } saveComponentState(); diff --git a/src/declarative/qml/qmlcontext.cpp b/src/declarative/qml/qmlcontext.cpp index f97f142..0eb497d 100644 --- a/src/declarative/qml/qmlcontext.cpp +++ b/src/declarative/qml/qmlcontext.cpp @@ -45,7 +45,7 @@ #include "qmlexpression_p.h" #include "qmlengine_p.h" #include "qmlengine.h" -#include "qmlbindingoptimizations_p.h" +#include "qmlcompiledbindings_p.h" #include "qmlinfo.h" #include <qscriptengine.h> @@ -108,7 +108,7 @@ void QmlContextPrivate::destroyed(ContextGuard *guard) while(guard->bindings) { QObject *o = guard->bindings->target; int mi = guard->bindings->methodIndex; - guard->bindings->reset(); + guard->bindings->clear(); if (o) o->qt_metacall(QMetaObject::InvokeMetaMethod, mi, 0); } diff --git a/src/declarative/qml/qmlcontext_p.h b/src/declarative/qml/qmlcontext_p.h index ffb4298..cd7e1b6 100644 --- a/src/declarative/qml/qmlcontext_p.h +++ b/src/declarative/qml/qmlcontext_p.h @@ -59,7 +59,6 @@ #include "qmlengine_p.h" #include "qmlintegercache_p.h" #include "qmltypenamecache_p.h" -#include "qmlbindingvme_p.h" #include <QtCore/qhash.h> #include <QtScript/qscriptvalue.h> @@ -77,7 +76,7 @@ class QmlExpression; class QmlExpressionPrivate; class QmlAbstractExpression; class QmlBinding_Id; -class QmlOptimizedBindings; +class QmlCompiledBindings; class Q_DECLARATIVE_EXPORT QmlContextPrivate : public QObjectPrivate { @@ -114,15 +113,27 @@ public: QmlDeclarativeData *contextObjects; + struct IdNotifier + { + inline IdNotifier(); + inline ~IdNotifier(); + + inline void clear(); + + IdNotifier *next; + IdNotifier**prev; + QObject *target; + int methodIndex; + }; + struct ContextGuard : public QmlGuard<QObject> { - ContextGuard() : priv(0), bindings(0) {} + inline ContextGuard(); + inline ContextGuard &operator=(QObject *obj); + inline virtual void objectDestroyed(QObject *); + QmlContextPrivate *priv; - QmlBindingVME::Config::Subscription::Id *bindings; - ContextGuard &operator=(QObject *obj) { - (QmlGuard<QObject>&)*this = obj; return *this; - } - void objectDestroyed(QObject *) { priv->destroyed(this); } + IdNotifier *bindings; }; ContextGuard *idValues; int idValueCount; @@ -137,12 +148,45 @@ public: return static_cast<QmlContext *>(context->q_func()); } - QmlOptimizedBindings *optimizedBindings; + QmlCompiledBindings *optimizedBindings; // Only used for debugging QList<QPointer<QObject> > instances; }; +QmlContextPrivate::IdNotifier::IdNotifier() +: next(0), prev(0), target(0), methodIndex(-1) +{ +} + +QmlContextPrivate::IdNotifier::~IdNotifier() +{ + clear(); +} + +void QmlContextPrivate::IdNotifier::clear() +{ + if (next) next->prev = prev; + if (prev) *prev = next; + next = 0; prev = 0; target = 0; + methodIndex = -1; +} + +QmlContextPrivate::ContextGuard::ContextGuard() +: priv(0), bindings(0) +{ +} + +QmlContextPrivate::ContextGuard &QmlContextPrivate::ContextGuard::operator=(QObject *obj) +{ + (QmlGuard<QObject>&)*this = obj; return *this; +} + +void QmlContextPrivate::ContextGuard::objectDestroyed(QObject *) +{ + priv->destroyed(this); +} + QT_END_NAMESPACE #endif // QMLCONTEXT_P_H diff --git a/src/declarative/qml/qmlcontextscriptclass.cpp b/src/declarative/qml/qmlcontextscriptclass.cpp index eecc611..80d52ad 100644 --- a/src/declarative/qml/qmlcontextscriptclass.cpp +++ b/src/declarative/qml/qmlcontextscriptclass.cpp @@ -174,7 +174,8 @@ QmlContextScriptClass::queryProperty(QmlContext *bindContext, QObject *scopeObje if (scopeObject) { QScriptClass::QueryFlags rv = - ep->objectClass->queryProperty(scopeObject, name, flags, bindContext, QmlObjectScriptClass::ImplicitObject); + ep->objectClass->queryProperty(scopeObject, name, flags, bindContext, + QmlObjectScriptClass::ImplicitObject | QmlObjectScriptClass::SkipAttachedProperties); if (rv) { lastScopeObject = scopeObject; lastContext = bindContext; @@ -184,7 +185,8 @@ QmlContextScriptClass::queryProperty(QmlContext *bindContext, QObject *scopeObje for (int ii = cp->defaultObjects.count() - 1; ii >= 0; --ii) { QScriptClass::QueryFlags rv = - ep->objectClass->queryProperty(cp->defaultObjects.at(ii), name, flags, bindContext, QmlObjectScriptClass::ImplicitObject); + ep->objectClass->queryProperty(cp->defaultObjects.at(ii), name, flags, bindContext, + QmlObjectScriptClass::ImplicitObject | QmlObjectScriptClass::SkipAttachedProperties); if (rv) { lastDefaultObject = ii; diff --git a/src/declarative/qml/qmllistscriptclass.cpp b/src/declarative/qml/qmllistscriptclass.cpp index 441c410..d4cdc6e 100644 --- a/src/declarative/qml/qmllistscriptclass.cpp +++ b/src/declarative/qml/qmllistscriptclass.cpp @@ -49,7 +49,8 @@ QT_BEGIN_NAMESPACE struct ListData : public QScriptDeclarativeClass::Object { QmlGuard<QObject> object; int propertyIdx; - QmlListScriptClass::ListType type; + QmlListScriptClass::ListCategory type; + int propertyType; }; QmlListScriptClass::QmlListScriptClass(QmlEngine *e) @@ -65,7 +66,7 @@ QmlListScriptClass::~QmlListScriptClass() { } -QScriptValue QmlListScriptClass::newList(QObject *object, int propId, ListType type) +QScriptValue QmlListScriptClass::newList(QObject *object, int propId, ListCategory type, int propType) { QScriptEngine *scriptEngine = QmlEnginePrivate::getScriptEngine(engine); @@ -76,6 +77,7 @@ QScriptValue QmlListScriptClass::newList(QObject *object, int propId, ListType t data->object = object; data->propertyIdx = propId; data->type = type; + data->propertyType = propType; return newObject(scriptEngine, this, data); } @@ -144,5 +146,28 @@ QmlListScriptClass::ScriptValue QmlListScriptClass::property(Object *obj, const } } +QVariant QmlListScriptClass::toVariant(Object *obj, bool *ok) +{ + ListData *data = (ListData *)obj; + + if (!data->object) { + if (ok) *ok = false; + return QVariant(); + } + + void *list = 0; + void *args[] = { &list, 0 }; + QMetaObject::metacall(data->object, QMetaObject::ReadProperty, + data->propertyIdx, args); + + if (!list) { + if (ok) *ok = false; + return QVariant(); + } + + if (ok) *ok = true; + return QVariant(data->propertyType, &list); +} + QT_END_NAMESPACE diff --git a/src/declarative/qml/qmllistscriptclass_p.h b/src/declarative/qml/qmllistscriptclass_p.h index 0c6c5b2..e484b34 100644 --- a/src/declarative/qml/qmllistscriptclass_p.h +++ b/src/declarative/qml/qmllistscriptclass_p.h @@ -64,13 +64,14 @@ public: QmlListScriptClass(QmlEngine *); ~QmlListScriptClass(); - enum ListType { QListPtr, QmlListPtr }; - QScriptValue newList(QObject *, int, ListType); + enum ListCategory { QListPtr, QmlListPtr }; + QScriptValue newList(QObject *, int, ListCategory, int); protected: virtual QScriptClass::QueryFlags queryProperty(Object *, const Identifier &, QScriptClass::QueryFlags flags); virtual ScriptValue property(Object *, const Identifier &); + virtual QVariant toVariant(Object *, bool *ok); private: PersistentIdentifier m_lengthId; diff --git a/src/declarative/qml/qmlmetaproperty.cpp b/src/declarative/qml/qmlmetaproperty.cpp index 4717782..0603a9c 100644 --- a/src/declarative/qml/qmlmetaproperty.cpp +++ b/src/declarative/qml/qmlmetaproperty.cpp @@ -51,6 +51,7 @@ #include "qmlengine.h" #include "qmlengine_p.h" #include "qmldeclarativedata_p.h" +#include "qmlstringconverters_p.h" #include <qfxperf_p_p.h> @@ -435,6 +436,17 @@ bool QmlMetaProperty::isDesignable() const } /*! + Returns true if the property is resettable, otherwise false. +*/ +bool QmlMetaProperty::isResettable() const +{ + if (type() & Property && d->core.isValid() && d->object) + return d->core.flags & QmlPropertyCache::Data::IsResettable; + else + return false; +} + +/*! Returns true if the QmlMetaProperty refers to a valid property, otherwise false. */ @@ -951,6 +963,14 @@ bool QmlMetaPropertyPrivate::write(QObject *object, const QmlPropertyCache::Data void *a[] = { (void *)v.constData(), 0, &status, &flags}; QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, a); } + } else if (vt == QVariant::String) { + bool ok = false; + QVariant v = QmlStringConverters::variantFromString(value.toString(), t, &ok); + if (!ok) + return false; + + void *a[] = { (void *)v.constData(), 0, &status, &flags}; + QMetaObject::metacall(object, QMetaObject::WriteProperty, coreIdx, a); } else { return false; } @@ -967,6 +987,20 @@ bool QmlMetaProperty::write(const QVariant &value) const return write(value, 0); } +/*! + Resets the property value. +*/ +bool QmlMetaProperty::reset() const +{ + if (isResettable()) { + void *args[] = { 0 }; + QMetaObject::metacall(d->object, QMetaObject::ResetProperty, d->core.coreIndex, args); + return true; + } else { + return false; + } +} + bool QmlMetaProperty::write(const QVariant &value, QmlMetaProperty::WriteFlags flags) const { if (d->object && type() & Property && d->core.isValid() && isWritable()) diff --git a/src/declarative/qml/qmlmetaproperty.h b/src/declarative/qml/qmlmetaproperty.h index dcb5905..240f5a2 100644 --- a/src/declarative/qml/qmlmetaproperty.h +++ b/src/declarative/qml/qmlmetaproperty.h @@ -88,6 +88,7 @@ public: enum WriteFlag { BypassInterceptor = 0x01, DontRemoveBinding = 0x02 }; Q_DECLARE_FLAGS(WriteFlags, WriteFlag) bool write(const QVariant &, QmlMetaProperty::WriteFlags) const; + bool reset() const; bool hasChangedNotifier() const; bool needsChangedNotifier() const; @@ -108,6 +109,7 @@ public: bool isDefault() const; bool isWritable() const; bool isDesignable() const; + bool isResettable() const; bool isValid() const; QObject *object() const; diff --git a/src/declarative/qml/qmlobjectscriptclass.cpp b/src/declarative/qml/qmlobjectscriptclass.cpp index 86f0afc..5fd76c6 100644 --- a/src/declarative/qml/qmlobjectscriptclass.cpp +++ b/src/declarative/qml/qmlobjectscriptclass.cpp @@ -165,23 +165,25 @@ QmlObjectScriptClass::queryProperty(QObject *obj, const Identifier &name, if (lastData) return QScriptClass::HandlesReadAccess | QScriptClass::HandlesWriteAccess; - 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 (!(hints & SkipAttachedProperties)) { + 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 (evalContext) { + QmlContextPrivate *cp = QmlContextPrivate::get(evalContext); - if (cp->imports) { - QmlTypeNameCache::Data *data = cp->imports->data(name); - if (data) { - lastTNData = data; - return QScriptClass::HandlesReadAccess; + if (cp->imports) { + QmlTypeNameCache::Data *data = cp->imports->data(name); + if (data) { + lastTNData = data; + return QScriptClass::HandlesReadAccess; + } } } } @@ -252,9 +254,9 @@ QmlObjectScriptClass::property(QObject *obj, const Identifier &name) } if (lastData->flags & QmlPropertyCache::Data::IsQList) { - return Value(scriptEngine, enginePriv->listClass->newList(obj, lastData->coreIndex, QmlListScriptClass::QListPtr)); + return Value(scriptEngine, enginePriv->listClass->newList(obj, lastData->coreIndex, QmlListScriptClass::QListPtr, lastData->propType)); } else if (lastData->flags & QmlPropertyCache::Data::IsQmlList) { - return Value(scriptEngine, enginePriv->listClass->newList(obj, lastData->coreIndex, QmlListScriptClass::QmlListPtr)); + return Value(scriptEngine, enginePriv->listClass->newList(obj, lastData->coreIndex, QmlListScriptClass::QmlListPtr, lastData->propType)); } else if (lastData->flags & QmlPropertyCache::Data::IsQObjectDerived) { QObject *rv = 0; void *args[] = { &rv, 0 }; @@ -352,12 +354,18 @@ void QmlObjectScriptClass::setProperty(QObject *obj, evalContext = enginePriv->contextClass->contextFromValue(scopeNode); } - // ### Can well known types be optimized? - QVariant v = QmlScriptClass::toVariant(engine, value); QmlAbstractBinding *delBinding = QmlMetaPropertyPrivate::setBinding(obj, *lastData, 0); if (delBinding) delBinding->destroy(); - QmlMetaPropertyPrivate::write(obj, *lastData, v, evalContext); + + if (value.isUndefined() && lastData->flags & QmlPropertyCache::Data::IsResettable) { + void *a[] = { 0 }; + QMetaObject::metacall(obj, QMetaObject::ResetProperty, lastData->coreIndex, a); + } else { + // ### Can well known types be optimized? + QVariant v = QmlScriptClass::toVariant(engine, value); + QmlMetaPropertyPrivate::write(obj, *lastData, v, evalContext); + } } bool QmlObjectScriptClass::isQObject() const diff --git a/src/declarative/qml/qmlobjectscriptclass_p.h b/src/declarative/qml/qmlobjectscriptclass_p.h index 36ba44f..ebb2c2a 100644 --- a/src/declarative/qml/qmlobjectscriptclass_p.h +++ b/src/declarative/qml/qmlobjectscriptclass_p.h @@ -136,6 +136,7 @@ private: QmlEngine *engine; }; +Q_DECLARE_OPERATORS_FOR_FLAGS(QmlObjectScriptClass::QueryHints); QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlpropertycache.cpp b/src/declarative/qml/qmlpropertycache.cpp index 77a3a47..51753b8 100644 --- a/src/declarative/qml/qmlpropertycache.cpp +++ b/src/declarative/qml/qmlpropertycache.cpp @@ -61,6 +61,8 @@ void QmlPropertyCache::Data::load(const QMetaProperty &p, QmlEngine *engine) flags |= Data::IsConstant; if (p.isWritable()) flags |= Data::IsWritable; + if (p.isResettable()) + flags |= Data::IsResettable; if (propType == qMetaTypeId<QmlBinding *>()) { flags |= Data::IsQmlBinding; diff --git a/src/declarative/qml/qmlpropertycache_p.h b/src/declarative/qml/qmlpropertycache_p.h index 8c3b75e..8d54e35 100644 --- a/src/declarative/qml/qmlpropertycache_p.h +++ b/src/declarative/qml/qmlpropertycache_p.h @@ -80,19 +80,20 @@ public: // Can apply to all properties, except IsFunction IsConstant = 0x00000001, IsWritable = 0x00000002, + IsResettable = 0x00000004, // These are mutualy exclusive - IsFunction = 0x00000004, - IsQObjectDerived = 0x00000008, - IsEnumType = 0x00000010, - IsQmlList = 0x00000020, - IsQList = 0x00000040, - IsQmlBinding = 0x00000080, - IsQScriptValue = 0x00000100, + IsFunction = 0x00000008, + IsQObjectDerived = 0x00000010, + IsEnumType = 0x00000020, + IsQmlList = 0x00000040, + IsQList = 0x00000080, + IsQmlBinding = 0x00000100, + IsQScriptValue = 0x00000200, // Apply only to IsFunctions - IsVMEFunction = 0x00000200, - HasArguments = 0x00000400 + IsVMEFunction = 0x00000400, + HasArguments = 0x00000800 }; Q_DECLARE_FLAGS(Flags, Flag) diff --git a/src/declarative/qml/qmlstringconverters.cpp b/src/declarative/qml/qmlstringconverters.cpp index c68654f..2963ab5 100644 --- a/src/declarative/qml/qmlstringconverters.cpp +++ b/src/declarative/qml/qmlstringconverters.cpp @@ -47,6 +47,7 @@ #include <QtCore/qrect.h> #include <QtCore/qsize.h> #include <QtCore/qvariant.h> +#include <QtCore/qdatetime.h> QT_BEGIN_NAMESPACE @@ -94,14 +95,43 @@ QVariant QmlStringConverters::variantFromString(const QString &s) if (ok) return QVariant(p); QSizeF sz = sizeFFromString(s, &ok); if (ok) return QVariant(sz); - bool b = boolFromString(s, &ok); - if (ok) return QVariant(b); QVector3D v = vector3DFromString(s, &ok); if (ok) return qVariantFromValue(v); return QVariant(s); } +QVariant QmlStringConverters::variantFromString(const QString &s, int preferredType, bool *ok) +{ + switch (preferredType) { + case QMetaType::QColor: + return QVariant::fromValue(colorFromString(s, ok)); + case QMetaType::QDate: + return QVariant::fromValue(dateFromString(s, ok)); + case QMetaType::QTime: + return QVariant::fromValue(timeFromString(s, ok)); + case QMetaType::QDateTime: + return QVariant::fromValue(dateTimeFromString(s, ok)); + case QMetaType::QPointF: + return QVariant::fromValue(pointFFromString(s, ok)); + case QMetaType::QPoint: + return QVariant::fromValue(pointFFromString(s, ok).toPoint()); + case QMetaType::QSizeF: + return QVariant::fromValue(sizeFFromString(s, ok)); + case QMetaType::QSize: + return QVariant::fromValue(sizeFFromString(s, ok).toSize()); + case QMetaType::QRectF: + return QVariant::fromValue(rectFFromString(s, ok)); + case QMetaType::QRect: + return QVariant::fromValue(rectFFromString(s, ok).toRect()); + case QMetaType::QVector3D: + return QVariant::fromValue(vector3DFromString(s, ok)); + default: + if (ok) *ok = false; + return QVariant(); + } +} + QColor QmlStringConverters::colorFromString(const QString &s, bool *ok) { if (s.startsWith(QLatin1Char('#')) && s.length() == 9) { @@ -120,6 +150,27 @@ QColor QmlStringConverters::colorFromString(const QString &s, bool *ok) } } +QDate QmlStringConverters::dateFromString(const QString &s, bool *ok) +{ + QDate d = QDate::fromString(s, Qt::ISODate); + if (ok) *ok = d.isValid(); + return d; +} + +QTime QmlStringConverters::timeFromString(const QString &s, bool *ok) +{ + QTime t = QTime::fromString(s, Qt::ISODate); + if (ok) *ok = t.isValid(); + return t; +} + +QDateTime QmlStringConverters::dateTimeFromString(const QString &s, bool *ok) +{ + QDateTime d = QDateTime::fromString(s, Qt::ISODate); + if (ok) *ok = d.isValid(); + return d; +} + //expects input of "x,y" QPointF QmlStringConverters::pointFFromString(const QString &s, bool *ok) { @@ -196,23 +247,6 @@ QRectF QmlStringConverters::rectFFromString(const QString &s, bool *ok) return QRectF(x, y, width, height); } -bool QmlStringConverters::boolFromString(const QString &str, bool *ok) -{ - if (str.isEmpty() || str == QLatin1String("false") || str == QLatin1String("0")) { - if (ok) - *ok = true; - return false; - } else if (str == QLatin1String("true") || str == QLatin1String("1")) { - if (ok) - *ok = true; - return true; - } - - if (ok) - *ok = false; - return true; -} - //expects input of "x,y,z" QVector3D QmlStringConverters::vector3DFromString(const QString &s, bool *ok) { diff --git a/src/declarative/qml/qmlstringconverters_p.h b/src/declarative/qml/qmlstringconverters_p.h index 380a904..dfc59ce 100644 --- a/src/declarative/qml/qmlstringconverters_p.h +++ b/src/declarative/qml/qmlstringconverters_p.h @@ -70,11 +70,15 @@ QT_BEGIN_NAMESPACE namespace QmlStringConverters { QVariant Q_DECLARATIVE_EXPORT variantFromString(const QString &); + QVariant Q_DECLARATIVE_EXPORT variantFromString(const QString &, int preferredType, bool *ok = 0); + QColor Q_DECLARATIVE_EXPORT colorFromString(const QString &, bool *ok = 0); + QDate Q_DECLARATIVE_EXPORT dateFromString(const QString &, bool *ok = 0); + QTime Q_DECLARATIVE_EXPORT timeFromString(const QString &, bool *ok = 0); + QDateTime Q_DECLARATIVE_EXPORT dateTimeFromString(const QString &, bool *ok = 0); QPointF Q_DECLARATIVE_EXPORT pointFFromString(const QString &, bool *ok = 0); QSizeF Q_DECLARATIVE_EXPORT sizeFFromString(const QString &, bool *ok = 0); QRectF Q_DECLARATIVE_EXPORT rectFFromString(const QString &, bool *ok = 0); - bool Q_DECLARATIVE_EXPORT boolFromString(const QString &, bool *ok = 0); QVector3D Q_DECLARATIVE_EXPORT vector3DFromString(const QString &, bool *ok = 0); }; diff --git a/src/declarative/qml/qmlvme.cpp b/src/declarative/qml/qmlvme.cpp index 6b2e7af..e9a0449 100644 --- a/src/declarative/qml/qmlvme.cpp +++ b/src/declarative/qml/qmlvme.cpp @@ -57,7 +57,7 @@ #include "qmlvmemetaobject_p.h" #include "qmlbinding_p.h" #include "qmlcontext_p.h" -#include "qmlbindingoptimizations_p.h" +#include "qmlcompiledbindings_p.h" #include "qmlglobal_p.h" #include "qmlscriptstring.h" @@ -173,7 +173,7 @@ QObject *QmlVME::run(QmlVMEStack<QObject *> &stack, QmlContext *ctxt, if (instr.init.contextCache != -1) cp->setIdPropertyData(comp->contextCaches.at(instr.init.contextCache)); if (instr.init.compiledBinding != -1) - cp->optimizedBindings = new QmlOptimizedBindings(datas.at(instr.init.compiledBinding).constData(), ctxt); + cp->optimizedBindings = new QmlCompiledBindings(datas.at(instr.init.compiledBinding).constData(), ctxt); } break; diff --git a/src/declarative/util/qmlanimation.cpp b/src/declarative/util/qmlanimation.cpp index f5333a6..efb4159 100644 --- a/src/declarative/util/qmlanimation.cpp +++ b/src/declarative/util/qmlanimation.cpp @@ -1660,10 +1660,12 @@ void QmlPropertyAnimationPrivate::convertVariant(QVariant &variant, int type) \inherits Animation \brief The PropertyAnimation element allows you to animate property changes. - Animate a size property over 200ms, from its current size to 20-by-20: + Animate theObject's size property over 200ms, from its current size to 20-by-20: \code - PropertyAnimation { property: "size"; to: "20x20"; duration: 200 } + PropertyAnimation { target: theObject; property: "size"; to: "20x20"; duration: 200 } \endcode + + For an introduction to animation in QML, see \l{QML Animation}. */ QmlPropertyAnimation::QmlPropertyAnimation(QObject *parent) |