src/declarative/util/qdeclarativestate.cpp
changeset 30 5dc02b23752f
child 33 3e2da88830cd
equal deleted inserted replaced
29:b72c6db6890b 30:5dc02b23752f
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2010 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/qdeclarativestate_p_p.h"
       
    43 #include "private/qdeclarativestate_p.h"
       
    44 
       
    45 #include "private/qdeclarativetransition_p.h"
       
    46 #include "private/qdeclarativestategroup_p.h"
       
    47 #include "private/qdeclarativestateoperations_p.h"
       
    48 #include "private/qdeclarativeanimation_p.h"
       
    49 #include "private/qdeclarativeanimation_p_p.h"
       
    50 
       
    51 #include <qdeclarativebinding_p.h>
       
    52 #include <qdeclarativeglobal_p.h>
       
    53 
       
    54 #include <QtCore/qdebug.h>
       
    55 
       
    56 QT_BEGIN_NAMESPACE
       
    57 
       
    58 DEFINE_BOOL_CONFIG_OPTION(stateChangeDebug, STATECHANGE_DEBUG);
       
    59 
       
    60 QDeclarativeAction::QDeclarativeAction()
       
    61 : restore(true), actionDone(false), reverseEvent(false), deletableToBinding(false), fromBinding(0), toBinding(0), event(0),
       
    62   specifiedObject(0)
       
    63 {
       
    64 }
       
    65 
       
    66 QDeclarativeAction::QDeclarativeAction(QObject *target, const QString &propertyName,
       
    67                const QVariant &value)
       
    68 : restore(true), actionDone(false), reverseEvent(false), deletableToBinding(false), 
       
    69   property(target, propertyName), toValue(value), 
       
    70   fromBinding(0), toBinding(0), event(0), 
       
    71   specifiedObject(target), specifiedProperty(propertyName)
       
    72 {
       
    73     if (property.isValid())
       
    74         fromValue = property.read();
       
    75 }
       
    76 
       
    77 QDeclarativeAction::QDeclarativeAction(QObject *target, const QString &propertyName,
       
    78                QDeclarativeContext *context, const QVariant &value)
       
    79 : restore(true), actionDone(false), reverseEvent(false), deletableToBinding(false),
       
    80   property(target, propertyName, context), toValue(value),
       
    81   fromBinding(0), toBinding(0), event(0),
       
    82   specifiedObject(target), specifiedProperty(propertyName)
       
    83 {
       
    84     if (property.isValid())
       
    85         fromValue = property.read();
       
    86 }
       
    87 
       
    88 
       
    89 QDeclarativeActionEvent::~QDeclarativeActionEvent()
       
    90 {
       
    91 }
       
    92 
       
    93 QString QDeclarativeActionEvent::typeName() const
       
    94 {
       
    95     return QString();
       
    96 }
       
    97 
       
    98 void QDeclarativeActionEvent::execute(Reason)
       
    99 {
       
   100 }
       
   101 
       
   102 bool QDeclarativeActionEvent::isReversable()
       
   103 {
       
   104     return false;
       
   105 }
       
   106 
       
   107 void QDeclarativeActionEvent::reverse(Reason)
       
   108 {
       
   109 }
       
   110 
       
   111 bool QDeclarativeActionEvent::changesBindings()
       
   112 {
       
   113     return false;
       
   114 }
       
   115 
       
   116 void QDeclarativeActionEvent::clearBindings()
       
   117 {
       
   118 }
       
   119 
       
   120 bool QDeclarativeActionEvent::override(QDeclarativeActionEvent *other)
       
   121 {
       
   122     Q_UNUSED(other);
       
   123     return false;
       
   124 }
       
   125 
       
   126 /*!
       
   127     \internal
       
   128 */
       
   129 QDeclarativeStateOperation::QDeclarativeStateOperation(QObjectPrivate &dd, QObject *parent)
       
   130     : QObject(dd, parent)
       
   131 {
       
   132 }
       
   133 
       
   134 /*!
       
   135     \qmlclass State QDeclarativeState
       
   136     \since 4.7
       
   137     \brief The State element defines configurations of objects and properties.
       
   138 
       
   139     A state is specified as a set of batched changes from the default configuration.
       
   140 
       
   141     \note setting the state of an object from within another state of the same object is
       
   142     not allowed.
       
   143 
       
   144     \sa {qmlstates}{States}, {state-transitions}{Transitions}, QtDeclarative
       
   145 */
       
   146 
       
   147 /*!
       
   148     \internal
       
   149     \class QDeclarativeState
       
   150     \brief The QDeclarativeState class allows you to define configurations of objects and properties.
       
   151 
       
   152 
       
   153     QDeclarativeState allows you to specify a state as a set of batched changes from the default
       
   154     configuration.
       
   155 
       
   156     \sa {states-transitions}{States and Transitions}
       
   157 */
       
   158 
       
   159 
       
   160 QDeclarativeState::QDeclarativeState(QObject *parent)
       
   161 : QObject(*(new QDeclarativeStatePrivate), parent)
       
   162 {
       
   163     Q_D(QDeclarativeState);
       
   164     d->transitionManager.setState(this);
       
   165 }
       
   166 
       
   167 QDeclarativeState::~QDeclarativeState()
       
   168 {
       
   169     Q_D(QDeclarativeState);
       
   170     if (d->group)
       
   171         d->group->removeState(this);
       
   172 }
       
   173 
       
   174 /*!
       
   175     \qmlproperty string State::name
       
   176     This property holds the name of the state
       
   177 
       
   178     Each state should have a unique name.
       
   179 */
       
   180 QString QDeclarativeState::name() const
       
   181 {
       
   182     Q_D(const QDeclarativeState);
       
   183     return d->name;
       
   184 }
       
   185 
       
   186 void QDeclarativeState::setName(const QString &n)
       
   187 {
       
   188     Q_D(QDeclarativeState);
       
   189     d->name = n;
       
   190 }
       
   191 
       
   192 bool QDeclarativeState::isWhenKnown() const
       
   193 {
       
   194     Q_D(const QDeclarativeState);
       
   195     return d->when != 0;
       
   196 }
       
   197 
       
   198 /*!
       
   199     \qmlproperty bool State::when
       
   200     This property holds when the state should be applied
       
   201 
       
   202     This should be set to an expression that evaluates to true when you want the state to
       
   203     be applied.
       
   204 
       
   205     If multiple states in a group have \c when clauses that evaluate to true at the same time,
       
   206     the first matching state will be applied. For example, in the following snippet
       
   207     \c state1 will always be selected rather than \c state2 when sharedCondition becomes
       
   208     \c true.
       
   209     \qml
       
   210     states: [
       
   211         State { name: "state1"; when: sharedCondition },
       
   212         State { name: "state2"; when: sharedCondition }
       
   213     ]
       
   214     \endqml
       
   215 */
       
   216 QDeclarativeBinding *QDeclarativeState::when() const
       
   217 {
       
   218     Q_D(const QDeclarativeState);
       
   219     return d->when;
       
   220 }
       
   221 
       
   222 void QDeclarativeState::setWhen(QDeclarativeBinding *when)
       
   223 {
       
   224     Q_D(QDeclarativeState);
       
   225     d->when = when;
       
   226     if (d->group)
       
   227         d->group->updateAutoState();
       
   228 }
       
   229 
       
   230 /*!
       
   231     \qmlproperty string State::extend
       
   232     This property holds the state that this state extends
       
   233 
       
   234     The state being extended is treated as the base state in regards to
       
   235     the changes specified by the extending state.
       
   236 */
       
   237 QString QDeclarativeState::extends() const
       
   238 {
       
   239     Q_D(const QDeclarativeState);
       
   240     return d->extends;
       
   241 }
       
   242 
       
   243 void QDeclarativeState::setExtends(const QString &extends)
       
   244 {
       
   245     Q_D(QDeclarativeState);
       
   246     d->extends = extends;
       
   247 }
       
   248 
       
   249 /*!
       
   250     \qmlproperty list<Change> State::changes
       
   251     This property holds the changes to apply for this state
       
   252     \default
       
   253 
       
   254     By default these changes are applied against the default state. If the state
       
   255     extends another state, then the changes are applied against the state being
       
   256     extended.
       
   257 */
       
   258 QDeclarativeListProperty<QDeclarativeStateOperation> QDeclarativeState::changes()
       
   259 {
       
   260     Q_D(QDeclarativeState);
       
   261     return QDeclarativeListProperty<QDeclarativeStateOperation>(this, &d->operations, QDeclarativeStatePrivate::operations_append,
       
   262                                               QDeclarativeStatePrivate::operations_count, QDeclarativeStatePrivate::operations_at,
       
   263                                               QDeclarativeStatePrivate::operations_clear);
       
   264 }
       
   265 
       
   266 int QDeclarativeState::operationCount() const
       
   267 {
       
   268     Q_D(const QDeclarativeState);
       
   269     return d->operations.count();
       
   270 }
       
   271 
       
   272 QDeclarativeStateOperation *QDeclarativeState::operationAt(int index) const
       
   273 {
       
   274     Q_D(const QDeclarativeState);
       
   275     return d->operations.at(index);
       
   276 }
       
   277 
       
   278 QDeclarativeState &QDeclarativeState::operator<<(QDeclarativeStateOperation *op)
       
   279 {
       
   280     Q_D(QDeclarativeState);
       
   281     d->operations.append(QDeclarativeStatePrivate::OperationGuard(op, &d->operations));
       
   282     return *this;
       
   283 }
       
   284 
       
   285 void QDeclarativeStatePrivate::complete()
       
   286 {
       
   287     Q_Q(QDeclarativeState);
       
   288 
       
   289     for (int ii = 0; ii < reverting.count(); ++ii) {
       
   290         for (int jj = 0; jj < revertList.count(); ++jj) {
       
   291             if (revertList.at(jj).property == reverting.at(ii)) {
       
   292                 revertList.removeAt(jj);
       
   293                 break;
       
   294             }
       
   295         }
       
   296     }
       
   297     reverting.clear();
       
   298 
       
   299     emit q->completed();
       
   300 }
       
   301 
       
   302 // Generate a list of actions for this state.  This includes coelescing state
       
   303 // actions that this state "extends"
       
   304 QDeclarativeStateOperation::ActionList
       
   305 QDeclarativeStatePrivate::generateActionList(QDeclarativeStateGroup *group) const
       
   306 {
       
   307     QDeclarativeStateOperation::ActionList applyList;
       
   308     if (inState)
       
   309         return applyList;
       
   310 
       
   311     // Prevent "extends" recursion
       
   312     inState = true;
       
   313 
       
   314     if (!extends.isEmpty()) {
       
   315         QList<QDeclarativeState *> states = group->states();
       
   316         for (int ii = 0; ii < states.count(); ++ii)
       
   317             if (states.at(ii)->name() == extends)
       
   318                 applyList = static_cast<QDeclarativeStatePrivate*>(states.at(ii)->d_func())->generateActionList(group);
       
   319     }
       
   320 
       
   321     foreach(QDeclarativeStateOperation *op, operations)
       
   322         applyList << op->actions();
       
   323 
       
   324     inState = false;
       
   325     return applyList;
       
   326 }
       
   327 
       
   328 QDeclarativeStateGroup *QDeclarativeState::stateGroup() const
       
   329 {
       
   330     Q_D(const QDeclarativeState);
       
   331     return d->group;
       
   332 }
       
   333 
       
   334 void QDeclarativeState::setStateGroup(QDeclarativeStateGroup *group)
       
   335 {
       
   336     Q_D(QDeclarativeState);
       
   337     d->group = group;
       
   338 }
       
   339 
       
   340 void QDeclarativeState::cancel()
       
   341 {
       
   342     Q_D(QDeclarativeState);
       
   343     d->transitionManager.cancel();
       
   344 }
       
   345 
       
   346 void QDeclarativeAction::deleteFromBinding()
       
   347 {
       
   348     if (fromBinding) {
       
   349         QDeclarativePropertyPrivate::setBinding(property, 0);
       
   350         fromBinding->destroy();
       
   351         fromBinding = 0;
       
   352     }
       
   353 }
       
   354 
       
   355 void QDeclarativeState::apply(QDeclarativeStateGroup *group, QDeclarativeTransition *trans, QDeclarativeState *revert)
       
   356 {
       
   357     Q_D(QDeclarativeState);
       
   358 
       
   359     qmlExecuteDeferred(this);
       
   360 
       
   361     cancel();
       
   362     if (revert)
       
   363         revert->cancel();
       
   364     d->revertList.clear();
       
   365     d->reverting.clear();
       
   366 
       
   367     if (revert) {
       
   368         QDeclarativeStatePrivate *revertPrivate =
       
   369             static_cast<QDeclarativeStatePrivate*>(revert->d_func());
       
   370         d->revertList = revertPrivate->revertList;
       
   371         revertPrivate->revertList.clear();
       
   372     }
       
   373 
       
   374     // List of actions caused by this state
       
   375     QDeclarativeStateOperation::ActionList applyList = d->generateActionList(group);
       
   376 
       
   377     // List of actions that need to be reverted to roll back (just) this state
       
   378     QDeclarativeStatePrivate::SimpleActionList additionalReverts;
       
   379     // First add the reverse of all the applyList actions
       
   380     for (int ii = 0; ii < applyList.count(); ++ii) {
       
   381         QDeclarativeAction &action = applyList[ii];
       
   382 
       
   383         if (action.event) {
       
   384             if (!action.event->isReversable())
       
   385                 continue;
       
   386             bool found = false;
       
   387             for (int jj = 0; jj < d->revertList.count(); ++jj) {
       
   388                 QDeclarativeActionEvent *event = d->revertList.at(jj).event;
       
   389                 if (event && event->typeName() == action.event->typeName()) {
       
   390                     if (action.event->override(event)) {
       
   391                         found = true;
       
   392 
       
   393                         if (action.event != d->revertList.at(jj).event && action.event->needsCopy()) {
       
   394                             action.event->copyOriginals(d->revertList.at(jj).event);
       
   395 
       
   396                             QDeclarativeSimpleAction r(action);
       
   397                             additionalReverts << r;
       
   398                             d->revertList.removeAt(jj);
       
   399                             --jj;
       
   400                         } else if (action.event->isRewindable())    //###why needed?
       
   401                             action.event->saveCurrentValues();
       
   402 
       
   403                         break;
       
   404                     }
       
   405                 }
       
   406             }
       
   407             if (!found) {
       
   408                 action.event->saveOriginals();
       
   409                 // Only need to revert the applyList action if the previous
       
   410                 // state doesn't have a higher priority revert already
       
   411                 QDeclarativeSimpleAction r(action);
       
   412                 additionalReverts << r;
       
   413             }
       
   414         } else {
       
   415             bool found = false;
       
   416             action.fromBinding = QDeclarativePropertyPrivate::binding(action.property);
       
   417 
       
   418             for (int jj = 0; jj < d->revertList.count(); ++jj) {
       
   419                 if (d->revertList.at(jj).property == action.property) {
       
   420                     found = true;
       
   421                     if (d->revertList.at(jj).binding != action.fromBinding) {
       
   422                         action.deleteFromBinding();
       
   423                     }
       
   424                     break;
       
   425                 }
       
   426             }
       
   427 
       
   428             if (!found) {
       
   429                 if (!action.restore) {
       
   430                     action.deleteFromBinding();
       
   431                 } else {
       
   432                     // Only need to revert the applyList action if the previous
       
   433                     // state doesn't have a higher priority revert already
       
   434                     QDeclarativeSimpleAction r(action);
       
   435                     additionalReverts << r;
       
   436                 }
       
   437             }
       
   438         }
       
   439     }
       
   440 
       
   441     // Any reverts from a previous state that aren't carried forth
       
   442     // into this state need to be translated into apply actions
       
   443     for (int ii = 0; ii < d->revertList.count(); ++ii) {
       
   444         bool found = false;
       
   445         if (d->revertList.at(ii).event) {
       
   446             QDeclarativeActionEvent *event = d->revertList.at(ii).event;
       
   447             if (!event->isReversable())
       
   448                 continue;
       
   449             for (int jj = 0; !found && jj < applyList.count(); ++jj) {
       
   450                 const QDeclarativeAction &action = applyList.at(jj);
       
   451                 if (action.event && action.event->typeName() == event->typeName()) {
       
   452                     if (action.event->override(event))
       
   453                         found = true;
       
   454                 }
       
   455             }
       
   456         } else {
       
   457             for (int jj = 0; !found && jj < applyList.count(); ++jj) {
       
   458                 const QDeclarativeAction &action = applyList.at(jj);
       
   459                 if (action.property == d->revertList.at(ii).property)
       
   460                     found = true;
       
   461             }
       
   462         }
       
   463         if (!found) {
       
   464             QVariant cur = d->revertList.at(ii).property.read();
       
   465             QDeclarativeAbstractBinding *delBinding = 
       
   466                 QDeclarativePropertyPrivate::setBinding(d->revertList.at(ii).property, 0);
       
   467             if (delBinding)
       
   468                 delBinding->destroy();
       
   469 
       
   470             QDeclarativeAction a;
       
   471             a.property = d->revertList.at(ii).property;
       
   472             a.fromValue = cur;
       
   473             a.toValue = d->revertList.at(ii).value;
       
   474             a.toBinding = d->revertList.at(ii).binding;
       
   475             a.specifiedObject = d->revertList.at(ii).specifiedObject;
       
   476             a.specifiedProperty = d->revertList.at(ii).specifiedProperty;
       
   477             a.event = d->revertList.at(ii).event;
       
   478             a.reverseEvent = d->revertList.at(ii).reverseEvent;
       
   479             if (a.event && a.event->isRewindable())
       
   480                 a.event->saveCurrentValues();
       
   481             applyList << a;
       
   482             // Store these special reverts in the reverting list
       
   483             d->reverting << d->revertList.at(ii).property;
       
   484         }
       
   485     }
       
   486     // All the local reverts now become part of the ongoing revertList
       
   487     d->revertList << additionalReverts;
       
   488 
       
   489     // Output for debugging
       
   490     if (stateChangeDebug()) {
       
   491         foreach(const QDeclarativeAction &action, applyList) {
       
   492             if (action.event)
       
   493                 qWarning() << "    QDeclarativeAction event:" << action.event->typeName();
       
   494             else
       
   495                 qWarning() << "    QDeclarativeAction:" << action.property.object()
       
   496                            << action.property.name() << "From:" << action.fromValue 
       
   497                            << "To:" << action.toValue;
       
   498         }
       
   499     }
       
   500 
       
   501     d->transitionManager.transition(applyList, trans);
       
   502 }
       
   503 
       
   504 QDeclarativeStateOperation::ActionList QDeclarativeStateOperation::actions()
       
   505 {
       
   506     return ActionList();
       
   507 }
       
   508 
       
   509 QT_END_NAMESPACE