From 3218d437a13ac82f65abcea0db099f54504c8875 Mon Sep 17 00:00:00 2001
From: Michael Brasser <michael.brasser@nokia.com>
Date: Mon, 22 Feb 2010 17:27:11 +1000
Subject: Add ParentAnimation.

ParentAnimation will replace ParentAction. It provides two advantages:
* It will animate correctly when reversed.
* It allows reparenting via another item, which is useful in
  the presence of clips, for example.
---
 src/declarative/util/qdeclarativeanimation.cpp     | 242 ++++++++++++++++++++-
 src/declarative/util/qdeclarativeanimation_p.h     |  31 +++
 src/declarative/util/qdeclarativeanimation_p_p.h   |  28 ++-
 .../util/qdeclarativestateoperations.cpp           | 159 +++++++++++++-
 .../util/qdeclarativestateoperations_p.h           |  32 +++
 src/declarative/util/qdeclarativeutilmodule.cpp    |   1 +
 6 files changed, 486 insertions(+), 7 deletions(-)

diff --git a/src/declarative/util/qdeclarativeanimation.cpp b/src/declarative/util/qdeclarativeanimation.cpp
index 264b88c..8af8fc2 100644
--- a/src/declarative/util/qdeclarativeanimation.cpp
+++ b/src/declarative/util/qdeclarativeanimation.cpp
@@ -63,6 +63,7 @@
 #include <QtCore/qrect.h>
 #include <QtCore/qpoint.h>
 #include <QtCore/qsize.h>
+#include <QtCore/qmath.h>
 
 #include <private/qvariantanimation_p.h>
 
@@ -360,9 +361,6 @@ void QDeclarativeAbstractAnimation::setGroup(QDeclarativeAnimationGroup *g)
     if (d->group && !static_cast<QDeclarativeAnimationGroupPrivate *>(d->group->d_func())->animations.contains(this))
         static_cast<QDeclarativeAnimationGroupPrivate *>(d->group->d_func())->animations.append(this);
 
-    if (d->group)
-        ((QAnimationGroup*)d->group->qtAnimation())->addAnimation(qtAnimation());
-
     //if (g) //if removed from a group, then the group should no longer be the parent
         setParent(g);
 }
@@ -1517,6 +1515,7 @@ void QDeclarativeAnimationGroupPrivate::append_animation(QDeclarativeListPropert
     if (q) {
         q->d_func()->animations.append(a);
         a->setGroup(q);
+        q->d_func()->ag->addAnimation(a->qtAnimation());
     }
 }
 
