1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the QtDeclarative module of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include "QtQuick1/private/qdeclarativestategroup_p.h"
44 #include "QtQuick1/private/qdeclarativetransition_p.h"
45 #include "QtQuick1/private/qdeclarativestate_p_p.h"
47 #include <QtDeclarative/private/qdeclarativebinding_p.h>
48 #include <QtDeclarative/private/qdeclarativeglobal_p.h>
50 #include <QtCore/qstringbuilder.h>
51 #include <QtCore/qdebug.h>
53 #include <private/qobject_p.h>
54 #include <QtDeclarative/qdeclarativeinfo.h>
60 DEFINE_BOOL_CONFIG_OPTION(stateChangeDebug, STATECHANGE_DEBUG);
62 class QDeclarative1StateGroupPrivate : public QObjectPrivate
64 Q_DECLARE_PUBLIC(QDeclarative1StateGroup)
66 QDeclarative1StateGroupPrivate()
67 : nullState(0), componentComplete(true),
68 ignoreTrans(false), applyingState(false), unnamedCount(0) {}
71 QDeclarative1State *nullState;
73 static void append_state(QDeclarativeListProperty<QDeclarative1State> *list, QDeclarative1State *state);
74 static int count_state(QDeclarativeListProperty<QDeclarative1State> *list);
75 static QDeclarative1State *at_state(QDeclarativeListProperty<QDeclarative1State> *list, int index);
76 static void clear_states(QDeclarativeListProperty<QDeclarative1State> *list);
78 static void append_transition(QDeclarativeListProperty<QDeclarative1Transition> *list, QDeclarative1Transition *state);
79 static int count_transitions(QDeclarativeListProperty<QDeclarative1Transition> *list);
80 static QDeclarative1Transition *at_transition(QDeclarativeListProperty<QDeclarative1Transition> *list, int index);
81 static void clear_transitions(QDeclarativeListProperty<QDeclarative1Transition> *list);
83 QList<QDeclarative1State *> states;
84 QList<QDeclarative1Transition *> transitions;
86 bool componentComplete;
91 QDeclarative1Transition *findTransition(const QString &from, const QString &to);
92 void setCurrentStateInternal(const QString &state, bool = false);
93 bool updateAutoState();
97 \qmlclass StateGroup QDeclarative1StateGroup
98 \inqmlmodule QtQuick 1
99 \ingroup qml-state-elements
101 \brief The StateGroup element provides state support for non-Item elements.
103 Item (and all derived elements) provides built in support for states and transitions
104 via its \l{Item::state}{state}, \l{Item::states}{states} and \l{Item::transitions}{transitions} properties. StateGroup provides an easy way to
105 use this support in other (non-Item-derived) elements.
115 transitions: Transition {
120 onSomethingHappened: myStateGroup.state = "state1";
124 \sa {qmlstate}{States} {QML Animation and Transitions}{Transitions}, {QtDeclarative}
127 QDeclarative1StateGroup::QDeclarative1StateGroup(QObject *parent)
128 : QObject(*(new QDeclarative1StateGroupPrivate), parent)
132 QDeclarative1StateGroup::~QDeclarative1StateGroup()
134 Q_D(const QDeclarative1StateGroup);
135 for (int i = 0; i < d->states.count(); ++i)
136 d->states.at(i)->setStateGroup(0);
139 QList<QDeclarative1State *> QDeclarative1StateGroup::states() const
141 Q_D(const QDeclarative1StateGroup);
146 \qmlproperty list<State> QtQuick1::StateGroup::states
147 This property holds a list of states defined by the state group.
153 // State definition...
163 \sa {qmlstate}{States}
165 QDeclarativeListProperty<QDeclarative1State> QDeclarative1StateGroup::statesProperty()
167 Q_D(QDeclarative1StateGroup);
168 return QDeclarativeListProperty<QDeclarative1State>(this, &d->states, &QDeclarative1StateGroupPrivate::append_state,
169 &QDeclarative1StateGroupPrivate::count_state,
170 &QDeclarative1StateGroupPrivate::at_state,
171 &QDeclarative1StateGroupPrivate::clear_states);
174 void QDeclarative1StateGroupPrivate::append_state(QDeclarativeListProperty<QDeclarative1State> *list, QDeclarative1State *state)
176 QDeclarative1StateGroup *_this = static_cast<QDeclarative1StateGroup *>(list->object);
178 _this->d_func()->states.append(state);
179 state->setStateGroup(_this);
184 int QDeclarative1StateGroupPrivate::count_state(QDeclarativeListProperty<QDeclarative1State> *list)
186 QDeclarative1StateGroup *_this = static_cast<QDeclarative1StateGroup *>(list->object);
187 return _this->d_func()->states.count();
190 QDeclarative1State *QDeclarative1StateGroupPrivate::at_state(QDeclarativeListProperty<QDeclarative1State> *list, int index)
192 QDeclarative1StateGroup *_this = static_cast<QDeclarative1StateGroup *>(list->object);
193 return _this->d_func()->states.at(index);
196 void QDeclarative1StateGroupPrivate::clear_states(QDeclarativeListProperty<QDeclarative1State> *list)
198 QDeclarative1StateGroup *_this = static_cast<QDeclarative1StateGroup *>(list->object);
199 _this->d_func()->setCurrentStateInternal(QString(), true);
200 for (int i = 0; i < _this->d_func()->states.count(); ++i) {
201 _this->d_func()->states.at(i)->setStateGroup(0);
203 _this->d_func()->states.clear();
207 \qmlproperty list<Transition> QtQuick1::StateGroup::transitions
208 This property holds a list of transitions defined by the state group.
224 \sa {QML Animation and Transitions}{Transitions}
226 QDeclarativeListProperty<QDeclarative1Transition> QDeclarative1StateGroup::transitionsProperty()
228 Q_D(QDeclarative1StateGroup);
229 return QDeclarativeListProperty<QDeclarative1Transition>(this, &d->transitions, &QDeclarative1StateGroupPrivate::append_transition,
230 &QDeclarative1StateGroupPrivate::count_transitions,
231 &QDeclarative1StateGroupPrivate::at_transition,
232 &QDeclarative1StateGroupPrivate::clear_transitions);
235 void QDeclarative1StateGroupPrivate::append_transition(QDeclarativeListProperty<QDeclarative1Transition> *list, QDeclarative1Transition *trans)
237 QDeclarative1StateGroup *_this = static_cast<QDeclarative1StateGroup *>(list->object);
239 _this->d_func()->transitions.append(trans);
242 int QDeclarative1StateGroupPrivate::count_transitions(QDeclarativeListProperty<QDeclarative1Transition> *list)
244 QDeclarative1StateGroup *_this = static_cast<QDeclarative1StateGroup *>(list->object);
245 return _this->d_func()->transitions.count();
248 QDeclarative1Transition *QDeclarative1StateGroupPrivate::at_transition(QDeclarativeListProperty<QDeclarative1Transition> *list, int index)
250 QDeclarative1StateGroup *_this = static_cast<QDeclarative1StateGroup *>(list->object);
251 return _this->d_func()->transitions.at(index);
254 void QDeclarative1StateGroupPrivate::clear_transitions(QDeclarativeListProperty<QDeclarative1Transition> *list)
256 QDeclarative1StateGroup *_this = static_cast<QDeclarative1StateGroup *>(list->object);
257 _this->d_func()->transitions.clear();
261 \qmlproperty string QtQuick1::StateGroup::state
263 This property holds the name of the current state of the state group.
265 This property is often used in scripts to change between states. For
270 if (button.state == 'On')
271 button.state = 'Off';
277 If the state group is in its base state (i.e. no explicit state has been
278 set), \c state will be a blank string. Likewise, you can return a
279 state group to its base state by setting its current state to \c ''.
281 \sa {qmlstates}{States}
283 QString QDeclarative1StateGroup::state() const
285 Q_D(const QDeclarative1StateGroup);
286 return d->currentState;
289 void QDeclarative1StateGroup::setState(const QString &state)
291 Q_D(QDeclarative1StateGroup);
292 if (d->currentState == state)
295 d->setCurrentStateInternal(state);
298 void QDeclarative1StateGroup::classBegin()
300 Q_D(QDeclarative1StateGroup);
301 d->componentComplete = false;
304 void QDeclarative1StateGroup::componentComplete()
306 Q_D(QDeclarative1StateGroup);
307 d->componentComplete = true;
309 for (int ii = 0; ii < d->states.count(); ++ii) {
310 QDeclarative1State *state = d->states.at(ii);
311 if (!state->isNamed())
312 state->setName(QLatin1String("anonymousState") % QString::number(++d->unnamedCount));
315 if (d->updateAutoState()) {
317 } else if (!d->currentState.isEmpty()) {
318 QString cs = d->currentState;
319 d->currentState.clear();
320 d->setCurrentStateInternal(cs, true);
325 Returns true if the state was changed, otherwise false.
327 bool QDeclarative1StateGroup::updateAutoState()
329 Q_D(QDeclarative1StateGroup);
330 return d->updateAutoState();
333 bool QDeclarative1StateGroupPrivate::updateAutoState()
335 Q_Q(QDeclarative1StateGroup);
336 if (!componentComplete)
340 for (int ii = 0; ii < states.count(); ++ii) {
341 QDeclarative1State *state = states.at(ii);
342 if (state->isWhenKnown()) {
343 if (state->isNamed()) {
344 if (state->when() && state->when()->evaluate().toBool()) {
345 if (stateChangeDebug())
346 qWarning() << "Setting auto state due to:"
347 << state->when()->expression();
348 if (currentState != state->name()) {
349 q->setState(state->name());
354 } else if (state->name() == currentState) {
361 bool rv = !currentState.isEmpty();
362 q->setState(QString());
369 QDeclarative1Transition *QDeclarative1StateGroupPrivate::findTransition(const QString &from, const QString &to)
371 QDeclarative1Transition *highest = 0;
373 bool reversed = false;
376 for (int ii = 0; !done && ii < transitions.count(); ++ii) {
377 QDeclarative1Transition *t = transitions.at(ii);
378 for (int ii = 0; ii < 2; ++ii)
380 if (ii && (!t->reversible() ||
381 (t->fromState() == QLatin1String("*") &&
382 t->toState() == QLatin1String("*"))))
384 QStringList fromState;
387 fromState = t->fromState().split(QLatin1Char(','));
388 for (int jj = 0; jj < fromState.count(); ++jj)
389 fromState[jj] = fromState.at(jj).trimmed();
390 toState = t->toState().split(QLatin1Char(','));
391 for (int jj = 0; jj < toState.count(); ++jj)
392 toState[jj] = toState.at(jj).trimmed();
394 qSwap(fromState, toState);
396 if (fromState.contains(from))
398 else if (fromState.contains(QLatin1String("*")))
403 if (toState.contains(to))
405 else if (toState.contains(QLatin1String("*")))
419 } else if (tScore > score) {
427 highest->setReversed(reversed);
432 void QDeclarative1StateGroupPrivate::setCurrentStateInternal(const QString &state,
435 Q_Q(QDeclarative1StateGroup);
436 if (!componentComplete) {
437 currentState = state;
442 qmlInfo(q) << "Can't apply a state change as part of a state definition.";
446 applyingState = true;
448 QDeclarative1Transition *transition = ignoreTrans ? 0 : findTransition(currentState, state);
449 if (stateChangeDebug()) {
450 qWarning() << this << "Changing state. From" << currentState << ". To" << state;
452 qWarning() << " using transition" << transition->fromState()
453 << transition->toState();
456 QDeclarative1State *oldState = 0;
457 if (!currentState.isEmpty()) {
458 for (int ii = 0; ii < states.count(); ++ii) {
459 if (states.at(ii)->name() == currentState) {
460 oldState = states.at(ii);
466 currentState = state;
467 emit q->stateChanged(currentState);
469 QDeclarative1State *newState = 0;
470 for (int ii = 0; ii < states.count(); ++ii) {
471 if (states.at(ii)->name() == currentState) {
472 newState = states.at(ii);
477 if (oldState == 0 || newState == 0) {
478 if (!nullState) { nullState = new QDeclarative1State; QDeclarative_setParent_noEvent(nullState, q); }
479 if (!oldState) oldState = nullState;
480 if (!newState) newState = nullState;
483 newState->apply(q, transition, oldState);
484 applyingState = false;
486 static_cast<QDeclarative1StatePrivate*>(QObjectPrivate::get(newState))->complete();
489 QDeclarative1State *QDeclarative1StateGroup::findState(const QString &name) const
491 Q_D(const QDeclarative1StateGroup);
492 for (int i = 0; i < d->states.count(); ++i) {
493 QDeclarative1State *state = d->states.at(i);
494 if (state->name() == name)
501 void QDeclarative1StateGroup::removeState(QDeclarative1State *state)
503 Q_D(QDeclarative1StateGroup);
504 d->states.removeOne(state);