Qt 4.8
qdeclarativestate.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
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 Digia. For licensing terms and
14 ** conditions see http://qt.digia.com/licensing. For further information
15 ** use the contact form at http://qt.digia.com/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 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights. These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file. Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
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 
57 
58 DEFINE_BOOL_CONFIG_OPTION(stateChangeDebug, STATECHANGE_DEBUG);
59 
61 : restore(true), actionDone(false), reverseEvent(false), deletableToBinding(false), fromBinding(0), event(0),
62  specifiedObject(0)
63 {
64 }
65 
67  const QVariant &value)
68 : restore(true), actionDone(false), reverseEvent(false), deletableToBinding(false),
69  property(target, propertyName, qmlEngine(target)), toValue(value),
70  fromBinding(0), event(0),
71  specifiedObject(target), specifiedProperty(propertyName)
72 {
73  if (property.isValid())
75 }
76 
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), event(0),
82  specifiedObject(target), specifiedProperty(propertyName)
83 {
84  if (property.isValid())
86 }
87 
88 
90 {
91 }
92 
94 {
95  return QString();
96 }
97 
99 {
100 }
101 
103 {
104  return false;
105 }
106 
108 {
109 }
110 
112 {
113  return false;
114 }
115 
117 {
118 }
119 
121 {
122  Q_UNUSED(other);
123  return false;
124 }
125 
127  : QObject(dd, parent)
128 {
129 }
130 
168 : QObject(*(new QDeclarativeStatePrivate), parent)
169 {
171  d->transitionManager.setState(this);
172 }
173 
175 {
177  if (d->group)
178  d->group->removeState(this);
179 
180  /*
181  destroying an active state does not return us to the
182  base state, so we need to clean up our revert list to
183  prevent leaks. In the future we may want to redconsider
184  this overall architecture.
185  */
186  for (int i = 0; i < d->revertList.count(); ++i) {
187  if (d->revertList.at(i).binding()) {
188  d->revertList.at(i).binding()->destroy();
189  }
190  }
191 }
192 
203 {
204  Q_D(const QDeclarativeState);
205  return d->name;
206 }
207 
209 {
211  d->name = n;
212  d->named = true;
213 }
214 
216 {
217  Q_D(const QDeclarativeState);
218  return d->named;
219 }
220 
222 {
223  Q_D(const QDeclarativeState);
224  return d->when != 0;
225 }
226 
255 {
256  Q_D(const QDeclarativeState);
257  return d->when;
258 }
259 
261 {
263  d->when = when;
264  if (d->group)
265  d->group->updateAutoState();
266 }
267 
281 {
282  Q_D(const QDeclarativeState);
283  return d->extends;
284 }
285 
287 {
289  d->extends = extends;
290 }
291 
305 {
310 }
311 
313 {
314  Q_D(const QDeclarativeState);
315  return d->operations.count();
316 }
317 
319 {
320  Q_D(const QDeclarativeState);
321  return d->operations.at(index);
322 }
323 
325 {
327  d->operations.append(QDeclarativeStatePrivate::OperationGuard(op, &d->operations));
328  return *this;
329 }
330 
332 {
334 
335  for (int ii = 0; ii < reverting.count(); ++ii) {
336  for (int jj = 0; jj < revertList.count(); ++jj) {
337  if (revertList.at(jj).property() == reverting.at(ii)) {
338  revertList.removeAt(jj);
339  break;
340  }
341  }
342  }
343  reverting.clear();
344 
345  emit q->completed();
346 }
347 
348 // Generate a list of actions for this state. This includes coelescing state
349 // actions that this state "extends"
352 {
354  if (inState)
355  return applyList;
356 
357  // Prevent "extends" recursion
358  inState = true;
359 
360  if (!extends.isEmpty()) {
361  QList<QDeclarativeState *> states = group->states();
362  for (int ii = 0; ii < states.count(); ++ii)
363  if (states.at(ii)->name() == extends) {
364  qmlExecuteDeferred(states.at(ii));
365  applyList = static_cast<QDeclarativeStatePrivate*>(states.at(ii)->d_func())->generateActionList(group);
366  }
367  }
368 
369  foreach(QDeclarativeStateOperation *op, operations)
370  applyList << op->actions();
371 
372  inState = false;
373  return applyList;
374 }
375 
377 {
378  Q_D(const QDeclarativeState);
379  return d->group;
380 }
381 
383 {
385  d->group = group;
386 }
387 
389 {
391  d->transitionManager.cancel();
392 }
393 
395 {
396  if (fromBinding) {
398  fromBinding->destroy();
399  fromBinding = 0;
400  }
401 }
402 
404 {
405  Q_D(const QDeclarativeState);
406 
407  if (isStateActive()) {
408  QListIterator<QDeclarativeSimpleAction> revertListIterator(d->revertList);
409 
410  while (revertListIterator.hasNext()) {
411  const QDeclarativeSimpleAction &simpleAction = revertListIterator.next();
412  if (simpleAction.specifiedObject() == target && simpleAction.specifiedProperty() == name)
413  return true;
414  }
415  }
416 
417  return false;
418 }
419 
420 bool QDeclarativeState::changeValueInRevertList(QObject *target, const QString &name, const QVariant &revertValue)
421 {
423 
424  if (isStateActive()) {
425  QMutableListIterator<QDeclarativeSimpleAction> revertListIterator(d->revertList);
426 
427  while (revertListIterator.hasNext()) {
428  QDeclarativeSimpleAction &simpleAction = revertListIterator.next();
429  if (simpleAction.specifiedObject() == target && simpleAction.specifiedProperty() == name) {
430  simpleAction.setValue(revertValue);
431  return true;
432  }
433  }
434  }
435 
436  return false;
437 }
438 
440 {
442 
443  if (isStateActive()) {
444  QMutableListIterator<QDeclarativeSimpleAction> revertListIterator(d->revertList);
445 
446  while (revertListIterator.hasNext()) {
447  QDeclarativeSimpleAction &simpleAction = revertListIterator.next();
448  if (simpleAction.specifiedObject() == target && simpleAction.specifiedProperty() == name) {
449  if (simpleAction.binding())
450  simpleAction.binding()->destroy();
451 
452  simpleAction.setBinding(binding);
453  return true;
454  }
455  }
456  }
457 
458  return false;
459 }
460 
462 {
464 
465  if (isStateActive()) {
466  QMutableListIterator<QDeclarativeSimpleAction> revertListIterator(d->revertList);
467 
468  while (revertListIterator.hasNext()) {
469  QDeclarativeSimpleAction &simpleAction = revertListIterator.next();
470  if (simpleAction.property().object() == target && simpleAction.property().name() == name) {
472  if (oldBinding) {
474  oldBinding->destroy();
475  }
476 
477  simpleAction.property().write(simpleAction.value());
478  if (simpleAction.binding())
479  QDeclarativePropertyPrivate::setBinding(simpleAction.property(), simpleAction.binding());
480 
481  revertListIterator.remove();
482  return true;
483  }
484  }
485  }
486 
487  return false;
488 }
489 
491 {
493 
494  QDeclarativeSimpleAction simpleAction(action);
495 
496  d->revertList.append(simpleAction);
497 }
498 
500 {
502 
503  if (isStateActive()) {
504  QMutableListIterator<QDeclarativeSimpleAction> revertListIterator(d->revertList);
505 
506  while (revertListIterator.hasNext()) {
507  QDeclarativeSimpleAction &simpleAction = revertListIterator.next();
508  if (simpleAction.property().object() == target) {
510  if (oldBinding) {
512  oldBinding->destroy();
513  }
514 
515  simpleAction.property().write(simpleAction.value());
516  if (simpleAction.binding())
517  QDeclarativePropertyPrivate::setBinding(simpleAction.property(), simpleAction.binding());
518 
519  revertListIterator.remove();
520  }
521  }
522  }
523 }
524 
526 {
528  if (isStateActive()) {
529  QList<QDeclarativeSimpleAction> simpleActionList;
530 
531  QListIterator<QDeclarativeAction> actionListIterator(actionList);
532  while(actionListIterator.hasNext()) {
533  const QDeclarativeAction &action = actionListIterator.next();
534  QDeclarativeSimpleAction simpleAction(action);
535  action.property.write(action.toValue);
536  if (!action.toBinding.isNull()) {
538  if (oldBinding)
541  }
542 
543  simpleActionList.append(simpleAction);
544  }
545 
546  d->revertList.append(simpleActionList);
547  }
548 }
549 
551 {
552  Q_D(const QDeclarativeState);
553 
554  if (isStateActive()) {
555  QListIterator<QDeclarativeSimpleAction> revertListIterator(d->revertList);
556 
557  while (revertListIterator.hasNext()) {
558  const QDeclarativeSimpleAction &simpleAction = revertListIterator.next();
559  if (simpleAction.specifiedObject() == target && simpleAction.specifiedProperty() == name)
560  return simpleAction.value();
561  }
562  }
563 
564  return QVariant();
565 }
566 
568 {
569  Q_D(const QDeclarativeState);
570 
571  if (isStateActive()) {
572  QListIterator<QDeclarativeSimpleAction> revertListIterator(d->revertList);
573 
574  while (revertListIterator.hasNext()) {
575  const QDeclarativeSimpleAction &simpleAction = revertListIterator.next();
576  if (simpleAction.specifiedObject() == target && simpleAction.specifiedProperty() == name)
577  return simpleAction.binding();
578  }
579  }
580 
581  return 0;
582 }
583 
585 {
586  return stateGroup() && stateGroup()->state() == name();
587 }
588 
590 {
592 
593  qmlExecuteDeferred(this);
594 
595  cancel();
596  if (revert)
597  revert->cancel();
598  d->revertList.clear();
599  d->reverting.clear();
600 
601  if (revert) {
602  QDeclarativeStatePrivate *revertPrivate =
603  static_cast<QDeclarativeStatePrivate*>(revert->d_func());
604  d->revertList = revertPrivate->revertList;
605  revertPrivate->revertList.clear();
606  }
607 
608  // List of actions caused by this state
609  QDeclarativeStateOperation::ActionList applyList = d->generateActionList(group);
610 
611  // List of actions that need to be reverted to roll back (just) this state
613  // First add the reverse of all the applyList actions
614  for (int ii = 0; ii < applyList.count(); ++ii) {
615  QDeclarativeAction &action = applyList[ii];
616 
617  if (action.event) {
618  if (!action.event->isReversable())
619  continue;
620  bool found = false;
621  for (int jj = 0; jj < d->revertList.count(); ++jj) {
622  QDeclarativeActionEvent *event = d->revertList.at(jj).event();
623  if (event && event->typeName() == action.event->typeName()) {
624  if (action.event->override(event)) {
625  found = true;
626 
627  if (action.event != d->revertList.at(jj).event() && action.event->needsCopy()) {
628  action.event->copyOriginals(d->revertList.at(jj).event());
629 
630  QDeclarativeSimpleAction r(action);
631  additionalReverts << r;
632  d->revertList.removeAt(jj);
633  --jj;
634  } else if (action.event->isRewindable()) //###why needed?
635  action.event->saveCurrentValues();
636 
637  break;
638  }
639  }
640  }
641  if (!found) {
642  action.event->saveOriginals();
643  // Only need to revert the applyList action if the previous
644  // state doesn't have a higher priority revert already
645  QDeclarativeSimpleAction r(action);
646  additionalReverts << r;
647  }
648  } else {
649  bool found = false;
651 
652  for (int jj = 0; jj < d->revertList.count(); ++jj) {
653  if (d->revertList.at(jj).property() == action.property) {
654  found = true;
655  if (d->revertList.at(jj).binding() != action.fromBinding) {
656  action.deleteFromBinding();
657  }
658  break;
659  }
660  }
661 
662  if (!found) {
663  if (!action.restore) {
664  action.deleteFromBinding();;
665  } else {
666  // Only need to revert the applyList action if the previous
667  // state doesn't have a higher priority revert already
668  QDeclarativeSimpleAction r(action);
669  additionalReverts << r;
670  }
671  }
672  }
673  }
674 
675  // Any reverts from a previous state that aren't carried forth
676  // into this state need to be translated into apply actions
677  for (int ii = 0; ii < d->revertList.count(); ++ii) {
678  bool found = false;
679  if (d->revertList.at(ii).event()) {
680  QDeclarativeActionEvent *event = d->revertList.at(ii).event();
681  if (!event->isReversable())
682  continue;
683  for (int jj = 0; !found && jj < applyList.count(); ++jj) {
684  const QDeclarativeAction &action = applyList.at(jj);
685  if (action.event && action.event->typeName() == event->typeName()) {
686  if (action.event->override(event))
687  found = true;
688  }
689  }
690  } else {
691  for (int jj = 0; !found && jj < applyList.count(); ++jj) {
692  const QDeclarativeAction &action = applyList.at(jj);
693  if (action.property == d->revertList.at(ii).property())
694  found = true;
695  }
696  }
697  if (!found) {
698  QVariant cur = d->revertList.at(ii).property().read();
699  QDeclarativeAbstractBinding *delBinding =
700  QDeclarativePropertyPrivate::setBinding(d->revertList.at(ii).property(), 0);
701  if (delBinding)
702  delBinding->destroy();
703 
705  a.property = d->revertList.at(ii).property();
706  a.fromValue = cur;
707  a.toValue = d->revertList.at(ii).value();
708  a.toBinding = QDeclarativeAbstractBinding::getPointer(d->revertList.at(ii).binding());
709  a.specifiedObject = d->revertList.at(ii).specifiedObject();
710  a.specifiedProperty = d->revertList.at(ii).specifiedProperty();
711  a.event = d->revertList.at(ii).event();
712  a.reverseEvent = d->revertList.at(ii).reverseEvent();
713  if (a.event && a.event->isRewindable())
715  applyList << a;
716  // Store these special reverts in the reverting list
717  d->reverting << d->revertList.at(ii).property();
718  }
719  }
720  // All the local reverts now become part of the ongoing revertList
721  d->revertList << additionalReverts;
722 
723 #ifndef QT_NO_DEBUG_STREAM
724  // Output for debugging
725  if (stateChangeDebug()) {
726  foreach(const QDeclarativeAction &action, applyList) {
727  if (action.event)
728  qWarning() << " QDeclarativeAction event:" << action.event->typeName();
729  else
730  qWarning() << " QDeclarativeAction:" << action.property.object()
731  << action.property.name() << "From:" << action.fromValue
732  << "To:" << action.toValue;
733  }
734  }
735 #endif
736 
737  d->transitionManager.transition(applyList, trans);
738 }
739 
741 {
742  return ActionList();
743 }
744 
746 {
748  return d->m_state;
749 }
750 
752 {
754  d->m_state = state;
755 }
756 
The QVariant class acts like a union for the most common Qt data types.
Definition: qvariant.h:92
void setValue(const QVariant &value)
double d
Definition: qnumeric_p.h:62
QDeclarativeProperty property
#define QT_END_NAMESPACE
This macro expands to.
Definition: qglobal.h:90
EventRef event
QDeclarativeStateGroup * stateGroup() const
static Pointer getPointer(QDeclarativeAbstractBinding *p)
QDeclarativeState(QObject *parent=0)
virtual void destroy(DestroyMode mode=DisconnectBinding)
Destroy the binding.
static QDeclarativeAbstractBinding * binding(QObject *, int coreIndex, int valueTypeIndex)
void removeAllEntriesFromRevertList(QObject *target)
void setBinding(QDeclarativeAbstractBinding *binding)
long ASN1_INTEGER_get ASN1_INTEGER * a
int count(const T &t) const
Returns the number of occurrences of value in the list.
Definition: qlist.h:891
virtual ActionList actions()
The QString class provides a Unicode character string.
Definition: qstring.h:83
bool isNull() const
Returns true if this object is holding a reference to a null pointer.
The QObject class is the base class of all Qt objects.
Definition: qobject.h:111
virtual bool event(QEvent *)
This virtual function receives events to an object and should return true if the event e was recogniz...
Definition: qobject.cpp:1200
#define Q_D(Class)
Definition: qglobal.h:2482
bool isValid() const
Returns true if the QDeclarativeProperty refers to a valid property, otherwise false.
T * data() const
void addEntriesToRevertList(const QList< QDeclarativeAction > &actions)
static void operations_clear(QDeclarativeListProperty< QDeclarativeStateOperation > *prop)
#define Q_Q(Class)
Definition: qglobal.h:2483
QString extends() const
virtual bool override(QDeclarativeActionEvent *other)
QDeclarativeBinding * when() const
QObject * object() const
Returns the QDeclarativeProperty&#39;s QObject.
void append(const T &t)
Inserts value at the end of the list.
Definition: qlist.h:507
#define QT_BEGIN_NAMESPACE
This macro expands to.
Definition: qglobal.h:89
QDeclarativeStateOperation * operationAt(int) const
bool isEmpty() const
Returns true if the string has no characters; otherwise returns false.
Definition: qstring.h:704
void setState(QDeclarativeState *state)
Q_DECLARATIVE_EXPORT void qmlExecuteDeferred(QObject *)
const T & at(int i) const
Returns the item at index position i in the list.
Definition: qlist.h:468
#define emit
Definition: qobjectdefs.h:76
QDeclarativeStateOperation::ActionList generateActionList(QDeclarativeStateGroup *) const
Q_CORE_EXPORT void qWarning(const char *,...)
QDeclarativeState * state() const
QDeclarativeAbstractBinding * binding() const
QVariant valueInRevertList(QObject *target, const QString &name) const
virtual void execute(Reason reason=ActualChange)
QWeakPointer< QDeclarativeAbstractBinding > toBinding
const QString & specifiedProperty() const
void clear()
Removes all items from the list.
Definition: qlist.h:764
static QDeclarativeAbstractBinding * setBinding(QObject *, int coreIndex, int valueTypeIndex, QDeclarativeAbstractBinding *, WriteFlags flags=DontRemoveBinding)
void setExtends(const QString &)
void setName(const QString &)
const QVariant & value() const
bool changeBindingInRevertList(QObject *target, const QString &name, QDeclarativeAbstractBinding *binding)
virtual QString typeName() const
DEFINE_BOOL_CONFIG_OPTION(stateChangeDebug, STATECHANGE_DEBUG)
QDeclarativeState & operator<<(QDeclarativeStateOperation *)
static void operations_append(QDeclarativeListProperty< QDeclarativeStateOperation > *prop, QDeclarativeStateOperation *op)
Q_DECLARATIVE_EXPORT QDeclarativeEngine * qmlEngine(const QObject *)
bool removeEntryFromRevertList(QObject *target, const QString &name)
void addEntryToRevertList(const QDeclarativeAction &action)
void setWhen(QDeclarativeBinding *)
QObject * parent() const
Returns a pointer to the parent object.
Definition: qobject.h:273
bool changeValueInRevertList(QObject *target, const QString &name, const QVariant &revertValue)
void apply(QDeclarativeStateGroup *, QDeclarativeTransition *, QDeclarativeState *revert)
The QDeclarativeContext class defines a context within a QML engine.
const QDeclarativeProperty & property() const
bool isStateActive() const
quint16 index
QVariant property(const char *name) const
Returns the value of the object&#39;s name property.
Definition: qobject.cpp:3807
bool write(const QVariant &) const
Sets the property value to value and returns true.
QDeclarativeActionEvent * event
QDeclarativeStateOperation(QObject *parent=0)
QDeclarativeListProperty< QDeclarativeState > states
bool containsPropertyInRevertList(QObject *target, const QString &name) const
QDeclarativeAbstractBinding * bindingInRevertList(QObject *target, const QString &name) const
QString name() const
static QDeclarativeStateOperation * operations_at(QDeclarativeListProperty< QDeclarativeStateOperation > *prop, int index)
QString name() const
Return the name of this QML property.
QDeclarativeListProperty< QDeclarativeStateOperation > changes()
#define Q_UNUSED(x)
Indicates to the compiler that the parameter with the specified name is not used in the body of a fun...
Definition: qglobal.h:1729
virtual void copyOriginals(QDeclarativeActionEvent *)
virtual void reverse(Reason reason=ActualChange)
static int operations_count(QDeclarativeListProperty< QDeclarativeStateOperation > *prop)
QVariant read() const
Returns the property value.
QDeclarativeAbstractBinding * fromBinding
void setStateGroup(QDeclarativeStateGroup *)