@@ -2368,4 +2367,241 @@ void QDeclarativePropertyAnimation::transition(QDeclarativeStateActions &actions
 
 
 
+QDeclarativeParentAnimation::QDeclarativeParentAnimation(QObject *parent)
+    : QDeclarativeAnimationGroup(parent)
+{
+    Q_D(QDeclarativeParentAnimation);
+    d->topLevelGroup = new QSequentialAnimationGroup;
+    QDeclarativeGraphics_setParent_noEvent(d->topLevelGroup, this);
+
+    d->startAction = new QActionAnimation;
+    d->topLevelGroup->addAnimation(d->startAction);
+
+    d->ag = new QParallelAnimationGroup;
+    d->topLevelGroup->addAnimation(d->ag);
+
+    d->endAction = new QActionAnimation;
+    d->topLevelGroup->addAnimation(d->endAction);
+}
+
+QDeclarativeParentAnimation::~QDeclarativeParentAnimation()
+{
+}
+
+QDeclarativeItem *QDeclarativeParentAnimation::target() const
+{
+    Q_D(const QDeclarativeParentAnimation);
+    return d->target;
+}
+
+void QDeclarativeParentAnimation::setTarget(QDeclarativeItem *target)
+{
+    Q_D(QDeclarativeParentAnimation);
+    d->target = target;
+}
+
+QDeclarativeItem *QDeclarativeParentAnimation::newParent() const
+{
+    Q_D(const QDeclarativeParentAnimation);
+    return d->newParent;
+}
+
+void QDeclarativeParentAnimation::setNewParent(QDeclarativeItem *newParent)
+{
+    Q_D(QDeclarativeParentAnimation);
+    d->newParent = newParent;
+}
+
+QDeclarativeItem *QDeclarativeParentAnimation::via() const
+{
+    Q_D(const QDeclarativeParentAnimation);
+    return d->via;
+}
+
+void QDeclarativeParentAnimation::setVia(QDeclarativeItem *via)
+{
+    Q_D(QDeclarativeParentAnimation);
+    d->via = via;
+}
+
+//### mirrors same-named function in QDeclarativeItem
+QPointF QDeclarativeParentAnimationPrivate::computeTransformOrigin(QDeclarativeItem::TransformOrigin origin, qreal width, qreal height) const
+{
+    switch(origin) {
+    default:
+    case QDeclarativeItem::TopLeft:
+        return QPointF(0, 0);
+    case QDeclarativeItem::Top:
+        return QPointF(width / 2., 0);
+    case QDeclarativeItem::TopRight:
+        return QPointF(width, 0);
+    case QDeclarativeItem::Left:
+        return QPointF(0, height / 2.);
+    case QDeclarativeItem::Center:
+        return QPointF(width / 2., height / 2.);
+    case QDeclarativeItem::Right:
+        return QPointF(width, height / 2.);
+    case QDeclarativeItem::BottomLeft:
+        return QPointF(0, height);
+    case QDeclarativeItem::Bottom:
+        return QPointF(width / 2., height);
+    case QDeclarativeItem::BottomRight:
+        return QPointF(width, height);
+    }
+}
+
+void QDeclarativeParentAnimation::transition(QDeclarativeStateActions &actions,
+                        QDeclarativeProperties &modified,
+                        TransitionDirection direction)
+{
+    Q_D(QDeclarativeParentAnimation);
+
+    struct QDeclarativeParentActionData : public QAbstractAnimationAction
+    {
+        QDeclarativeParentActionData(): pc(0) {}
+        ~QDeclarativeParentActionData() { delete pc; }
+
+        QDeclarativeStateActions actions;
+        bool reverse;
+        QDeclarativeParentChange *pc;
+        virtual void doAction()
+        {
+            for (int ii = 0; ii < actions.count(); ++ii) {
+                const QDeclarativeAction &action = actions.at(ii);
+                if (reverse)
+                    action.event->reverse();
+                else
+                    action.event->execute();
+            }
+        }
+    };
+
+    QDeclarativeParentActionData *data = new QDeclarativeParentActionData;
+    QDeclarativeParentActionData *viaData = new QDeclarativeParentActionData;
+    for (int i = 0; i < actions.size(); ++i) {
+        QDeclarativeAction &action = actions[i];
+        if (action.event && action.event->typeName() == QLatin1String("ParentChange")
+            && (!d->target || static_cast<QDeclarativeParentChange*>(action.event)->object() == d->target)) {
+
+            QDeclarativeParentChange *pc = static_cast<QDeclarativeParentChange*>(action.event);
+            QDeclarativeAction myAction = action;
+            data->reverse = action.reverseEvent;
+            action.actionDone = true;
+            data->actions << myAction;
+
+            if (d->via) {
+                viaData->reverse = false;
+                QDeclarativeAction myAction;
+                QDeclarativeParentChange *vpc = new QDeclarativeParentChange;
+                vpc->setObject(pc->object());
+                vpc->setParent(d->via);
+                myAction.event = vpc;
+                viaData->pc = vpc;
+                viaData->actions << myAction;
+                QDeclarativeAction dummyAction;
+                QDeclarativeAction &xAction = pc->xIsSet() ? actions[++i] : dummyAction;
+                QDeclarativeAction &yAction = pc->yIsSet() ? actions[++i] : dummyAction;
+                QDeclarativeAction &sAction = pc->scaleIsSet() ? actions[++i] : dummyAction;
+                QDeclarativeAction &rAction = pc->rotationIsSet() ? actions[++i] : dummyAction;
+                bool forward = (direction == QDeclarativeAbstractAnimation::Forward);
+                QDeclarativeItem *target = pc->object();
+                QDeclarativeItem *targetParent = forward ? pc->parent() : pc->originalParent();
+
+                //### this mirrors the logic in QDeclarativeParentChange.
+                bool ok;
+                const QTransform &transform = targetParent->itemTransform(d->via, &ok);
+                if (transform.type() >= QTransform::TxShear || !ok) {
+                    qmlInfo(this) << QDeclarativeParentAnimation::tr("Unable to preserve appearance under complex transform");
+                    ok = false;
+                }
+
+                qreal scale = 1;
+                qreal rotation = 0;
+                if (ok && transform.type() != QTransform::TxRotate) {
+                    if (transform.m11() == transform.m22())
+                        scale = transform.m11();
+                    else {
+                        qmlInfo(this) << QDeclarativeParentAnimation::tr("Unable to preserve appearance under non-uniform scale");
+                        ok = false;
+                    }
+                } else if (ok && transform.type() == QTransform::TxRotate) {
+                    if (transform.m11() == transform.m22())
+                        scale = qSqrt(transform.m11()*transform.m11() + transform.m12()*transform.m12());
+                    else {
+                        qmlInfo(this) << QDeclarativeParentAnimation::tr("Unable to preserve appearance under non-uniform scale");
+                        ok = false;
+                    }
+
+                    if (scale != 0)
+                        rotation = atan2(transform.m12()/scale, transform.m11()/scale) * 180/M_PI;
+                    else {
+                        qmlInfo(this) << QDeclarativeParentAnimation::tr("Unable to preserve appearance under scale of 0");
+                        ok = false;
+                    }
+                }
+
+                const QPointF &point = transform.map(QPointF(xAction.toValue.toReal(),yAction.toValue.toReal()));
+                qreal x = point.x();
+                qreal y = point.y();
+                if (ok && target->transformOrigin() != QDeclarativeItem::TopLeft) {
+                    qreal w = target->width();
+                    qreal h = target->height();
+                    if (pc->widthIsSet())
+                        w = actions[++i].toValue.toReal();
+                    if (pc->heightIsSet())
+                        h = actions[++i].toValue.toReal();
+                    const QPointF &transformOrigin
+                            = d->computeTransformOrigin(target->transformOrigin(), w,h);
+                    qreal tempxt = transformOrigin.x();
+                    qreal tempyt = transformOrigin.y();
+                    QTransform t;
+                    t.translate(-tempxt, -tempyt);
+                    t.rotate(rotation);
+                    t.scale(scale, scale);
+                    t.translate(tempxt, tempyt);
+                    const QPointF &offset = t.map(QPointF(0,0));
+                    x += offset.x();
+                    y += offset.y();
+                }
+
+                if (ok) {
+                    //qDebug() << x << y << rotation << scale;
+                    xAction.toValue = x;
+                    yAction.toValue = y;
+                    sAction.toValue = sAction.toValue.toReal() * scale;
+                    rAction.toValue = rAction.toValue.toReal() + rotation;
+                }
+            }
+        }
+    }
+
+    if (data->actions.count()) {
+        if (direction == QDeclarativeAbstractAnimation::Forward) {
+            d->startAction->setAnimAction(d->via ? viaData : data, QActionAnimation::DeleteWhenStopped);
+            d->endAction->setAnimAction(d->via ? data : 0, QActionAnimation::DeleteWhenStopped);
+        } else {
+            d->endAction->setAnimAction(d->via ? viaData : data, QActionAnimation::DeleteWhenStopped);
+            d->startAction->setAnimAction(d->via ? data : 0, QActionAnimation::DeleteWhenStopped);
+        }
+    } else {
+        delete data;
+        delete viaData;
+    }
+
+    //take care of any child animations
+    bool valid = d->defaultProperty.isValid();
+    for (int ii = 0; ii < d->animations.count(); ++ii) {
+        if (valid)
+            d->animations.at(ii)->setDefaultTarget(d->defaultProperty);
+        d->animations.at(ii)->transition(actions, modified, direction);
+    }
+
+}
+
+QAbstractAnimation *QDeclarativeParentAnimation::qtAnimation()
+{
+    Q_D(QDeclarativeParentAnimation);
+    return d->topLevelGroup;
+}
+
 QT_END_NAMESPACE
diff --git a/src/declarative/util/qdeclarativeanimation_p.h b/src/declarative/util/qdeclarativeanimation_p.h
index 53afbb5..b57bd9e 100644
--- a/src/declarative/util/qdeclarativeanimation_p.h
+++ b/src/declarative/util/qdeclarativeanimation_p.h
@@ -447,6 +447,36 @@ protected:
     virtual QAbstractAnimation *qtAnimation();
 };
 
