1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include "QtQuick1/private/qdeclarativestate_p_p.h"
43 #include "QtQuick1/private/qdeclarativestate_p.h"
45 #include "QtQuick1/private/qdeclarativetransition_p.h"
46 #include "QtQuick1/private/qdeclarativestategroup_p.h"
47 #include "QtQuick1/private/qdeclarativestateoperations_p.h"
48 #include "QtQuick1/private/qdeclarativeanimation_p.h"
49 #include "QtQuick1/private/qdeclarativeanimation_p_p.h"
51 #include <QtDeclarative/private/qdeclarativebinding_p.h>
52 #include <QtDeclarative/private/qdeclarativeglobal_p.h>
54 #include <QtCore/qdebug.h>
60 DEFINE_BOOL_CONFIG_OPTION(stateChangeDebug, STATECHANGE_DEBUG);
62 QDeclarative1Action::QDeclarative1Action()
63 : restore(true), actionDone(false), reverseEvent(false), deletableToBinding(false), fromBinding(0), event(0),
68 QDeclarative1Action::QDeclarative1Action(QObject *target, const QString &propertyName,
69 const QVariant &value)
70 : restore(true), actionDone(false), reverseEvent(false), deletableToBinding(false),
71 property(target, propertyName, qmlEngine(target)), toValue(value),
72 fromBinding(0), event(0),
73 specifiedObject(target), specifiedProperty(propertyName)
75 if (property.isValid())
76 fromValue = property.read();
79 QDeclarative1Action::QDeclarative1Action(QObject *target, const QString &propertyName,
80 QDeclarativeContext *context, const QVariant &value)
81 : restore(true), actionDone(false), reverseEvent(false), deletableToBinding(false),
82 property(target, propertyName, context), toValue(value),
83 fromBinding(0), event(0),
84 specifiedObject(target), specifiedProperty(propertyName)
86 if (property.isValid())
87 fromValue = property.read();
91 QDeclarative1ActionEvent::~QDeclarative1ActionEvent()
95 QString QDeclarative1ActionEvent::typeName() const
100 void QDeclarative1ActionEvent::execute(Reason)
104 bool QDeclarative1ActionEvent::isReversable()
109 void QDeclarative1ActionEvent::reverse(Reason)
113 bool QDeclarative1ActionEvent::changesBindings()
118 void QDeclarative1ActionEvent::clearBindings()
122 bool QDeclarative1ActionEvent::override(QDeclarative1ActionEvent *other)
128 QDeclarative1StateOperation::QDeclarative1StateOperation(QObjectPrivate &dd, QObject *parent)
129 : QObject(dd, parent)
134 \qmlclass State QDeclarative1State
135 \inqmlmodule QtQuick 1
136 \ingroup qml-state-elements
138 \brief The State element defines configurations of objects and properties.
140 A \e state is a set of batched changes from the default configuration.
142 All items have a default state that defines the default configuration of objects
143 and property values. New states can be defined by adding State items to the \l {Item::states}{states} property to
144 allow items to switch between different configurations. These configurations
145 can, for example, be used to apply different sets of property values or execute
148 The following example displays a single \l Rectangle. In the default state, the rectangle
149 is colored black. In the "clicked" state, a PropertyChanges element changes the
150 rectangle's color to red. Clicking within the MouseArea toggles the rectangle's state
151 between the default state and the "clicked" state, thus toggling the color of the
152 rectangle between black and red.
154 \snippet doc/src/snippets/qtquick1/state.qml 0
156 Notice the default state is referred to using an empty string ("").
158 States are commonly used together with \l{QML Animation and Transitions}{Transitions} to provide
159 animations when state changes occur.
161 \note Setting the state of an object from within another state of the same object is
164 \sa {declarative/animation/states}{states example}, {qmlstates}{States},
165 {QML Animation and Transitions}{Transitions}, QtDeclarative
167 QDeclarative1State::QDeclarative1State(QObject *parent)
168 : QObject(*(new QDeclarative1StatePrivate), parent)
170 Q_D(QDeclarative1State);
171 d->transitionManager.setState(this);
174 QDeclarative1State::~QDeclarative1State()
176 Q_D(QDeclarative1State);
178 d->group->removeState(this);
182 \qmlproperty string QtQuick1::State::name
183 This property holds the name of the state.
185 Each state should have a unique name within its item.
187 QString QDeclarative1State::name() const
189 Q_D(const QDeclarative1State);
193 void QDeclarative1State::setName(const QString &n)
195 Q_D(QDeclarative1State);
200 bool QDeclarative1State::isNamed() const
202 Q_D(const QDeclarative1State);
206 bool QDeclarative1State::isWhenKnown() const
208 Q_D(const QDeclarative1State);
213 \qmlproperty bool QtQuick1::State::when
214 This property holds when the state should be applied.
216 This should be set to an expression that evaluates to \c true when you want the state to
217 be applied. For example, the following \l Rectangle changes in and out of the "hidden"
218 state when the \l MouseArea is pressed:
220 \snippet doc/src/snippets/qtquick1/state-when.qml 0
222 If multiple states in a group have \c when clauses that evaluate to \c true
223 at the same time, the first matching state will be applied. For example, in
224 the following snippet \c state1 will always be selected rather than
225 \c state2 when sharedCondition becomes \c true.
229 State { name: "state1"; when: sharedCondition },
230 State { name: "state2"; when: sharedCondition }
236 QDeclarativeBinding *QDeclarative1State::when() const
238 Q_D(const QDeclarative1State);
242 void QDeclarative1State::setWhen(QDeclarativeBinding *when)
244 Q_D(QDeclarative1State);
247 d->group->updateAutoState();
251 \qmlproperty string QtQuick1::State::extend
252 This property holds the state that this state extends.
254 When a state extends another state, it inherits all the changes of that state.
256 The state being extended is treated as the base state in regards to
257 the changes specified by the extending state.
259 QString QDeclarative1State::extends() const
261 Q_D(const QDeclarative1State);
265 void QDeclarative1State::setExtends(const QString &extends)
267 Q_D(QDeclarative1State);
268 d->extends = extends;
272 \qmlproperty list<Change> QtQuick1::State::changes
273 This property holds the changes to apply for this state
276 By default these changes are applied against the default state. If the state
277 extends another state, then the changes are applied against the state being
280 QDeclarativeListProperty<QDeclarative1StateOperation> QDeclarative1State::changes()
282 Q_D(QDeclarative1State);
283 return QDeclarativeListProperty<QDeclarative1StateOperation>(this, &d->operations, QDeclarative1StatePrivate::operations_append,
284 QDeclarative1StatePrivate::operations_count, QDeclarative1StatePrivate::operations_at,
285 QDeclarative1StatePrivate::operations_clear);
288 int QDeclarative1State::operationCount() const
290 Q_D(const QDeclarative1State);
291 return d->operations.count();
294 QDeclarative1StateOperation *QDeclarative1State::operationAt(int index) const
296 Q_D(const QDeclarative1State);
297 return d->operations.at(index);
300 QDeclarative1State &QDeclarative1State::operator<<(QDeclarative1StateOperation *op)
302 Q_D(QDeclarative1State);
303 d->operations.append(QDeclarative1StatePrivate::OperationGuard(op, &d->operations));
307 void QDeclarative1StatePrivate::complete()
309 Q_Q(QDeclarative1State);
311 for (int ii = 0; ii < reverting.count(); ++ii) {
312 for (int jj = 0; jj < revertList.count(); ++jj) {
313 if (revertList.at(jj).property() == reverting.at(ii)) {
314 revertList.removeAt(jj);
324 // Generate a list of actions for this state. This includes coelescing state
325 // actions that this state "extends"
326 QDeclarative1StateOperation::ActionList
327 QDeclarative1StatePrivate::generateActionList(QDeclarative1StateGroup *group) const
329 QDeclarative1StateOperation::ActionList applyList;
333 // Prevent "extends" recursion
336 if (!extends.isEmpty()) {
337 QList<QDeclarative1State *> states = group->states();
338 for (int ii = 0; ii < states.count(); ++ii)
339 if (states.at(ii)->name() == extends) {
340 qmlExecuteDeferred(states.at(ii));
341 applyList = static_cast<QDeclarative1StatePrivate*>(states.at(ii)->d_func())->generateActionList(group);
345 foreach(QDeclarative1StateOperation *op, operations)
346 applyList << op->actions();
352 QDeclarative1StateGroup *QDeclarative1State::stateGroup() const
354 Q_D(const QDeclarative1State);
358 void QDeclarative1State::setStateGroup(QDeclarative1StateGroup *group)
360 Q_D(QDeclarative1State);
364 void QDeclarative1State::cancel()
366 Q_D(QDeclarative1State);
367 d->transitionManager.cancel();
370 void QDeclarative1Action::deleteFromBinding()
373 QDeclarativePropertyPrivate::setBinding(property, 0);
374 fromBinding->destroy();
379 bool QDeclarative1State::containsPropertyInRevertList(QObject *target, const QString &name) const
381 Q_D(const QDeclarative1State);
383 if (isStateActive()) {
384 QListIterator<QDeclarative1SimpleAction> revertListIterator(d->revertList);
386 while (revertListIterator.hasNext()) {
387 const QDeclarative1SimpleAction &simpleAction = revertListIterator.next();
388 if (simpleAction.specifiedObject() == target && simpleAction.specifiedProperty() == name)
396 bool QDeclarative1State::changeValueInRevertList(QObject *target, const QString &name, const QVariant &revertValue)
398 Q_D(QDeclarative1State);
400 if (isStateActive()) {
401 QMutableListIterator<QDeclarative1SimpleAction> revertListIterator(d->revertList);
403 while (revertListIterator.hasNext()) {
404 QDeclarative1SimpleAction &simpleAction = revertListIterator.next();
405 if (simpleAction.specifiedObject() == target && simpleAction.specifiedProperty() == name) {
406 simpleAction.setValue(revertValue);
415 bool QDeclarative1State::changeBindingInRevertList(QObject *target, const QString &name, QDeclarativeAbstractBinding *binding)
417 Q_D(QDeclarative1State);
419 if (isStateActive()) {
420 QMutableListIterator<QDeclarative1SimpleAction> revertListIterator(d->revertList);
422 while (revertListIterator.hasNext()) {
423 QDeclarative1SimpleAction &simpleAction = revertListIterator.next();
424 if (simpleAction.specifiedObject() == target && simpleAction.specifiedProperty() == name) {
425 if (simpleAction.binding())
426 simpleAction.binding()->destroy();
428 simpleAction.setBinding(binding);
437 bool QDeclarative1State::removeEntryFromRevertList(QObject *target, const QString &name)
439 Q_D(QDeclarative1State);
441 if (isStateActive()) {
442 QMutableListIterator<QDeclarative1SimpleAction> revertListIterator(d->revertList);
444 while (revertListIterator.hasNext()) {
445 QDeclarative1SimpleAction &simpleAction = revertListIterator.next();
446 if (simpleAction.property().object() == target && simpleAction.property().name() == name) {
447 QDeclarativeAbstractBinding *oldBinding = QDeclarativePropertyPrivate::binding(simpleAction.property());
449 QDeclarativePropertyPrivate::setBinding(simpleAction.property(), 0);
450 oldBinding->destroy();
453 simpleAction.property().write(simpleAction.value());
454 if (simpleAction.binding())
455 QDeclarativePropertyPrivate::setBinding(simpleAction.property(), simpleAction.binding());
457 revertListIterator.remove();
466 void QDeclarative1State::addEntryToRevertList(const QDeclarative1Action &action)
468 Q_D(QDeclarative1State);
470 QDeclarative1SimpleAction simpleAction(action);
472 d->revertList.append(simpleAction);
475 void QDeclarative1State::removeAllEntriesFromRevertList(QObject *target)
477 Q_D(QDeclarative1State);
479 if (isStateActive()) {
480 QMutableListIterator<QDeclarative1SimpleAction> revertListIterator(d->revertList);
482 while (revertListIterator.hasNext()) {
483 QDeclarative1SimpleAction &simpleAction = revertListIterator.next();
484 if (simpleAction.property().object() == target) {
485 QDeclarativeAbstractBinding *oldBinding = QDeclarativePropertyPrivate::binding(simpleAction.property());
487 QDeclarativePropertyPrivate::setBinding(simpleAction.property(), 0);
488 oldBinding->destroy();
491 simpleAction.property().write(simpleAction.value());
492 if (simpleAction.binding())
493 QDeclarativePropertyPrivate::setBinding(simpleAction.property(), simpleAction.binding());
495 revertListIterator.remove();
501 void QDeclarative1State::addEntriesToRevertList(const QList<QDeclarative1Action> &actionList)
503 Q_D(QDeclarative1State);
504 if (isStateActive()) {
505 QList<QDeclarative1SimpleAction> simpleActionList;
507 QListIterator<QDeclarative1Action> actionListIterator(actionList);
508 while(actionListIterator.hasNext()) {
509 const QDeclarative1Action &action = actionListIterator.next();
510 QDeclarative1SimpleAction simpleAction(action);
511 action.property.write(action.toValue);
512 if (!action.toBinding.isNull()) {
513 QDeclarativeAbstractBinding *oldBinding = QDeclarativePropertyPrivate::binding(simpleAction.property());
515 QDeclarativePropertyPrivate::setBinding(simpleAction.property(), 0);
516 QDeclarativePropertyPrivate::setBinding(simpleAction.property(), action.toBinding.data(), QDeclarativePropertyPrivate::DontRemoveBinding);
519 simpleActionList.append(simpleAction);
522 d->revertList.append(simpleActionList);
526 QVariant QDeclarative1State::valueInRevertList(QObject *target, const QString &name) const
528 Q_D(const QDeclarative1State);
530 if (isStateActive()) {
531 QListIterator<QDeclarative1SimpleAction> revertListIterator(d->revertList);
533 while (revertListIterator.hasNext()) {
534 const QDeclarative1SimpleAction &simpleAction = revertListIterator.next();
535 if (simpleAction.specifiedObject() == target && simpleAction.specifiedProperty() == name)
536 return simpleAction.value();
543 QDeclarativeAbstractBinding *QDeclarative1State::bindingInRevertList(QObject *target, const QString &name) const
545 Q_D(const QDeclarative1State);
547 if (isStateActive()) {
548 QListIterator<QDeclarative1SimpleAction> revertListIterator(d->revertList);
550 while (revertListIterator.hasNext()) {
551 const QDeclarative1SimpleAction &simpleAction = revertListIterator.next();
552 if (simpleAction.specifiedObject() == target && simpleAction.specifiedProperty() == name)
553 return simpleAction.binding();
560 bool QDeclarative1State::isStateActive() const
562 return stateGroup() && stateGroup()->state() == name();
565 void QDeclarative1State::apply(QDeclarative1StateGroup *group, QDeclarative1Transition *trans, QDeclarative1State *revert)
567 Q_D(QDeclarative1State);
569 qmlExecuteDeferred(this);
574 d->revertList.clear();
575 d->reverting.clear();
578 QDeclarative1StatePrivate *revertPrivate =
579 static_cast<QDeclarative1StatePrivate*>(revert->d_func());
580 d->revertList = revertPrivate->revertList;
581 revertPrivate->revertList.clear();
584 // List of actions caused by this state
585 QDeclarative1StateOperation::ActionList applyList = d->generateActionList(group);
587 // List of actions that need to be reverted to roll back (just) this state
588 QDeclarative1StatePrivate::SimpleActionList additionalReverts;
589 // First add the reverse of all the applyList actions
590 for (int ii = 0; ii < applyList.count(); ++ii) {
591 QDeclarative1Action &action = applyList[ii];
594 if (!action.event->isReversable())
597 for (int jj = 0; jj < d->revertList.count(); ++jj) {
598 QDeclarative1ActionEvent *event = d->revertList.at(jj).event();
599 if (event && event->typeName() == action.event->typeName()) {
600 if (action.event->override(event)) {
603 if (action.event != d->revertList.at(jj).event() && action.event->needsCopy()) {
604 action.event->copyOriginals(d->revertList.at(jj).event());
606 QDeclarative1SimpleAction r(action);
607 additionalReverts << r;
608 d->revertList.removeAt(jj);
610 } else if (action.event->isRewindable()) //###why needed?
611 action.event->saveCurrentValues();
618 action.event->saveOriginals();
619 // Only need to revert the applyList action if the previous
620 // state doesn't have a higher priority revert already
621 QDeclarative1SimpleAction r(action);
622 additionalReverts << r;
626 action.fromBinding = QDeclarativePropertyPrivate::binding(action.property);
628 for (int jj = 0; jj < d->revertList.count(); ++jj) {
629 if (d->revertList.at(jj).property() == action.property) {
631 if (d->revertList.at(jj).binding() != action.fromBinding) {
632 action.deleteFromBinding();
639 if (!action.restore) {
640 action.deleteFromBinding();;
642 // Only need to revert the applyList action if the previous
643 // state doesn't have a higher priority revert already
644 QDeclarative1SimpleAction r(action);
645 additionalReverts << r;
651 // Any reverts from a previous state that aren't carried forth
652 // into this state need to be translated into apply actions
653 for (int ii = 0; ii < d->revertList.count(); ++ii) {
655 if (d->revertList.at(ii).event()) {
656 QDeclarative1ActionEvent *event = d->revertList.at(ii).event();
657 if (!event->isReversable())
659 for (int jj = 0; !found && jj < applyList.count(); ++jj) {
660 const QDeclarative1Action &action = applyList.at(jj);
661 if (action.event && action.event->typeName() == event->typeName()) {
662 if (action.event->override(event))
667 for (int jj = 0; !found && jj < applyList.count(); ++jj) {
668 const QDeclarative1Action &action = applyList.at(jj);
669 if (action.property == d->revertList.at(ii).property())
674 QVariant cur = d->revertList.at(ii).property().read();
675 QDeclarativeAbstractBinding *delBinding =
676 QDeclarativePropertyPrivate::setBinding(d->revertList.at(ii).property(), 0);
678 delBinding->destroy();
680 QDeclarative1Action a;
681 a.property = d->revertList.at(ii).property();
683 a.toValue = d->revertList.at(ii).value();
684 a.toBinding = QDeclarativeAbstractBinding::getPointer(d->revertList.at(ii).binding());
685 a.specifiedObject = d->revertList.at(ii).specifiedObject();
686 a.specifiedProperty = d->revertList.at(ii).specifiedProperty();
687 a.event = d->revertList.at(ii).event();
688 a.reverseEvent = d->revertList.at(ii).reverseEvent();
689 if (a.event && a.event->isRewindable())
690 a.event->saveCurrentValues();
692 // Store these special reverts in the reverting list
693 d->reverting << d->revertList.at(ii).property();
696 // All the local reverts now become part of the ongoing revertList
697 d->revertList << additionalReverts;
699 #ifndef QT_NO_DEBUG_STREAM
700 // Output for debugging
701 if (stateChangeDebug()) {
702 foreach(const QDeclarative1Action &action, applyList) {
704 qWarning() << " QDeclarative1Action event:" << action.event->typeName();
706 qWarning() << " QDeclarative1Action:" << action.property.object()
707 << action.property.name() << "From:" << action.fromValue
708 << "To:" << action.toValue;
713 d->transitionManager.transition(applyList, trans);
716 QDeclarative1StateOperation::ActionList QDeclarative1StateOperation::actions()
721 QDeclarative1State *QDeclarative1StateOperation::state() const
723 Q_D(const QDeclarative1StateOperation);
727 void QDeclarative1StateOperation::setState(QDeclarative1State *state)
729 Q_D(QDeclarative1StateOperation);