diff options
author | Warwick Allison <warwick.allison@nokia.com> | 2010-02-26 07:04:38 (GMT) |
---|---|---|
committer | Warwick Allison <warwick.allison@nokia.com> | 2010-02-26 07:04:38 (GMT) |
commit | e1f33f2e4689a59de2814ffdea7ea246bbfe0283 (patch) | |
tree | e3a0d74f5e54f78b83d0c05d6e1588c5f1d47e37 /src/declarative/util | |
parent | 93b02976b7c9c3a36cac475c1935622ebc2f1fe1 (diff) | |
download | Qt-e1f33f2e4689a59de2814ffdea7ea246bbfe0283.zip Qt-e1f33f2e4689a59de2814ffdea7ea246bbfe0283.tar.gz Qt-e1f33f2e4689a59de2814ffdea7ea246bbfe0283.tar.bz2 |
Change Connection syntax as per QT-2822.
Diffstat (limited to 'src/declarative/util')
-rw-r--r-- | src/declarative/util/qdeclarativeconnection.cpp | 250 | ||||
-rw-r--r-- | src/declarative/util/qdeclarativeconnection_p.h | 43 | ||||
-rw-r--r-- | src/declarative/util/qdeclarativeutilmodule.cpp | 3 |
3 files changed, 130 insertions, 166 deletions
diff --git a/src/declarative/util/qdeclarativeconnection.cpp b/src/declarative/util/qdeclarativeconnection.cpp index e9ae74b..a180509 100644 --- a/src/declarative/util/qdeclarativeconnection.cpp +++ b/src/declarative/util/qdeclarativeconnection.cpp @@ -42,8 +42,10 @@ #include "qdeclarativeconnection_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> @@ -52,236 +54,192 @@ QT_BEGIN_NAMESPACE -class QDeclarativeConnectionPrivate : public QObjectPrivate +class QDeclarativeConnectionsPrivate : public QObjectPrivate { public: - QDeclarativeConnectionPrivate() : boundsignal(0), signalSender(0), scriptset(false), componentcomplete(false) {} + QDeclarativeConnectionsPrivate() : target(0), componentcomplete(false) {} + + QList<QDeclarativeBoundSignal*> boundsignals; + QObject *target; - QDeclarativeBoundSignal *boundsignal; - QObject *signalSender; - QDeclarativeScriptString script; - bool scriptset; - QString signal; bool componentcomplete; + + QByteArray data; }; /*! - \qmlclass Connection QDeclarativeConnection + \qmlclass Connections QDeclarativeConnections \since 4.7 - \brief A Connection object describes generalized connections to signals. + \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(x+123,y+456) } + onClicked: { foo(...) } } \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: + way, such as: \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 + \i connections to targets not defined in QML \endlist - When any of these are needed, the Connection object can be used instead. + When any of these are needed, the Connections object can be used instead. - For example, the above code can be changed to use a Connection object, + For example, the above code can be changed to use a Connections object, like this: \qml MouseArea { - Connection { - signal: "clicked(x,y)" - script: { foo(x+123,y+456) } + Connections { + onClicked: foo(...) } } \endqml - More generally, the Connection object can be a child of some other object than + More generally, the Connections object can be a child of some other object than the sender of the signal: \qml MouseArea { - id: mr + id: area } ... - Connection { - sender: mr - signal: "clicked(x,y)" - script: { foo(x+123,y+456) } + Connections { + target: area + onClicked: foo(...) } \endqml */ /*! \internal - \class QDeclarativeConnection - \brief The QDeclarativeConnection class describes generalized connections to signals. + \class QDeclarativeConnections + \brief The QDeclarativeConnections class describes generalized connections to signals. */ -QDeclarativeConnection::QDeclarativeConnection(QObject *parent) : - QObject(*(new QDeclarativeConnectionPrivate), parent) +QDeclarativeConnections::QDeclarativeConnections(QObject *parent) : + QObject(*(new QDeclarativeConnectionsPrivate), parent) { } -QDeclarativeConnection::~QDeclarativeConnection() +QDeclarativeConnections::~QDeclarativeConnections() { - Q_D(QDeclarativeConnection); - delete d->boundsignal; } /*! - \qmlproperty Object Connection::sender + \qmlproperty Object Connections::target This property holds the object that sends the signal. - By default, the sender is assumed to be the parent of the Connection. + By default, the target is assumed to be the parent of the Connections. */ -QObject *QDeclarativeConnection::signalSender() const +QObject *QDeclarativeConnections::target() const { - Q_D(const QDeclarativeConnection); - return d->signalSender ? d->signalSender : parent(); + Q_D(const QDeclarativeConnections); + return d->target ? d->target : parent(); } -void QDeclarativeConnection::setSignalSender(QObject *obj) +void QDeclarativeConnections::setTarget(QObject *obj) { - Q_D(QDeclarativeConnection); - if (d->signalSender == obj) + Q_D(QDeclarativeConnections); + if (d->target == obj) return; - disconnectIfValid(); - d->signalSender = obj; - connectIfValid(); + foreach (QDeclarativeBoundSignal *s, d->boundsignals) + delete s; + d->boundsignals.clear(); + d->target = obj; + connectSignals(); + emit targetChanged(); } -void QDeclarativeConnection::connectIfValid() + +QByteArray +QDeclarativeConnectionsParser::compile(const QList<QDeclarativeCustomParserProperty> &props) { - 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()); - } + 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(); } - 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; + + 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(); + } } } - 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; - } + return rv; } -void QDeclarativeConnection::componentComplete() +void QDeclarativeConnectionsParser::setCustomData(QObject *object, + const QByteArray &data) { - Q_D(QDeclarativeConnection); - d->componentcomplete=true; - connectIfValid(); + QDeclarativeConnectionsPrivate *p = + static_cast<QDeclarativeConnectionsPrivate *>(QObjectPrivate::get(object)); + p->data = data; } -/*! - \qmlproperty script Connection::script - This property holds the JavaScript executed whenever the signal is sent. -*/ -QDeclarativeScriptString QDeclarativeConnection::script() const +void QDeclarativeConnections::connectSignals() { - Q_D(const QDeclarativeConnection); - return d->script; -} + Q_D(QDeclarativeConnections); + if (!d->componentcomplete) + return; -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(); + 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 { - // must exist - update - d->script = script; - d->boundsignal->expression()->setExpression(script.script()); + qmlInfo(this) << tr("Cannot assign to non-existent property \"%1\"").arg(propName); } - } 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) +void QDeclarativeConnections::componentComplete() { - Q_D(QDeclarativeConnection); - if (d->signal == sig) - return; - disconnectIfValid(); - d->signal = sig; - connectIfValid(); + Q_D(QDeclarativeConnections); + d->componentcomplete=true; + connectSignals(); } - - QT_END_NAMESPACE diff --git a/src/declarative/util/qdeclarativeconnection_p.h b/src/declarative/util/qdeclarativeconnection_p.h index ae2efe9..3eacf12 100644 --- a/src/declarative/util/qdeclarativeconnection_p.h +++ b/src/declarative/util/qdeclarativeconnection_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..3d34e33 100644 --- a/src/declarative/util/qdeclarativeutilmodule.cpp +++ b/src/declarative/util/qdeclarativeutilmodule.cpp @@ -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); } |