+class QDeclarativeParentAnimationPrivate;
+class QDeclarativeParentAnimation : public QDeclarativeAnimationGroup
+{
+    Q_OBJECT
+    Q_DECLARE_PRIVATE(QDeclarativeParentAnimation)
+
+    Q_PROPERTY(QDeclarativeItem *target READ target WRITE setTarget)
+    //Q_PROPERTY(QDeclarativeItem *newParent READ newParent WRITE setNewParent)
+    Q_PROPERTY(QDeclarativeItem *via READ via WRITE setVia)
+
+public:
+    QDeclarativeParentAnimation(QObject *parent=0);
+    virtual ~QDeclarativeParentAnimation();
+
+    QDeclarativeItem *target() const;
+    void setTarget(QDeclarativeItem *);
+
+    QDeclarativeItem *newParent() const;
+    void setNewParent(QDeclarativeItem *);
+
+    QDeclarativeItem *via() const;
+    void setVia(QDeclarativeItem *);
+
+protected:
+    virtual void transition(QDeclarativeStateActions &actions,
+                            QDeclarativeProperties &modified,
+                            TransitionDirection direction);
+    virtual QAbstractAnimation *qtAnimation();
+};
+
 QT_END_NAMESPACE
 
 QML_DECLARE_TYPE(QDeclarativeAbstractAnimation)
