Initial import from the monolithic Qt.
[profile/ivi/qtdeclarative.git] / src / declarative / util / qdeclarativestateoperations.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** No Commercial Usage
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
14 ** this package.
15 **
16 ** GNU Lesser General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU Lesser
18 ** General Public License version 2.1 as published by the Free Software
19 ** Foundation and appearing in the file LICENSE.LGPL included in the
20 ** packaging of this file.  Please review the following information to
21 ** ensure the GNU Lesser General Public License version 2.1 requirements
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23 **
24 ** In addition, as a special exception, Nokia gives you certain additional
25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27 **
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
30 **
31 **
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "private/qdeclarativestateoperations_p.h"
43
44 #include <qdeclarative.h>
45 #include <qdeclarativecontext.h>
46 #include <qdeclarativeexpression.h>
47 #include <qdeclarativeinfo.h>
48 #include <qdeclarativeanchors_p_p.h>
49 #include <qdeclarativeitem_p.h>
50 #include <qdeclarativeguard_p.h>
51 #include <qdeclarativenullablevalue_p_p.h>
52 #include "private/qdeclarativecontext_p.h"
53 #include "private/qdeclarativeproperty_p.h"
54 #include "private/qdeclarativebinding_p.h"
55 #include "private/qdeclarativestate_p_p.h"
56
57 #include <QtCore/qdebug.h>
58 #include <QtGui/qgraphicsitem.h>
59 #include <QtCore/qmath.h>
60
61 #include <private/qobject_p.h>
62
63 QT_BEGIN_NAMESPACE
64
65 class QDeclarativeParentChangePrivate : public QDeclarativeStateOperationPrivate
66 {
67     Q_DECLARE_PUBLIC(QDeclarativeParentChange)
68 public:
69     QDeclarativeParentChangePrivate() : target(0), parent(0), origParent(0), origStackBefore(0),
70         rewindParent(0), rewindStackBefore(0) {}
71
72     QDeclarativeItem *target;
73     QDeclarativeGuard<QDeclarativeItem> parent;
74     QDeclarativeGuard<QDeclarativeItem> origParent;
75     QDeclarativeGuard<QDeclarativeItem> origStackBefore;
76     QDeclarativeItem *rewindParent;
77     QDeclarativeItem *rewindStackBefore;
78
79     QDeclarativeNullableValue<QDeclarativeScriptString> xString;
80     QDeclarativeNullableValue<QDeclarativeScriptString> yString;
81     QDeclarativeNullableValue<QDeclarativeScriptString> widthString;
82     QDeclarativeNullableValue<QDeclarativeScriptString> heightString;
83     QDeclarativeNullableValue<QDeclarativeScriptString> scaleString;
84     QDeclarativeNullableValue<QDeclarativeScriptString> rotationString;
85
86     QDeclarativeNullableValue<qreal> x;
87     QDeclarativeNullableValue<qreal> y;
88     QDeclarativeNullableValue<qreal> width;
89     QDeclarativeNullableValue<qreal> height;
90     QDeclarativeNullableValue<qreal> scale;
91     QDeclarativeNullableValue<qreal> rotation;
92
93     void doChange(QDeclarativeItem *targetParent, QDeclarativeItem *stackBefore = 0);
94 };
95
96 void QDeclarativeParentChangePrivate::doChange(QDeclarativeItem *targetParent, QDeclarativeItem *stackBefore)
97 {
98     if (targetParent && target && target->parentItem()) {
99         Q_Q(QDeclarativeParentChange);
100         bool ok;
101         const QTransform &transform = target->parentItem()->itemTransform(targetParent, &ok);
102         if (transform.type() >= QTransform::TxShear || !ok) {
103             qmlInfo(q) << QDeclarativeParentChange::tr("Unable to preserve appearance under complex transform");
104             ok = false;
105         }
106
107         qreal scale = 1;
108         qreal rotation = 0;
109         bool isRotate = (transform.type() == QTransform::TxRotate) || (transform.m11() < 0);
110         if (ok && !isRotate) {
111             if (transform.m11() == transform.m22())
112                 scale = transform.m11();
113             else {
114                 qmlInfo(q) << QDeclarativeParentChange::tr("Unable to preserve appearance under non-uniform scale");
115                 ok = false;
116             }
117         } else if (ok && isRotate) {
118             if (transform.m11() == transform.m22())
119                 scale = qSqrt(transform.m11()*transform.m11() + transform.m12()*transform.m12());
120             else {
121                 qmlInfo(q) << QDeclarativeParentChange::tr("Unable to preserve appearance under non-uniform scale");
122                 ok = false;
123             }
124
125             if (scale != 0)
126                 rotation = atan2(transform.m12()/scale, transform.m11()/scale) * 180/M_PI;
127             else {
128                 qmlInfo(q) << QDeclarativeParentChange::tr("Unable to preserve appearance under scale of 0");
129                 ok = false;
130             }
131         }
132
133         const QPointF &point = transform.map(QPointF(target->x(),target->y()));
134         qreal x = point.x();
135         qreal y = point.y();
136
137         // setParentItem will update the transformOriginPoint if needed
138         target->setParentItem(targetParent);
139
140         if (ok && target->transformOrigin() != QDeclarativeItem::TopLeft) {
141             qreal tempxt = target->transformOriginPoint().x();
142             qreal tempyt = target->transformOriginPoint().y();
143             QTransform t;
144             t.translate(-tempxt, -tempyt);
145             t.rotate(rotation);
146             t.scale(scale, scale);
147             t.translate(tempxt, tempyt);
148             const QPointF &offset = t.map(QPointF(0,0));
149             x += offset.x();
150             y += offset.y();
151         }
152
153         if (ok) {
154             //qDebug() << x << y << rotation << scale;
155             target->setX(x);
156             target->setY(y);
157             target->setRotation(target->rotation() + rotation);
158             target->setScale(target->scale() * scale);
159         }
160     } else if (target) {
161         target->setParentItem(targetParent);
162     }
163
164     //restore the original stack position.
165     //### if stackBefore has also been reparented this won't work
166     if (stackBefore)
167         target->stackBefore(stackBefore);
168 }
169
170 /*!
171     \preliminary
172     \qmlclass ParentChange QDeclarativeParentChange
173     \ingroup qml-state-elements
174     \brief The ParentChange element allows you to reparent an Item in a state change.
175
176     ParentChange reparents an item while preserving its visual appearance (position, size,
177     rotation, and scale) on screen. You can then specify a transition to move/resize/rotate/scale
178     the item to its final intended appearance.
179
180     ParentChange can only preserve visual appearance if no complex transforms are involved.
181     More specifically, it will not work if the transform property has been set for any
182     items involved in the reparenting (i.e. items in the common ancestor tree
183     for the original and new parent).
184
185     The example below displays a large red rectangle and a small blue rectangle, side by side. 
186     When the \c blueRect is clicked, it changes to the "reparented" state: its parent is changed to \c redRect and it is 
187     positioned at (10, 10) within the red rectangle, as specified in the ParentChange.
188
189     \snippet doc/src/snippets/declarative/parentchange.qml 0
190
191     \image parentchange.png
192
193     You can specify at which point in a transition you want a ParentChange to occur by
194     using a ParentAnimation.
195 */
196
197
198 QDeclarativeParentChange::QDeclarativeParentChange(QObject *parent)
199     : QDeclarativeStateOperation(*(new QDeclarativeParentChangePrivate), parent)
200 {
201 }
202
203 QDeclarativeParentChange::~QDeclarativeParentChange()
204 {
205 }
206
207 /*!
208     \qmlproperty real ParentChange::x
209     \qmlproperty real ParentChange::y
210     \qmlproperty real ParentChange::width
211     \qmlproperty real ParentChange::height
212     \qmlproperty real ParentChange::scale
213     \qmlproperty real ParentChange::rotation
214     These properties hold the new position, size, scale, and rotation
215     for the item in this state.
216 */
217 QDeclarativeScriptString QDeclarativeParentChange::x() const
218 {
219     Q_D(const QDeclarativeParentChange);
220     return d->xString.value;
221 }
222
223 void tryReal(QDeclarativeNullableValue<qreal> &value, const QString &string)
224 {
225     bool ok = false;
226     qreal realValue = string.toFloat(&ok);
227     if (ok)
228         value = realValue;
229     else
230         value.invalidate();
231 }
232
233 void QDeclarativeParentChange::setX(QDeclarativeScriptString x)
234 {
235     Q_D(QDeclarativeParentChange);
236     d->xString = x;
237     tryReal(d->x, x.script());
238 }
239
240 bool QDeclarativeParentChange::xIsSet() const
241 {
242     Q_D(const QDeclarativeParentChange);
243     return d->xString.isValid();
244 }
245
246 QDeclarativeScriptString QDeclarativeParentChange::y() const
247 {
248     Q_D(const QDeclarativeParentChange);
249     return d->yString.value;
250 }
251
252 void QDeclarativeParentChange::setY(QDeclarativeScriptString y)
253 {
254     Q_D(QDeclarativeParentChange);
255     d->yString = y;
256     tryReal(d->y, y.script());
257 }
258
259 bool QDeclarativeParentChange::yIsSet() const
260 {
261     Q_D(const QDeclarativeParentChange);
262     return d->yString.isValid();
263 }
264
265 QDeclarativeScriptString QDeclarativeParentChange::width() const
266 {
267     Q_D(const QDeclarativeParentChange);
268     return d->widthString.value;
269 }
270
271 void QDeclarativeParentChange::setWidth(QDeclarativeScriptString width)
272 {
273     Q_D(QDeclarativeParentChange);
274     d->widthString = width;
275     tryReal(d->width, width.script());
276 }
277
278 bool QDeclarativeParentChange::widthIsSet() const
279 {
280     Q_D(const QDeclarativeParentChange);
281     return d->widthString.isValid();
282 }
283
284 QDeclarativeScriptString QDeclarativeParentChange::height() const
285 {
286     Q_D(const QDeclarativeParentChange);
287     return d->heightString.value;
288 }
289
290 void QDeclarativeParentChange::setHeight(QDeclarativeScriptString height)
291 {
292     Q_D(QDeclarativeParentChange);
293     d->heightString = height;
294     tryReal(d->height, height.script());
295 }
296
297 bool QDeclarativeParentChange::heightIsSet() const
298 {
299     Q_D(const QDeclarativeParentChange);
300     return d->heightString.isValid();
301 }
302
303 QDeclarativeScriptString QDeclarativeParentChange::scale() const
304 {
305     Q_D(const QDeclarativeParentChange);
306     return d->scaleString.value;
307 }
308
309 void QDeclarativeParentChange::setScale(QDeclarativeScriptString scale)
310 {
311     Q_D(QDeclarativeParentChange);
312     d->scaleString = scale;
313     tryReal(d->scale, scale.script());
314 }
315
316 bool QDeclarativeParentChange::scaleIsSet() const
317 {
318     Q_D(const QDeclarativeParentChange);
319     return d->scaleString.isValid();
320 }
321
322 QDeclarativeScriptString QDeclarativeParentChange::rotation() const
323 {
324     Q_D(const QDeclarativeParentChange);
325     return d->rotationString.value;
326 }
327
328 void QDeclarativeParentChange::setRotation(QDeclarativeScriptString rotation)
329 {
330     Q_D(QDeclarativeParentChange);
331     d->rotationString = rotation;
332     tryReal(d->rotation, rotation.script());
333 }
334
335 bool QDeclarativeParentChange::rotationIsSet() const
336 {
337     Q_D(const QDeclarativeParentChange);
338     return d->rotationString.isValid();
339 }
340
341 QDeclarativeItem *QDeclarativeParentChange::originalParent() const
342 {
343     Q_D(const QDeclarativeParentChange);
344     return d->origParent;
345 }
346
347 /*!
348     \qmlproperty Item ParentChange::target
349     This property holds the item to be reparented
350 */
351
352 QDeclarativeItem *QDeclarativeParentChange::object() const
353 {
354     Q_D(const QDeclarativeParentChange);
355     return d->target;
356 }
357
358 void QDeclarativeParentChange::setObject(QDeclarativeItem *target)
359 {
360     Q_D(QDeclarativeParentChange);
361     d->target = target;
362 }
363
364 /*!
365     \qmlproperty Item ParentChange::parent
366     This property holds the new parent for the item in this state.
367 */
368
369 QDeclarativeItem *QDeclarativeParentChange::parent() const
370 {
371     Q_D(const QDeclarativeParentChange);
372     return d->parent;
373 }
374
375 void QDeclarativeParentChange::setParent(QDeclarativeItem *parent)
376 {
377     Q_D(QDeclarativeParentChange);
378     d->parent = parent;
379 }
380
381 QDeclarativeStateOperation::ActionList QDeclarativeParentChange::actions()
382 {
383     Q_D(QDeclarativeParentChange);
384     if (!d->target || !d->parent)
385         return ActionList();
386
387     ActionList actions;
388
389     QDeclarativeAction a;
390     a.event = this;
391     actions << a;
392
393     QDeclarativeContext *ctxt = qmlContext(this);
394
395     if (d->xString.isValid()) {
396         if (d->x.isValid()) {
397             QDeclarativeAction xa(d->target, QLatin1String("x"), ctxt, d->x.value);
398             actions << xa;
399         } else {
400             QDeclarativeBinding *newBinding = new QDeclarativeBinding(d->xString.value.script(), d->target, ctxt);
401             newBinding->setTarget(QDeclarativeProperty(d->target, QLatin1String("x"), ctxt));
402             QDeclarativeAction xa;
403             xa.property = newBinding->property();
404             xa.toBinding = newBinding;
405             xa.fromValue = xa.property.read();
406             xa.deletableToBinding = true;
407             actions << xa;
408         }
409     }
410
411     if (d->yString.isValid()) {
412         if (d->y.isValid()) {
413             QDeclarativeAction ya(d->target, QLatin1String("y"), ctxt, d->y.value);
414             actions << ya;
415         } else {
416             QDeclarativeBinding *newBinding = new QDeclarativeBinding(d->yString.value.script(), d->target, ctxt);
417             newBinding->setTarget(QDeclarativeProperty(d->target, QLatin1String("y"), ctxt));
418             QDeclarativeAction ya;
419             ya.property = newBinding->property();
420             ya.toBinding = newBinding;
421             ya.fromValue = ya.property.read();
422             ya.deletableToBinding = true;
423             actions << ya;
424         }
425     }
426
427     if (d->scaleString.isValid()) {
428         if (d->scale.isValid()) {
429             QDeclarativeAction sa(d->target, QLatin1String("scale"), ctxt, d->scale.value);
430             actions << sa;
431         } else {
432             QDeclarativeBinding *newBinding = new QDeclarativeBinding(d->scaleString.value.script(), d->target, ctxt);
433             newBinding->setTarget(QDeclarativeProperty(d->target, QLatin1String("scale"), ctxt));
434             QDeclarativeAction sa;
435             sa.property = newBinding->property();
436             sa.toBinding = newBinding;
437             sa.fromValue = sa.property.read();
438             sa.deletableToBinding = true;
439             actions << sa;
440         }
441     }
442
443     if (d->rotationString.isValid()) {
444         if (d->rotation.isValid()) {
445             QDeclarativeAction ra(d->target, QLatin1String("rotation"), ctxt, d->rotation.value);
446             actions << ra;
447         } else {
448             QDeclarativeBinding *newBinding = new QDeclarativeBinding(d->rotationString.value.script(), d->target, ctxt);
449             newBinding->setTarget(QDeclarativeProperty(d->target, QLatin1String("rotation"), ctxt));
450             QDeclarativeAction ra;
451             ra.property = newBinding->property();
452             ra.toBinding = newBinding;
453             ra.fromValue = ra.property.read();
454             ra.deletableToBinding = true;
455             actions << ra;
456         }
457     }
458
459     if (d->widthString.isValid()) {
460         if (d->width.isValid()) {
461             QDeclarativeAction wa(d->target, QLatin1String("width"), ctxt, d->width.value);
462             actions << wa;
463         } else {
464             QDeclarativeBinding *newBinding = new QDeclarativeBinding(d->widthString.value.script(), d->target, ctxt);
465             newBinding->setTarget(QDeclarativeProperty(d->target, QLatin1String("width"), ctxt));
466             QDeclarativeAction wa;
467             wa.property = newBinding->property();
468             wa.toBinding = newBinding;
469             wa.fromValue = wa.property.read();
470             wa.deletableToBinding = true;
471             actions << wa;
472         }
473     }
474
475     if (d->heightString.isValid()) {
476         if (d->height.isValid()) {
477             QDeclarativeAction ha(d->target, QLatin1String("height"), ctxt, d->height.value);
478             actions << ha;
479         } else {
480             QDeclarativeBinding *newBinding = new QDeclarativeBinding(d->heightString.value.script(), d->target, ctxt);
481             newBinding->setTarget(QDeclarativeProperty(d->target, QLatin1String("height"), ctxt));
482             QDeclarativeAction ha;
483             ha.property = newBinding->property();
484             ha.toBinding = newBinding;
485             ha.fromValue = ha.property.read();
486             ha.deletableToBinding = true;
487             actions << ha;
488         }
489     }
490
491     return actions;
492 }
493
494 class AccessibleFxItem : public QDeclarativeItem
495 {
496     Q_OBJECT
497     Q_DECLARE_PRIVATE_D(QGraphicsItem::d_ptr.data(), QDeclarativeItem)
498 public:
499     int siblingIndex() {
500         Q_D(QDeclarativeItem);
501         return d->siblingIndex;
502     }
503 };
504
505 void QDeclarativeParentChange::saveOriginals()
506 {
507     Q_D(QDeclarativeParentChange);
508     saveCurrentValues();
509     d->origParent = d->rewindParent;
510     d->origStackBefore = d->rewindStackBefore;
511 }
512
513 /*void QDeclarativeParentChange::copyOriginals(QDeclarativeActionEvent *other)
514 {
515     Q_D(QDeclarativeParentChange);
516     QDeclarativeParentChange *pc = static_cast<QDeclarativeParentChange*>(other);
517
518     d->origParent = pc->d_func()->rewindParent;
519     d->origStackBefore = pc->d_func()->rewindStackBefore;
520
521     saveCurrentValues();
522 }*/
523
524 void QDeclarativeParentChange::execute(Reason)
525 {
526     Q_D(QDeclarativeParentChange);
527     d->doChange(d->parent);
528 }
529
530 bool QDeclarativeParentChange::isReversable()
531 {
532     return true;
533 }
534
535 void QDeclarativeParentChange::reverse(Reason)
536 {
537     Q_D(QDeclarativeParentChange);
538     d->doChange(d->origParent, d->origStackBefore);
539 }
540
541 QString QDeclarativeParentChange::typeName() const
542 {
543     return QLatin1String("ParentChange");
544 }
545
546 bool QDeclarativeParentChange::override(QDeclarativeActionEvent*other)
547 {
548     Q_D(QDeclarativeParentChange);
549     if (other->typeName() != QLatin1String("ParentChange"))
550         return false;
551     if (QDeclarativeParentChange *otherPC = static_cast<QDeclarativeParentChange*>(other))
552         return (d->target == otherPC->object());
553     return false;
554 }
555
556 void QDeclarativeParentChange::saveCurrentValues()
557 {
558     Q_D(QDeclarativeParentChange);
559     if (!d->target) {
560         d->rewindParent = 0;
561         d->rewindStackBefore = 0;
562         return;
563     }
564
565     d->rewindParent = d->target->parentItem();
566     d->rewindStackBefore = 0;
567
568     if (!d->rewindParent)
569         return;
570
571     //try to determine the item's original stack position so we can restore it
572     int siblingIndex = ((AccessibleFxItem*)d->target)->siblingIndex() + 1;
573     QList<QGraphicsItem*> children = d->rewindParent->childItems();
574     for (int i = 0; i < children.count(); ++i) {
575         QDeclarativeItem *child = qobject_cast<QDeclarativeItem*>(children.at(i));
576         if (!child)
577             continue;
578         if (((AccessibleFxItem*)child)->siblingIndex() == siblingIndex) {
579             d->rewindStackBefore = child;
580             break;
581         }
582     }
583 }
584
585 void QDeclarativeParentChange::rewind()
586 {
587     Q_D(QDeclarativeParentChange);
588     d->doChange(d->rewindParent, d->rewindStackBefore);
589 }
590
591 class QDeclarativeStateChangeScriptPrivate : public QDeclarativeStateOperationPrivate
592 {
593 public:
594     QDeclarativeStateChangeScriptPrivate() {}
595
596     QDeclarativeScriptString script;
597     QString name;
598 };
599
600 /*!
601     \qmlclass StateChangeScript QDeclarativeStateChangeScript
602     \ingroup qml-state-elements
603     \brief The StateChangeScript element allows you to run a script in a state.
604
605     A StateChangeScript is run upon entering a state. You can optionally use
606     ScriptAction to specify the point in the transition at which
607     the StateChangeScript should to be run.
608
609     \snippet snippets/declarative/states/statechangescript.qml state and transition
610
611     \sa ScriptAction
612 */
613
614 QDeclarativeStateChangeScript::QDeclarativeStateChangeScript(QObject *parent)
615 : QDeclarativeStateOperation(*(new QDeclarativeStateChangeScriptPrivate), parent)
616 {
617 }
618
619 QDeclarativeStateChangeScript::~QDeclarativeStateChangeScript()
620 {
621 }
622
623 /*!
624     \qmlproperty script StateChangeScript::script
625     This property holds the script to run when the state is current.
626 */
627 QDeclarativeScriptString QDeclarativeStateChangeScript::script() const
628 {
629     Q_D(const QDeclarativeStateChangeScript);
630     return d->script;
631 }
632
633 void QDeclarativeStateChangeScript::setScript(const QDeclarativeScriptString &s)
634 {
635     Q_D(QDeclarativeStateChangeScript);
636     d->script = s;
637 }
638
639 /*!
640     \qmlproperty string StateChangeScript::name
641     This property holds the name of the script. This name can be used by a
642     ScriptAction to target a specific script.
643
644     \sa ScriptAction::scriptName
645 */
646 QString QDeclarativeStateChangeScript::name() const
647 {
648     Q_D(const QDeclarativeStateChangeScript);
649     return d->name;
650 }
651
652 void QDeclarativeStateChangeScript::setName(const QString &n)
653 {
654     Q_D(QDeclarativeStateChangeScript);
655     d->name = n;
656 }
657
658 void QDeclarativeStateChangeScript::execute(Reason)
659 {
660     Q_D(QDeclarativeStateChangeScript);
661     const QString &script = d->script.script();
662     if (!script.isEmpty()) {
663         QDeclarativeExpression expr(d->script.context(), d->script.scopeObject(), script);
664         QDeclarativeData *ddata = QDeclarativeData::get(this);
665         if (ddata && ddata->outerContext && !ddata->outerContext->url.isEmpty())
666             expr.setSourceLocation(ddata->outerContext->url.toString(), ddata->lineNumber);
667         expr.evaluate();
668         if (expr.hasError())
669             qmlInfo(this, expr.error());
670     }
671 }
672
673 QDeclarativeStateChangeScript::ActionList QDeclarativeStateChangeScript::actions()
674 {
675     ActionList rv;
676     QDeclarativeAction a;
677     a.event = this;
678     rv << a;
679     return rv;
680 }
681
682 QString QDeclarativeStateChangeScript::typeName() const
683 {
684     return QLatin1String("StateChangeScript");
685 }
686
687 /*!
688     \qmlclass AnchorChanges QDeclarativeAnchorChanges
689     \ingroup qml-state-elements
690     \brief The AnchorChanges element allows you to change the anchors of an item in a state.
691
692     The AnchorChanges element is used to modify the anchors of an item in a \l State.
693
694     AnchorChanges cannot be used to modify the margins on an item. For this, use
695     PropertyChanges intead.
696
697     In the following example we change the top and bottom anchors of an item
698     using AnchorChanges, and the top and bottom anchor margins using
699     PropertyChanges:
700
701     \snippet doc/src/snippets/declarative/anchorchanges.qml 0
702
703     \image anchorchanges.png
704
705     AnchorChanges can be animated using AnchorAnimation.
706     \qml
707     //animate our anchor changes
708     Transition {
709         AnchorAnimation {}
710     }
711     \endqml
712
713     Margin animations can be animated using NumberAnimation.
714
715     For more information on anchors see \l {anchor-layout}{Anchor Layouts}.
716 */
717
718 class QDeclarativeAnchorSetPrivate : public QObjectPrivate
719 {
720     Q_DECLARE_PUBLIC(QDeclarativeAnchorSet)
721 public:
722     QDeclarativeAnchorSetPrivate()
723       : usedAnchors(0), resetAnchors(0), fill(0),
724         centerIn(0)/*, leftMargin(0), rightMargin(0), topMargin(0), bottomMargin(0),
725         margins(0), vCenterOffset(0), hCenterOffset(0), baselineOffset(0)*/
726     {
727     }
728
729     QDeclarativeAnchors::Anchors usedAnchors;
730     QDeclarativeAnchors::Anchors resetAnchors;
731
732     QDeclarativeItem *fill;
733     QDeclarativeItem *centerIn;
734
735     QDeclarativeScriptString leftScript;
736     QDeclarativeScriptString rightScript;
737     QDeclarativeScriptString topScript;
738     QDeclarativeScriptString bottomScript;
739     QDeclarativeScriptString hCenterScript;
740     QDeclarativeScriptString vCenterScript;
741     QDeclarativeScriptString baselineScript;
742
743     /*qreal leftMargin;
744     qreal rightMargin;
745     qreal topMargin;
746     qreal bottomMargin;
747     qreal margins;
748     qreal vCenterOffset;
749     qreal hCenterOffset;
750     qreal baselineOffset;*/
751 };
752
753 QDeclarativeAnchorSet::QDeclarativeAnchorSet(QObject *parent)
754   : QObject(*new QDeclarativeAnchorSetPrivate, parent)
755 {
756 }
757
758 QDeclarativeAnchorSet::~QDeclarativeAnchorSet()
759 {
760 }
761
762 QDeclarativeScriptString QDeclarativeAnchorSet::top() const
763 {
764     Q_D(const QDeclarativeAnchorSet);
765     return d->topScript;
766 }
767
768 void QDeclarativeAnchorSet::setTop(const QDeclarativeScriptString &edge)
769 {
770     Q_D(QDeclarativeAnchorSet);
771     d->usedAnchors |= QDeclarativeAnchors::TopAnchor;
772     d->topScript = edge;
773     if (edge.script() == QLatin1String("undefined"))
774         resetTop();
775 }
776
777 void QDeclarativeAnchorSet::resetTop()
778 {
779     Q_D(QDeclarativeAnchorSet);
780     d->usedAnchors &= ~QDeclarativeAnchors::TopAnchor;
781     d->topScript = QDeclarativeScriptString();
782     d->resetAnchors |= QDeclarativeAnchors::TopAnchor;
783 }
784
785 QDeclarativeScriptString QDeclarativeAnchorSet::bottom() const
786 {
787     Q_D(const QDeclarativeAnchorSet);
788     return d->bottomScript;
789 }
790
791 void QDeclarativeAnchorSet::setBottom(const QDeclarativeScriptString &edge)
792 {
793     Q_D(QDeclarativeAnchorSet);
794     d->usedAnchors |= QDeclarativeAnchors::BottomAnchor;
795     d->bottomScript = edge;
796     if (edge.script() == QLatin1String("undefined"))
797         resetBottom();
798 }
799
800 void QDeclarativeAnchorSet::resetBottom()
801 {
802     Q_D(QDeclarativeAnchorSet);
803     d->usedAnchors &= ~QDeclarativeAnchors::BottomAnchor;
804     d->bottomScript = QDeclarativeScriptString();
805     d->resetAnchors |= QDeclarativeAnchors::BottomAnchor;
806 }
807
808 QDeclarativeScriptString QDeclarativeAnchorSet::verticalCenter() const
809 {
810     Q_D(const QDeclarativeAnchorSet);
811     return d->vCenterScript;
812 }
813
814 void QDeclarativeAnchorSet::setVerticalCenter(const QDeclarativeScriptString &edge)
815 {
816     Q_D(QDeclarativeAnchorSet);
817     d->usedAnchors |= QDeclarativeAnchors::VCenterAnchor;
818     d->vCenterScript = edge;
819     if (edge.script() == QLatin1String("undefined"))
820         resetVerticalCenter();
821 }
822
823 void QDeclarativeAnchorSet::resetVerticalCenter()
824 {
825     Q_D(QDeclarativeAnchorSet);
826     d->usedAnchors &= ~QDeclarativeAnchors::VCenterAnchor;
827     d->vCenterScript = QDeclarativeScriptString();
828     d->resetAnchors |= QDeclarativeAnchors::VCenterAnchor;
829 }
830
831 QDeclarativeScriptString QDeclarativeAnchorSet::baseline() const
832 {
833     Q_D(const QDeclarativeAnchorSet);
834     return d->baselineScript;
835 }
836
837 void QDeclarativeAnchorSet::setBaseline(const QDeclarativeScriptString &edge)
838 {
839     Q_D(QDeclarativeAnchorSet);
840     d->usedAnchors |= QDeclarativeAnchors::BaselineAnchor;
841     d->baselineScript = edge;
842     if (edge.script() == QLatin1String("undefined"))
843         resetBaseline();
844 }
845
846 void QDeclarativeAnchorSet::resetBaseline()
847 {
848     Q_D(QDeclarativeAnchorSet);
849     d->usedAnchors &= ~QDeclarativeAnchors::BaselineAnchor;
850     d->baselineScript = QDeclarativeScriptString();
851     d->resetAnchors |= QDeclarativeAnchors::BaselineAnchor;
852 }
853
854 QDeclarativeScriptString QDeclarativeAnchorSet::left() const
855 {
856     Q_D(const QDeclarativeAnchorSet);
857     return d->leftScript;
858 }
859
860 void QDeclarativeAnchorSet::setLeft(const QDeclarativeScriptString &edge)
861 {
862     Q_D(QDeclarativeAnchorSet);
863     d->usedAnchors |= QDeclarativeAnchors::LeftAnchor;
864     d->leftScript = edge;
865     if (edge.script() == QLatin1String("undefined"))
866         resetLeft();
867 }
868
869 void QDeclarativeAnchorSet::resetLeft()
870 {
871     Q_D(QDeclarativeAnchorSet);
872     d->usedAnchors &= ~QDeclarativeAnchors::LeftAnchor;
873     d->leftScript = QDeclarativeScriptString();
874     d->resetAnchors |= QDeclarativeAnchors::LeftAnchor;
875 }
876
877 QDeclarativeScriptString QDeclarativeAnchorSet::right() const
878 {
879     Q_D(const QDeclarativeAnchorSet);
880     return d->rightScript;
881 }
882
883 void QDeclarativeAnchorSet::setRight(const QDeclarativeScriptString &edge)
884 {
885     Q_D(QDeclarativeAnchorSet);
886     d->usedAnchors |= QDeclarativeAnchors::RightAnchor;
887     d->rightScript = edge;
888     if (edge.script() == QLatin1String("undefined"))
889         resetRight();
890 }
891
892 void QDeclarativeAnchorSet::resetRight()
893 {
894     Q_D(QDeclarativeAnchorSet);
895     d->usedAnchors &= ~QDeclarativeAnchors::RightAnchor;
896     d->rightScript = QDeclarativeScriptString();
897     d->resetAnchors |= QDeclarativeAnchors::RightAnchor;
898 }
899
900 QDeclarativeScriptString QDeclarativeAnchorSet::horizontalCenter() const
901 {
902     Q_D(const QDeclarativeAnchorSet);
903     return d->hCenterScript;
904 }
905
906 void QDeclarativeAnchorSet::setHorizontalCenter(const QDeclarativeScriptString &edge)
907 {
908     Q_D(QDeclarativeAnchorSet);
909     d->usedAnchors |= QDeclarativeAnchors::HCenterAnchor;
910     d->hCenterScript = edge;
911     if (edge.script() == QLatin1String("undefined"))
912         resetHorizontalCenter();
913 }
914
915 void QDeclarativeAnchorSet::resetHorizontalCenter()
916 {
917     Q_D(QDeclarativeAnchorSet);
918     d->usedAnchors &= ~QDeclarativeAnchors::HCenterAnchor;
919     d->hCenterScript = QDeclarativeScriptString();
920     d->resetAnchors |= QDeclarativeAnchors::HCenterAnchor;
921 }
922
923 QDeclarativeItem *QDeclarativeAnchorSet::fill() const
924 {
925     Q_D(const QDeclarativeAnchorSet);
926     return d->fill;
927 }
928
929 void QDeclarativeAnchorSet::setFill(QDeclarativeItem *f)
930 {
931     Q_D(QDeclarativeAnchorSet);
932     d->fill = f;
933 }
934
935 void QDeclarativeAnchorSet::resetFill()
936 {
937     setFill(0);
938 }
939
940 QDeclarativeItem *QDeclarativeAnchorSet::centerIn() const
941 {
942     Q_D(const QDeclarativeAnchorSet);
943     return d->centerIn;
944 }
945
946 void QDeclarativeAnchorSet::setCenterIn(QDeclarativeItem* c)
947 {
948     Q_D(QDeclarativeAnchorSet);
949     d->centerIn = c;
950 }
951
952 void QDeclarativeAnchorSet::resetCenterIn()
953 {
954     setCenterIn(0);
955 }
956
957
958 class QDeclarativeAnchorChangesPrivate : public QDeclarativeStateOperationPrivate
959 {
960 public:
961     QDeclarativeAnchorChangesPrivate()
962         : target(0), anchorSet(new QDeclarativeAnchorSet),
963           leftBinding(0), rightBinding(0), hCenterBinding(0),
964           topBinding(0), bottomBinding(0), vCenterBinding(0), baselineBinding(0),
965           origLeftBinding(0), origRightBinding(0), origHCenterBinding(0),
966           origTopBinding(0), origBottomBinding(0), origVCenterBinding(0),
967           origBaselineBinding(0)
968     {
969
970     }
971     ~QDeclarativeAnchorChangesPrivate() { delete anchorSet; }
972
973     QDeclarativeItem *target;
974     QDeclarativeAnchorSet *anchorSet;
975
976     QDeclarativeBinding *leftBinding;
977     QDeclarativeBinding *rightBinding;
978     QDeclarativeBinding *hCenterBinding;
979     QDeclarativeBinding *topBinding;
980     QDeclarativeBinding *bottomBinding;
981     QDeclarativeBinding *vCenterBinding;
982     QDeclarativeBinding *baselineBinding;
983
984     QDeclarativeAbstractBinding *origLeftBinding;
985     QDeclarativeAbstractBinding *origRightBinding;
986     QDeclarativeAbstractBinding *origHCenterBinding;
987     QDeclarativeAbstractBinding *origTopBinding;
988     QDeclarativeAbstractBinding *origBottomBinding;
989     QDeclarativeAbstractBinding *origVCenterBinding;
990     QDeclarativeAbstractBinding *origBaselineBinding;
991
992     QDeclarativeAnchorLine rewindLeft;
993     QDeclarativeAnchorLine rewindRight;
994     QDeclarativeAnchorLine rewindHCenter;
995     QDeclarativeAnchorLine rewindTop;
996     QDeclarativeAnchorLine rewindBottom;
997     QDeclarativeAnchorLine rewindVCenter;
998     QDeclarativeAnchorLine rewindBaseline;
999
1000     qreal fromX;
1001     qreal fromY;
1002     qreal fromWidth;
1003     qreal fromHeight;
1004
1005     qreal toX;
1006     qreal toY;
1007     qreal toWidth;
1008     qreal toHeight;
1009
1010     qreal rewindX;
1011     qreal rewindY;
1012     qreal rewindWidth;
1013     qreal rewindHeight;
1014
1015     bool applyOrigLeft;
1016     bool applyOrigRight;
1017     bool applyOrigHCenter;
1018     bool applyOrigTop;
1019     bool applyOrigBottom;
1020     bool applyOrigVCenter;
1021     bool applyOrigBaseline;
1022
1023     QDeclarativeNullableValue<qreal> origWidth;
1024     QDeclarativeNullableValue<qreal> origHeight;
1025     qreal origX;
1026     qreal origY;
1027
1028     QList<QDeclarativeAbstractBinding*> oldBindings;
1029
1030     QDeclarativeProperty leftProp;
1031     QDeclarativeProperty rightProp;
1032     QDeclarativeProperty hCenterProp;
1033     QDeclarativeProperty topProp;
1034     QDeclarativeProperty bottomProp;
1035     QDeclarativeProperty vCenterProp;
1036     QDeclarativeProperty baselineProp;
1037 };
1038
1039 /*!
1040     \qmlproperty Item AnchorChanges::target
1041     This property holds the \l Item for which the anchor changes will be applied.
1042 */
1043
1044 QDeclarativeAnchorChanges::QDeclarativeAnchorChanges(QObject *parent)
1045  : QDeclarativeStateOperation(*(new QDeclarativeAnchorChangesPrivate), parent)
1046 {
1047 }
1048
1049 QDeclarativeAnchorChanges::~QDeclarativeAnchorChanges()
1050 {
1051 }
1052
1053 QDeclarativeAnchorChanges::ActionList QDeclarativeAnchorChanges::actions()
1054 {
1055     Q_D(QDeclarativeAnchorChanges);
1056     d->leftBinding = d->rightBinding = d->hCenterBinding = d->topBinding
1057                    = d->bottomBinding = d->vCenterBinding = d->baselineBinding = 0;
1058
1059     d->leftProp = QDeclarativeProperty(d->target, QLatin1String("anchors.left"));
1060     d->rightProp = QDeclarativeProperty(d->target, QLatin1String("anchors.right"));
1061     d->hCenterProp = QDeclarativeProperty(d->target, QLatin1String("anchors.horizontalCenter"));
1062     d->topProp = QDeclarativeProperty(d->target, QLatin1String("anchors.top"));
1063     d->bottomProp = QDeclarativeProperty(d->target, QLatin1String("anchors.bottom"));
1064     d->vCenterProp = QDeclarativeProperty(d->target, QLatin1String("anchors.verticalCenter"));
1065     d->baselineProp = QDeclarativeProperty(d->target, QLatin1String("anchors.baseline"));
1066
1067     QDeclarativeContext *ctxt = qmlContext(this);
1068
1069     if (d->anchorSet->d_func()->usedAnchors & QDeclarativeAnchors::LeftAnchor) {
1070         d->leftBinding = new QDeclarativeBinding(d->anchorSet->d_func()->leftScript.script(), d->target, ctxt);
1071         d->leftBinding->setTarget(d->leftProp);
1072     }
1073     if (d->anchorSet->d_func()->usedAnchors & QDeclarativeAnchors::RightAnchor) {
1074         d->rightBinding = new QDeclarativeBinding(d->anchorSet->d_func()->rightScript.script(), d->target, ctxt);
1075         d->rightBinding->setTarget(d->rightProp);
1076     }
1077     if (d->anchorSet->d_func()->usedAnchors & QDeclarativeAnchors::HCenterAnchor) {
1078         d->hCenterBinding = new QDeclarativeBinding(d->anchorSet->d_func()->hCenterScript.script(), d->target, ctxt);
1079         d->hCenterBinding->setTarget(d->hCenterProp);
1080     }
1081     if (d->anchorSet->d_func()->usedAnchors & QDeclarativeAnchors::TopAnchor) {
1082         d->topBinding = new QDeclarativeBinding(d->anchorSet->d_func()->topScript.script(), d->target, ctxt);
1083         d->topBinding->setTarget(d->topProp);
1084     }
1085     if (d->anchorSet->d_func()->usedAnchors & QDeclarativeAnchors::BottomAnchor) {
1086         d->bottomBinding = new QDeclarativeBinding(d->anchorSet->d_func()->bottomScript.script(), d->target, ctxt);
1087         d->bottomBinding->setTarget(d->bottomProp);
1088     }
1089     if (d->anchorSet->d_func()->usedAnchors & QDeclarativeAnchors::VCenterAnchor) {
1090         d->vCenterBinding = new QDeclarativeBinding(d->anchorSet->d_func()->vCenterScript.script(), d->target, ctxt);
1091         d->vCenterBinding->setTarget(d->vCenterProp);
1092     }
1093     if (d->anchorSet->d_func()->usedAnchors & QDeclarativeAnchors::BaselineAnchor) {
1094         d->baselineBinding = new QDeclarativeBinding(d->anchorSet->d_func()->baselineScript.script(), d->target, ctxt);
1095         d->baselineBinding->setTarget(d->baselineProp);
1096     }
1097
1098     QDeclarativeAction a;
1099     a.event = this;
1100     return ActionList() << a;
1101 }
1102
1103 QDeclarativeAnchorSet *QDeclarativeAnchorChanges::anchors()
1104 {
1105     Q_D(QDeclarativeAnchorChanges);
1106     return d->anchorSet;
1107 }
1108
1109 QDeclarativeItem *QDeclarativeAnchorChanges::object() const
1110 {
1111     Q_D(const QDeclarativeAnchorChanges);
1112     return d->target;
1113 }
1114
1115 void QDeclarativeAnchorChanges::setObject(QDeclarativeItem *target)
1116 {
1117     Q_D(QDeclarativeAnchorChanges);
1118     d->target = target;
1119 }
1120
1121 /*!
1122     \qmlproperty AnchorLine AnchorChanges::anchors.left
1123     \qmlproperty AnchorLine AnchorChanges::anchors.right
1124     \qmlproperty AnchorLine AnchorChanges::anchors.horizontalCenter
1125     \qmlproperty AnchorLine AnchorChanges::anchors.top
1126     \qmlproperty AnchorLine AnchorChanges::anchors.bottom
1127     \qmlproperty AnchorLine AnchorChanges::anchors.verticalCenter
1128     \qmlproperty AnchorLine AnchorChanges::anchors.baseline
1129
1130     These properties change the respective anchors of the item.
1131
1132     To reset an anchor you can assign \c undefined:
1133     \qml
1134     AnchorChanges {
1135         target: myItem
1136         anchors.left: undefined          //remove myItem's left anchor
1137         anchors.right: otherItem.right
1138     }
1139     \endqml
1140 */
1141
1142 void QDeclarativeAnchorChanges::execute(Reason reason)
1143 {
1144     Q_D(QDeclarativeAnchorChanges);
1145     if (!d->target)
1146         return;
1147
1148     QDeclarativeItemPrivate *targetPrivate = QDeclarativeItemPrivate::get(d->target);
1149     //incorporate any needed "reverts"
1150     if (d->applyOrigLeft) {
1151         if (!d->origLeftBinding)
1152             targetPrivate->anchors()->resetLeft();
1153         QDeclarativePropertyPrivate::setBinding(d->leftProp, d->origLeftBinding);
1154     }
1155     if (d->applyOrigRight) {
1156         if (!d->origRightBinding)
1157             targetPrivate->anchors()->resetRight();
1158         QDeclarativePropertyPrivate::setBinding(d->rightProp, d->origRightBinding);
1159     }
1160     if (d->applyOrigHCenter) {
1161         if (!d->origHCenterBinding)
1162             targetPrivate->anchors()->resetHorizontalCenter();
1163         QDeclarativePropertyPrivate::setBinding(d->hCenterProp, d->origHCenterBinding);
1164     }
1165     if (d->applyOrigTop) {
1166         if (!d->origTopBinding)
1167             targetPrivate->anchors()->resetTop();
1168         QDeclarativePropertyPrivate::setBinding(d->topProp, d->origTopBinding);
1169     }
1170     if (d->applyOrigBottom) {
1171         if (!d->origBottomBinding)
1172             targetPrivate->anchors()->resetBottom();
1173         QDeclarativePropertyPrivate::setBinding(d->bottomProp, d->origBottomBinding);
1174     }
1175     if (d->applyOrigVCenter) {
1176         if (!d->origVCenterBinding)
1177             targetPrivate->anchors()->resetVerticalCenter();
1178         QDeclarativePropertyPrivate::setBinding(d->vCenterProp, d->origVCenterBinding);
1179     }
1180     if (d->applyOrigBaseline) {
1181         if (!d->origBaselineBinding)
1182             targetPrivate->anchors()->resetBaseline();
1183         QDeclarativePropertyPrivate::setBinding(d->baselineProp, d->origBaselineBinding);
1184     }
1185
1186     //destroy old bindings
1187     if (reason == ActualChange) {
1188         for (int i = 0; i < d->oldBindings.size(); ++i) {
1189             QDeclarativeAbstractBinding *binding = d->oldBindings.at(i);
1190             if (binding)
1191                 binding->destroy();
1192         }
1193         d->oldBindings.clear();
1194     }
1195
1196     //reset any anchors that have been specified as "undefined"
1197     if (d->anchorSet->d_func()->resetAnchors & QDeclarativeAnchors::LeftAnchor) {
1198         targetPrivate->anchors()->resetLeft();
1199         QDeclarativePropertyPrivate::setBinding(d->leftProp, 0);
1200     }
1201     if (d->anchorSet->d_func()->resetAnchors & QDeclarativeAnchors::RightAnchor) {
1202         targetPrivate->anchors()->resetRight();
1203         QDeclarativePropertyPrivate::setBinding(d->rightProp, 0);
1204     }
1205     if (d->anchorSet->d_func()->resetAnchors & QDeclarativeAnchors::HCenterAnchor) {
1206         targetPrivate->anchors()->resetHorizontalCenter();
1207         QDeclarativePropertyPrivate::setBinding(d->hCenterProp, 0);
1208     }
1209     if (d->anchorSet->d_func()->resetAnchors & QDeclarativeAnchors::TopAnchor) {
1210         targetPrivate->anchors()->resetTop();
1211         QDeclarativePropertyPrivate::setBinding(d->topProp, 0);
1212     }
1213     if (d->anchorSet->d_func()->resetAnchors & QDeclarativeAnchors::BottomAnchor) {
1214         targetPrivate->anchors()->resetBottom();
1215         QDeclarativePropertyPrivate::setBinding(d->bottomProp, 0);
1216     }
1217     if (d->anchorSet->d_func()->resetAnchors & QDeclarativeAnchors::VCenterAnchor) {
1218         targetPrivate->anchors()->resetVerticalCenter();
1219         QDeclarativePropertyPrivate::setBinding(d->vCenterProp, 0);
1220     }
1221     if (d->anchorSet->d_func()->resetAnchors & QDeclarativeAnchors::BaselineAnchor) {
1222         targetPrivate->anchors()->resetBaseline();
1223         QDeclarativePropertyPrivate::setBinding(d->baselineProp, 0);
1224     }
1225
1226     //set any anchors that have been specified
1227     if (d->leftBinding)
1228         QDeclarativePropertyPrivate::setBinding(d->leftBinding->property(), d->leftBinding);
1229     if (d->rightBinding)
1230         QDeclarativePropertyPrivate::setBinding(d->rightBinding->property(), d->rightBinding);
1231     if (d->hCenterBinding)
1232         QDeclarativePropertyPrivate::setBinding(d->hCenterBinding->property(), d->hCenterBinding);
1233     if (d->topBinding)
1234         QDeclarativePropertyPrivate::setBinding(d->topBinding->property(), d->topBinding);
1235     if (d->bottomBinding)
1236         QDeclarativePropertyPrivate::setBinding(d->bottomBinding->property(), d->bottomBinding);
1237     if (d->vCenterBinding)
1238         QDeclarativePropertyPrivate::setBinding(d->vCenterBinding->property(), d->vCenterBinding);
1239     if (d->baselineBinding)
1240         QDeclarativePropertyPrivate::setBinding(d->baselineBinding->property(), d->baselineBinding);
1241 }
1242
1243 bool QDeclarativeAnchorChanges::isReversable()
1244 {
1245     return true;
1246 }
1247
1248 void QDeclarativeAnchorChanges::reverse(Reason reason)
1249 {
1250     Q_D(QDeclarativeAnchorChanges);
1251     if (!d->target)
1252         return;
1253
1254     QDeclarativeItemPrivate *targetPrivate = QDeclarativeItemPrivate::get(d->target);
1255     //reset any anchors set by the state
1256     if (d->leftBinding) {
1257         targetPrivate->anchors()->resetLeft();
1258         QDeclarativePropertyPrivate::setBinding(d->leftBinding->property(), 0);
1259         if (reason == ActualChange) {
1260             d->leftBinding->destroy(); d->leftBinding = 0;
1261         }
1262     }
1263     if (d->rightBinding) {
1264         targetPrivate->anchors()->resetRight();
1265         QDeclarativePropertyPrivate::setBinding(d->rightBinding->property(), 0);
1266         if (reason == ActualChange) {
1267             d->rightBinding->destroy(); d->rightBinding = 0;
1268         }
1269     }
1270     if (d->hCenterBinding) {
1271         targetPrivate->anchors()->resetHorizontalCenter();
1272         QDeclarativePropertyPrivate::setBinding(d->hCenterBinding->property(), 0);
1273         if (reason == ActualChange) {
1274             d->hCenterBinding->destroy(); d->hCenterBinding = 0;
1275         }
1276     }
1277     if (d->topBinding) {
1278         targetPrivate->anchors()->resetTop();
1279         QDeclarativePropertyPrivate::setBinding(d->topBinding->property(), 0);
1280         if (reason == ActualChange) {
1281             d->topBinding->destroy(); d->topBinding = 0;
1282         }
1283     }
1284     if (d->bottomBinding) {
1285         targetPrivate->anchors()->resetBottom();
1286         QDeclarativePropertyPrivate::setBinding(d->bottomBinding->property(), 0);
1287         if (reason == ActualChange) {
1288             d->bottomBinding->destroy(); d->bottomBinding = 0;
1289         }
1290     }
1291     if (d->vCenterBinding) {
1292         targetPrivate->anchors()->resetVerticalCenter();
1293         QDeclarativePropertyPrivate::setBinding(d->vCenterBinding->property(), 0);
1294         if (reason == ActualChange) {
1295             d->vCenterBinding->destroy(); d->vCenterBinding = 0;
1296         }
1297     }
1298     if (d->baselineBinding) {
1299         targetPrivate->anchors()->resetBaseline();
1300         QDeclarativePropertyPrivate::setBinding(d->baselineBinding->property(), 0);
1301         if (reason == ActualChange) {
1302             d->baselineBinding->destroy(); d->baselineBinding = 0;
1303         }
1304     }
1305
1306     //restore previous anchors
1307     if (d->origLeftBinding)
1308         QDeclarativePropertyPrivate::setBinding(d->leftProp, d->origLeftBinding);
1309     if (d->origRightBinding)
1310         QDeclarativePropertyPrivate::setBinding(d->rightProp, d->origRightBinding);
1311     if (d->origHCenterBinding)
1312         QDeclarativePropertyPrivate::setBinding(d->hCenterProp, d->origHCenterBinding);
1313     if (d->origTopBinding)
1314         QDeclarativePropertyPrivate::setBinding(d->topProp, d->origTopBinding);
1315     if (d->origBottomBinding)
1316         QDeclarativePropertyPrivate::setBinding(d->bottomProp, d->origBottomBinding);
1317     if (d->origVCenterBinding)
1318         QDeclarativePropertyPrivate::setBinding(d->vCenterProp, d->origVCenterBinding);
1319     if (d->origBaselineBinding)
1320         QDeclarativePropertyPrivate::setBinding(d->baselineProp, d->origBaselineBinding);
1321
1322     //restore any absolute geometry changed by the state's anchors
1323     QDeclarativeAnchors::Anchors stateVAnchors = d->anchorSet->d_func()->usedAnchors & QDeclarativeAnchors::Vertical_Mask;
1324     QDeclarativeAnchors::Anchors origVAnchors = targetPrivate->anchors()->usedAnchors() & QDeclarativeAnchors::Vertical_Mask;
1325     QDeclarativeAnchors::Anchors stateHAnchors = d->anchorSet->d_func()->usedAnchors & QDeclarativeAnchors::Horizontal_Mask;
1326     QDeclarativeAnchors::Anchors origHAnchors = targetPrivate->anchors()->usedAnchors() & QDeclarativeAnchors::Horizontal_Mask;
1327
1328     bool stateSetWidth = (stateHAnchors &&
1329                           stateHAnchors != QDeclarativeAnchors::LeftAnchor &&
1330                           stateHAnchors != QDeclarativeAnchors::RightAnchor &&
1331                           stateHAnchors != QDeclarativeAnchors::HCenterAnchor);
1332     bool origSetWidth = (origHAnchors &&
1333                          origHAnchors != QDeclarativeAnchors::LeftAnchor &&
1334                          origHAnchors != QDeclarativeAnchors::RightAnchor &&
1335                          origHAnchors != QDeclarativeAnchors::HCenterAnchor);
1336     if (d->origWidth.isValid() && stateSetWidth && !origSetWidth)
1337         d->target->setWidth(d->origWidth.value);
1338
1339     bool stateSetHeight = (stateVAnchors &&
1340                            stateVAnchors != QDeclarativeAnchors::TopAnchor &&
1341                            stateVAnchors != QDeclarativeAnchors::BottomAnchor &&
1342                            stateVAnchors != QDeclarativeAnchors::VCenterAnchor &&
1343                            stateVAnchors != QDeclarativeAnchors::BaselineAnchor);
1344     bool origSetHeight = (origVAnchors &&
1345                           origVAnchors != QDeclarativeAnchors::TopAnchor &&
1346                           origVAnchors != QDeclarativeAnchors::BottomAnchor &&
1347                           origVAnchors != QDeclarativeAnchors::VCenterAnchor &&
1348                           origVAnchors != QDeclarativeAnchors::BaselineAnchor);
1349     if (d->origHeight.isValid() && stateSetHeight && !origSetHeight)
1350         d->target->setHeight(d->origHeight.value);
1351
1352     if (stateHAnchors && !origHAnchors)
1353         d->target->setX(d->origX);
1354
1355     if (stateVAnchors && !origVAnchors)
1356         d->target->setY(d->origY);
1357 }
1358
1359 QString QDeclarativeAnchorChanges::typeName() const
1360 {
1361     return QLatin1String("AnchorChanges");
1362 }
1363
1364 QList<QDeclarativeAction> QDeclarativeAnchorChanges::additionalActions()
1365 {
1366     Q_D(QDeclarativeAnchorChanges);
1367     QList<QDeclarativeAction> extra;
1368
1369     QDeclarativeAnchors::Anchors combined = d->anchorSet->d_func()->usedAnchors | d->anchorSet->d_func()->resetAnchors;
1370     bool hChange = combined & QDeclarativeAnchors::Horizontal_Mask;
1371     bool vChange = combined & QDeclarativeAnchors::Vertical_Mask;
1372
1373     if (d->target) {
1374         QDeclarativeContext *ctxt = qmlContext(this);
1375         QDeclarativeAction a;
1376         if (hChange && d->fromX != d->toX) {
1377             a.property = QDeclarativeProperty(d->target, QLatin1String("x"), ctxt);
1378             a.toValue = d->toX;
1379             extra << a;
1380         }
1381         if (vChange && d->fromY != d->toY) {
1382             a.property = QDeclarativeProperty(d->target, QLatin1String("y"), ctxt);
1383             a.toValue = d->toY;
1384             extra << a;
1385         }
1386         if (hChange && d->fromWidth != d->toWidth) {
1387             a.property = QDeclarativeProperty(d->target, QLatin1String("width"), ctxt);
1388             a.toValue = d->toWidth;
1389             extra << a;
1390         }
1391         if (vChange && d->fromHeight != d->toHeight) {
1392             a.property = QDeclarativeProperty(d->target, QLatin1String("height"), ctxt);
1393             a.toValue = d->toHeight;
1394             extra << a;
1395         }
1396     }
1397
1398     return extra;
1399 }
1400
1401 bool QDeclarativeAnchorChanges::changesBindings()
1402 {
1403     return true;
1404 }
1405
1406 void QDeclarativeAnchorChanges::saveOriginals()
1407 {
1408     Q_D(QDeclarativeAnchorChanges);
1409     if (!d->target)
1410         return;
1411
1412     d->origLeftBinding = QDeclarativePropertyPrivate::binding(d->leftProp);
1413     d->origRightBinding = QDeclarativePropertyPrivate::binding(d->rightProp);
1414     d->origHCenterBinding = QDeclarativePropertyPrivate::binding(d->hCenterProp);
1415     d->origTopBinding = QDeclarativePropertyPrivate::binding(d->topProp);
1416     d->origBottomBinding = QDeclarativePropertyPrivate::binding(d->bottomProp);
1417     d->origVCenterBinding = QDeclarativePropertyPrivate::binding(d->vCenterProp);
1418     d->origBaselineBinding = QDeclarativePropertyPrivate::binding(d->baselineProp);
1419
1420     QDeclarativeItemPrivate *targetPrivate = QDeclarativeItemPrivate::get(d->target);
1421     if (targetPrivate->widthValid)
1422         d->origWidth = d->target->width();
1423     if (targetPrivate->heightValid)
1424         d->origHeight = d->target->height();
1425     d->origX = d->target->x();
1426     d->origY = d->target->y();
1427
1428     d->applyOrigLeft = d->applyOrigRight = d->applyOrigHCenter = d->applyOrigTop
1429       = d->applyOrigBottom = d->applyOrigVCenter = d->applyOrigBaseline = false;
1430
1431     saveCurrentValues();
1432 }
1433
1434 void QDeclarativeAnchorChanges::copyOriginals(QDeclarativeActionEvent *other)
1435 {
1436     Q_D(QDeclarativeAnchorChanges);
1437     QDeclarativeAnchorChanges *ac = static_cast<QDeclarativeAnchorChanges*>(other);
1438     QDeclarativeAnchorChangesPrivate *acp = ac->d_func();
1439
1440     QDeclarativeAnchors::Anchors combined = acp->anchorSet->d_func()->usedAnchors |
1441                                             acp->anchorSet->d_func()->resetAnchors;
1442
1443     //probably also need to revert some things
1444     d->applyOrigLeft = (combined & QDeclarativeAnchors::LeftAnchor);
1445     d->applyOrigRight = (combined & QDeclarativeAnchors::RightAnchor);
1446     d->applyOrigHCenter = (combined & QDeclarativeAnchors::HCenterAnchor);
1447     d->applyOrigTop = (combined & QDeclarativeAnchors::TopAnchor);
1448     d->applyOrigBottom = (combined & QDeclarativeAnchors::BottomAnchor);
1449     d->applyOrigVCenter = (combined & QDeclarativeAnchors::VCenterAnchor);
1450     d->applyOrigBaseline = (combined & QDeclarativeAnchors::BaselineAnchor);
1451
1452     d->origLeftBinding = acp->origLeftBinding;
1453     d->origRightBinding = acp->origRightBinding;
1454     d->origHCenterBinding = acp->origHCenterBinding;
1455     d->origTopBinding = acp->origTopBinding;
1456     d->origBottomBinding = acp->origBottomBinding;
1457     d->origVCenterBinding = acp->origVCenterBinding;
1458     d->origBaselineBinding = acp->origBaselineBinding;
1459
1460     d->origWidth = acp->origWidth;
1461     d->origHeight = acp->origHeight;
1462     d->origX = acp->origX;
1463     d->origY = acp->origY;
1464
1465     d->oldBindings.clear();
1466     d->oldBindings << acp->leftBinding << acp->rightBinding << acp->hCenterBinding
1467                 << acp->topBinding << acp->bottomBinding << acp->baselineBinding;
1468
1469     saveCurrentValues();
1470 }
1471
1472 void QDeclarativeAnchorChanges::clearBindings()
1473 {
1474     Q_D(QDeclarativeAnchorChanges);
1475     if (!d->target)
1476         return;
1477
1478     //### should this (saving "from" values) be moved to saveCurrentValues()?
1479     d->fromX = d->target->x();
1480     d->fromY = d->target->y();
1481     d->fromWidth = d->target->width();
1482     d->fromHeight = d->target->height();
1483
1484     QDeclarativeItemPrivate *targetPrivate = QDeclarativeItemPrivate::get(d->target);
1485     //reset any anchors with corresponding reverts
1486     //reset any anchors that have been specified as "undefined"
1487     //reset any anchors that we'll be setting in the state
1488     QDeclarativeAnchors::Anchors combined = d->anchorSet->d_func()->resetAnchors |
1489                                             d->anchorSet->d_func()->usedAnchors;
1490     if (d->applyOrigLeft || (combined & QDeclarativeAnchors::LeftAnchor)) {
1491         targetPrivate->anchors()->resetLeft();
1492         QDeclarativePropertyPrivate::setBinding(d->leftProp, 0);
1493     }
1494     if (d->applyOrigRight || (combined & QDeclarativeAnchors::RightAnchor)) {
1495         targetPrivate->anchors()->resetRight();
1496         QDeclarativePropertyPrivate::setBinding(d->rightProp, 0);
1497     }
1498     if (d->applyOrigHCenter || (combined & QDeclarativeAnchors::HCenterAnchor)) {
1499         targetPrivate->anchors()->resetHorizontalCenter();
1500         QDeclarativePropertyPrivate::setBinding(d->hCenterProp, 0);
1501     }
1502     if (d->applyOrigTop || (combined & QDeclarativeAnchors::TopAnchor)) {
1503         targetPrivate->anchors()->resetTop();
1504         QDeclarativePropertyPrivate::setBinding(d->topProp, 0);
1505     }
1506     if (d->applyOrigBottom || (combined & QDeclarativeAnchors::BottomAnchor)) {
1507         targetPrivate->anchors()->resetBottom();
1508         QDeclarativePropertyPrivate::setBinding(d->bottomProp, 0);
1509     }
1510     if (d->applyOrigVCenter || (combined & QDeclarativeAnchors::VCenterAnchor)) {
1511         targetPrivate->anchors()->resetVerticalCenter();
1512         QDeclarativePropertyPrivate::setBinding(d->vCenterProp, 0);
1513     }
1514     if (d->applyOrigBaseline || (combined & QDeclarativeAnchors::BaselineAnchor)) {
1515         targetPrivate->anchors()->resetBaseline();
1516         QDeclarativePropertyPrivate::setBinding(d->baselineProp, 0);
1517     }
1518 }
1519
1520 bool QDeclarativeAnchorChanges::override(QDeclarativeActionEvent*other)
1521 {
1522     if (other->typeName() != QLatin1String("AnchorChanges"))
1523         return false;
1524     if (static_cast<QDeclarativeActionEvent*>(this) == other)
1525         return true;
1526     if (static_cast<QDeclarativeAnchorChanges*>(other)->object() == object())
1527         return true;
1528     return false;
1529 }
1530
1531 void QDeclarativeAnchorChanges::rewind()
1532 {
1533     Q_D(QDeclarativeAnchorChanges);
1534     if (!d->target)
1535         return;
1536
1537     QDeclarativeItemPrivate *targetPrivate = QDeclarativeItemPrivate::get(d->target);
1538
1539     //restore previous values (but not previous bindings, i.e. anchors)
1540     d->target->setX(d->rewindX);
1541     d->target->setY(d->rewindY);
1542     if (targetPrivate->widthValid) {
1543         d->target->setWidth(d->rewindWidth);
1544     }
1545     if (targetPrivate->heightValid) {
1546         d->target->setHeight(d->rewindHeight);
1547     }
1548 }
1549
1550 void QDeclarativeAnchorChanges::saveCurrentValues()
1551 {
1552     Q_D(QDeclarativeAnchorChanges);
1553     if (!d->target)
1554         return;
1555
1556     QDeclarativeItemPrivate *targetPrivate = QDeclarativeItemPrivate::get(d->target);
1557     d->rewindLeft = targetPrivate->anchors()->left();
1558     d->rewindRight = targetPrivate->anchors()->right();
1559     d->rewindHCenter = targetPrivate->anchors()->horizontalCenter();
1560     d->rewindTop = targetPrivate->anchors()->top();
1561     d->rewindBottom = targetPrivate->anchors()->bottom();
1562     d->rewindVCenter = targetPrivate->anchors()->verticalCenter();
1563     d->rewindBaseline = targetPrivate->anchors()->baseline();
1564
1565     d->rewindX = d->target->x();
1566     d->rewindY = d->target->y();
1567     d->rewindWidth = d->target->width();
1568     d->rewindHeight = d->target->height();
1569 }
1570
1571 void QDeclarativeAnchorChanges::saveTargetValues()
1572 {
1573     Q_D(QDeclarativeAnchorChanges);
1574     if (!d->target)
1575         return;
1576
1577     d->toX = d->target->x();
1578     d->toY = d->target->y();
1579     d->toWidth = d->target->width();
1580     d->toHeight = d->target->height();
1581 }
1582
1583 #include <qdeclarativestateoperations.moc>
1584 #include <moc_qdeclarativestateoperations_p.cpp>
1585
1586 QT_END_NAMESPACE
1587