From 3c6648385e8637536292c1351ef0d52708bd07d2 Mon Sep 17 00:00:00 2001 From: Michael Brasser Date: Tue, 30 Jun 2009 12:55:10 +1000 Subject: Support animating dot properties. Make sure we can handle things like PropertyAnimation { property: "anchors.leftMargin" } --- src/declarative/qml/qmlmetaproperty.cpp | 30 +++++++++++++++++++ src/declarative/qml/qmlmetaproperty.h | 1 + src/declarative/util/qmlanimation.cpp | 48 +++++++++++++++++++++++-------- src/declarative/util/qmlanimation_p.h | 2 ++ src/declarative/util/qmlsetproperties.cpp | 37 +++++++----------------- src/declarative/util/qmlstate.cpp | 4 ++- src/declarative/util/qmlstate.h | 3 ++ src/declarative/util/qmlstate_p.h | 4 +++ 8 files changed, 89 insertions(+), 40 deletions(-) diff --git a/src/declarative/qml/qmlmetaproperty.cpp b/src/declarative/qml/qmlmetaproperty.cpp index 30e818b..682b8ad 100644 --- a/src/declarative/qml/qmlmetaproperty.cpp +++ b/src/declarative/qml/qmlmetaproperty.cpp @@ -1035,4 +1035,34 @@ QMetaMethod QmlMetaProperty::method() const return d->signal; } +/*! + \internal + + Creates a QmlMetaProperty for the property \a name of \a obj. Unlike + the QmlMetaProperty(QObject*, QString) constructor, this static function + will correctly handle dot properties. +*/ +QmlMetaProperty QmlMetaProperty::createProperty(QObject *obj, const QString &name) +{ + QStringList path = name.split('.'); + + QObject *object = obj; + + for (int jj = 0; jj < path.count() - 1; ++jj) { + const QString &pathName = path.at(jj); + QmlMetaProperty prop(object, pathName); + QObject *objVal = QmlMetaType::toQObject(prop.read()); + if (!objVal) + return QmlMetaProperty(); + object = objVal; + } + + const QString &propName = path.last(); + QmlMetaProperty prop(object, propName); + if (!prop.isValid()) + return QmlMetaProperty(); + else + return prop; +} + QT_END_NAMESPACE diff --git a/src/declarative/qml/qmlmetaproperty.h b/src/declarative/qml/qmlmetaproperty.h index ce2fbcf..6c28a86 100644 --- a/src/declarative/qml/qmlmetaproperty.h +++ b/src/declarative/qml/qmlmetaproperty.h @@ -127,6 +127,7 @@ public: QmlBindableValue *setBinding(QmlBindableValue *) const; static int findSignal(const QObject *, const char *); + static QmlMetaProperty createProperty(QObject *, const QString &); int coreIndex() const; private: diff --git a/src/declarative/util/qmlanimation.cpp b/src/declarative/util/qmlanimation.cpp index 4ee5545..da26bdd 100644 --- a/src/declarative/util/qmlanimation.cpp +++ b/src/declarative/util/qmlanimation.cpp @@ -45,6 +45,7 @@ #include "qfile.h" #include "qmlpropertyvaluesource.h" #include "qml.h" +#include "qmlinfo.h" #include "qmlanimation_p.h" #include "qmlbehaviour.h" #include @@ -225,6 +226,21 @@ void QmlAbstractAnimationPrivate::commence() } } +//### make static? +QmlMetaProperty QmlAbstractAnimationPrivate::createProperty(QObject *obj, const QString &str) +{ + Q_Q(QmlAbstractAnimation); + QmlMetaProperty prop = QmlMetaProperty::createProperty(obj, str); + if (!prop.isValid()) { + qmlInfo(q) << "Cannot animate non-existant property" << str; + return QmlMetaProperty(); + } else if (!prop.isWritable()) { + qmlInfo(q) << "Cannot animate read-only property" << str; + return QmlMetaProperty(); + } + return prop; +} + void QmlAbstractAnimation::setRunning(bool r) { Q_D(QmlAbstractAnimation); @@ -434,7 +450,7 @@ void QmlAbstractAnimation::setTarget(QObject *o) d->target = o; if (d->target && !d->propertyName.isEmpty()) { - d->userProperty = QmlMetaProperty(d->target, d->propertyName); + d->userProperty = d->createProperty(d->target, d->propertyName); } else { d->userProperty.invalidate(); } @@ -463,7 +479,7 @@ void QmlAbstractAnimation::setProperty(const QString &n) d->propertyName = n; if (d->target && !d->propertyName.isEmpty()) { - d->userProperty = QmlMetaProperty(d->target, d->propertyName); + d->userProperty = d->createProperty(d->target, d->propertyName); } else { d->userProperty.invalidate(); } @@ -1031,10 +1047,14 @@ void QmlSetPropertyAction::transition(QmlStateActions &actions, QObject *obj = action.property.object(); QString propertyName = action.property.name(); - - if ((d->filter.isEmpty() || d->filter.contains(obj)) && - (!d->exclude.contains(obj)) && props.contains(propertyName) && - (!target() || target() == obj)) { + QObject *sObj = action.specifiedObject; + QString sPropertyName = action.specifiedProperty; + bool same = (obj == sObj); + + if ((d->filter.isEmpty() || d->filter.contains(obj) || (!same && d->filter.contains(sObj))) && + (!d->exclude.contains(obj)) && (same || (!d->exclude.contains(sObj))) && + (props.contains(propertyName) || (!same && props.contains(sPropertyName))) && + (!target() || target() == obj || (!same && target() == sObj))) { objs.insert(obj); Action myAction = action; @@ -1051,7 +1071,7 @@ void QmlSetPropertyAction::transition(QmlStateActions &actions, QObject *obj = target(); for (int jj = 0; jj < props.count(); ++jj) { Action myAction; - myAction.property = QmlMetaProperty(obj, props.at(jj)); + myAction.property = d->createProperty(obj, props.at(jj)); myAction.toValue = d->value; data->actions << myAction; } @@ -1841,10 +1861,14 @@ void QmlPropertyAnimation::transition(QmlStateActions &actions, QObject *obj = action.property.object(); QString propertyName = action.property.name(); - - if ((d->filter.isEmpty() || d->filter.contains(obj)) && - (!d->exclude.contains(obj)) && props.contains(propertyName) && - (!target() || target() == obj)) { + QObject *sObj = action.specifiedObject; + QString sPropertyName = action.specifiedProperty; + bool same = (obj == sObj); + + if ((d->filter.isEmpty() || d->filter.contains(obj) || (!same && d->filter.contains(sObj))) && + (!d->exclude.contains(obj)) && (same || (!d->exclude.contains(sObj))) && + (props.contains(propertyName) || (!same && props.contains(sPropertyName))) && + (!target() || target() == obj || (!same && target() == sObj))) { objs.insert(obj); Action myAction = action; @@ -1870,7 +1894,7 @@ void QmlPropertyAnimation::transition(QmlStateActions &actions, QObject *obj = target(); for (int jj = 0; jj < props.count(); ++jj) { Action myAction; - myAction.property = QmlMetaProperty(obj, props.at(jj)); + myAction.property = d->createProperty(obj, props.at(jj)); if (d->fromIsDefined) { d->convertVariant(d->from, (QVariant::Type)(d->interpolatorType ? d->interpolatorType : myAction.property.propertyType())); diff --git a/src/declarative/util/qmlanimation_p.h b/src/declarative/util/qmlanimation_p.h index da5ed97..b801d01 100644 --- a/src/declarative/util/qmlanimation_p.h +++ b/src/declarative/util/qmlanimation_p.h @@ -193,6 +193,8 @@ public: QmlMetaProperty property; QmlAnimationGroup *group; + + QmlMetaProperty createProperty(QObject *obj, const QString &str); }; class QmlPauseAnimationPrivate : public QmlAbstractAnimationPrivate diff --git a/src/declarative/util/qmlsetproperties.cpp b/src/declarative/util/qmlsetproperties.cpp index 240e37b..7ceed5e 100644 --- a/src/declarative/util/qmlsetproperties.cpp +++ b/src/declarative/util/qmlsetproperties.cpp @@ -282,39 +282,19 @@ void QmlSetProperties::setRestoreEntryValues(bool v) d->restore = v; } -QmlMetaProperty -QmlSetPropertiesPrivate::property(const QByteArray &property) +QmlMetaProperty +QmlSetPropertiesPrivate::property(const QByteArray &property) { Q_Q(QmlSetProperties); - QList path = property.split('.'); - - QObject *obj = this->object; - - for (int jj = 0; jj < path.count() - 1; ++jj) { - const QByteArray &pathName = path.at(jj); - QmlMetaProperty prop(obj, QLatin1String(pathName)); - QObject *objVal = QmlMetaType::toQObject(prop.read()); - if (!objVal) { - qmlInfo(q) << obj->metaObject()->className() - << "has no object property named" << pathName; - return QmlMetaProperty(); - } - obj = objVal; - } - - const QByteArray &name = path.last(); - QmlMetaProperty prop(obj, QLatin1String(name)); + QmlMetaProperty prop = QmlMetaProperty::createProperty(object, QString::fromLatin1(property)); if (!prop.isValid()) { - qmlInfo(q) << obj->metaObject()->className() - << "has no property named" << name; + qmlInfo(q) << "Cannot assign to non-existant property" << property; return QmlMetaProperty(); } else if (!prop.isWritable()) { - qmlInfo(q) << obj->metaObject()->className() - << name << "is not writable, and cannot be set."; + qmlInfo(q) << "Cannot assign to read-only property" << property; return QmlMetaProperty(); - } else { - return prop; } + return prop; } QmlSetProperties::ActionList QmlSetProperties::actions() @@ -336,6 +316,8 @@ QmlSetProperties::ActionList QmlSetProperties::actions() a.property = prop; a.fromValue = a.property.read(); a.toValue = d->properties.at(ii).second; + a.specifiedObject = d->object; + a.specifiedProperty = QString::fromLatin1(property); list << a; } @@ -351,6 +333,8 @@ QmlSetProperties::ActionList QmlSetProperties::actions() a.restore = restoreEntryValues(); a.property = prop; a.fromValue = a.property.read(); + a.specifiedObject = d->object; + a.specifiedProperty = QString::fromLatin1(property); if (d->isExplicit) { a.toValue = d->expressions.at(ii).second->value(); @@ -361,7 +345,6 @@ QmlSetProperties::ActionList QmlSetProperties::actions() list << a; } - } return list; diff --git a/src/declarative/util/qmlstate.cpp b/src/declarative/util/qmlstate.cpp index fe215e7..8ac1b33 100644 --- a/src/declarative/util/qmlstate.cpp +++ b/src/declarative/util/qmlstate.cpp @@ -53,7 +53,7 @@ QT_BEGIN_NAMESPACE DEFINE_BOOL_CONFIG_OPTION(stateChangeDebug, STATECHANGE_DEBUG); -Action::Action() : restore(true), actionDone(false), fromBinding(0), toBinding(0), event(0) +Action::Action() : restore(true), actionDone(false), fromBinding(0), toBinding(0), event(0), specifiedObject(0) { } @@ -403,6 +403,8 @@ void QmlState::apply(QmlStateGroup *group, QmlTransition *trans, QmlState *rever a.fromValue = cur; a.toValue = d->revertList.at(ii).value; a.toBinding = d->revertList.at(ii).binding; + a.specifiedObject = d->revertList.at(ii).specifiedObject; //### + a.specifiedProperty = d->revertList.at(ii).specifiedProperty; applyList << a; // Store these special reverts in the reverting list d->reverting << d->revertList.at(ii).property; diff --git a/src/declarative/util/qmlstate.h b/src/declarative/util/qmlstate.h index e9a173c..b219b99 100644 --- a/src/declarative/util/qmlstate.h +++ b/src/declarative/util/qmlstate.h @@ -71,6 +71,9 @@ public: QmlBindableValue *toBinding; ActionEvent *event; + QObject *specifiedObject; + QString specifiedProperty; + void deleteFromBinding(); }; diff --git a/src/declarative/util/qmlstate_p.h b/src/declarative/util/qmlstate_p.h index b4ec476..2f6ff42 100644 --- a/src/declarative/util/qmlstate_p.h +++ b/src/declarative/util/qmlstate_p.h @@ -55,6 +55,8 @@ public: SimpleAction(const Action &a, State state = StartState) { property = a.property; + specifiedObject = a.specifiedObject; + specifiedProperty = a.specifiedProperty; if (state == StartState) { value = a.fromValue; binding = property.binding(); @@ -67,6 +69,8 @@ public: QmlMetaProperty property; QVariant value; QmlBindableValue *binding; + QObject *specifiedObject; + QString specifiedProperty; }; class QmlStatePrivate : public QObjectPrivate -- cgit v0.12