@@ -461,6 +491,7 @@ QML_DECLARE_TYPE(QDeclarativeSequentialAnimation)
 QML_DECLARE_TYPE(QDeclarativeParallelAnimation)
 QML_DECLARE_TYPE(QDeclarativeVector3dAnimation)
 QML_DECLARE_TYPE(QDeclarativeRotationAnimation)
+QML_DECLARE_TYPE(QDeclarativeParentAnimation)
 
 QT_END_HEADER
 
diff --git a/src/declarative/util/qdeclarativeanimation_p_p.h b/src/declarative/util/qdeclarativeanimation_p_p.h
index fc4e6e6..e582066 100644
--- a/src/declarative/util/qdeclarativeanimation_p_p.h
+++ b/src/declarative/util/qdeclarativeanimation_p_p.h
@@ -59,6 +59,7 @@
 #include "qdeclarativetimeline_p_p.h"
 
 #include <qdeclarative.h>
+#include <qdeclarativeitem.h>
 #include <qdeclarativecontext.h>
 
 #include <QtCore/QPauseAnimation>
@@ -104,6 +105,12 @@ public:
         : QAbstractAnimation(parent), animAction(action), policy(KeepWhenStopped), running(false) {}
     ~QActionAnimation() { if (policy == DeleteWhenStopped) { delete animAction; animAction = 0; } }
     virtual int duration() const { return 0; }
