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