From 46dfe1e6dad1f3a74cb15bfd538e9fe28ffac5b3 Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Wed, 10 Mar 2010 15:56:38 +1000 Subject: Unify binding optimizer and QtScript binding signal management logic --- .../qml/qdeclarativecompiledbindings.cpp | 97 +------- src/declarative/qml/qdeclarativecontext.cpp | 7 +- src/declarative/qml/qdeclarativecontext_p.h | 5 +- src/declarative/qml/qdeclarativeexpression.cpp | 153 ++++-------- src/declarative/qml/qdeclarativeexpression_p.h | 19 +- src/declarative/qml/qdeclarativenotifier.cpp | 109 +++++++++ src/declarative/qml/qdeclarativenotifier_p.h | 272 +++++++++++++++++++++ src/declarative/qml/qdeclarativepropertycache.cpp | 4 + src/declarative/qml/qdeclarativepropertycache_p.h | 19 +- src/declarative/qml/qml.pri | 2 + .../tst_qdeclarativeanchors.cpp | 1 - 11 files changed, 458 insertions(+), 230 deletions(-) create mode 100644 src/declarative/qml/qdeclarativenotifier.cpp create mode 100644 src/declarative/qml/qdeclarativenotifier_p.h diff --git a/src/declarative/qml/qdeclarativecompiledbindings.cpp b/src/declarative/qml/qdeclarativecompiledbindings.cpp index 17937fd..b35b5b5 100644 --- a/src/declarative/qml/qdeclarativecompiledbindings.cpp +++ b/src/declarative/qml/qdeclarativecompiledbindings.cpp @@ -124,24 +124,7 @@ public: QDeclarativeCompiledBindingsPrivate *parent; }; - struct Subscription { - struct Signal { - QDeclarativeGuard 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 QDeclarativeContextPrivate::IdNotifier *id(); - union { - char signalData[sizeof(Signal)]; - char idData[sizeof(QDeclarativeContextPrivate::IdNotifier)]; - }; - }; + typedef QDeclarativeNotifierEndpoint Subscription; Subscription *subscriptions; QScriptDeclarativeClass::PersistentIdentifier *identifiers; @@ -190,18 +173,6 @@ QDeclarativeCompiledBindingsPrivate::~QDeclarativeCompiledBindingsPrivate() delete [] identifiers; identifiers = 0; } -QDeclarativeCompiledBindingsPrivate::Subscription::Subscription() -: type(InvalidType) -{ -} - -QDeclarativeCompiledBindingsPrivate::Subscription::~Subscription() -{ - if (type == SignalType) ((Signal *)signalData)->~Signal(); - else if (type == IdType) ((QDeclarativeContextPrivate::IdNotifier *)idData)->~IdNotifier(); -} - - int QDeclarativeCompiledBindingsPrivate::methodCount = -1; QDeclarativeCompiledBindings::QDeclarativeCompiledBindings(const char *program, QDeclarativeContext *context) @@ -330,22 +301,6 @@ void QDeclarativeCompiledBindingsPrivate::run(Binding *binding) } } -QDeclarativeCompiledBindingsPrivate::Subscription::Signal *QDeclarativeCompiledBindingsPrivate::Subscription::signal() -{ - if (type == IdType) ((QDeclarativeContextPrivate::IdNotifier *)idData)->~IdNotifier(); - if (type != SignalType) new (signalData) Signal; - type = SignalType; - return (Signal *)signalData; -} - -QDeclarativeContextPrivate::IdNotifier *QDeclarativeCompiledBindingsPrivate::Subscription::id() -{ - if (type == SignalType) ((Signal *)signalData)->~Signal(); - if (type != IdType) new (idData) QDeclarativeContextPrivate::IdNotifier; - type = IdType; - return (QDeclarativeContextPrivate::IdNotifier *)idData; -} - namespace { // This structure is exactly 8-bytes in size struct Instr { @@ -656,20 +611,7 @@ void QDeclarativeCompiledBindingsPrivate::unsubscribe(int subIndex) Q_Q(QDeclarativeCompiledBindings); QDeclarativeCompiledBindingsPrivate::Subscription *sub = (subscriptions + subIndex); - if (sub->isSignal()) { - QDeclarativeCompiledBindingsPrivate::Subscription::Signal *s = sub->signal(); - if (s->source) -#if (QT_VERSION >= QT_VERSION_CHECK(4, 6, 2)) - QMetaObject::disconnectOne(s->source, s->notifyIndex, - q, methodCount + subIndex); -#else - // QTBUG-6781 - QMetaObject::disconnect(s->source, s->notifyIndex, - q, methodCount + subIndex); -#endif - } else if (sub->isId()) { - sub->id()->clear(); - } + sub->disconnect(); } void QDeclarativeCompiledBindingsPrivate::subscribeId(QDeclarativeContextPrivate *p, int idIndex, int subIndex) @@ -680,15 +622,8 @@ void QDeclarativeCompiledBindingsPrivate::subscribeId(QDeclarativeContextPrivate if (p->idValues[idIndex]) { QDeclarativeCompiledBindingsPrivate::Subscription *sub = (subscriptions + subIndex); - QDeclarativeContextPrivate::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 = q; - i->methodIndex = methodCount + subIndex; + sub->target = q; + sub->targetMethod = methodCount + subIndex; } } @@ -697,27 +632,9 @@ void QDeclarativeCompiledBindingsPrivate::subscribe(QObject *o, int notifyIndex, Q_Q(QDeclarativeCompiledBindings); QDeclarativeCompiledBindingsPrivate::Subscription *sub = (subscriptions + subIndex); - - if (sub->isId()) - unsubscribe(subIndex); - - QDeclarativeCompiledBindingsPrivate::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, - q, methodCount + subIndex); -#else - // QTBUG-6781 - QMetaObject::disconnect(s->source, s->notifyIndex, - q, methodCount + subIndex); -#endif - s->source = o; - s->notifyIndex = notifyIndex; - if (s->source && s->notifyIndex != -1) - QMetaObject::connect(s->source, s->notifyIndex, q, - methodCount + subIndex, Qt::DirectConnection); - } + sub->target = q; + sub->targetMethod = methodCount + subIndex; + sub->connect(o, notifyIndex); } // Conversion functions - these MUST match the QtScript expression path diff --git a/src/declarative/qml/qdeclarativecontext.cpp b/src/declarative/qml/qdeclarativecontext.cpp index f70e143..356a4ab 100644 --- a/src/declarative/qml/qdeclarativecontext.cpp +++ b/src/declarative/qml/qdeclarativecontext.cpp @@ -109,12 +109,7 @@ void QDeclarativeContextPrivate::destroyed(ContextGuard *guard) if (parent && QObjectPrivate::get(parent)->wasDeleted) return; - while(guard->bindings) { - QObject *o = guard->bindings->target; - int mi = guard->bindings->methodIndex; - guard->bindings->clear(); - if (o) o->qt_metacall(QMetaObject::InvokeMetaMethod, mi, 0); - } + guard->bindings.notify(); for (int ii = 0; ii < idValueCount; ++ii) { if (&idValues[ii] == guard) { diff --git a/src/declarative/qml/qdeclarativecontext_p.h b/src/declarative/qml/qdeclarativecontext_p.h index 8297280..5b597fa 100644 --- a/src/declarative/qml/qdeclarativecontext_p.h +++ b/src/declarative/qml/qdeclarativecontext_p.h @@ -59,6 +59,7 @@ #include "qdeclarativeengine_p.h" #include "qdeclarativeintegercache_p.h" #include "qdeclarativetypenamecache_p.h" +#include "qdeclarativenotifier_p.h" #include #include @@ -133,7 +134,7 @@ public: inline virtual void objectDestroyed(QObject *); QDeclarativeContextPrivate *priv; - IdNotifier *bindings; + QDeclarativeNotifier bindings; }; ContextGuard *idValues; int idValueCount; @@ -176,7 +177,7 @@ void QDeclarativeContextPrivate::IdNotifier::clear() } QDeclarativeContextPrivate::ContextGuard::ContextGuard() -: priv(0), bindings(0) +: priv(0) { } diff --git a/src/declarative/qml/qdeclarativeexpression.cpp b/src/declarative/qml/qdeclarativeexpression.cpp index e528e9e..207ded6 100644 --- a/src/declarative/qml/qdeclarativeexpression.cpp +++ b/src/declarative/qml/qdeclarativeexpression.cpp @@ -621,137 +621,74 @@ void QDeclarativeExpression::__q_notify() void QDeclarativeExpressionPrivate::clearGuards() { - Q_Q(QDeclarativeExpression); - - static int notifyIdx = -1; - if (notifyIdx == -1) - notifyIdx = - QDeclarativeExpression::staticMetaObject.indexOfMethod("__q_notify()"); - - for (int ii = 0; ii < data->guardListLength; ++ii) { - if (data->guardList[ii].data()) { -#if (QT_VERSION >= QT_VERSION_CHECK(4, 6, 2)) - QMetaObject::disconnectOne(data->guardList[ii].data(), - data->guardList[ii].notifyIndex, - q, notifyIdx); -#else - // QTBUG-6781 - QMetaObject::disconnect(data->guardList[ii].data(), - data->guardList[ii].notifyIndex, - q, notifyIdx); -#endif - } - } - - delete [] data->guardList; data->guardList = 0; + delete [] data->guardList; + data->guardList = 0; data->guardListLength = 0; } void QDeclarativeExpressionPrivate::updateGuards(const QPODVector &properties) { - //clearGuards(); Q_Q(QDeclarativeExpression); static int notifyIdx = -1; if (notifyIdx == -1) - notifyIdx = - QDeclarativeExpression::staticMetaObject.indexOfMethod("__q_notify()"); + notifyIdx = QDeclarativeExpression::staticMetaObject.indexOfMethod("__q_notify()"); - QDeclarativeExpressionData::SignalGuard *newGuardList = 0; - - if (properties.count() != data->guardListLength) - newGuardList = new QDeclarativeExpressionData::SignalGuard[properties.count()]; + if (properties.count() != data->guardListLength) { + QDeclarativeNotifierEndpoint *newGuardList = + new QDeclarativeNotifierEndpoint[properties.count()]; + + for (int ii = 0; ii < qMin(data->guardListLength, properties.count()); ++ii) + data->guardList[ii].copyAndClear(newGuardList[ii]); + + delete [] data->guardList; + data->guardList = newGuardList; + data->guardListLength = properties.count(); + } bool outputWarningHeader = false; - int hit = 0; + bool noChanges = true; for (int ii = 0; ii < properties.count(); ++ii) { + QDeclarativeNotifierEndpoint &guard = data->guardList[ii]; const QDeclarativeEnginePrivate::CapturedProperty &property = properties.at(ii); - bool needGuard = true; - if (ii >= data->guardListLength) { - // New guard - } else if(data->guardList[ii].data() == property.object && - data->guardList[ii].notifyIndex == property.notifyIndex) { - // Cache hit - if (!data->guardList[ii].isDuplicate || - (data->guardList[ii].isDuplicate && hit == ii)) { - needGuard = false; - ++hit; - } - } else if(data->guardList[ii].data() && !data->guardList[ii].isDuplicate) { - // Cache miss -#if (QT_VERSION >= QT_VERSION_CHECK(4, 6, 2)) - QMetaObject::disconnectOne(data->guardList[ii].data(), - data->guardList[ii].notifyIndex, - q, notifyIdx); -#else - // QTBUG-6781 - QMetaObject::disconnect(data->guardList[ii].data(), - data->guardList[ii].notifyIndex, - q, notifyIdx); -#endif - } - /* else { - // Cache miss, but nothing to do - } */ - - if (needGuard) { - if (!newGuardList) { - newGuardList = new QDeclarativeExpressionData::SignalGuard[properties.count()]; - for (int jj = 0; jj < ii; ++jj) - newGuardList[jj] = data->guardList[jj]; - } + guard.target = q; + guard.targetMethod = notifyIdx; + + if (property.notifyIndex != -1) { + + if (!noChanges && guard.isConnected(property.object, property.notifyIndex)) { + // Nothing to do + + } else { + noChanges = false; - if (property.notifyIndex != -1) { bool existing = false; for (int jj = 0; !existing && jj < ii; ++jj) - existing = newGuardList[jj].data() == property.object && - newGuardList[jj].notifyIndex == property.notifyIndex; - - newGuardList[ii] = property.object; - newGuardList[ii].notifyIndex = property.notifyIndex; - if (existing) - newGuardList[ii].isDuplicate = true; - else - QMetaObject::connect(property.object, property.notifyIndex, - q, notifyIdx); - } else { - if (!outputWarningHeader) { - outputWarningHeader = true; - qWarning() << "QDeclarativeExpression: Expression" << q->expression() - << "depends on non-NOTIFYable properties:"; + if (data->guardList[jj].isConnected(property.object, property.notifyIndex)) + existing = true; + + if (existing) { + // duplicate + guard.disconnect(); + } else { + guard.connect(property.object, property.notifyIndex); } + } - const QMetaObject *metaObj = property.object->metaObject(); - QMetaProperty metaProp = metaObj->property(property.coreIndex); - - qWarning().nospace() << " " << metaObj->className() - << "::" << metaProp.name(); + } else { + if (!outputWarningHeader) { + outputWarningHeader = true; + qWarning() << "QDeclarativeExpression: Expression" << q->expression() + << "depends on non-NOTIFYable properties:"; } - } else if (newGuardList) { - newGuardList[ii] = data->guardList[ii]; - } - } - for (int ii = properties.count(); ii < data->guardListLength; ++ii) { - if (data->guardList[ii].data() && !data->guardList[ii].isDuplicate) { -#if (QT_VERSION >= QT_VERSION_CHECK(4, 6, 2)) - QMetaObject::disconnectOne(data->guardList[ii].data(), - data->guardList[ii].notifyIndex, - q, notifyIdx); -#else - // QTBUG-6781 - QMetaObject::disconnect(data->guardList[ii].data(), - data->guardList[ii].notifyIndex, - q, notifyIdx); -#endif - } - } + const QMetaObject *metaObj = property.object->metaObject(); + QMetaProperty metaProp = metaObj->property(property.coreIndex); - if (newGuardList) { - if (data->guardList) delete [] data->guardList; - data->guardList = newGuardList; - data->guardListLength = properties.count(); + qWarning().nospace() << " " << metaObj->className() + << "::" << metaProp.name(); + } } } diff --git a/src/declarative/qml/qdeclarativeexpression_p.h b/src/declarative/qml/qdeclarativeexpression_p.h index cd1729d..d170559 100644 --- a/src/declarative/qml/qdeclarativeexpression_p.h +++ b/src/declarative/qml/qdeclarativeexpression_p.h @@ -129,24 +129,7 @@ public: QString url; // This is a QString for a reason. QUrls are slooooooow... int line; - struct SignalGuard : public QDeclarativeGuard { - SignalGuard() : isDuplicate(false), notifyIndex(-1) {} - - SignalGuard &operator=(QObject *obj) { - QDeclarativeGuard::operator=(obj); - return *this; - } - SignalGuard &operator=(const SignalGuard &o) { - QDeclarativeGuard::operator=(o); - isDuplicate = o.isDuplicate; - notifyIndex = o.notifyIndex; - return *this; - } - - bool isDuplicate:1; - int notifyIndex:31; - }; - SignalGuard *guardList; + QDeclarativeNotifierEndpoint *guardList; int guardListLength; }; diff --git a/src/declarative/qml/qdeclarativenotifier.cpp b/src/declarative/qml/qdeclarativenotifier.cpp new file mode 100644 index 0000000..0a8783a --- /dev/null +++ b/src/declarative/qml/qdeclarativenotifier.cpp @@ -0,0 +1,109 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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 "qdeclarativenotifier_p.h" + +QT_BEGIN_NAMESPACE + +void QDeclarativeNotifier::emitNotify(QDeclarativeNotifierEndpoint *endpoint) +{ + QDeclarativeNotifierEndpoint::Notifier *n = endpoint->asNotifier(); + + QDeclarativeNotifierEndpoint::Notifier **oldDisconnected = n->disconnected; + n->disconnected = &n; + + if (n->next) + emitNotify(n->next); + + if (n) { + void *args[] = { 0 }; + + QMetaObject::metacall(endpoint->target, QMetaObject::InvokeMetaMethod, + endpoint->targetMethod, args); + + n->disconnected = oldDisconnected; + } + + if (oldDisconnected) *oldDisconnected = n; +} + +void QDeclarativeNotifierEndpoint::copyAndClear(QDeclarativeNotifierEndpoint &other) +{ + other.disconnect(); + + other.target = target; + other.targetMethod = targetMethod; + + if (!isConnected()) + return; + + if (SignalType == type) { + Signal *other_s = other.toSignal(); + Signal *s = asSignal(); + + other_s->source = s->source; + other_s->sourceSignal = s->sourceSignal; + s->source = 0; + } else if(NotifierType == type) { + Notifier *other_n = other.toNotifier(); + Notifier *n = asNotifier(); + + other_n->notifier = n->notifier; + other_n->disconnected = n->disconnected; + if (other_n->disconnected) *other_n->disconnected = other_n; + + if (n->next) { + other_n->next = n->next; + n->next->asNotifier()->prev = &other_n->next; + } + other_n->prev = n->prev; + *other_n->prev = &other; + + n->prev = 0; + n->next = 0; + n->disconnected = 0; + n->notifier = 0; + } +} + + +QT_END_NAMESPACE + diff --git a/src/declarative/qml/qdeclarativenotifier_p.h b/src/declarative/qml/qdeclarativenotifier_p.h new file mode 100644 index 0000000..a0e6b43 --- /dev/null +++ b/src/declarative/qml/qdeclarativenotifier_p.h @@ -0,0 +1,272 @@ +/**************************************************************************** +** +** Copyright (C) 2010 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 QDECLARATIVENOTIFIER_P_H +#define QDECLARATIVENOTIFIER_P_H + +#include "qdeclarativeguard_p.h" + +QT_BEGIN_NAMESPACE + +class QDeclarativeNotifierEndpoint; +class QDeclarativeNotifier +{ +public: + inline QDeclarativeNotifier(); + inline ~QDeclarativeNotifier(); + inline void notify(); + +private: + friend class QDeclarativeNotifierEndpoint; + + static void emitNotify(QDeclarativeNotifierEndpoint *); + QDeclarativeNotifierEndpoint *endpoints; +}; + +class QDeclarativeNotifierEndpoint +{ +public: + inline QDeclarativeNotifierEndpoint(); + inline QDeclarativeNotifierEndpoint(QObject *t, int m); + inline ~QDeclarativeNotifierEndpoint(); + + QObject *target; + int targetMethod; + + inline bool isConnected(); + inline bool isConnected(QObject *source, int sourceSignal); + inline bool isConnected(QDeclarativeNotifier *); + + inline void connect(QObject *source, int sourceSignal); + inline void connect(QDeclarativeNotifier *); + inline void disconnect(); + + void copyAndClear(QDeclarativeNotifierEndpoint &other); + +private: + friend class QDeclarativeNotifier; + + struct Signal { + QDeclarativeGuard source; + int sourceSignal; + }; + + struct Notifier { + QDeclarativeNotifier *notifier; + Notifier **disconnected; + + QDeclarativeNotifierEndpoint *next; + QDeclarativeNotifierEndpoint **prev; + }; + + enum { InvalidType, SignalType, NotifierType } type; + union { + char signalData[sizeof(Signal)]; + char notifierData[sizeof(Notifier)]; + }; + + inline Notifier *toNotifier(); + inline Notifier *asNotifier(); + inline Signal *toSignal(); + inline Signal *asSignal(); +}; + +QDeclarativeNotifier::QDeclarativeNotifier() +: endpoints(0) +{ + QDeclarativeNotifierEndpoint *endpoint = endpoints; + while (endpoint) { + QDeclarativeNotifierEndpoint *next = endpoint->asNotifier()->next; + endpoint->asNotifier()->next = 0; + endpoint->asNotifier()->prev = 0; + endpoint->asNotifier()->notifier = 0; + endpoint = next; + } +} + +QDeclarativeNotifier::~QDeclarativeNotifier() +{ +} + +void QDeclarativeNotifier::notify() +{ + if (endpoints) emitNotify(endpoints); +} + +QDeclarativeNotifierEndpoint::QDeclarativeNotifierEndpoint() +: target(0), targetMethod(0), type(InvalidType) +{ +} + +QDeclarativeNotifierEndpoint::QDeclarativeNotifierEndpoint(QObject *t, int m) +: target(t), targetMethod(m), type(InvalidType) +{ +} + +QDeclarativeNotifierEndpoint::~QDeclarativeNotifierEndpoint() +{ + disconnect(); + if (SignalType == type) { + Signal *s = asSignal(); + s->~Signal(); + } +} + +bool QDeclarativeNotifierEndpoint::isConnected() +{ + if (SignalType == type) { + return asSignal()->source; + } else if (NotifierType == type) { + return asNotifier()->notifier; + } else { + return false; + } +} + +bool QDeclarativeNotifierEndpoint::isConnected(QObject *source, int sourceSignal) +{ + return SignalType == type && asSignal()->source == source && asSignal()->sourceSignal == sourceSignal; +} + +bool QDeclarativeNotifierEndpoint::isConnected(QDeclarativeNotifier *notifier) +{ + return NotifierType == type && asNotifier()->notifier == notifier; +} + +void QDeclarativeNotifierEndpoint::connect(QObject *source, int sourceSignal) +{ + Signal *s = toSignal(); + + if (s->source == source && s->sourceSignal == sourceSignal) + return; + + disconnect(); + + QMetaObject::connect(source, sourceSignal, target, targetMethod); + + s->source = source; + s->sourceSignal = sourceSignal; +} + +void QDeclarativeNotifierEndpoint::connect(QDeclarativeNotifier *notifier) +{ + Notifier *n = toNotifier(); + + if (n->notifier == notifier) + return; + + disconnect(); + + n->next = notifier->endpoints; + if (n->next) { n->next->asNotifier()->prev = &n->next; } + notifier->endpoints = this; + n->prev = ¬ifier->endpoints; + n->notifier = notifier; +} + +void QDeclarativeNotifierEndpoint::disconnect() +{ + if (type == SignalType) { + Signal *s = (Signal *)&signalData; + if (s->source) { + QMetaObject::disconnectOne(s->source, s->sourceSignal, target, targetMethod); + s->source = 0; + } + } else if (type == NotifierType) { + Notifier *n = asNotifier(); + + if (n->next) n->next->asNotifier()->prev = n->prev; + if (n->prev) *n->prev = n->next; + if (n->disconnected) *n->disconnected = 0; + n->next = 0; + n->prev = 0; + n->disconnected = 0; + n->notifier = 0; + } +} + +QDeclarativeNotifierEndpoint::Notifier *QDeclarativeNotifierEndpoint::toNotifier() +{ + if (NotifierType == type) + return asNotifier(); + + if (SignalType == type) { + disconnect(); + Signal *s = asSignal(); + s->~Signal(); + } + + Notifier *n = asNotifier(); + n->next = 0; + n->prev = 0; + n->disconnected = 0; + n->notifier = 0; + type = NotifierType; + return n; +} + +QDeclarativeNotifierEndpoint::Notifier *QDeclarativeNotifierEndpoint::asNotifier() +{ + return (Notifier *)(¬ifierData); +} + +QDeclarativeNotifierEndpoint::Signal *QDeclarativeNotifierEndpoint::toSignal() +{ + if (SignalType == type) + return asSignal(); + + disconnect(); + Signal *s = asSignal(); + new (s) Signal; + type = SignalType; + + return s; +} + +QDeclarativeNotifierEndpoint::Signal *QDeclarativeNotifierEndpoint::asSignal() +{ + return (Signal *)(&signalData); +} + +QT_END_NAMESPACE + +#endif // QDECLARATIVENOTIFIER_P_H + diff --git a/src/declarative/qml/qdeclarativepropertycache.cpp b/src/declarative/qml/qdeclarativepropertycache.cpp index fea59e5..cbb67e1 100644 --- a/src/declarative/qml/qdeclarativepropertycache.cpp +++ b/src/declarative/qml/qdeclarativepropertycache.cpp @@ -420,4 +420,8 @@ QDeclarativePropertyCache::Data *QDeclarativePropertyCache::property(QDeclarativ return rv; } +QDeclarativePropertyCache::Data QDeclarativePropertyCache::property(const QMetaObject *, const char *) +{ +} + QT_END_NAMESPACE diff --git a/src/declarative/qml/qdeclarativepropertycache_p.h b/src/declarative/qml/qdeclarativepropertycache_p.h index 68e6e6b..ea2f01a 100644 --- a/src/declarative/qml/qdeclarativepropertycache_p.h +++ b/src/declarative/qml/qdeclarativepropertycache_p.h @@ -55,15 +55,16 @@ #include "qdeclarativerefcount_p.h" #include "qdeclarativecleanup_p.h" +#include "qdeclarativenotifier_p.h" #include #include - QT_BEGIN_NAMESPACE class QDeclarativeEngine; class QMetaProperty; + class QDeclarativePropertyCache : public QDeclarativeRefCount, public QDeclarativeCleanup { public: @@ -81,11 +82,12 @@ public: IsConstant = 0x00000001, IsWritable = 0x00000002, IsResettable = 0x00000004, + HasNotify = 0x00000008, // These are mutualy exclusive - IsFunction = 0x00000008, - IsQObjectDerived = 0x00000010, - IsEnumType = 0x00000020, + IsFunction = 0x00000010, + IsQObjectDerived = 0x00000020, + IsEnumType = 0x00000040, IsQList = 0x00000080, IsQmlBinding = 0x00000100, IsQScriptValue = 0x00000200, @@ -97,11 +99,17 @@ public: }; Q_DECLARE_FLAGS(Flags, Flag) + enum Call { ReadProperty, WriteProperty, ConnectNotify, DisconnectNotify }; + typedef void (*MetaCall)(QObject *, Call, void *); + bool isValid() const { return coreIndex != -1; } Flags flags; int propType; - int coreIndex; + union { + MetaCall call; + int coreIndex; + }; int notifyIndex; static Flags flagsForProperty(const QMetaProperty &, QDeclarativeEngine *engine = 0); @@ -136,6 +144,7 @@ public: inline QDeclarativeEngine *qmlEngine() const; static Data *property(QDeclarativeEngine *, QObject *, const QScriptDeclarativeClass::Identifier &, Data &); static Data *property(QDeclarativeEngine *, QObject *, const QString &, Data &); + static Data property(const QMetaObject *, const char *); protected: virtual void clear(); diff --git a/src/declarative/qml/qml.pri b/src/declarative/qml/qml.pri index aa1a34b..49888c3 100644 --- a/src/declarative/qml/qml.pri +++ b/src/declarative/qml/qml.pri @@ -38,6 +38,7 @@ SOURCES += \ $$PWD/qdeclarativescript.cpp \ $$PWD/qdeclarativecleanup.cpp \ $$PWD/qdeclarativepropertycache.cpp \ + $$PWD/qdeclarativenotifier.cpp \ $$PWD/qdeclarativeintegercache.cpp \ $$PWD/qdeclarativetypenamecache.cpp \ $$PWD/qdeclarativescriptstring.cpp \ @@ -108,6 +109,7 @@ HEADERS += \ $$PWD/qdeclarativewatcher_p.h \ $$PWD/qdeclarativecleanup_p.h \ $$PWD/qdeclarativepropertycache_p.h \ + $$PWD/qdeclarativenotifier_p.h \ $$PWD/qdeclarativeintegercache_p.h \ $$PWD/qdeclarativetypenamecache_p.h \ $$PWD/qdeclarativescriptstring.h \ diff --git a/tests/auto/declarative/qdeclarativeanchors/tst_qdeclarativeanchors.cpp b/tests/auto/declarative/qdeclarativeanchors/tst_qdeclarativeanchors.cpp index 9d8ba6c..6b7d57f 100644 --- a/tests/auto/declarative/qdeclarativeanchors/tst_qdeclarativeanchors.cpp +++ b/tests/auto/declarative/qdeclarativeanchors/tst_qdeclarativeanchors.cpp @@ -373,7 +373,6 @@ void tst_qdeclarativeanchors::crash1() QString expect = "QML Text (" + source.toString() + ":4:5" + ") Possible anchor loop detected on fill."; QTest::ignoreMessage(QtWarningMsg, expect.toLatin1()); - QTest::ignoreMessage(QtWarningMsg, expect.toLatin1()); // XXX ideally, should be one message QDeclarativeView *view = new QDeclarativeView(source); qApp->processEvents(); -- cgit v0.12