+    void clearAnimAction()
+    {
+        if (policy == DeleteWhenStopped)
+            delete animAction;
+        animAction = 0;
+    }
     void setAnimAction(QAbstractAnimationAction *action, DeletionPolicy p)
     {
         if (state() == Running)
@@ -311,8 +318,6 @@ public:
 
     static void append_animation(QDeclarativeListProperty<QDeclarativeAbstractAnimation> *list, QDeclarativeAbstractAnimation *role);
     static void clear_animation(QDeclarativeListProperty<QDeclarativeAbstractAnimation> *list);
-    static void removeAt_animation(QDeclarativeListProperty<QDeclarativeAbstractAnimation> *list, int i);
-    static void insert_animation(QDeclarativeListProperty<QDeclarativeAbstractAnimation> *list, int i, QDeclarativeAbstractAnimation *role);
     QList<QDeclarativeAbstractAnimation *> animations;
     QAnimationGroup *ag;
 };
@@ -362,6 +367,25 @@ public:
     QDeclarativeRotationAnimation::RotationDirection direction;
 };
 
+class QDeclarativeParentAnimationPrivate : public QDeclarativeAnimationGroupPrivate
+{
+    Q_DECLARE_PUBLIC(QDeclarativeParentAnimation)
+public:
+    QDeclarativeParentAnimationPrivate()
+    : QDeclarativeAnimationGroupPrivate(), target(0), newParent(0),
+       via(0), topLevelGroup(0), startAction(0), endAction(0) {}
+
+    QDeclarativeItem *target;
+    QDeclarativeItem *newParent;
+    QDeclarativeItem *via;
+
+    QSequentialAnimationGroup *topLevelGroup;
+    QActionAnimation *startAction;
+    QActionAnimation *endAction;
+
+    QPointF computeTransformOrigin(QDeclarativeItem::TransformOrigin origin, qreal width, qreal height) const;
+};
+
 QT_END_NAMESPACE
 
 #endif // QDECLARATIVEANIMATION_P_H
diff --git a/src/declarative/util/qdeclarativestateoperations.cpp b/src/declarative/util/qdeclarativestateoperations.cpp
index 9df8658..cea9ad7 100644
--- a/src/declarative/util/qdeclarativestateoperations.cpp
+++ b/src/declarative/util/qdeclarativestateoperations.cpp
@@ -48,6 +48,7 @@
 #include <qdeclarativeanchors_p_p.h>
 #include <qdeclarativeitem_p.h>
 #include <qdeclarativeguard_p.h>
+#include <qdeclarativenullablevalue_p_p.h>
 
 #include <QtCore/qdebug.h>
 #include <QtGui/qgraphicsitem.h>
@@ -62,7 +63,7 @@ class QDeclarativeParentChangePrivate : public QObjectPrivate
     Q_DECLARE_PUBLIC(QDeclarativeParentChange)
 public:
     QDeclarativeParentChangePrivate() : target(0), parent(0), origParent(0), origStackBefore(0),
-                               rewindParent(0), rewindStackBefore(0) {}
+        rewindParent(0), rewindStackBefore(0) {}
 
     QDeclarativeItem *target;
     QDeclarativeItem *parent;
@@ -71,6 +72,13 @@ public:
     QDeclarativeItem *rewindParent;
     QDeclarativeItem *rewindStackBefore;
 
+    QDeclarativeNullableValue<qreal> x;
+    QDeclarativeNullableValue<qreal> y;
+    QDeclarativeNullableValue<qreal> width;
+    QDeclarativeNullableValue<qreal> height;
+    QDeclarativeNullableValue<qreal> scale;
+    QDeclarativeNullableValue<qreal> rotation;
+
     void doChange(QDeclarativeItem *targetParent, QDeclarativeItem *stackBefore = 0);
 };
 
@@ -173,6 +181,120 @@ QDeclarativeParentChange::~QDeclarativeParentChange()
 {
 }
 
