diff options
26 files changed, 469 insertions, 383 deletions
diff --git a/demos/declarative/flickr/flickr-desktop.qml b/demos/declarative/flickr/flickr-desktop.qml index 3a86347..99216cb 100644 --- a/demos/declarative/flickr/flickr-desktop.qml +++ b/demos/declarative/flickr/flickr-desktop.qml @@ -21,9 +21,9 @@ Item { angle: wrapper.PathView.angle ? wrapper.PathView.angle : 0 } - Connection { - sender: imageDetails; signal: "closed()" - script: { + Connections { + target: imageDetails + onClosed: { if (wrapper.state == 'Details') { wrapper.state = ''; imageDetails.photoUrl = ""; diff --git a/demos/declarative/flickr/flickr-mobile.qml b/demos/declarative/flickr/flickr-mobile.qml index 77ccd08..21e4c49 100644 --- a/demos/declarative/flickr/flickr-mobile.qml +++ b/demos/declarative/flickr/flickr-mobile.qml @@ -53,9 +53,9 @@ Item { onButton2Clicked: if (screen.inListView == true) screen.inListView = false; else screen.inListView = true } - Connection { - sender: imageDetails; signal: "closed()" - script: { + Connections { + target: imageDetails + onClosed: { if (background.state == "DetailedView") { background.state = ''; imageDetails.photoUrl = ""; diff --git a/demos/declarative/flickr/mobile/GridDelegate.qml b/demos/declarative/flickr/mobile/GridDelegate.qml index 5722f10..7634573 100644 --- a/demos/declarative/flickr/mobile/GridDelegate.qml +++ b/demos/declarative/flickr/mobile/GridDelegate.qml @@ -33,9 +33,9 @@ Image { source: "images/gloss.png" } } - Connection { - sender: toolBar; signal: "button2Clicked()" - script: if (scaleMe.state == 'Details' ) scaleMe.state = 'Show'; + Connections { + target: toolBar + onButton2Clicked: if (scaleMe.state == 'Details' ) scaleMe.state = 'Show' } states: [ diff --git a/doc/src/declarative/elements.qdoc b/doc/src/declarative/elements.qdoc index da96b8e..1fd4dad 100644 --- a/doc/src/declarative/elements.qdoc +++ b/doc/src/declarative/elements.qdoc @@ -98,7 +98,7 @@ The following table lists the QML elements provided by the Qt Declarative module \o \list \o \l Script -\o \l Connection +\o \l Connections \o \l Component \o \l Timer \o \l QtObject diff --git a/doc/src/declarative/extending.qdoc b/doc/src/declarative/extending.qdoc index d823bf6..5aaa7bd 100644 --- a/doc/src/declarative/extending.qdoc +++ b/doc/src/declarative/extending.qdoc @@ -421,9 +421,8 @@ C++ signature: \snippet examples/declarative/extending/signal/birthdayparty.h 0 In classes with multiple signals with the same name, only the final signal -is accessible as a signal property. Although QML provides an element, -\l Connection, for accessing the other signals it is less elegant. For the best -QML API, class developers should avoid overloading signal names. +is accessible as a signal property. Note that signals with the same name +but different parameters cannot be distinguished. Signal parameters become accessible by name to the assigned script. An unnamed parameter cannot be accessed, so care should be taken to name all the diff --git a/examples/declarative/connections/connections.qml b/examples/declarative/connections/connections.qml index c140017..4692343 100644 --- a/examples/declarative/connections/connections.qml +++ b/examples/declarative/connections/connections.qml @@ -22,6 +22,6 @@ Rectangle { anchors { right: parent.right; bottom: parent.bottom; rightMargin: 10; bottomMargin: 10 } } - Connection { sender: leftButton; signal: "clicked()"; script: window.angle -= 90 } - Connection { sender: rightButton; signal: "clicked()"; script: window.angle += 90 } + Connections { target: leftButton; onClicked: window.angle -= 90 } + Connections { target: rightButton; onClicked: window.angle += 90 } } diff --git a/src/declarative/QmlChanges.txt b/src/declarative/QmlChanges.txt index 25e0088..34e4834 100644 --- a/src/declarative/QmlChanges.txt +++ b/src/declarative/QmlChanges.txt @@ -7,6 +7,11 @@ Flickable: renamed viewportX -> contentX Flickable: renamed viewportY -> contentY Removed Flickable.reportedVelocitySmoothing Renamed MouseRegion -> MouseArea +Connection: syntax and rename: + Connection { sender: a; signal: foo(); script: xxx } + Connection { sender: a; signal: bar(); script: yyy } + becomes: + Connections { target: a; onFoo: xxx; onBar: yyy } QmlView ------- diff --git a/src/declarative/graphicsitems/qdeclarativeimage.cpp b/src/declarative/graphicsitems/qdeclarativeimage.cpp index 338b086..99ab053 100644 --- a/src/declarative/graphicsitems/qdeclarativeimage.cpp +++ b/src/declarative/graphicsitems/qdeclarativeimage.cpp @@ -127,7 +127,7 @@ QT_BEGIN_NAMESPACE QDeclarativeImage::QDeclarativeImage(QDeclarativeItem *parent) : QDeclarativeImageBase(*(new QDeclarativeImagePrivate), parent) { - connect(this, SIGNAL(sourceChanged(QUrl)), this, SLOT(updatePaintedGeometry())); + connect(this, SIGNAL(pixmapChanged()), this, SLOT(updatePaintedGeometry())); } QDeclarativeImage::QDeclarativeImage(QDeclarativeImagePrivate &dd, QDeclarativeItem *parent) @@ -139,12 +139,6 @@ QDeclarativeImage::~QDeclarativeImage() { } -void QDeclarativeImage::setSource(const QUrl &url) -{ - QDeclarativeImageBase::setSource(url); - updatePaintedGeometry(); -} - /*! \qmlproperty QPixmap Image::pixmap @@ -268,10 +262,10 @@ void QDeclarativeImage::updatePaintedGeometry() Q_D(QDeclarativeImage); if (d->fillMode == PreserveAspectFit) { - qreal widthScale = width() / qreal(d->pix.width()); - qreal heightScale = height() / qreal(d->pix.height()); if (!d->pix.width() || !d->pix.height()) return; + qreal widthScale = width() / qreal(d->pix.width()); + qreal heightScale = height() / qreal(d->pix.height()); if (widthScale <= heightScale) { d->paintedWidth = width(); d->paintedHeight = widthScale * qreal(d->pix.height()); diff --git a/src/declarative/graphicsitems/qdeclarativeimage_p.h b/src/declarative/graphicsitems/qdeclarativeimage_p.h index 5b365e7..fb77ac9 100644 --- a/src/declarative/graphicsitems/qdeclarativeimage_p.h +++ b/src/declarative/graphicsitems/qdeclarativeimage_p.h @@ -76,7 +76,6 @@ public: qreal paintedWidth() const; qreal paintedHeight() const; - void setSource(const QUrl &url); void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *); Q_SIGNALS: diff --git a/src/declarative/qml/qdeclarativelist.cpp b/src/declarative/qml/qdeclarativelist.cpp index af720d7..9691f32 100644 --- a/src/declarative/qml/qdeclarativelist.cpp +++ b/src/declarative/qml/qdeclarativelist.cpp @@ -85,18 +85,57 @@ void QDeclarativeListReferencePrivate::release() delete this; } +/*! +\class QDeclarativeListReference +\brief The QDeclarativeListReference class allows the manipulation of QDeclarativeListProperty properties. + +QDeclarativeListReference allows programs to read from, and assign values to a QML list property in a +simple and type safe way. A QDeclarativeListReference can be created by passing an object and property +name or through a QDeclarativeProperty instance. These two are equivalant: + +\code +QDeclarativeListReference ref1(object, "children"); + +QDeclarativeProperty ref2(object, "children"); +QDeclarativeListReference ref2 = qvariant_cast<QDeclarativeListReference>(ref2.read()); +\endcode + +Not all QML list properties support all operations. A set of methods, canAppend(), canAt(), canClear() and +canCount() allow programs to query whether an operation is supported on a given property. + +QML list properties are typesafe. Only QObject's that derive from the correct base class can be assigned to +the list. The listElementType() method can be used to query the QMetaObject of the QObject type supported. +Attempting to add objects of the incorrect type to a list property will fail. + +Like with normal lists, when accessing a list element by index, it is the callers responsibility to ensure +that it does not request an out of range element using the count() method before calling at(). +*/ + +/*! +Constructs an invalid instance. +*/ QDeclarativeListReference::QDeclarativeListReference() : d(0) { } -QDeclarativeListReference::QDeclarativeListReference(QObject *o, const char *property, QDeclarativeEngine *engine) +/*! +Constructs a QDeclarativeListReference for \a object's \a property. If \a property is not a list +property, an invalid QDeclarativeListReference is created. If \a object is destroyed after +the reference is constructed, it will automatically become invalid. That is, it is safe to hold +QDeclarativeListReference instances even after \a object is deleted. + +Passing \a engine is required to access some QML created list properties. If in doubt, and an engine +is available, pass it. +*/ +QDeclarativeListReference::QDeclarativeListReference(QObject *object, const char *property, QDeclarativeEngine *engine) : d(0) { - if (!o || !property) return; + if (!object || !property) return; QDeclarativePropertyCache::Data local; - QDeclarativePropertyCache::Data *data = QDeclarativePropertyCache::property(engine, o, QLatin1String(property), local); + QDeclarativePropertyCache::Data *data = + QDeclarativePropertyCache::property(engine, object, QLatin1String(property), local); if (!data || !(data->flags & QDeclarativePropertyCache::Data::IsQList)) return; @@ -106,20 +145,22 @@ QDeclarativeListReference::QDeclarativeListReference(QObject *o, const char *pro if (listType == -1) return; d = new QDeclarativeListReferencePrivate; - d->object = o; + d->object = object; d->elementType = p?p->rawMetaObjectForType(listType):QDeclarativeMetaType::qmlType(listType)->baseMetaObject(); d->propertyType = data->propType; void *args[] = { &d->property, 0 }; - QMetaObject::metacall(o, QMetaObject::ReadProperty, data->coreIndex, args); + QMetaObject::metacall(object, QMetaObject::ReadProperty, data->coreIndex, args); } +/*! \internal */ QDeclarativeListReference::QDeclarativeListReference(const QDeclarativeListReference &o) : d(o.d) { if (d) d->addref(); } +/*! \internal */ QDeclarativeListReference &QDeclarativeListReference::operator=(const QDeclarativeListReference &o) { if (o.d) o.d->addref(); @@ -128,60 +169,108 @@ QDeclarativeListReference &QDeclarativeListReference::operator=(const QDeclarati return *this; } +/*! \internal */ QDeclarativeListReference::~QDeclarativeListReference() { if (d) d->release(); } +/*! +Returns true if the instance refers to a valid list property, otherwise false. +*/ bool QDeclarativeListReference::isValid() const { return d && d->object; } +/*! +Returns the list property's object. Returns 0 if the reference is invalid. +*/ QObject *QDeclarativeListReference::object() const { if (isValid()) return d->object; else return 0; } +/*! +Returns the QMetaObject for the elements stored in the list property. Returns 0 if the reference +is invalid. + +The QMetaObject can be used ahead of time to determine whether a given instance can be added +to a list. +*/ const QMetaObject *QDeclarativeListReference::listElementType() const { if (isValid()) return d->elementType; else return 0; } +/*! +Returns true if the list property can be appended to, otherwise false. Returns false if the +reference is invalid. + +\sa append() +*/ bool QDeclarativeListReference::canAppend() const { return (isValid() && d->property.append); } +/*! +Returns true if the list property can queried by index, otherwise false. Returns false if the +reference is invalid. + +\sa at() +*/ bool QDeclarativeListReference::canAt() const { return (isValid() && d->property.at); } +/*! +Returns true if the list property can be cleared, otherwise false. Returns false if the +reference is invalid. + +\sa clear() +*/ bool QDeclarativeListReference::canClear() const { return (isValid() && d->property.clear); } +/*! +Returns true if the list property can be queried for its element count, otherwise false. +Returns false if the reference is invalid. + +\sa count() +*/ bool QDeclarativeListReference::canCount() const { return (isValid() && d->property.count); } -bool QDeclarativeListReference::append(QObject *o) const +/*! +Appends \a object to the list. Returns true if the operation succeeded, otherwise false. + +\sa canAppend() +*/ +bool QDeclarativeListReference::append(QObject *object) const { if (!canAppend()) return false; - if (o && !QDeclarativePropertyPrivate::canConvert(o->metaObject(), d->elementType)) + if (object && !QDeclarativePropertyPrivate::canConvert(object->metaObject(), d->elementType)) return false; - d->property.append(&d->property, o); + d->property.append(&d->property, object); return true; } +/*! +Returns the list element at \a index, or 0 if the operation failed. + +\sa canAt() +*/ QObject *QDeclarativeListReference::at(int index) const { if (!canAt()) return 0; @@ -189,6 +278,11 @@ QObject *QDeclarativeListReference::at(int index) const return d->property.at(&d->property, index); } +/*! +Clears the list. Returns true if the operation succeeded, otherwise false. + +\sa canClear() +*/ bool QDeclarativeListReference::clear() const { if (!canClear()) return false; @@ -198,6 +292,9 @@ bool QDeclarativeListReference::clear() const return true; } +/*! +Returns the number of objects in the list, or 0 if the operation failed. +*/ int QDeclarativeListReference::count() const { if (!canCount()) return 0; diff --git a/src/declarative/qml/qdeclarativeproperty.cpp b/src/declarative/qml/qdeclarativeproperty.cpp index 9ed760e..e1ec2cd 100644 --- a/src/declarative/qml/qdeclarativeproperty.cpp +++ b/src/declarative/qml/qdeclarativeproperty.cpp @@ -311,10 +311,10 @@ QDeclarativeProperty::QDeclarativeProperty(const QDeclarativeProperty &other) This enum specifies a category of QML property. - \value InvalidCategory The property is invalid. - \value List The property is a QList pointer + \value InvalidCategory The property is invalid, or is a signal property. + \value List The property is a QDeclarativeListProperty list property \value Object The property is a QObject derived type pointer - \value Normal The property is none of the above. + \value Normal The property is a normal value property. */ /*! @@ -752,18 +752,39 @@ QVariant QDeclarativeProperty::read() const return QVariant(); } +/*! +Return the \a name property value of \a object. This method is equivalent to: +\code + QDeclarativeProperty p(object, name); + p.read(); +\endcode +*/ QVariant QDeclarativeProperty::read(QObject *object, const QString &name) { QDeclarativeProperty p(object, name); return p.read(); } +/*! +Return the \a name property value of \a object. This method is equivalent to: +\code + QDeclarativeProperty p(object, name, context); + p.read(); +\endcode +*/ QVariant QDeclarativeProperty::read(QObject *object, const QString &name, QDeclarativeContext *ctxt) { QDeclarativeProperty p(object, name, ctxt); return p.read(); } +/*! +Return the \a name property value of \a object. This method is equivalent to: +\code + QDeclarativeProperty p(object, name, engine); + p.read(); +\endcode +*/ QVariant QDeclarativeProperty::read(QObject *object, const QString &name, QDeclarativeEngine *engine) { QDeclarativeProperty p(object, name, engine); @@ -802,9 +823,7 @@ QVariant QDeclarativePropertyPrivate::readValueProperty() } } -//### //writeEnumProperty MIRRORS the relelvant bit of QMetaProperty::write AND MUST BE KEPT IN SYNC! -//### bool QDeclarativePropertyPrivate::writeEnumProperty(const QMetaProperty &prop, int idx, QObject *object, const QVariant &value, int flags) { if (!object || !prop.isWritable()) @@ -1054,12 +1073,26 @@ bool QDeclarativeProperty::write(const QVariant &value) const return QDeclarativePropertyPrivate::write(*this, value, 0); } +/*! +Writes \a value to the \a name property of \a object. This method is equivalent to: +\code + QDeclarativeProperty p(object, name); + p.write(value); +\endcode +*/ bool QDeclarativeProperty::write(QObject *object, const QString &name, const QVariant &value) { QDeclarativeProperty p(object, name); return p.write(value); } +/*! +Writes \a value to the \a name property of \a object. This method is equivalent to: +\code + QDeclarativeProperty p(object, name, ctxt); + p.write(value); +\endcode +*/ bool QDeclarativeProperty::write(QObject *object, const QString &name, const QVariant &value, QDeclarativeContext *ctxt) { @@ -1067,6 +1100,13 @@ bool QDeclarativeProperty::write(QObject *object, const QString &name, const QVa return p.write(value); } +/*! +Writes \a value to the \a name property of \a object. This method is equivalent to: +\code + QDeclarativeProperty p(object, name, engine); + p.write(value); +\endcode +*/ bool QDeclarativeProperty::write(QObject *object, const QString &name, const QVariant &value, QDeclarativeEngine *engine) { diff --git a/src/declarative/util/qdeclarativeanimation.cpp b/src/declarative/util/qdeclarativeanimation.cpp index 328f0e4..181ef0a 100644 --- a/src/declarative/util/qdeclarativeanimation.cpp +++ b/src/declarative/util/qdeclarativeanimation.cpp @@ -1572,8 +1572,7 @@ QDeclarativeSequentialAnimation::QDeclarativeSequentialAnimation(QObject *parent QDeclarativeAnimationGroup(parent) { Q_D(QDeclarativeAnimationGroup); - d->ag = new QSequentialAnimationGroup; - QDeclarativeGraphics_setParent_noEvent(d->ag, this); + d->ag = new QSequentialAnimationGroup(this); } QDeclarativeSequentialAnimation::~QDeclarativeSequentialAnimation() @@ -1638,8 +1637,7 @@ QDeclarativeParallelAnimation::QDeclarativeParallelAnimation(QObject *parent) : QDeclarativeAnimationGroup(parent) { Q_D(QDeclarativeAnimationGroup); - d->ag = new QParallelAnimationGroup; - QDeclarativeGraphics_setParent_noEvent(d->ag, this); + d->ag = new QParallelAnimationGroup(this); } QDeclarativeParallelAnimation::~QDeclarativeParallelAnimation() @@ -1798,7 +1796,7 @@ QDeclarativePropertyAnimation::~QDeclarativePropertyAnimation() void QDeclarativePropertyAnimationPrivate::init() { Q_Q(QDeclarativePropertyAnimation); - va = new QDeclarativeBulkValueAnimator; + va = new QDeclarativeTimeLineValueAnimator; QDeclarativeGraphics_setParent_noEvent(va, q); } @@ -2214,7 +2212,7 @@ QAbstractAnimation *QDeclarativePropertyAnimation::qtAnimation() return d->va; } -struct PropertyUpdater : public QDeclarativeBulkValueUpdater +struct PropertyUpdater : public QDeclarativeTimeLineValue { QDeclarativeStateActions actions; int interpolatorType; //for Number/ColorAnimation @@ -2232,6 +2230,7 @@ struct PropertyUpdater : public QDeclarativeBulkValueUpdater wasDeleted = &deleted; if (reverse) //QVariantAnimation sends us 1->0 when reversed, but we are expecting 0->1 v = 1 - v; + QDeclarativeTimeLineValue::setValue(v); for (int ii = 0; ii < actions.count(); ++ii) { QDeclarativeAction &action = actions[ii]; diff --git a/src/declarative/util/qdeclarativeanimation_p_p.h b/src/declarative/util/qdeclarativeanimation_p_p.h index ae82a90..e582066 100644 --- a/src/declarative/util/qdeclarativeanimation_p_p.h +++ b/src/declarative/util/qdeclarativeanimation_p_p.h @@ -149,21 +149,14 @@ private: bool running; }; -class QDeclarativeBulkValueUpdater -{ -public: - virtual ~QDeclarativeBulkValueUpdater() {} - virtual void setValue(qreal value) = 0; -}; - -//animates QDeclarativeBulkValueUpdater (assumes start and end values will be reals or compatible) -class QDeclarativeBulkValueAnimator : public QVariantAnimation +//animates QDeclarativeTimeLineValue (assumes start and end values will be reals or compatible) +class QDeclarativeTimeLineValueAnimator : public QVariantAnimation { Q_OBJECT public: - QDeclarativeBulkValueAnimator(QObject *parent = 0) : QVariantAnimation(parent), animValue(0), fromSourced(0), policy(KeepWhenStopped) {} - ~QDeclarativeBulkValueAnimator() { if (policy == DeleteWhenStopped) { delete animValue; animValue = 0; } } - void setAnimValue(QDeclarativeBulkValueUpdater *value, DeletionPolicy p) + QDeclarativeTimeLineValueAnimator(QObject *parent = 0) : QVariantAnimation(parent), animValue(0), fromSourced(0), policy(KeepWhenStopped) {} + ~QDeclarativeTimeLineValueAnimator() { if (policy == DeleteWhenStopped) { delete animValue; animValue = 0; } } + void setAnimValue(QDeclarativeTimeLineValue *value, DeletionPolicy p) { if (state() == Running) stop(); @@ -200,7 +193,7 @@ protected: } private: - QDeclarativeBulkValueUpdater *animValue; + QDeclarativeTimeLineValue *animValue; bool *fromSourced; DeletionPolicy policy; }; @@ -359,7 +352,7 @@ public: int interpolatorType; QVariantAnimation::Interpolator interpolator; - QDeclarativeBulkValueAnimator *va; + QDeclarativeTimeLineValueAnimator *va; static QVariant interpolateVariant(const QVariant &from, const QVariant &to, qreal progress); static void convertVariant(QVariant &variant, int type); diff --git a/src/declarative/util/qdeclarativeconnection.cpp b/src/declarative/util/qdeclarativeconnection.cpp deleted file mode 100644 index e9ae74b..0000000 --- a/src/declarative/util/qdeclarativeconnection.cpp +++ /dev/null @@ -1,287 +0,0 @@ -/**************************************************************************** -** -** 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 "qdeclarativeconnection_p.h" - -#include <qdeclarativeexpression.h> -#include <qdeclarativeboundsignal_p.h> -#include <qdeclarativecontext.h> - -#include <QtCore/qdebug.h> -#include <QtCore/qstringlist.h> - -#include <private/qobject_p.h> - -QT_BEGIN_NAMESPACE - -class QDeclarativeConnectionPrivate : public QObjectPrivate -{ -public: - QDeclarativeConnectionPrivate() : boundsignal(0), signalSender(0), scriptset(false), componentcomplete(false) {} - - QDeclarativeBoundSignal *boundsignal; - QObject *signalSender; - QDeclarativeScriptString script; - bool scriptset; - QString signal; - bool componentcomplete; -}; - -/*! - \qmlclass Connection QDeclarativeConnection - \since 4.7 - \brief A Connection object describes generalized connections to signals. - - When connecting to signals in QML, the usual way is to create an - "on<Signal>" handler that reacts when a signal is received, like this: - - \qml - MouseArea { - onClicked: { foo(x+123,y+456) } - } - \endqml - - However, in some cases, it is not possible to connect to a signal in this - way. For example, JavaScript-in-HTML style signal properties do not allow: - - \list - \i connecting to signals with the same name but different parameters - \i conformance checking that parameters are correctly named - \i multiple connections to the same signal - \i connections outside the scope of the signal sender - \i signals in classes with coincidentally-named on<Signal> properties - \endlist - - When any of these are needed, the Connection object can be used instead. - - For example, the above code can be changed to use a Connection object, - like this: - - \qml - MouseArea { - Connection { - signal: "clicked(x,y)" - script: { foo(x+123,y+456) } - } - } - \endqml - - More generally, the Connection object can be a child of some other object than - the sender of the signal: - - \qml - MouseArea { - id: mr - } - ... - Connection { - sender: mr - signal: "clicked(x,y)" - script: { foo(x+123,y+456) } - } - \endqml -*/ - -/*! - \internal - \class QDeclarativeConnection - \brief The QDeclarativeConnection class describes generalized connections to signals. - -*/ -QDeclarativeConnection::QDeclarativeConnection(QObject *parent) : - QObject(*(new QDeclarativeConnectionPrivate), parent) -{ -} - -QDeclarativeConnection::~QDeclarativeConnection() -{ - Q_D(QDeclarativeConnection); - delete d->boundsignal; -} - -/*! - \qmlproperty Object Connection::sender - This property holds the object that sends the signal. - - By default, the sender is assumed to be the parent of the Connection. -*/ -QObject *QDeclarativeConnection::signalSender() const -{ - Q_D(const QDeclarativeConnection); - return d->signalSender ? d->signalSender : parent(); -} - -void QDeclarativeConnection::setSignalSender(QObject *obj) -{ - Q_D(QDeclarativeConnection); - if (d->signalSender == obj) - return; - disconnectIfValid(); - d->signalSender = obj; - connectIfValid(); -} - -void QDeclarativeConnection::connectIfValid() -{ - Q_D(QDeclarativeConnection); - if (!d->componentcomplete) - return; - // boundsignal must not exist - if ((d->signalSender || parent()) && !d->signal.isEmpty() && d->scriptset) { - // create - // XXX scope? - int sigIdx = -1; - int lparen = d->signal.indexOf(QLatin1Char('(')); - QList<QByteArray> sigparams; - if (lparen >= 0 && d->signal.length() > lparen+2) { - QStringList l = d->signal.mid(lparen+1,d->signal.length()-lparen-2).split(QLatin1Char(',')); - foreach (const QString &s, l) { - sigparams.append(s.trimmed().toUtf8()); - } - } - QString signalname = d->signal.left(lparen); - QObject *sender = d->signalSender ? d->signalSender : parent(); - const QMetaObject *mo = sender->metaObject(); - int methods = mo->methodCount(); - for (int ii = 0; ii < methods; ++ii) { - QMetaMethod method = mo->method(ii); - QString methodName = QString::fromUtf8(method.signature()); - int idx = methodName.indexOf(QLatin1Char('(')); - methodName = methodName.left(idx); - if (methodName == signalname && (lparen<0 || method.parameterNames() == sigparams)) { - sigIdx = ii; - break; - } - } - if (sigIdx < 0) { - // Cannot usefully warn, since could be in middle of - // changing sender and signal. - // XXX need state change transactions to do better - return; - } - - d->boundsignal = new QDeclarativeBoundSignal(qmlContext(this), d->script.script(), sender, mo->method(sigIdx), this); - } -} - -void QDeclarativeConnection::disconnectIfValid() -{ - Q_D(QDeclarativeConnection); - if (!d->componentcomplete) - return; - if ((d->signalSender || parent()) && !d->signal.isEmpty() && d->scriptset) { - // boundsignal must exist - // destroy - delete d->boundsignal; - d->boundsignal = 0; - } -} - -void QDeclarativeConnection::componentComplete() -{ - Q_D(QDeclarativeConnection); - d->componentcomplete=true; - connectIfValid(); -} - - -/*! - \qmlproperty script Connection::script - This property holds the JavaScript executed whenever the signal is sent. -*/ -QDeclarativeScriptString QDeclarativeConnection::script() const -{ - Q_D(const QDeclarativeConnection); - return d->script; -} - -void QDeclarativeConnection::setScript(const QDeclarativeScriptString& script) -{ - Q_D(QDeclarativeConnection); - if ((d->signalSender || parent()) && !d->signal.isEmpty()) { - if (!d->scriptset) { - // mustn't exist - create - d->scriptset = true; - d->script = script; - connectIfValid(); - } else { - // must exist - update - d->script = script; - d->boundsignal->expression()->setExpression(script.script()); - } - } else { - d->scriptset = true; - d->script = script; - } -} - -/*! - \qmlproperty string Connection::signal - This property holds the signal from the sender to which the script is attached. - - The signal's formal parameter names must be given in parentheses: - - \qml -Connection { - signal: "clicked(x,y)" - script: { ... } -} - \endqml -*/ -QString QDeclarativeConnection::signal() const -{ - Q_D(const QDeclarativeConnection); - return d->signal; -} - -void QDeclarativeConnection::setSignal(const QString& sig) -{ - Q_D(QDeclarativeConnection); - if (d->signal == sig) - return; - disconnectIfValid(); - d->signal = sig; - connectIfValid(); -} - - - -QT_END_NAMESPACE diff --git a/src/declarative/util/qdeclarativeconnections.cpp b/src/declarative/util/qdeclarativeconnections.cpp new file mode 100644 index 0000000..0b9e3ab --- /dev/null +++ b/src/declarative/util/qdeclarativeconnections.cpp @@ -0,0 +1,245 @@ +/**************************************************************************** +** +** 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 "qdeclarativeconnections_p.h" + +#include <qdeclarativeexpression.h> +#include <qdeclarativeproperty_p.h> +#include <qdeclarativeboundsignal_p.h> +#include <qdeclarativecontext.h> +#include <qdeclarativeinfo.h> + +#include <QtCore/qdebug.h> +#include <QtCore/qstringlist.h> + +#include <private/qobject_p.h> + +QT_BEGIN_NAMESPACE + +class QDeclarativeConnectionsPrivate : public QObjectPrivate +{ +public: + QDeclarativeConnectionsPrivate() : target(0), componentcomplete(false) {} + + QList<QDeclarativeBoundSignal*> boundsignals; + QObject *target; + + bool componentcomplete; + + QByteArray data; +}; + +/*! + \qmlclass Connections QDeclarativeConnections + \since 4.7 + \brief A Connections object describes generalized connections to signals. + + When connecting to signals in QML, the usual way is to create an + "on<Signal>" handler that reacts when a signal is received, like this: + + \qml + MouseArea { + onClicked: { foo(...) } + } + \endqml + + However, in some cases, it is not possible to connect to a signal in this + way, such as: + + \list + \i multiple connections to the same signal + \i connections outside the scope of the signal sender + \i connections to targets not defined in QML + \endlist + + When any of these are needed, the Connections object can be used instead. + + For example, the above code can be changed to use a Connections object, + like this: + + \qml + MouseArea { + Connections { + onClicked: foo(...) + } + } + \endqml + + More generally, the Connections object can be a child of some other object than + the sender of the signal: + + \qml + MouseArea { + id: area + } + ... + Connections { + target: area + onClicked: foo(...) + } + \endqml +*/ + +/*! + \internal + \class QDeclarativeConnections + \brief The QDeclarativeConnections class describes generalized connections to signals. + +*/ +QDeclarativeConnections::QDeclarativeConnections(QObject *parent) : + QObject(*(new QDeclarativeConnectionsPrivate), parent) +{ +} + +QDeclarativeConnections::~QDeclarativeConnections() +{ +} + +/*! + \qmlproperty Object Connections::target + This property holds the object that sends the signal. + + By default, the target is assumed to be the parent of the Connections. +*/ +QObject *QDeclarativeConnections::target() const +{ + Q_D(const QDeclarativeConnections); + return d->target ? d->target : parent(); +} + +void QDeclarativeConnections::setTarget(QObject *obj) +{ + Q_D(QDeclarativeConnections); + if (d->target == obj) + return; + foreach (QDeclarativeBoundSignal *s, d->boundsignals) + delete s; + d->boundsignals.clear(); + d->target = obj; + connectSignals(); + emit targetChanged(); +} + + +QByteArray +QDeclarativeConnectionsParser::compile(const QList<QDeclarativeCustomParserProperty> &props) +{ + QByteArray rv; + QDataStream ds(&rv, QIODevice::WriteOnly); + + for(int ii = 0; ii < props.count(); ++ii) + { + QString propName = QString::fromUtf8(props.at(ii).name()); + if (!propName.startsWith(QLatin1String("on")) || !propName.at(2).isUpper()) { + error(props.at(ii), QDeclarativeConnections::tr("Cannot assign to non-existent property \"%1\"").arg(propName)); + return QByteArray(); + } + + QList<QVariant> values = props.at(ii).assignedValues(); + + for (int i = 0; i < values.count(); ++i) { + const QVariant &value = values.at(i); + + if (value.userType() == qMetaTypeId<QDeclarativeCustomParserNode>()) { + error(props.at(ii), QDeclarativeConnections::tr("Connections: nested objects not allowed")); + return QByteArray(); + } else if (value.userType() == qMetaTypeId<QDeclarativeCustomParserProperty>()) { + error(props.at(ii), QDeclarativeConnections::tr("Connections: syntax error")); + return QByteArray(); + } else { + QDeclarativeParser::Variant v = qvariant_cast<QDeclarativeParser::Variant>(value); + if (v.isScript()) { + ds << propName; + ds << v.asScript(); + } else { + error(props.at(ii), QDeclarativeConnections::tr("Connections: script expected")); + return QByteArray(); + } + } + } + } + + return rv; +} + +void QDeclarativeConnectionsParser::setCustomData(QObject *object, + const QByteArray &data) +{ + QDeclarativeConnectionsPrivate *p = + static_cast<QDeclarativeConnectionsPrivate *>(QObjectPrivate::get(object)); + p->data = data; +} + + +void QDeclarativeConnections::connectSignals() +{ + Q_D(QDeclarativeConnections); + if (!d->componentcomplete) + return; + + QDataStream ds(d->data); + while (!ds.atEnd()) { + QString propName; + ds >> propName; + QString script; + ds >> script; + QDeclarativeProperty prop(target(), propName); + if (!prop.isValid()) { + qmlInfo(this) << tr("Cannot assign to non-existent property \"%1\"").arg(propName); + } else if (prop.type() & QDeclarativeProperty::SignalProperty) { + QDeclarativeBoundSignal *signal = + new QDeclarativeBoundSignal(target(), prop.method(), this); + signal->setExpression(new QDeclarativeExpression(qmlContext(this), script, 0)); + d->boundsignals += signal; + } else { + qmlInfo(this) << tr("Cannot assign to non-existent property \"%1\"").arg(propName); + } + } +} + +void QDeclarativeConnections::componentComplete() +{ + Q_D(QDeclarativeConnections); + d->componentcomplete=true; + connectSignals(); +} + +QT_END_NAMESPACE diff --git a/src/declarative/util/qdeclarativeconnection_p.h b/src/declarative/util/qdeclarativeconnections_p.h index ae2efe9..3eacf12 100644 --- a/src/declarative/util/qdeclarativeconnection_p.h +++ b/src/declarative/util/qdeclarativeconnections_p.h @@ -39,11 +39,12 @@ ** ****************************************************************************/ -#ifndef QDECLARATIVECONNECTION_H -#define QDECLARATIVECONNECTION_H +#ifndef QDECLARATIVECONNECTIONS_H +#define QDECLARATIVECONNECTIONS_H #include <qdeclarative.h> #include <qdeclarativescriptstring.h> +#include <private/qdeclarativecustomparser_p.h> #include <QtCore/qobject.h> #include <QtCore/qstring.h> @@ -56,37 +57,41 @@ QT_MODULE(Declarative) class QDeclarativeBoundSignal; class QDeclarativeContext; -class QDeclarativeConnectionPrivate; -class Q_DECLARATIVE_EXPORT QDeclarativeConnection : public QObject, public QDeclarativeParserStatus +class QDeclarativeConnectionsPrivate; +class Q_DECLARATIVE_EXPORT QDeclarativeConnections : public QObject, public QDeclarativeParserStatus { Q_OBJECT - Q_DECLARE_PRIVATE(QDeclarativeConnection) + Q_DECLARE_PRIVATE(QDeclarativeConnections) Q_INTERFACES(QDeclarativeParserStatus) - Q_PROPERTY(QObject *sender READ signalSender WRITE setSignalSender) - Q_PROPERTY(QDeclarativeScriptString script READ script WRITE setScript) - Q_PROPERTY(QString signal READ signal WRITE setSignal) + Q_PROPERTY(QObject *target READ target WRITE setTarget NOTIFY targetChanged) public: - QDeclarativeConnection(QObject *parent=0); - ~QDeclarativeConnection(); + QDeclarativeConnections(QObject *parent=0); + ~QDeclarativeConnections(); - QObject *signalSender() const; - void setSignalSender(QObject *); - QDeclarativeScriptString script() const; - void setScript(const QDeclarativeScriptString&); - QString signal() const; - void setSignal(const QString&); + QObject *target() const; + void setTarget(QObject *); + +Q_SIGNALS: + void targetChanged(); private: - void disconnectIfValid(); - void connectIfValid(); + void connectSignals(); void componentComplete(); }; +class QDeclarativeConnectionsParser : public QDeclarativeCustomParser +{ +public: + virtual QByteArray compile(const QList<QDeclarativeCustomParserProperty> &); + virtual void setCustomData(QObject *, const QByteArray &); +}; + + QT_END_NAMESPACE -QML_DECLARE_TYPE(QDeclarativeConnection) +QML_DECLARE_TYPE(QDeclarativeConnections) QT_END_HEADER diff --git a/src/declarative/util/qdeclarativeutilmodule.cpp b/src/declarative/util/qdeclarativeutilmodule.cpp index 8d3d682..2b8c7de 100644 --- a/src/declarative/util/qdeclarativeutilmodule.cpp +++ b/src/declarative/util/qdeclarativeutilmodule.cpp @@ -45,7 +45,7 @@ #include "qdeclarativeanimation_p_p.h" #include "qdeclarativebehavior_p.h" #include "qdeclarativebind_p.h" -#include "qdeclarativeconnection_p.h" +#include "qdeclarativeconnections_p.h" #include "qdeclarativedatetimeformatter_p.h" #include "qdeclarativeeasefollow_p.h" #include "qdeclarativefontloader_p.h" @@ -80,7 +80,7 @@ void QDeclarativeUtilModule::defineModule() QML_REGISTER_TYPE(Qt,4,6,Behavior,QDeclarativeBehavior); QML_REGISTER_TYPE(Qt,4,6,Binding,QDeclarativeBind); QML_REGISTER_TYPE(Qt,4,6,ColorAnimation,QDeclarativeColorAnimation); - QML_REGISTER_TYPE(Qt,4,6,Connection,QDeclarativeConnection); + QML_REGISTER_TYPE(Qt,4,6,Connections,QDeclarativeConnections); QML_REGISTER_TYPE(Qt,4,6,DateTimeFormatter,QDeclarativeDateTimeFormatter); QML_REGISTER_TYPE(Qt,4,6,EaseFollow,QDeclarativeEaseFollow);; QML_REGISTER_TYPE(Qt,4,6,FontLoader,QDeclarativeFontLoader); @@ -118,4 +118,5 @@ void QDeclarativeUtilModule::defineModule() QML_REGISTER_CUSTOM_TYPE(Qt, 4,6, ListModel, QDeclarativeListModel, QDeclarativeListModelParser); QML_REGISTER_CUSTOM_TYPE(Qt, 4,6, PropertyChanges, QDeclarativePropertyChanges, QDeclarativePropertyChangesParser); + QML_REGISTER_CUSTOM_TYPE(Qt, 4,6, Connections, QDeclarativeConnections, QDeclarativeConnectionsParser); } diff --git a/src/declarative/util/util.pri b/src/declarative/util/util.pri index 610eb3f..198e9e5 100644 --- a/src/declarative/util/util.pri +++ b/src/declarative/util/util.pri @@ -5,7 +5,7 @@ SOURCES += \ $$PWD/qdeclarativeview.cpp \ $$PWD/qfxperf.cpp \ $$PWD/qperformancelog.cpp \ - $$PWD/qdeclarativeconnection.cpp \ + $$PWD/qdeclarativeconnections.cpp \ $$PWD/qdeclarativepackage.cpp \ $$PWD/qdeclarativeanimation.cpp \ $$PWD/qdeclarativesystempalette.cpp \ @@ -37,7 +37,7 @@ HEADERS += \ $$PWD/qdeclarativeview.h \ $$PWD/qfxperf_p_p.h \ $$PWD/qperformancelog_p_p.h \ - $$PWD/qdeclarativeconnection_p.h \ + $$PWD/qdeclarativeconnections_p.h \ $$PWD/qdeclarativepackage_p.h \ $$PWD/qdeclarativeanimation_p.h \ $$PWD/qdeclarativeanimation_p_p.h \ diff --git a/tests/auto/declarative/declarative.pro b/tests/auto/declarative/declarative.pro index 42ff523..4387875 100644 --- a/tests/auto/declarative/declarative.pro +++ b/tests/auto/declarative/declarative.pro @@ -7,7 +7,7 @@ SUBDIRS += \ qdeclarativeanimations \ # Cover qdeclarativebehaviors \ # Cover qdeclarativebinding \ # Cover - qdeclarativeconnection \ # Cover + qdeclarativeconnections \ # Cover qdeclarativecontext \ # Cover qdeclarativedatetimeformatter \ # Cover qdeclarativedebug \ # Cover diff --git a/tests/auto/declarative/qdeclarativeconnection/data/test-connection2.qml b/tests/auto/declarative/qdeclarativeconnection/data/test-connection2.qml deleted file mode 100644 index 65fe23a..0000000 --- a/tests/auto/declarative/qdeclarativeconnection/data/test-connection2.qml +++ /dev/null @@ -1,3 +0,0 @@ -import Qt 4.6 - -Connection { id: connection; sender: connection; signal: "widthChanged()"; script: 1 == 1 } diff --git a/tests/auto/declarative/qdeclarativeconnection/data/test-connection.qml b/tests/auto/declarative/qdeclarativeconnections/data/test-connection.qml index 9534621..81ab599 100644 --- a/tests/auto/declarative/qdeclarativeconnection/data/test-connection.qml +++ b/tests/auto/declarative/qdeclarativeconnections/data/test-connection.qml @@ -6,5 +6,5 @@ Item { property bool tested: false signal testMe - Connection { sender: screen; signal: "widthChanged()"; script: screen.tested = true } + Connections { target: screen; onWidthChanged: screen.tested = true } } diff --git a/tests/auto/declarative/qdeclarativeconnections/data/test-connection2.qml b/tests/auto/declarative/qdeclarativeconnections/data/test-connection2.qml new file mode 100644 index 0000000..22e9422 --- /dev/null +++ b/tests/auto/declarative/qdeclarativeconnections/data/test-connection2.qml @@ -0,0 +1,3 @@ +import Qt 4.6 + +Connections { id: connection; target: connection; onTargetChanged: 1 == 1 } diff --git a/tests/auto/declarative/qdeclarativeconnection/data/test-connection3.qml b/tests/auto/declarative/qdeclarativeconnections/data/test-connection3.qml index 32133f9..6e396c0 100644 --- a/tests/auto/declarative/qdeclarativeconnection/data/test-connection3.qml +++ b/tests/auto/declarative/qdeclarativeconnections/data/test-connection3.qml @@ -1,3 +1,3 @@ import Qt 4.6 -Connection {} +Connections {} diff --git a/tests/auto/declarative/qdeclarativeconnection/data/trimming.qml b/tests/auto/declarative/qdeclarativeconnections/data/trimming.qml index c27dc46..736d5e8 100644 --- a/tests/auto/declarative/qdeclarativeconnection/data/trimming.qml +++ b/tests/auto/declarative/qdeclarativeconnections/data/trimming.qml @@ -6,5 +6,5 @@ Item { property string tested signal testMe(int param1, string param2) - Connection { sender: screen; signal: "testMe(param1, param2)"; script: screen.tested = param2 + param1 } + Connections { target: screen; onTestMe: screen.tested = param2 + param1 } } diff --git a/tests/auto/declarative/qdeclarativeconnection/qdeclarativeconnection.pro b/tests/auto/declarative/qdeclarativeconnections/qdeclarativeconnection.pro index a6adfa4..a6adfa4 100644 --- a/tests/auto/declarative/qdeclarativeconnection/qdeclarativeconnection.pro +++ b/tests/auto/declarative/qdeclarativeconnections/qdeclarativeconnection.pro diff --git a/tests/auto/declarative/qdeclarativeconnection/tst_qdeclarativeconnection.cpp b/tests/auto/declarative/qdeclarativeconnections/tst_qdeclarativeconnection.cpp index adf343f..f10217c 100644 --- a/tests/auto/declarative/qdeclarativeconnection/tst_qdeclarativeconnection.cpp +++ b/tests/auto/declarative/qdeclarativeconnections/tst_qdeclarativeconnection.cpp @@ -71,12 +71,10 @@ void tst_qdeclarativeconnection::defaultValues() { QDeclarativeEngine engine; QDeclarativeComponent c(&engine, QUrl::fromLocalFile(SRCDIR "/data/test-connection3.qml")); - QDeclarativeConnection *item = qobject_cast<QDeclarativeConnection*>(c.create()); + QDeclarativeConnections *item = qobject_cast<QDeclarativeConnections*>(c.create()); QVERIFY(item != 0); - QVERIFY(item->signalSender() == 0); - QCOMPARE(item->script().script(), QString()); - QCOMPARE(item->signal(), QString()); + QVERIFY(item->target() == 0); delete item; } @@ -85,14 +83,12 @@ void tst_qdeclarativeconnection::properties() { QDeclarativeEngine engine; QDeclarativeComponent c(&engine, QUrl::fromLocalFile(SRCDIR "/data/test-connection2.qml")); - QDeclarativeConnection *item = qobject_cast<QDeclarativeConnection*>(c.create()); + QDeclarativeConnections *item = qobject_cast<QDeclarativeConnections*>(c.create()); QVERIFY(item != 0); QVERIFY(item != 0); - QVERIFY(item->signalSender() == item); - QCOMPARE(item->script().script(), QString("1 == 1")); - QCOMPARE(item->signal(), QString("widthChanged()")); + QVERIFY(item->target() == item); delete item; } |