+qreal QDeclarativeParentChange::x() const
+{
+    Q_D(const QDeclarativeParentChange);
+    return d->x.isNull ? qreal(0.) : d->x.value;
+}
+
+void QDeclarativeParentChange::setX(qreal x)
+{
+    Q_D(QDeclarativeParentChange);
+    d->x = x;
+}
+
+bool QDeclarativeParentChange::xIsSet() const
+{
+    Q_D(const QDeclarativeParentChange);
+    return d->x.isValid();
+}
+
+qreal QDeclarativeParentChange::y() const
+{
+    Q_D(const QDeclarativeParentChange);
+    return d->y.isNull ? qreal(0.) : d->y.value;
+}
+
+void QDeclarativeParentChange::setY(qreal y)
+{
+    Q_D(QDeclarativeParentChange);
+    d->y = y;
+}
+
+bool QDeclarativeParentChange::yIsSet() const
+{
+    Q_D(const QDeclarativeParentChange);
+    return d->y.isValid();
+}
+
+qreal QDeclarativeParentChange::width() const
+{
+    Q_D(const QDeclarativeParentChange);
+    return d->width.isNull ? qreal(0.) : d->width.value;
+}
+
+void QDeclarativeParentChange::setWidth(qreal width)
+{
+    Q_D(QDeclarativeParentChange);
+    d->width = width;
+}
+
+bool QDeclarativeParentChange::widthIsSet() const
+{
+    Q_D(const QDeclarativeParentChange);
+    return d->width.isValid();
+}
+
+qreal QDeclarativeParentChange::height() const
+{
+    Q_D(const QDeclarativeParentChange);
+    return d->height.isNull ? qreal(0.) : d->height.value;
+}
+
+void QDeclarativeParentChange::setHeight(qreal height)
+{
+    Q_D(QDeclarativeParentChange);
+    d->height = height;
+}
+
+bool QDeclarativeParentChange::heightIsSet() const
+{
+    Q_D(const QDeclarativeParentChange);
+    return d->height.isValid();
+}
+
+qreal QDeclarativeParentChange::scale() const
+{
+    Q_D(const QDeclarativeParentChange);
+    return d->scale.isNull ? qreal(1.) : d->scale.value;
+}
+
+void QDeclarativeParentChange::setScale(qreal scale)
+{
+    Q_D(QDeclarativeParentChange);
+    d->scale = scale;
+}
+
+bool QDeclarativeParentChange::scaleIsSet() const
+{
+    Q_D(const QDeclarativeParentChange);
+    return d->scale.isValid();
+}
+
+qreal QDeclarativeParentChange::rotation() const
+{
+    Q_D(const QDeclarativeParentChange);
+    return d->rotation.isNull ? qreal(0.) : d->rotation.value;
+}
+
+void QDeclarativeParentChange::setRotation(qreal rotation)
+{
+    Q_D(QDeclarativeParentChange);
+    d->rotation = rotation;
+}
+
+bool QDeclarativeParentChange::rotationIsSet() const
+{
+    Q_D(const QDeclarativeParentChange);
+    return d->rotation.isValid();
+}
+
+QDeclarativeItem *QDeclarativeParentChange::originalParent() const
+{
+    Q_D(const QDeclarativeParentChange);
+    return d->origParent;
+}
+
 /*!
     \qmlproperty Item ParentChange::target
     This property holds the item to be reparented
@@ -213,10 +335,43 @@ QDeclarativeStateOperation::ActionList QDeclarativeParentChange::actions()
     if (!d->target || !d->parent)
         return ActionList();
 
+    ActionList actions;
+
     QDeclarativeAction a;
     a.event = this;
+    actions << a;
 
-    return ActionList() << a;
+    if (d->x.isValid()) {
+        QDeclarativeAction xa(d->target, QLatin1String("x"), x());
+        actions << xa;
+    }
+
+    if (d->y.isValid()) {
+        QDeclarativeAction ya(d->target, QLatin1String("y"), y());
+        actions << ya;
+    }
+
+    if (d->scale.isValid()) {
+        QDeclarativeAction sa(d->target, QLatin1String("scale"), scale());
+        actions << sa;
+    }
+
+    if (d->rotation.isValid()) {
+        QDeclarativeAction ra(d->target, QLatin1String("rotation"), rotation());
+        actions << ra;
+    }
+
+    if (d->width.isValid()) {
+        QDeclarativeAction wa(d->target, QLatin1String("width"), width());
+        actions << wa;
+    }
+
+    if (d->height.isValid()) {
+        QDeclarativeAction ha(d->target, QLatin1String("height"), height());
+        actions << ha;
+    }
+
+    return actions;
 }
 
 class AccessibleFxItem : public QDeclarativeItem
diff --git a/src/declarative/util/qdeclarativestateoperations_p.h b/src/declarative/util/qdeclarativestateoperations_p.h
index 9204a58..026a64d 100644
--- a/src/declarative/util/qdeclarativestateoperations_p.h
+++ b/src/declarative/util/qdeclarativestateoperations_p.h
@@ -62,6 +62,12 @@ class Q_DECLARATIVE_EXPORT QDeclarativeParentChange : public QDeclarativeStateOp
 
     Q_PROPERTY(QDeclarativeItem *target READ object WRITE setObject)
     Q_PROPERTY(QDeclarativeItem *parent READ parent WRITE setParent)
+    Q_PROPERTY(qreal x READ x WRITE setX)
+    Q_PROPERTY(qreal y READ y WRITE setY)
+    Q_PROPERTY(qreal width READ width WRITE setWidth)
+    Q_PROPERTY(qreal height READ height WRITE setHeight)
+    Q_PROPERTY(qreal scale READ scale WRITE setScale)
+    Q_PROPERTY(qreal rotation READ rotation WRITE setRotation)
 public:
     QDeclarativeParentChange(QObject *parent=0);
     ~QDeclarativeParentChange();
@@ -72,6 +78,32 @@ public:
     QDeclarativeItem *parent() const;
     void setParent(QDeclarativeItem *);
 
+    QDeclarativeItem *originalParent() const;
+
+    qreal x() const;
+    void setX(qreal x);
+    bool xIsSet() const;
+
+    qreal y() const;
+    void setY(qreal y);
+    bool yIsSet() const;
+
+    qreal width() const;
+    void setWidth(qreal width);
+    bool widthIsSet() const;
+
+    qreal height() const;
+    void setHeight(qreal height);
+    bool heightIsSet() const;
+
+    qreal scale() const;
+    void setScale(qreal scale);
+    bool scaleIsSet() const;
+
+    qreal rotation() const;
+    void setRotation(qreal rotation);
+    bool rotationIsSet() const;
+
     virtual ActionList actions();
 
     virtual void saveOriginals();
diff --git a/src/declarative/util/qdeclarativeutilmodule.cpp b/src/declarative/util/qdeclarativeutilmodule.cpp
index ecaa607c..8d3d682 100644
--- a/src/declarative/util/qdeclarativeutilmodule.cpp
+++ b/src/declarative/util/qdeclarativeutilmodule.cpp
@@ -90,6 +90,7 @@ void QDeclarativeUtilModule::defineModule()
     QML_REGISTER_TYPE(Qt,4,6,Package,QDeclarativePackage);
     QML_REGISTER_TYPE(Qt,4,6,ParallelAnimation,QDeclarativeParallelAnimation);
     QML_REGISTER_TYPE(Qt,4,6,ParentAction,QDeclarativeParentAction);
+    QML_REGISTER_TYPE(Qt,4,6,ParentAnimation,QDeclarativeParentAnimation);
     QML_REGISTER_TYPE(Qt,4,6,ParentChange,QDeclarativeParentChange);
     QML_REGISTER_TYPE(Qt,4,6,PauseAnimation,QDeclarativePauseAnimation);
     QML_REGISTER_TYPE(Qt,4,6,PropertyAction,QDeclarativePropertyAction);
-- 
cgit v0.12