summaryrefslogtreecommitdiffstats
path: root/src/corelib/statemachine
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib/statemachine')
-rw-r--r--src/corelib/statemachine/qabstractstate.cpp14
-rw-r--r--src/corelib/statemachine/qabstractstate.h28
-rw-r--r--src/corelib/statemachine/qabstractstate_p.h14
-rw-r--r--src/corelib/statemachine/qabstracttransition.cpp60
-rw-r--r--src/corelib/statemachine/qabstracttransition.h44
-rw-r--r--src/corelib/statemachine/qabstracttransition_p.h15
-rw-r--r--src/corelib/statemachine/qeventtransition.cpp14
-rw-r--r--src/corelib/statemachine/qeventtransition.h20
-rw-r--r--src/corelib/statemachine/qeventtransition_p.h16
-rw-r--r--src/corelib/statemachine/qfinalstate.cpp14
-rw-r--r--src/corelib/statemachine/qfinalstate.h20
-rw-r--r--src/corelib/statemachine/qhistorystate.cpp14
-rw-r--r--src/corelib/statemachine/qhistorystate.h34
-rw-r--r--src/corelib/statemachine/qhistorystate_p.h14
-rw-r--r--src/corelib/statemachine/qsignaleventgenerator_p.h14
-rw-r--r--src/corelib/statemachine/qsignaltransition.cpp14
-rw-r--r--src/corelib/statemachine/qsignaltransition.h32
-rw-r--r--src/corelib/statemachine/qsignaltransition_p.h16
-rw-r--r--src/corelib/statemachine/qstate.cpp29
-rw-r--r--src/corelib/statemachine/qstate.h67
-rw-r--r--src/corelib/statemachine/qstate_p.h16
-rw-r--r--src/corelib/statemachine/qstatemachine.cpp887
-rw-r--r--src/corelib/statemachine/qstatemachine.h34
-rw-r--r--src/corelib/statemachine/qstatemachine_p.h70
24 files changed, 1045 insertions, 455 deletions
diff --git a/src/corelib/statemachine/qabstractstate.cpp b/src/corelib/statemachine/qabstractstate.cpp
index f98674b17a..543edb2f98 100644
--- a/src/corelib/statemachine/qabstractstate.cpp
+++ b/src/corelib/statemachine/qabstractstate.cpp
@@ -1,7 +1,7 @@
/****************************************************************************
**
-** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
-** Contact: http://www.qt-project.org/legal
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
**
@@ -10,9 +10,9 @@
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and Digia. For licensing terms and
-** conditions see http://qt.digia.com/licensing. For further information
-** use the contact form at http://qt.digia.com/contact-us.
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
@@ -23,8 +23,8 @@
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
-** In addition, as a special exception, Digia gives you certain additional
-** rights. These rights are described in the Digia Qt LGPL Exception
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** $QT_END_LICENSE$
diff --git a/src/corelib/statemachine/qabstractstate.h b/src/corelib/statemachine/qabstractstate.h
index 5f2216a9da..592c841c18 100644
--- a/src/corelib/statemachine/qabstractstate.h
+++ b/src/corelib/statemachine/qabstractstate.h
@@ -1,7 +1,7 @@
/****************************************************************************
**
-** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
-** Contact: http://www.qt-project.org/legal
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
**
@@ -10,9 +10,9 @@
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and Digia. For licensing terms and
-** conditions see http://qt.digia.com/licensing. For further information
-** use the contact form at http://qt.digia.com/contact-us.
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
@@ -23,8 +23,8 @@
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
-** In addition, as a special exception, Digia gives you certain additional
-** rights. These rights are described in the Digia Qt LGPL Exception
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** $QT_END_LICENSE$
@@ -58,16 +58,8 @@ public:
bool active() const;
Q_SIGNALS:
- void entered(
-#if !defined(Q_QDOC)
- QPrivateSignal
-#endif
- );
- void exited(
-#if !defined(Q_QDOC)
- QPrivateSignal
-#endif
- );
+ void entered(QPrivateSignal);
+ void exited(QPrivateSignal);
void activeChanged(bool active);
protected:
@@ -76,7 +68,7 @@ protected:
virtual void onEntry(QEvent *event) = 0;
virtual void onExit(QEvent *event) = 0;
- bool event(QEvent *e);
+ bool event(QEvent *e) Q_DECL_OVERRIDE;
protected:
QAbstractState(QAbstractStatePrivate &dd, QState *parent);
diff --git a/src/corelib/statemachine/qabstractstate_p.h b/src/corelib/statemachine/qabstractstate_p.h
index 12e56364e8..087e355b71 100644
--- a/src/corelib/statemachine/qabstractstate_p.h
+++ b/src/corelib/statemachine/qabstractstate_p.h
@@ -1,7 +1,7 @@
/****************************************************************************
**
-** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
-** Contact: http://www.qt-project.org/legal
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
**
@@ -10,9 +10,9 @@
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and Digia. For licensing terms and
-** conditions see http://qt.digia.com/licensing. For further information
-** use the contact form at http://qt.digia.com/contact-us.
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
@@ -23,8 +23,8 @@
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
-** In addition, as a special exception, Digia gives you certain additional
-** rights. These rights are described in the Digia Qt LGPL Exception
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** $QT_END_LICENSE$
diff --git a/src/corelib/statemachine/qabstracttransition.cpp b/src/corelib/statemachine/qabstracttransition.cpp
index b8ec0fcbad..81b38ea4c4 100644
--- a/src/corelib/statemachine/qabstracttransition.cpp
+++ b/src/corelib/statemachine/qabstracttransition.cpp
@@ -1,7 +1,7 @@
/****************************************************************************
**
-** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
-** Contact: http://www.qt-project.org/legal
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
**
@@ -10,9 +10,9 @@
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and Digia. For licensing terms and
-** conditions see http://qt.digia.com/licensing. For further information
-** use the contact form at http://qt.digia.com/contact-us.
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
@@ -23,8 +23,8 @@
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
-** In addition, as a special exception, Digia gives you certain additional
-** rights. These rights are described in the Digia Qt LGPL Exception
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** $QT_END_LICENSE$
@@ -101,7 +101,35 @@ QT_BEGIN_NAMESPACE
parallel group state.
*/
+/*!
+ \property QAbstractTransition::transitionType
+
+ \brief indicates whether this transition is an internal transition, or an external transition.
+
+ Internal and external transitions behave the same, except for the case of a transition whose
+ source state is a compound state and whose target(s) is a descendant of the source. In such a
+ case, an internal transition will not exit and re-enter its source state, while an external one
+ will.
+
+ By default, the type is an external transition.
+*/
+
+/*!
+ \enum QAbstractTransition::TransitionType
+
+ This enum specifies the kind of transition. By default, the type is an external transition.
+
+ \value ExternalTransition Any state that is the source state of a transition (which is not a
+ target-less transition) is left, and re-entered when necessary.
+ \value InternalTransition If the target state of a transition is a sub-state of a compound state,
+ and that compound state is the source state, an internal transition will
+ not leave the source state.
+
+ \sa QAbstractTransition::transitionType
+*/
+
QAbstractTransitionPrivate::QAbstractTransitionPrivate()
+ : transitionType(QAbstractTransition::ExternalTransition)
{
}
@@ -249,6 +277,24 @@ void QAbstractTransition::setTargetStates(const QList<QAbstractState*> &targets)
}
/*!
+ Returns the type of the transition.
+*/
+QAbstractTransition::TransitionType QAbstractTransition::transitionType() const
+{
+ Q_D(const QAbstractTransition);
+ return d->transitionType;
+}
+
+/*!
+ Sets the type of the transition to \a type.
+*/
+void QAbstractTransition::setTransitionType(TransitionType type)
+{
+ Q_D(QAbstractTransition);
+ d->transitionType = type;
+}
+
+/*!
Returns the state machine that this transition is part of, or 0 if the
transition is not part of a state machine.
*/
diff --git a/src/corelib/statemachine/qabstracttransition.h b/src/corelib/statemachine/qabstracttransition.h
index 2676aba633..bf32b3e825 100644
--- a/src/corelib/statemachine/qabstracttransition.h
+++ b/src/corelib/statemachine/qabstracttransition.h
@@ -1,7 +1,7 @@
/****************************************************************************
**
-** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
-** Contact: http://www.qt-project.org/legal
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
**
@@ -10,9 +10,9 @@
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and Digia. For licensing terms and
-** conditions see http://qt.digia.com/licensing. For further information
-** use the contact form at http://qt.digia.com/contact-us.
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
@@ -23,8 +23,8 @@
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
-** In addition, as a special exception, Digia gives you certain additional
-** rights. These rights are described in the Digia Qt LGPL Exception
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** $QT_END_LICENSE$
@@ -59,7 +59,14 @@ class Q_CORE_EXPORT QAbstractTransition : public QObject
Q_PROPERTY(QState* sourceState READ sourceState)
Q_PROPERTY(QAbstractState* targetState READ targetState WRITE setTargetState NOTIFY targetStateChanged)
Q_PROPERTY(QList<QAbstractState*> targetStates READ targetStates WRITE setTargetStates NOTIFY targetStatesChanged)
+ Q_PROPERTY(TransitionType transitionType READ transitionType WRITE setTransitionType)
public:
+ enum TransitionType {
+ ExternalTransition,
+ InternalTransition
+ };
+ Q_ENUM(TransitionType)
+
QAbstractTransition(QState *sourceState = 0);
virtual ~QAbstractTransition();
@@ -69,6 +76,9 @@ public:
QList<QAbstractState*> targetStates() const;
void setTargetStates(const QList<QAbstractState*> &targets);
+ TransitionType transitionType() const;
+ void setTransitionType(TransitionType type);
+
QStateMachine *machine() const;
#ifndef QT_NO_ANIMATION
@@ -78,28 +88,16 @@ public:
#endif
Q_SIGNALS:
- void triggered(
-#if !defined(Q_QDOC)
- QPrivateSignal
-#endif
- );
- void targetStateChanged(
-#if !defined(Q_QDOC)
- QPrivateSignal
-#endif
- );
- void targetStatesChanged(
-#if !defined(Q_QDOC)
- QPrivateSignal
-#endif
- );
+ void triggered(QPrivateSignal);
+ void targetStateChanged(QPrivateSignal);
+ void targetStatesChanged(QPrivateSignal);
protected:
virtual bool eventTest(QEvent *event) = 0;
virtual void onTransition(QEvent *event) = 0;
- bool event(QEvent *e);
+ bool event(QEvent *e) Q_DECL_OVERRIDE;
protected:
QAbstractTransition(QAbstractTransitionPrivate &dd, QState *parent);
diff --git a/src/corelib/statemachine/qabstracttransition_p.h b/src/corelib/statemachine/qabstracttransition_p.h
index d4a61cf53c..4b0644acd9 100644
--- a/src/corelib/statemachine/qabstracttransition_p.h
+++ b/src/corelib/statemachine/qabstracttransition_p.h
@@ -1,7 +1,7 @@
/****************************************************************************
**
-** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
-** Contact: http://www.qt-project.org/legal
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
**
@@ -10,9 +10,9 @@
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and Digia. For licensing terms and
-** conditions see http://qt.digia.com/licensing. For further information
-** use the contact form at http://qt.digia.com/contact-us.
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
@@ -23,8 +23,8 @@
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
-** In addition, as a special exception, Digia gives you certain additional
-** rights. These rights are described in the Digia Qt LGPL Exception
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** $QT_END_LICENSE$
@@ -73,6 +73,7 @@ public:
void emitTriggered();
QList<QPointer<QAbstractState> > targetStates;
+ QAbstractTransition::TransitionType transitionType;
#ifndef QT_NO_ANIMATION
QList<QAbstractAnimation*> animations;
diff --git a/src/corelib/statemachine/qeventtransition.cpp b/src/corelib/statemachine/qeventtransition.cpp
index 395400abd9..096d667bc3 100644
--- a/src/corelib/statemachine/qeventtransition.cpp
+++ b/src/corelib/statemachine/qeventtransition.cpp
@@ -1,7 +1,7 @@
/****************************************************************************
**
-** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
-** Contact: http://www.qt-project.org/legal
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
**
@@ -10,9 +10,9 @@
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and Digia. For licensing terms and
-** conditions see http://qt.digia.com/licensing. For further information
-** use the contact form at http://qt.digia.com/contact-us.
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
@@ -23,8 +23,8 @@
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
-** In addition, as a special exception, Digia gives you certain additional
-** rights. These rights are described in the Digia Qt LGPL Exception
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** $QT_END_LICENSE$
diff --git a/src/corelib/statemachine/qeventtransition.h b/src/corelib/statemachine/qeventtransition.h
index bf282242d6..6909e855b1 100644
--- a/src/corelib/statemachine/qeventtransition.h
+++ b/src/corelib/statemachine/qeventtransition.h
@@ -1,7 +1,7 @@
/****************************************************************************
**
-** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
-** Contact: http://www.qt-project.org/legal
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
**
@@ -10,9 +10,9 @@
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and Digia. For licensing terms and
-** conditions see http://qt.digia.com/licensing. For further information
-** use the contact form at http://qt.digia.com/contact-us.
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
@@ -23,8 +23,8 @@
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
-** In addition, as a special exception, Digia gives you certain additional
-** rights. These rights are described in the Digia Qt LGPL Exception
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** $QT_END_LICENSE$
@@ -60,10 +60,10 @@ public:
void setEventType(QEvent::Type type);
protected:
- bool eventTest(QEvent *event);
- void onTransition(QEvent *event);
+ bool eventTest(QEvent *event) Q_DECL_OVERRIDE;
+ void onTransition(QEvent *event) Q_DECL_OVERRIDE;
- bool event(QEvent *e);
+ bool event(QEvent *e) Q_DECL_OVERRIDE;
protected:
QEventTransition(QEventTransitionPrivate &dd, QState *parent);
diff --git a/src/corelib/statemachine/qeventtransition_p.h b/src/corelib/statemachine/qeventtransition_p.h
index a77153256d..59b0fcb30f 100644
--- a/src/corelib/statemachine/qeventtransition_p.h
+++ b/src/corelib/statemachine/qeventtransition_p.h
@@ -1,7 +1,7 @@
/****************************************************************************
**
-** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
-** Contact: http://www.qt-project.org/legal
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
**
@@ -10,9 +10,9 @@
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and Digia. For licensing terms and
-** conditions see http://qt.digia.com/licensing. For further information
-** use the contact form at http://qt.digia.com/contact-us.
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
@@ -23,8 +23,8 @@
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
-** In addition, as a special exception, Digia gives you certain additional
-** rights. These rights are described in the Digia Qt LGPL Exception
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** $QT_END_LICENSE$
@@ -61,8 +61,8 @@ public:
void unregister();
void maybeRegister();
- bool registered;
QObject *object;
+ bool registered;
QEvent::Type eventType;
};
diff --git a/src/corelib/statemachine/qfinalstate.cpp b/src/corelib/statemachine/qfinalstate.cpp
index df8d677724..ea96cc64c4 100644
--- a/src/corelib/statemachine/qfinalstate.cpp
+++ b/src/corelib/statemachine/qfinalstate.cpp
@@ -1,7 +1,7 @@
/****************************************************************************
**
-** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
-** Contact: http://www.qt-project.org/legal
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
**
@@ -10,9 +10,9 @@
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and Digia. For licensing terms and
-** conditions see http://qt.digia.com/licensing. For further information
-** use the contact form at http://qt.digia.com/contact-us.
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
@@ -23,8 +23,8 @@
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
-** In addition, as a special exception, Digia gives you certain additional
-** rights. These rights are described in the Digia Qt LGPL Exception
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** $QT_END_LICENSE$
diff --git a/src/corelib/statemachine/qfinalstate.h b/src/corelib/statemachine/qfinalstate.h
index 804851c321..51c97b1545 100644
--- a/src/corelib/statemachine/qfinalstate.h
+++ b/src/corelib/statemachine/qfinalstate.h
@@ -1,7 +1,7 @@
/****************************************************************************
**
-** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
-** Contact: http://www.qt-project.org/legal
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
**
@@ -10,9 +10,9 @@
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and Digia. For licensing terms and
-** conditions see http://qt.digia.com/licensing. For further information
-** use the contact form at http://qt.digia.com/contact-us.
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
@@ -23,8 +23,8 @@
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
-** In addition, as a special exception, Digia gives you certain additional
-** rights. These rights are described in the Digia Qt LGPL Exception
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** $QT_END_LICENSE$
@@ -50,10 +50,10 @@ public:
~QFinalState();
protected:
- void onEntry(QEvent *event);
- void onExit(QEvent *event);
+ void onEntry(QEvent *event) Q_DECL_OVERRIDE;
+ void onExit(QEvent *event) Q_DECL_OVERRIDE;
- bool event(QEvent *e);
+ bool event(QEvent *e) Q_DECL_OVERRIDE;
private:
Q_DISABLE_COPY(QFinalState)
diff --git a/src/corelib/statemachine/qhistorystate.cpp b/src/corelib/statemachine/qhistorystate.cpp
index dc0aba4739..e58b0c16fc 100644
--- a/src/corelib/statemachine/qhistorystate.cpp
+++ b/src/corelib/statemachine/qhistorystate.cpp
@@ -1,7 +1,7 @@
/****************************************************************************
**
-** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
-** Contact: http://www.qt-project.org/legal
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
**
@@ -10,9 +10,9 @@
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and Digia. For licensing terms and
-** conditions see http://qt.digia.com/licensing. For further information
-** use the contact form at http://qt.digia.com/contact-us.
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
@@ -23,8 +23,8 @@
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
-** In addition, as a special exception, Digia gives you certain additional
-** rights. These rights are described in the Digia Qt LGPL Exception
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** $QT_END_LICENSE$
diff --git a/src/corelib/statemachine/qhistorystate.h b/src/corelib/statemachine/qhistorystate.h
index d05e4ba5eb..549be15ab0 100644
--- a/src/corelib/statemachine/qhistorystate.h
+++ b/src/corelib/statemachine/qhistorystate.h
@@ -1,7 +1,7 @@
/****************************************************************************
**
-** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
-** Contact: http://www.qt-project.org/legal
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
**
@@ -10,9 +10,9 @@
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and Digia. For licensing terms and
-** conditions see http://qt.digia.com/licensing. For further information
-** use the contact form at http://qt.digia.com/contact-us.
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
@@ -23,8 +23,8 @@
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
-** In addition, as a special exception, Digia gives you certain additional
-** rights. These rights are described in the Digia Qt LGPL Exception
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** $QT_END_LICENSE$
@@ -47,12 +47,12 @@ class Q_CORE_EXPORT QHistoryState : public QAbstractState
Q_OBJECT
Q_PROPERTY(QAbstractState* defaultState READ defaultState WRITE setDefaultState NOTIFY defaultStateChanged)
Q_PROPERTY(HistoryType historyType READ historyType WRITE setHistoryType NOTIFY historyTypeChanged)
- Q_ENUMS(HistoryType)
public:
enum HistoryType {
ShallowHistory,
DeepHistory
};
+ Q_ENUM(HistoryType)
QHistoryState(QState *parent = 0);
QHistoryState(HistoryType type, QState *parent = 0);
@@ -65,22 +65,14 @@ public:
void setHistoryType(HistoryType type);
Q_SIGNALS:
- void defaultStateChanged(
-#if !defined(Q_QDOC)
- QPrivateSignal
-#endif
- );
- void historyTypeChanged(
-#if !defined(Q_QDOC)
- QPrivateSignal
-#endif
- );
+ void defaultStateChanged(QPrivateSignal);
+ void historyTypeChanged(QPrivateSignal);
protected:
- void onEntry(QEvent *event);
- void onExit(QEvent *event);
+ void onEntry(QEvent *event) Q_DECL_OVERRIDE;
+ void onExit(QEvent *event) Q_DECL_OVERRIDE;
- bool event(QEvent *e);
+ bool event(QEvent *e) Q_DECL_OVERRIDE;
private:
Q_DISABLE_COPY(QHistoryState)
diff --git a/src/corelib/statemachine/qhistorystate_p.h b/src/corelib/statemachine/qhistorystate_p.h
index 3271102d16..b5c353fdff 100644
--- a/src/corelib/statemachine/qhistorystate_p.h
+++ b/src/corelib/statemachine/qhistorystate_p.h
@@ -1,7 +1,7 @@
/****************************************************************************
**
-** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
-** Contact: http://www.qt-project.org/legal
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
**
@@ -10,9 +10,9 @@
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and Digia. For licensing terms and
-** conditions see http://qt.digia.com/licensing. For further information
-** use the contact form at http://qt.digia.com/contact-us.
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
@@ -23,8 +23,8 @@
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
-** In addition, as a special exception, Digia gives you certain additional
-** rights. These rights are described in the Digia Qt LGPL Exception
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** $QT_END_LICENSE$
diff --git a/src/corelib/statemachine/qsignaleventgenerator_p.h b/src/corelib/statemachine/qsignaleventgenerator_p.h
index 1697c4b95d..25da7219c9 100644
--- a/src/corelib/statemachine/qsignaleventgenerator_p.h
+++ b/src/corelib/statemachine/qsignaleventgenerator_p.h
@@ -1,7 +1,7 @@
/****************************************************************************
**
-** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
-** Contact: http://www.qt-project.org/legal
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
**
@@ -10,9 +10,9 @@
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and Digia. For licensing terms and
-** conditions see http://qt.digia.com/licensing. For further information
-** use the contact form at http://qt.digia.com/contact-us.
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
@@ -23,8 +23,8 @@
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
-** In addition, as a special exception, Digia gives you certain additional
-** rights. These rights are described in the Digia Qt LGPL Exception
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** $QT_END_LICENSE$
diff --git a/src/corelib/statemachine/qsignaltransition.cpp b/src/corelib/statemachine/qsignaltransition.cpp
index 0f447db979..41005fca41 100644
--- a/src/corelib/statemachine/qsignaltransition.cpp
+++ b/src/corelib/statemachine/qsignaltransition.cpp
@@ -1,7 +1,7 @@
/****************************************************************************
**
-** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
-** Contact: http://www.qt-project.org/legal
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
**
@@ -10,9 +10,9 @@
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and Digia. For licensing terms and
-** conditions see http://qt.digia.com/licensing. For further information
-** use the contact form at http://qt.digia.com/contact-us.
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
@@ -23,8 +23,8 @@
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
-** In addition, as a special exception, Digia gives you certain additional
-** rights. These rights are described in the Digia Qt LGPL Exception
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** $QT_END_LICENSE$
diff --git a/src/corelib/statemachine/qsignaltransition.h b/src/corelib/statemachine/qsignaltransition.h
index 545374eb5c..bc56f4e9b7 100644
--- a/src/corelib/statemachine/qsignaltransition.h
+++ b/src/corelib/statemachine/qsignaltransition.h
@@ -1,7 +1,7 @@
/****************************************************************************
**
-** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
-** Contact: http://www.qt-project.org/legal
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
**
@@ -10,9 +10,9 @@
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and Digia. For licensing terms and
-** conditions see http://qt.digia.com/licensing. For further information
-** use the contact form at http://qt.digia.com/contact-us.
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
@@ -23,8 +23,8 @@
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
-** In addition, as a special exception, Digia gives you certain additional
-** rights. These rights are described in the Digia Qt LGPL Exception
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** $QT_END_LICENSE$
@@ -61,22 +61,14 @@ public:
void setSignal(const QByteArray &signal);
protected:
- bool eventTest(QEvent *event);
- void onTransition(QEvent *event);
+ bool eventTest(QEvent *event) Q_DECL_OVERRIDE;
+ void onTransition(QEvent *event) Q_DECL_OVERRIDE;
- bool event(QEvent *e);
+ bool event(QEvent *e) Q_DECL_OVERRIDE;
Q_SIGNALS:
- void senderObjectChanged(
-#if !defined(Q_QDOC)
- QPrivateSignal
-#endif
- );
- void signalChanged(
-#if !defined(Q_QDOC)
- QPrivateSignal
-#endif
- );
+ void senderObjectChanged(QPrivateSignal);
+ void signalChanged(QPrivateSignal);
private:
Q_DISABLE_COPY(QSignalTransition)
diff --git a/src/corelib/statemachine/qsignaltransition_p.h b/src/corelib/statemachine/qsignaltransition_p.h
index 1d09babe88..bed0abd9ff 100644
--- a/src/corelib/statemachine/qsignaltransition_p.h
+++ b/src/corelib/statemachine/qsignaltransition_p.h
@@ -1,7 +1,7 @@
/****************************************************************************
**
-** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
-** Contact: http://www.qt-project.org/legal
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
**
@@ -10,9 +10,9 @@
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and Digia. For licensing terms and
-** conditions see http://qt.digia.com/licensing. For further information
-** use the contact form at http://qt.digia.com/contact-us.
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
@@ -23,8 +23,8 @@
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
-** In addition, as a special exception, Digia gives you certain additional
-** rights. These rights are described in the Digia Qt LGPL Exception
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** $QT_END_LICENSE$
@@ -61,7 +61,7 @@ public:
void unregister();
void maybeRegister();
- virtual void callOnTransition(QEvent *e);
+ virtual void callOnTransition(QEvent *e) Q_DECL_OVERRIDE;
const QObject *sender;
QByteArray signal;
diff --git a/src/corelib/statemachine/qstate.cpp b/src/corelib/statemachine/qstate.cpp
index 29698d204f..6e9fb63554 100644
--- a/src/corelib/statemachine/qstate.cpp
+++ b/src/corelib/statemachine/qstate.cpp
@@ -1,7 +1,7 @@
/****************************************************************************
**
-** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
-** Contact: http://www.qt-project.org/legal
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
**
@@ -10,9 +10,9 @@
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and Digia. For licensing terms and
-** conditions see http://qt.digia.com/licensing. For further information
-** use the contact form at http://qt.digia.com/contact-us.
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
@@ -23,8 +23,8 @@
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
-** In addition, as a special exception, Digia gives you certain additional
-** rights. These rights are described in the Digia Qt LGPL Exception
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** $QT_END_LICENSE$
@@ -339,6 +339,17 @@ void QState::addTransition(QAbstractTransition *transition)
}
/*!
+ \fn QState::addTransition(const QObject *sender, PointerToMemberFunction signal,
+ QAbstractState *target);
+ \since 5.5
+ \overload
+
+ Adds a transition associated with the given \a signal of the given \a sender
+ object, and returns the new QSignalTransition object. The transition has
+ this state as the source, and the given \a target as the target state.
+*/
+
+/*!
Adds a transition associated with the given \a signal of the given \a sender
object, and returns the new QSignalTransition object. The transition has
this state as the source, and the given \a target as the target state.
@@ -383,8 +394,8 @@ public:
: QAbstractTransition()
{ setTargetState(target); }
protected:
- void onTransition(QEvent *) {}
- bool eventTest(QEvent *) { return true; }
+ void onTransition(QEvent *) Q_DECL_OVERRIDE {}
+ bool eventTest(QEvent *) Q_DECL_OVERRIDE { return true; }
};
} // namespace
diff --git a/src/corelib/statemachine/qstate.h b/src/corelib/statemachine/qstate.h
index dbc1ca97f9..a74c782027 100644
--- a/src/corelib/statemachine/qstate.h
+++ b/src/corelib/statemachine/qstate.h
@@ -1,7 +1,7 @@
/****************************************************************************
**
-** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
-** Contact: http://www.qt-project.org/legal
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
**
@@ -10,9 +10,9 @@
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and Digia. For licensing terms and
-** conditions see http://qt.digia.com/licensing. For further information
-** use the contact form at http://qt.digia.com/contact-us.
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
@@ -23,8 +23,8 @@
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
-** In addition, as a special exception, Digia gives you certain additional
-** rights. These rights are described in the Digia Qt LGPL Exception
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** $QT_END_LICENSE$
@@ -35,8 +35,8 @@
#define QSTATE_H
#include <QtCore/qabstractstate.h>
-
#include <QtCore/qlist.h>
+#include <QtCore/qmetaobject.h>
QT_BEGIN_NAMESPACE
@@ -53,17 +53,18 @@ class Q_CORE_EXPORT QState : public QAbstractState
Q_PROPERTY(QAbstractState* initialState READ initialState WRITE setInitialState NOTIFY initialStateChanged)
Q_PROPERTY(QAbstractState* errorState READ errorState WRITE setErrorState NOTIFY errorStateChanged)
Q_PROPERTY(ChildMode childMode READ childMode WRITE setChildMode NOTIFY childModeChanged)
- Q_ENUMS(ChildMode RestorePolicy)
public:
enum ChildMode {
ExclusiveStates,
ParallelStates
};
+ Q_ENUM(ChildMode)
enum RestorePolicy {
DontRestoreProperties,
RestoreProperties
};
+ Q_ENUM(RestorePolicy)
QState(QState *parent = 0);
QState(ChildMode childMode, QState *parent = 0);
@@ -74,6 +75,18 @@ public:
void addTransition(QAbstractTransition *transition);
QSignalTransition *addTransition(const QObject *sender, const char *signal, QAbstractState *target);
+#ifdef Q_QDOC
+ QSignalTransition *addTransition(const QObject *sender, PointerToMemberFunction signal,
+ QAbstractState *target);
+#else
+ template <typename Func>
+ QSignalTransition *addTransition(const typename QtPrivate::FunctionPointer<Func>::Object *obj,
+ Func signal, QAbstractState *target)
+ {
+ const QMetaMethod signalMetaMethod = QMetaMethod::fromSignal(signal);
+ return addTransition(obj, signalMetaMethod.methodSignature().constData(), target);
+ }
+#endif // Q_QDOC
QAbstractTransition *addTransition(QAbstractState *target);
void removeTransition(QAbstractTransition *transition);
QList<QAbstractTransition*> transitions() const;
@@ -90,37 +103,17 @@ public:
#endif
Q_SIGNALS:
- void finished(
-#if !defined(Q_QDOC)
- QPrivateSignal
-#endif
- );
- void propertiesAssigned(
-#if !defined(Q_QDOC)
- QPrivateSignal
-#endif
- );
- void childModeChanged(
-#if !defined(Q_QDOC)
- QPrivateSignal
-#endif
- );
- void initialStateChanged(
-#if !defined(Q_QDOC)
- QPrivateSignal
-#endif
- );
- void errorStateChanged(
-#if !defined(Q_QDOC)
- QPrivateSignal
-#endif
- );
+ void finished(QPrivateSignal);
+ void propertiesAssigned(QPrivateSignal);
+ void childModeChanged(QPrivateSignal);
+ void initialStateChanged(QPrivateSignal);
+ void errorStateChanged(QPrivateSignal);
protected:
- void onEntry(QEvent *event);
- void onExit(QEvent *event);
+ void onEntry(QEvent *event) Q_DECL_OVERRIDE;
+ void onExit(QEvent *event) Q_DECL_OVERRIDE;
- bool event(QEvent *e);
+ bool event(QEvent *e) Q_DECL_OVERRIDE;
protected:
QState(QStatePrivate &dd, QState *parent);
diff --git a/src/corelib/statemachine/qstate_p.h b/src/corelib/statemachine/qstate_p.h
index dd563803ff..2ce0c13522 100644
--- a/src/corelib/statemachine/qstate_p.h
+++ b/src/corelib/statemachine/qstate_p.h
@@ -1,7 +1,7 @@
/****************************************************************************
**
-** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
-** Contact: http://www.qt-project.org/legal
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
**
@@ -10,9 +10,9 @@
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and Digia. For licensing terms and
-** conditions see http://qt.digia.com/licensing. For further information
-** use the contact form at http://qt.digia.com/contact-us.
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
@@ -23,8 +23,8 @@
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
-** In addition, as a special exception, Digia gives you certain additional
-** rights. These rights are described in the Digia Qt LGPL Exception
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** $QT_END_LICENSE$
@@ -103,8 +103,8 @@ public:
QAbstractState *initialState;
QState::ChildMode childMode;
mutable bool childStatesListNeedsRefresh;
- mutable QList<QAbstractState*> childStatesList;
mutable bool transitionsListNeedsRefresh;
+ mutable QList<QAbstractState*> childStatesList;
mutable QList<QAbstractTransition*> transitionsList;
#ifndef QT_NO_PROPERTIES
diff --git a/src/corelib/statemachine/qstatemachine.cpp b/src/corelib/statemachine/qstatemachine.cpp
index 1350c8d99e..e5d019dc8b 100644
--- a/src/corelib/statemachine/qstatemachine.cpp
+++ b/src/corelib/statemachine/qstatemachine.cpp
@@ -1,7 +1,7 @@
/****************************************************************************
**
-** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
-** Contact: http://www.qt-project.org/legal
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
**
@@ -10,9 +10,9 @@
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and Digia. For licensing terms and
-** conditions see http://qt.digia.com/licensing. For further information
-** use the contact form at http://qt.digia.com/contact-us.
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
@@ -23,8 +23,8 @@
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
-** In addition, as a special exception, Digia gives you certain additional
-** rights. These rights are described in the Digia Qt LGPL Exception
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** $QT_END_LICENSE$
@@ -177,6 +177,212 @@ QT_BEGIN_NAMESPACE
// #define QSTATEMACHINE_DEBUG
// #define QSTATEMACHINE_RESTORE_PROPERTIES_DEBUG
+struct CalculationCache {
+ struct TransitionInfo {
+ QList<QAbstractState*> effectiveTargetStates;
+ QSet<QAbstractState*> exitSet;
+ QAbstractState *transitionDomain;
+
+ bool effectiveTargetStatesIsKnown: 1;
+ bool exitSetIsKnown : 1;
+ bool transitionDomainIsKnown : 1;
+
+ TransitionInfo()
+ : transitionDomain(0)
+ , effectiveTargetStatesIsKnown(false)
+ , exitSetIsKnown(false)
+ , transitionDomainIsKnown(false)
+ {}
+ };
+
+ typedef QHash<QAbstractTransition *, TransitionInfo> TransitionInfoCache;
+ TransitionInfoCache cache;
+
+ bool effectiveTargetStates(QAbstractTransition *t, QList<QAbstractState *> *targets) const
+ {
+ Q_ASSERT(targets);
+
+ TransitionInfoCache::const_iterator cacheIt = cache.find(t);
+ if (cacheIt == cache.end() || !cacheIt->effectiveTargetStatesIsKnown)
+ return false;
+
+ *targets = cacheIt->effectiveTargetStates;
+ return true;
+ }
+
+ void insert(QAbstractTransition *t, const QList<QAbstractState *> &targets)
+ {
+ TransitionInfoCache::iterator cacheIt = cache.find(t);
+ TransitionInfo &ti = cacheIt == cache.end()
+ ? *cache.insert(t, TransitionInfo())
+ : *cacheIt;
+
+ Q_ASSERT(!ti.effectiveTargetStatesIsKnown);
+ ti.effectiveTargetStates = targets;
+ ti.effectiveTargetStatesIsKnown = true;
+ }
+
+ bool exitSet(QAbstractTransition *t, QSet<QAbstractState *> *exits) const
+ {
+ Q_ASSERT(exits);
+
+ TransitionInfoCache::const_iterator cacheIt = cache.find(t);
+ if (cacheIt == cache.end() || !cacheIt->exitSetIsKnown)
+ return false;
+
+ *exits = cacheIt->exitSet;
+ return true;
+ }
+
+ void insert(QAbstractTransition *t, const QSet<QAbstractState *> &exits)
+ {
+ TransitionInfoCache::iterator cacheIt = cache.find(t);
+ TransitionInfo &ti = cacheIt == cache.end()
+ ? *cache.insert(t, TransitionInfo())
+ : *cacheIt;
+
+ Q_ASSERT(!ti.exitSetIsKnown);
+ ti.exitSet = exits;
+ ti.exitSetIsKnown = true;
+ }
+
+ bool transitionDomain(QAbstractTransition *t, QAbstractState **domain) const
+ {
+ Q_ASSERT(domain);
+
+ TransitionInfoCache::const_iterator cacheIt = cache.find(t);
+ if (cacheIt == cache.end() || !cacheIt->transitionDomainIsKnown)
+ return false;
+
+ *domain = cacheIt->transitionDomain;
+ return true;
+ }
+
+ void insert(QAbstractTransition *t, QAbstractState *domain)
+ {
+ TransitionInfoCache::iterator cacheIt = cache.find(t);
+ TransitionInfo &ti = cacheIt == cache.end()
+ ? *cache.insert(t, TransitionInfo())
+ : *cacheIt;
+
+ Q_ASSERT(!ti.transitionDomainIsKnown);
+ ti.transitionDomain = domain;
+ ti.transitionDomainIsKnown = true;
+ }
+};
+
+/* The function as described in http://www.w3.org/TR/2014/WD-scxml-20140529/ :
+
+function isDescendant(state1, state2)
+
+Returns 'true' if state1 is a descendant of state2 (a child, or a child of a child, or a child of a
+child of a child, etc.) Otherwise returns 'false'.
+*/
+static inline bool isDescendant(const QAbstractState *state1, const QAbstractState *state2)
+{
+ Q_ASSERT(state1 != 0);
+
+ for (QAbstractState *it = state1->parentState(); it != 0; it = it->parentState()) {
+ if (it == state2)
+ return true;
+ }
+
+ return false;
+}
+
+static bool containsDecendantOf(const QSet<QAbstractState *> &states, const QAbstractState *node)
+{
+ foreach (QAbstractState *s, states)
+ if (isDescendant(s, node))
+ return true;
+
+ return false;
+}
+
+static int descendantDepth(const QAbstractState *state, const QAbstractState *ancestor)
+{
+ int depth = 0;
+ for (const QAbstractState *it = state; it != 0; it = it->parentState()) {
+ if (it == ancestor)
+ break;
+ ++depth;
+ }
+ return depth;
+}
+
+/* The function as described in http://www.w3.org/TR/2014/WD-scxml-20140529/ :
+
+function getProperAncestors(state1, state2)
+
+If state2 is null, returns the set of all ancestors of state1 in ancestry order (state1's parent
+followed by the parent's parent, etc. up to an including the <scxml> element). If state2 is
+non-null, returns in ancestry order the set of all ancestors of state1, up to but not including
+state2. (A "proper ancestor" of a state is its parent, or the parent's parent, or the parent's
+parent's parent, etc.))If state2 is state1's parent, or equal to state1, or a descendant of state1,
+this returns the empty set.
+*/
+static QVector<QState*> getProperAncestors(const QAbstractState *state, const QAbstractState *upperBound)
+{
+ Q_ASSERT(state != 0);
+ QVector<QState*> result;
+ result.reserve(16);
+ for (QState *it = state->parentState(); it && it != upperBound; it = it->parentState()) {
+ result.append(it);
+ }
+ return result;
+}
+
+/* The function as described in http://www.w3.org/TR/2014/WD-scxml-20140529/ :
+
+function getEffectiveTargetStates(transition)
+
+Returns the states that will be the target when 'transition' is taken, dereferencing any history states.
+
+function getEffectiveTargetStates(transition)
+ targets = new OrderedSet()
+ for s in transition.target
+ if isHistoryState(s):
+ if historyValue[s.id]:
+ targets.union(historyValue[s.id])
+ else:
+ targets.union(getEffectiveTargetStates(s.transition))
+ else:
+ targets.add(s)
+ return targets
+*/
+static QList<QAbstractState *> getEffectiveTargetStates(QAbstractTransition *transition, CalculationCache *cache)
+{
+ Q_ASSERT(cache);
+
+ QList<QAbstractState *> targetsList;
+ if (cache->effectiveTargetStates(transition, &targetsList))
+ return targetsList;
+
+ QSet<QAbstractState *> targets;
+ foreach (QAbstractState *s, transition->targetStates()) {
+ if (QHistoryState *historyState = QStateMachinePrivate::toHistoryState(s)) {
+ QList<QAbstractState*> historyConfiguration = QHistoryStatePrivate::get(historyState)->configuration;
+ if (!historyConfiguration.isEmpty()) {
+ // There is a saved history, so apply that.
+ targets.unite(historyConfiguration.toSet());
+ } else if (QAbstractState *defaultState = historyState->defaultState()) {
+ // Qt does not support initial transitions, but uses the default state of the history state for this.
+ targets.insert(defaultState);
+ } else {
+ // Woops, we found a history state without a default state. That's not valid!
+ QStateMachinePrivate *m = QStateMachinePrivate::get(historyState->machine());
+ m->setError(QStateMachine::NoDefaultStateInHistoryStateError, historyState);
+ }
+ } else {
+ targets.insert(s);
+ }
+ }
+
+ targetsList = targets.toList();
+ cache->insert(transition, targetsList);
+ return targetsList;
+}
+
template <class T>
static uint qHash(const QPointer<T> &p)
{ return qHash(p.data()); }
@@ -246,21 +452,45 @@ static int indexOfDescendant(QState *s, QAbstractState *desc)
QList<QAbstractState*> childStates = QStatePrivate::get(s)->childStates();
for (int i = 0; i < childStates.size(); ++i) {
QAbstractState *c = childStates.at(i);
- if ((c == desc) || QStateMachinePrivate::isDescendantOf(desc, c)) {
+ if ((c == desc) || isDescendant(desc, c)) {
return i;
}
}
return -1;
}
+bool QStateMachinePrivate::transitionStateEntryLessThan(QAbstractTransition *t1, QAbstractTransition *t2)
+{
+ QState *s1 = t1->sourceState(), *s2 = t2->sourceState();
+ if (s1 == s2) {
+ QList<QAbstractTransition*> transitions = QStatePrivate::get(s1)->transitions();
+ return transitions.indexOf(t1) < transitions.indexOf(t2);
+ } else if (isDescendant(s1, s2)) {
+ return true;
+ } else if (isDescendant(s2, s1)) {
+ return false;
+ } else {
+ Q_ASSERT(s1->machine() != 0);
+ QStateMachinePrivate *mach = QStateMachinePrivate::get(s1->machine());
+ QState *lca = mach->findLCA(QList<QAbstractState*>() << s1 << s2);
+ Q_ASSERT(lca != 0);
+ int s1Depth = descendantDepth(s1, lca);
+ int s2Depth = descendantDepth(s2, lca);
+ if (s1Depth == s2Depth)
+ return (indexOfDescendant(lca, s1) < indexOfDescendant(lca, s2));
+ else
+ return s1Depth > s2Depth;
+ }
+}
+
bool QStateMachinePrivate::stateEntryLessThan(QAbstractState *s1, QAbstractState *s2)
{
if (s1->parent() == s2->parent()) {
return s1->parent()->children().indexOf(s1)
< s2->parent()->children().indexOf(s2);
- } else if (isDescendantOf(s1, s2)) {
+ } else if (isDescendant(s1, s2)) {
return false;
- } else if (isDescendantOf(s2, s1)) {
+ } else if (isDescendant(s2, s1)) {
return true;
} else {
Q_ASSERT(s1->machine() != 0);
@@ -276,9 +506,9 @@ bool QStateMachinePrivate::stateExitLessThan(QAbstractState *s1, QAbstractState
if (s1->parent() == s2->parent()) {
return s2->parent()->children().indexOf(s2)
< s1->parent()->children().indexOf(s1);
- } else if (isDescendantOf(s1, s2)) {
+ } else if (isDescendant(s1, s2)) {
return true;
- } else if (isDescendantOf(s2, s1)) {
+ } else if (isDescendant(s2, s1)) {
return false;
} else {
Q_ASSERT(s1->machine() != 0);
@@ -289,17 +519,20 @@ bool QStateMachinePrivate::stateExitLessThan(QAbstractState *s1, QAbstractState
}
}
-QState *QStateMachinePrivate::findLCA(const QList<QAbstractState*> &states) const
+QState *QStateMachinePrivate::findLCA(const QList<QAbstractState*> &states, bool onlyCompound) const
{
if (states.isEmpty())
return 0;
- QList<QState*> ancestors = properAncestors(states.at(0), rootState()->parentState());
+ QVector<QState*> ancestors = getProperAncestors(states.at(0), rootState()->parentState());
for (int i = 0; i < ancestors.size(); ++i) {
QState *anc = ancestors.at(i);
+ if (onlyCompound && !isCompound(anc))
+ continue;
+
bool ok = true;
for (int j = states.size() - 1; (j > 0) && ok; --j) {
const QAbstractState *s = states.at(j);
- if (!isDescendantOf(s, anc))
+ if (!isDescendant(s, anc))
ok = false;
}
if (ok)
@@ -308,40 +541,27 @@ QState *QStateMachinePrivate::findLCA(const QList<QAbstractState*> &states) cons
return 0;
}
-bool QStateMachinePrivate::isPreempted(const QAbstractState *s, const QSet<QAbstractTransition*> &transitions) const
+QState *QStateMachinePrivate::findLCCA(const QList<QAbstractState*> &states) const
{
- QSet<QAbstractTransition*>::const_iterator it;
- for (it = transitions.constBegin(); it != transitions.constEnd(); ++it) {
- QAbstractTransition *t = *it;
- QList<QAbstractState*> lst = t->targetStates();
- if (!lst.isEmpty()) {
- lst.prepend(t->sourceState());
- QAbstractState *lca = findLCA(lst);
- if (isDescendantOf(s, lca)) {
-#ifdef QSTATEMACHINE_DEBUG
- qDebug() << q_func() << ':' << transitions << "preempts selection of a transition from"
- << s << "because" << s << "is a descendant of" << lca;
-#endif
- return true;
- }
- }
- }
- return false;
+ return findLCA(states, true);
}
-QSet<QAbstractTransition*> QStateMachinePrivate::selectTransitions(QEvent *event) const
+QList<QAbstractTransition*> QStateMachinePrivate::selectTransitions(QEvent *event, CalculationCache *cache)
{
+ Q_ASSERT(cache);
Q_Q(const QStateMachine);
- QSet<QAbstractTransition*> enabledTransitions;
- QSet<QAbstractState*>::const_iterator it;
+
+ QVarLengthArray<QAbstractState *> configuration_sorted;
+ foreach (QAbstractState *s, configuration) {
+ if (isAtomic(s))
+ configuration_sorted.append(s);
+ }
+ std::sort(configuration_sorted.begin(), configuration_sorted.end(), stateEntryLessThan);
+
+ QList<QAbstractTransition*> enabledTransitions;
const_cast<QStateMachine*>(q)->beginSelectTransitions(event);
- for (it = configuration.constBegin(); it != configuration.constEnd(); ++it) {
- QAbstractState *state = *it;
- if (!isAtomic(state))
- continue;
- if (isPreempted(state, enabledTransitions))
- continue;
- QList<QState*> lst = properAncestors(state, rootState()->parentState());
+ foreach (QAbstractState *state, configuration_sorted) {
+ QVector<QState*> lst = getProperAncestors(state, Q_NULLPTR);
if (QState *grp = toStandardState(state))
lst.prepend(grp);
bool found = false;
@@ -354,28 +574,115 @@ QSet<QAbstractTransition*> QStateMachinePrivate::selectTransitions(QEvent *event
#ifdef QSTATEMACHINE_DEBUG
qDebug() << q << ": selecting transition" << t;
#endif
- enabledTransitions.insert(t);
+ enabledTransitions.append(t);
found = true;
break;
}
}
}
}
+
+ if (!enabledTransitions.isEmpty()) {
+ removeConflictingTransitions(enabledTransitions, cache);
+#ifdef QSTATEMACHINE_DEBUG
+ qDebug() << q << ": enabled transitions after removing conflicts:" << enabledTransitions;
+#endif
+ }
const_cast<QStateMachine*>(q)->endSelectTransitions(event);
return enabledTransitions;
}
-void QStateMachinePrivate::microstep(QEvent *event, const QList<QAbstractTransition*> &enabledTransitions)
+/* The function as described in http://www.w3.org/TR/2014/WD-scxml-20140529/ :
+
+function removeConflictingTransitions(enabledTransitions):
+ filteredTransitions = new OrderedSet()
+ // toList sorts the transitions in the order of the states that selected them
+ for t1 in enabledTransitions.toList():
+ t1Preempted = false;
+ transitionsToRemove = new OrderedSet()
+ for t2 in filteredTransitions.toList():
+ if computeExitSet([t1]).hasIntersection(computeExitSet([t2])):
+ if isDescendant(t1.source, t2.source):
+ transitionsToRemove.add(t2)
+ else:
+ t1Preempted = true
+ break
+ if not t1Preempted:
+ for t3 in transitionsToRemove.toList():
+ filteredTransitions.delete(t3)
+ filteredTransitions.add(t1)
+
+ return filteredTransitions
+
+Note: the implementation below does not build the transitionsToRemove, but removes them in-place.
+*/
+void QStateMachinePrivate::removeConflictingTransitions(QList<QAbstractTransition*> &enabledTransitions, CalculationCache *cache)
+{
+ Q_ASSERT(cache);
+
+ if (enabledTransitions.size() < 2)
+ return; // There is no transition to conflict with.
+
+ QList<QAbstractTransition*> filteredTransitions;
+ filteredTransitions.reserve(enabledTransitions.size());
+ std::sort(enabledTransitions.begin(), enabledTransitions.end(), transitionStateEntryLessThan);
+
+ foreach (QAbstractTransition *t1, enabledTransitions) {
+ bool t1Preempted = false;
+ QSet<QAbstractState*> exitSetT1 = computeExitSet_Unordered(t1, cache);
+ QList<QAbstractTransition*>::iterator t2It = filteredTransitions.begin();
+ while (t2It != filteredTransitions.end()) {
+ QAbstractTransition *t2 = *t2It;
+ if (t1 == t2) {
+ // Special case: someone added the same transition object to a state twice. In this
+ // case, t2 (which is already in the list) "preempts" t1.
+ t1Preempted = true;
+ break;
+ }
+
+ QSet<QAbstractState*> exitSetT2 = computeExitSet_Unordered(t2, cache);
+ if (exitSetT1.intersect(exitSetT2).isEmpty()) {
+ // No conflict, no cry. Next patient please.
+ ++t2It;
+ } else {
+ // Houston, we have a conflict. Check which transition can be removed.
+ if (isDescendant(t1->sourceState(), t2->sourceState())) {
+ // t1 preempts t2, so we can remove t2
+ t2It = filteredTransitions.erase(t2It);
+ } else {
+ // t2 preempts t1, so there's no use in looking further and we don't need to add
+ // t1 to the list.
+ t1Preempted = true;
+ break;
+ }
+ }
+ }
+ if (!t1Preempted)
+ filteredTransitions.append(t1);
+ }
+
+ enabledTransitions = filteredTransitions;
+}
+
+void QStateMachinePrivate::microstep(QEvent *event, const QList<QAbstractTransition*> &enabledTransitions,
+ CalculationCache *cache)
{
+ Q_ASSERT(cache);
+
#ifdef QSTATEMACHINE_DEBUG
qDebug() << q_func() << ": begin microstep( enabledTransitions:" << enabledTransitions << ')';
qDebug() << q_func() << ": configuration before exiting states:" << configuration;
#endif
- QList<QAbstractState*> exitedStates = computeStatesToExit(enabledTransitions);
+ QList<QAbstractState*> exitedStates = computeExitSet(enabledTransitions, cache);
QHash<RestorableId, QVariant> pendingRestorables = computePendingRestorables(exitedStates);
QSet<QAbstractState*> statesForDefaultEntry;
- QList<QAbstractState*> enteredStates = computeStatesToEnter(enabledTransitions, statesForDefaultEntry);
+ QList<QAbstractState*> enteredStates = computeEntrySet(enabledTransitions, statesForDefaultEntry, cache);
+
+#ifdef QSTATEMACHINE_DEBUG
+ qDebug() << q_func() << ": computed exit set:" << exitedStates;
+ qDebug() << q_func() << ": computed entry set:" << enteredStates;
+#endif
QHash<QAbstractState*, QList<QPropertyAssignment> > assignmentsForEnteredStates =
computePropertyAssignments(enteredStates, pendingRestorables);
@@ -409,38 +716,82 @@ void QStateMachinePrivate::microstep(QEvent *event, const QList<QAbstractTransit
#endif
}
-QList<QAbstractState*> QStateMachinePrivate::computeStatesToExit(const QList<QAbstractTransition*> &enabledTransitions)
+/* The function as described in http://www.w3.org/TR/2014/WD-scxml-20140529/ :
+
+procedure computeExitSet(enabledTransitions)
+
+For each transition t in enabledTransitions, if t is targetless then do nothing, else compute the
+transition's domain. (This will be the source state in the case of internal transitions) or the
+least common compound ancestor state of the source state and target states of t (in the case of
+external transitions. Add to the statesToExit set all states in the configuration that are
+descendants of the domain.
+
+function computeExitSet(transitions)
+ statesToExit = new OrderedSet
+ for t in transitions:
+ if (t.target):
+ domain = getTransitionDomain(t)
+ for s in configuration:
+ if isDescendant(s,domain):
+ statesToExit.add(s)
+ return statesToExit
+*/
+QList<QAbstractState*> QStateMachinePrivate::computeExitSet(const QList<QAbstractTransition*> &enabledTransitions,
+ CalculationCache *cache)
{
+ Q_ASSERT(cache);
+
+ QList<QAbstractState*> statesToExit_sorted = computeExitSet_Unordered(enabledTransitions, cache).toList();
+ std::sort(statesToExit_sorted.begin(), statesToExit_sorted.end(), stateExitLessThan);
+ return statesToExit_sorted;
+}
+
+QSet<QAbstractState*> QStateMachinePrivate::computeExitSet_Unordered(const QList<QAbstractTransition*> &enabledTransitions,
+ CalculationCache *cache)
+{
+ Q_ASSERT(cache);
+
QSet<QAbstractState*> statesToExit;
-// QSet<QAbstractState*> statesToSnapshot;
- for (int i = 0; i < enabledTransitions.size(); ++i) {
- QAbstractTransition *t = enabledTransitions.at(i);
- QList<QAbstractState*> lst = t->targetStates();
- if (lst.isEmpty())
- continue;
- lst.prepend(t->sourceState());
- QAbstractState *lca = findLCA(lst);
- if (lca == 0) {
+ foreach (QAbstractTransition *t, enabledTransitions)
+ statesToExit.unite(computeExitSet_Unordered(t, cache));
+ return statesToExit;
+}
+
+QSet<QAbstractState*> QStateMachinePrivate::computeExitSet_Unordered(QAbstractTransition *t,
+ CalculationCache *cache)
+{
+ Q_ASSERT(cache);
+
+ QSet<QAbstractState*> statesToExit;
+ if (cache->exitSet(t, &statesToExit))
+ return statesToExit;
+
+ QList<QAbstractState *> effectiveTargetStates = getEffectiveTargetStates(t, cache);
+ QAbstractState *domain = getTransitionDomain(t, effectiveTargetStates, cache);
+ if (domain == Q_NULLPTR && !t->targetStates().isEmpty()) {
+ // So we didn't find the least common ancestor for the source and target states of the
+ // transition. If there were not target states, that would be fine: then the transition
+ // will fire any events or signals, but not exit the state.
+ //
+ // However, there are target states, so it's either a node without a parent (or parent's
+ // parent, etc), or the state belongs to a different state machine. Either way, this
+ // makes the state machine invalid.
+ if (error == QStateMachine::NoError)
setError(QStateMachine::NoCommonAncestorForTransitionError, t->sourceState());
- lst = pendingErrorStates.toList();
- lst.prepend(t->sourceState());
+ QList<QAbstractState *> lst = pendingErrorStates.toList();
+ lst.prepend(t->sourceState());
- lca = findLCA(lst);
- Q_ASSERT(lca != 0);
- }
+ domain = findLCCA(lst);
+ Q_ASSERT(domain != 0);
+ }
- {
- QSet<QAbstractState*>::const_iterator it;
- for (it = configuration.constBegin(); it != configuration.constEnd(); ++it) {
- QAbstractState *s = *it;
- if (isDescendantOf(s, lca))
- statesToExit.insert(s);
- }
- }
+ foreach (QAbstractState* s, configuration) {
+ if (isDescendant(s, domain))
+ statesToExit.insert(s);
}
- QList<QAbstractState*> statesToExit_sorted = statesToExit.toList();
- std::sort(statesToExit_sorted.begin(), statesToExit_sorted.end(), stateExitLessThan);
- return statesToExit_sorted;
+
+ cache->insert(t, statesToExit);
+ return statesToExit;
}
void QStateMachinePrivate::exitStates(QEvent *event, const QList<QAbstractState*> &statesToExit_sorted,
@@ -457,7 +808,7 @@ void QStateMachinePrivate::exitStates(QEvent *event, const QList<QAbstractState*
for (it = configuration.constBegin(); it != configuration.constEnd(); ++it) {
QAbstractState *s0 = *it;
if (QHistoryStatePrivate::get(h)->historyType == QHistoryState::DeepHistory) {
- if (isAtomic(s0) && isDescendantOf(s0, s))
+ if (isAtomic(s0) && isDescendant(s0, s))
QHistoryStatePrivate::get(h)->configuration.append(s0);
} else if (s0->parentState() == s) {
QHistoryStatePrivate::get(h)->configuration.append(s0);
@@ -500,30 +851,23 @@ void QStateMachinePrivate::executeTransitionContent(QEvent *event, const QList<Q
}
}
-QList<QAbstractState*> QStateMachinePrivate::computeStatesToEnter(const QList<QAbstractTransition *> &enabledTransitions,
- QSet<QAbstractState *> &statesForDefaultEntry)
+QList<QAbstractState*> QStateMachinePrivate::computeEntrySet(const QList<QAbstractTransition *> &enabledTransitions,
+ QSet<QAbstractState *> &statesForDefaultEntry,
+ CalculationCache *cache)
{
+ Q_ASSERT(cache);
+
QSet<QAbstractState*> statesToEnter;
if (pendingErrorStates.isEmpty()) {
- for (int i = 0; i < enabledTransitions.size(); ++i) {
- QAbstractTransition *t = enabledTransitions.at(i);
- QList<QAbstractState*> lst = t->targetStates();
- if (lst.isEmpty())
- continue;
- QAbstractState *src = t->sourceState();
- if (src)
- lst.prepend(src);
- QState *lca = findLCA(lst);
- for (int j = src ? 1 : 0; j < lst.size(); ++j) {
- QAbstractState *s = lst.at(j);
- addStatesToEnter(s, lca, statesToEnter, statesForDefaultEntry);
+ foreach (QAbstractTransition *t, enabledTransitions) {
+ foreach (QAbstractState *s, t->targetStates()) {
+ addDescendantStatesToEnter(s, statesToEnter, statesForDefaultEntry);
}
- if (isParallel(lca)) {
- QList<QAbstractState*> lcac = QStatePrivate::get(lca)->childStates();
- foreach (QAbstractState* child,lcac) {
- if (!statesToEnter.contains(child))
- addStatesToEnter(child,lca,statesToEnter,statesForDefaultEntry);
- }
+
+ QList<QAbstractState *> effectiveTargetStates = getEffectiveTargetStates(t, cache);
+ QAbstractState *ancestor = getTransitionDomain(t, effectiveTargetStates, cache);
+ foreach (QAbstractState *s, effectiveTargetStates) {
+ addAncestorStatesToEnter(s, ancestor, statesToEnter, statesForDefaultEntry);
}
}
}
@@ -542,6 +886,60 @@ QList<QAbstractState*> QStateMachinePrivate::computeStatesToEnter(const QList<QA
return statesToEnter_sorted;
}
+/* The algorithm as described in http://www.w3.org/TR/2014/WD-scxml-20140529/ :
+
+function getTransitionDomain(transition)
+
+Return the compound state such that 1) all states that are exited or entered as a result of taking
+'transition' are descendants of it 2) no descendant of it has this property.
+
+function getTransitionDomain(t)
+ tstates = getEffectiveTargetStates(t)
+ if not tstates:
+ return null
+ elif t.type == "internal" and isCompoundState(t.source) and tstates.every(lambda s: isDescendant(s,t.source)):
+ return t.source
+ else:
+ return findLCCA([t.source].append(tstates))
+*/
+QAbstractState *QStateMachinePrivate::getTransitionDomain(QAbstractTransition *t,
+ const QList<QAbstractState *> &effectiveTargetStates,
+ CalculationCache *cache) const
+{
+ Q_ASSERT(cache);
+
+ if (effectiveTargetStates.isEmpty())
+ return 0;
+
+ QAbstractState *domain = Q_NULLPTR;
+ if (cache->transitionDomain(t, &domain))
+ return domain;
+
+ if (t->transitionType() == QAbstractTransition::InternalTransition) {
+ if (QState *tSource = t->sourceState()) {
+ if (isCompound(tSource)) {
+ bool allDescendants = true;
+ foreach (QAbstractState *s, effectiveTargetStates) {
+ if (!isDescendant(s, tSource)) {
+ allDescendants = false;
+ break;
+ }
+ }
+
+ if (allDescendants)
+ return tSource;
+ }
+ }
+ }
+
+ QList<QAbstractState *> states(effectiveTargetStates);
+ if (QAbstractState *src = t->sourceState())
+ states.prepend(src);
+ domain = findLCCA(states);
+ cache->insert(t, domain);
+ return domain;
+}
+
void QStateMachinePrivate::enterStates(QEvent *event, const QList<QAbstractState*> &exitedStates_sorted,
const QList<QAbstractState*> &statesToEnter_sorted,
const QSet<QAbstractState*> &statesForDefaultEntry,
@@ -610,10 +1008,9 @@ void QStateMachinePrivate::enterStates(QEvent *event, const QList<QAbstractState
QState *parent = s->parentState();
if (parent) {
if (parent != rootState()) {
-#ifdef QSTATEMACHINE_DEBUG
- qDebug() << q << ": emitting finished signal for" << parent;
-#endif
- QStatePrivate::get(parent)->emitFinished();
+ QFinalState *finalState = qobject_cast<QFinalState *>(s);
+ Q_ASSERT(finalState);
+ emitStateFinished(parent, finalState);
}
QState *grandparent = parent->parentState();
if (grandparent && isParallel(grandparent)) {
@@ -627,10 +1024,9 @@ void QStateMachinePrivate::enterStates(QEvent *event, const QList<QAbstractState
}
}
if (allChildStatesFinal && (grandparent != rootState())) {
-#ifdef QSTATEMACHINE_DEBUG
- qDebug() << q << ": emitting finished signal for" << grandparent;
-#endif
- QStatePrivate::get(grandparent)->emitFinished();
+ QFinalState *finalState = qobject_cast<QFinalState *>(s);
+ Q_ASSERT(finalState);
+ emitStateFinished(grandparent, finalState);
}
}
}
@@ -719,30 +1115,126 @@ void QStateMachinePrivate::addStatesToEnter(QAbstractState *s, QState *root,
}
}
-void QStateMachinePrivate::addAncestorStatesToEnter(QAbstractState *s, QState *root,
+/* The algorithm as described in http://www.w3.org/TR/2014/WD-scxml-20140529/ has a bug. See
+ * QTBUG-44963 for details. The algorithm here is as described in
+ * http://www.w3.org/Voice/2013/scxml-irp/SCXML.htm as of Friday March 13, 2015.
+
+procedure addDescendantStatesToEnter(state,statesToEnter,statesForDefaultEntry, defaultHistoryContent):
+ if isHistoryState(state):
+ if historyValue[state.id]:
+ for s in historyValue[state.id]:
+ addDescendantStatesToEnter(s,statesToEnter,statesForDefaultEntry, defaultHistoryContent)
+ for s in historyValue[state.id]:
+ addAncestorStatesToEnter(s, state.parent, statesToEnter, statesForDefaultEntry, defaultHistoryContent)
+ else:
+ defaultHistoryContent[state.parent.id] = state.transition.content
+ for s in state.transition.target:
+ addDescendantStatesToEnter(s,statesToEnter,statesForDefaultEntry, defaultHistoryContent)
+ for s in state.transition.target:
+ addAncestorStatesToEnter(s, state.parent, statesToEnter, statesForDefaultEntry, defaultHistoryContent)
+ else:
+ statesToEnter.add(state)
+ if isCompoundState(state):
+ statesForDefaultEntry.add(state)
+ for s in state.initial.transition.target:
+ addDescendantStatesToEnter(s,statesToEnter,statesForDefaultEntry, defaultHistoryContent)
+ for s in state.initial.transition.target:
+ addAncestorStatesToEnter(s, state, statesToEnter, statesForDefaultEntry, defaultHistoryContent)
+ else:
+ if isParallelState(state):
+ for child in getChildStates(state):
+ if not statesToEnter.some(lambda s: isDescendant(s,child)):
+ addDescendantStatesToEnter(child,statesToEnter,statesForDefaultEntry, defaultHistoryContent)
+*/
+void QStateMachinePrivate::addDescendantStatesToEnter(QAbstractState *state,
+ QSet<QAbstractState*> &statesToEnter,
+ QSet<QAbstractState*> &statesForDefaultEntry)
+{
+ if (QHistoryState *h = toHistoryState(state)) {
+ QList<QAbstractState*> historyConfiguration = QHistoryStatePrivate::get(h)->configuration;
+ if (!historyConfiguration.isEmpty()) {
+ foreach (QAbstractState *s, historyConfiguration)
+ addDescendantStatesToEnter(s, statesToEnter, statesForDefaultEntry);
+ foreach (QAbstractState *s, historyConfiguration)
+ addAncestorStatesToEnter(s, state->parentState(), statesToEnter, statesForDefaultEntry);
+
+#ifdef QSTATEMACHINE_DEBUG
+ qDebug() << q_func() << ": restoring"
+ << ((QHistoryStatePrivate::get(h)->historyType == QHistoryState::DeepHistory) ? "deep" : "shallow")
+ << "history from" << state << ':' << historyConfiguration;
+#endif
+ } else {
+ QList<QAbstractState*> defaultHistoryContent;
+ if (QHistoryStatePrivate::get(h)->defaultState)
+ defaultHistoryContent.append(QHistoryStatePrivate::get(h)->defaultState);
+
+ if (defaultHistoryContent.isEmpty()) {
+ setError(QStateMachine::NoDefaultStateInHistoryStateError, h);
+ } else {
+ foreach (QAbstractState *s, defaultHistoryContent)
+ addDescendantStatesToEnter(s, statesToEnter, statesForDefaultEntry);
+ foreach (QAbstractState *s, defaultHistoryContent)
+ addAncestorStatesToEnter(s, state->parentState(), statesToEnter, statesForDefaultEntry);
+#ifdef QSTATEMACHINE_DEBUG
+ qDebug() << q_func() << ": initial history targets for" << state << ':' << defaultHistoryContent;
+#endif
+ }
+ }
+ } else {
+ if (state == rootState()) {
+ // Error has already been set by exitStates().
+ Q_ASSERT(error != QStateMachine::NoError);
+ return;
+ }
+ statesToEnter.insert(state);
+ if (isCompound(state)) {
+ statesForDefaultEntry.insert(state);
+ if (QAbstractState *initial = toStandardState(state)->initialState()) {
+ Q_ASSERT(initial->machine() == q_func());
+
+ // Qt does not support initial transitions (which is a problem for parallel states).
+ // The way it simulates this for other states, is by having a single initial state.
+ statesForDefaultEntry.insert(initial);
+
+ addDescendantStatesToEnter(initial, statesToEnter, statesForDefaultEntry);
+ addAncestorStatesToEnter(initial, state, statesToEnter, statesForDefaultEntry);
+ } else {
+ setError(QStateMachine::NoInitialStateError, state);
+ return;
+ }
+ } else if (isParallel(state)) {
+ QState *grp = toStandardState(state);
+ foreach (QAbstractState *child, QStatePrivate::get(grp)->childStates()) {
+ if (!containsDecendantOf(statesToEnter, child))
+ addDescendantStatesToEnter(child, statesToEnter, statesForDefaultEntry);
+ }
+ }
+ }
+}
+
+
+/* The algorithm as described in http://www.w3.org/TR/2014/WD-scxml-20140529/ :
+
+procedure addAncestorStatesToEnter(state, ancestor, statesToEnter, statesForDefaultEntry, defaultHistoryContent)
+ for anc in getProperAncestors(state,ancestor):
+ statesToEnter.add(anc)
+ if isParallelState(anc):
+ for child in getChildStates(anc):
+ if not statesToEnter.some(lambda s: isDescendant(s,child)):
+ addDescendantStatesToEnter(child,statesToEnter,statesForDefaultEntry, defaultHistoryContent)
+*/
+void QStateMachinePrivate::addAncestorStatesToEnter(QAbstractState *s, QAbstractState *ancestor,
QSet<QAbstractState*> &statesToEnter,
QSet<QAbstractState*> &statesForDefaultEntry)
{
- QList<QState*> ancs = properAncestors(s, root);
- for (int i = 0; i < ancs.size(); ++i) {
- QState *anc = ancs.at(i);
+ foreach (QState *anc, getProperAncestors(s, ancestor)) {
if (!anc->parentState())
continue;
statesToEnter.insert(anc);
if (isParallel(anc)) {
- QList<QAbstractState*> lst = QStatePrivate::get(anc)->childStates();
- for (int j = 0; j < lst.size(); ++j) {
- QAbstractState *child = lst.at(j);
- bool hasDescendantInList = false;
- QSet<QAbstractState*>::const_iterator it;
- for (it = statesToEnter.constBegin(); it != statesToEnter.constEnd(); ++it) {
- if (isDescendantOf(*it, child)) {
- hasDescendantInList = true;
- break;
- }
- }
- if (!hasDescendantInList)
- addStatesToEnter(child, anc, statesToEnter, statesForDefaultEntry);
+ foreach (QAbstractState *child, QStatePrivate::get(anc)->childStates()) {
+ if (!containsDecendantOf(statesToEnter, child))
+ addDescendantStatesToEnter(child, statesToEnter, statesForDefaultEntry);
}
}
}
@@ -780,27 +1272,6 @@ bool QStateMachinePrivate::isAtomic(const QAbstractState *s) const
|| (ss && QStatePrivate::get(ss)->isMachine && (ss != rootState()));
}
-
-bool QStateMachinePrivate::isDescendantOf(const QAbstractState *state, const QAbstractState *other)
-{
- Q_ASSERT(state != 0);
- for (QAbstractState *s = state->parentState(); s != 0; s = s->parentState()) {
- if (s == other)
- return true;
- }
- return false;
-}
-
-QList<QState*> QStateMachinePrivate::properAncestors(const QAbstractState *state, const QState *upperBound)
-{
- Q_ASSERT(state != 0);
- QList<QState*> result;
- for (QState *s = state->parentState(); s && s != upperBound; s = s->parentState()) {
- result.append(s);
- }
- return result;
-}
-
QState *QStateMachinePrivate::toStandardState(QAbstractState *state)
{
if (state && (QAbstractStatePrivate::get(state)->stateType == QAbstractStatePrivate::StandardState))
@@ -882,11 +1353,10 @@ QVariant QStateMachinePrivate::savedValueForRestorable(const QList<QAbstractStat
#ifdef QSTATEMACHINE_RESTORE_PROPERTIES_DEBUG
qDebug() << q_func() << ": savedValueForRestorable(" << exitedStates_sorted << object << propertyName << ")";
#endif
- RestorableId id(object, propertyName);
for (int i = exitedStates_sorted.size() - 1; i >= 0; --i) {
QAbstractState *s = exitedStates_sorted.at(i);
QHash<RestorableId, QVariant> restorables = registeredRestorablesForState.value(s);
- QHash<RestorableId, QVariant>::const_iterator it = restorables.constFind(id);
+ QHash<RestorableId, QVariant>::const_iterator it = restorables.constFind(RestorableId(object, propertyName));
if (it != restorables.constEnd()) {
#ifdef QSTATEMACHINE_RESTORE_PROPERTIES_DEBUG
qDebug() << q_func() << ": using" << it.value() << "from" << s;
@@ -897,7 +1367,7 @@ QVariant QStateMachinePrivate::savedValueForRestorable(const QList<QAbstractStat
#ifdef QSTATEMACHINE_RESTORE_PROPERTIES_DEBUG
qDebug() << q_func() << ": falling back to current value";
#endif
- return id.first->property(id.second);
+ return object->property(propertyName);
}
void QStateMachinePrivate::registerRestorable(QAbstractState *state, QObject *object, const QByteArray &propertyName,
@@ -948,14 +1418,15 @@ QList<QPropertyAssignment> QStateMachinePrivate::restorablesToPropertyList(const
QList<QPropertyAssignment> result;
QHash<RestorableId, QVariant>::const_iterator it;
for (it = restorables.constBegin(); it != restorables.constEnd(); ++it) {
- if (!it.key().first) {
+ const RestorableId &id = it.key();
+ if (!id.object()) {
// Property object was deleted
continue;
}
#ifdef QSTATEMACHINE_RESTORE_PROPERTIES_DEBUG
- qDebug() << q_func() << ": restoring" << it.key().first << it.key().second << "to" << it.value();
+ qDebug() << q_func() << ": restoring" << id.object() << id.proertyName() << "to" << it.value();
#endif
- result.append(QPropertyAssignment(it.key().first, it.key().second, it.value(), /*explicitlySet=*/false));
+ result.append(QPropertyAssignment(id.object(), id.propertyName(), it.value(), /*explicitlySet=*/false));
}
return result;
}
@@ -1082,6 +1553,9 @@ void QStateMachinePrivate::setError(QStateMachine::Error errorCode, QAbstractSta
Q_ASSERT(currentErrorState != rootState());
if (currentErrorState != 0) {
+#ifdef QSTATEMACHINE_DEBUG
+ qDebug() << q << ": entering error state" << currentErrorState << "from" << currentContext;
+#endif
QState *lca = findLCA(QList<QAbstractState*>() << currentErrorState << currentContext);
addStatesToEnter(currentErrorState, lca, pendingErrorStates, pendingErrorStatesForDefaultEntry);
} else {
@@ -1303,8 +1777,8 @@ QAbstractTransition *QStateMachinePrivate::createInitialTransition() const
: QAbstractTransition()
{ setTargetStates(targets); }
protected:
- virtual bool eventTest(QEvent *) { return true; }
- virtual void onTransition(QEvent *) {}
+ virtual bool eventTest(QEvent *) Q_DECL_OVERRIDE { return true; }
+ virtual void onTransition(QEvent *) Q_DECL_OVERRIDE {}
};
QState *root = rootState();
@@ -1371,6 +1845,8 @@ void QStateMachinePrivate::_q_start()
registerMultiThreadedSignalTransitions();
+ startupHook();
+
#ifdef QSTATEMACHINE_DEBUG
qDebug() << q << ": starting";
#endif
@@ -1378,6 +1854,7 @@ void QStateMachinePrivate::_q_start()
processingScheduled = true; // we call _q_process() below
QList<QAbstractTransition*> transitions;
+ CalculationCache calculationCache;
QAbstractTransition *initialTransition = createInitialTransition();
transitions.append(initialTransition);
@@ -1385,8 +1862,7 @@ void QStateMachinePrivate::_q_start()
executeTransitionContent(&nullEvent, transitions);
QList<QAbstractState*> exitedStates = QList<QAbstractState*>();
QSet<QAbstractState*> statesForDefaultEntry;
- QList<QAbstractState*> enteredStates = computeStatesToEnter(transitions,
- statesForDefaultEntry);
+ QList<QAbstractState*> enteredStates = computeEntrySet(transitions, statesForDefaultEntry, &calculationCache);
QHash<RestorableId, QVariant> pendingRestorables;
QHash<QAbstractState*, QList<QPropertyAssignment> > assignmentsForEnteredStates =
computePropertyAssignments(enteredStates, pendingRestorables);
@@ -1430,58 +1906,58 @@ void QStateMachinePrivate::_q_process()
Q_ASSERT(!processing);
processing = true;
processingScheduled = false;
+ beginMacrostep();
#ifdef QSTATEMACHINE_DEBUG
qDebug() << q << ": starting the event processing loop";
#endif
+ bool didChange = false;
while (processing) {
if (stop) {
processing = false;
break;
}
- QSet<QAbstractTransition*> enabledTransitions;
+ QList<QAbstractTransition*> enabledTransitions;
+ CalculationCache calculationCache;
+
QEvent *e = new QEvent(QEvent::None);
- enabledTransitions = selectTransitions(e);
+ enabledTransitions = selectTransitions(e, &calculationCache);
if (enabledTransitions.isEmpty()) {
delete e;
e = 0;
}
- if (enabledTransitions.isEmpty() && ((e = dequeueInternalEvent()) != 0)) {
+ while (enabledTransitions.isEmpty() && ((e = dequeueInternalEvent()) != 0)) {
#ifdef QSTATEMACHINE_DEBUG
qDebug() << q << ": dequeued internal event" << e << "of type" << e->type();
#endif
- enabledTransitions = selectTransitions(e);
+ enabledTransitions = selectTransitions(e, &calculationCache);
if (enabledTransitions.isEmpty()) {
delete e;
e = 0;
}
}
- if (enabledTransitions.isEmpty()) {
- if ((e = dequeueExternalEvent()) != 0) {
+ while (enabledTransitions.isEmpty() && ((e = dequeueExternalEvent()) != 0)) {
#ifdef QSTATEMACHINE_DEBUG
qDebug() << q << ": dequeued external event" << e << "of type" << e->type();
#endif
- enabledTransitions = selectTransitions(e);
+ enabledTransitions = selectTransitions(e, &calculationCache);
if (enabledTransitions.isEmpty()) {
delete e;
e = 0;
}
- } else {
- if (isInternalEventQueueEmpty()) {
- processing = false;
- stopProcessingReason = EventQueueEmpty;
- }
- }
- }
- if (!enabledTransitions.isEmpty()) {
- q->beginMicrostep(e);
- microstep(e, enabledTransitions.toList());
- q->endMicrostep(e);
}
+ if (enabledTransitions.isEmpty()) {
+ processing = false;
+ stopProcessingReason = EventQueueEmpty;
+ noMicrostep();
#ifdef QSTATEMACHINE_DEBUG
- else {
qDebug() << q << ": no transitions enabled";
- }
#endif
+ } else {
+ didChange = true;
+ q->beginMicrostep(e);
+ microstep(e, enabledTransitions, &calculationCache);
+ q->endMicrostep(e);
+ }
delete e;
}
#ifdef QSTATEMACHINE_DEBUG
@@ -1494,6 +1970,7 @@ void QStateMachinePrivate::_q_process()
switch (stopProcessingReason) {
case EventQueueEmpty:
+ processedPendingEvents(didChange);
break;
case Finished:
state = NotRunning;
@@ -1510,6 +1987,7 @@ void QStateMachinePrivate::_q_process()
emit q->runningChanged(false);
break;
}
+ endMacrostep(didChange);
}
void QStateMachinePrivate::_q_startDelayedEventTimer(int id, int delay)
@@ -1619,6 +2097,63 @@ void QStateMachinePrivate::cancelAllDelayedEvents()
delayedEvents.clear();
}
+void QStateMachinePrivate::emitStateFinished(QState *forState, QFinalState *guiltyState)
+{
+ Q_UNUSED(guiltyState);
+ Q_ASSERT(guiltyState);
+
+#ifdef QSTATEMACHINE_DEBUG
+ Q_Q(QStateMachine);
+ qDebug() << q << ": emitting finished signal for" << forState;
+#endif
+
+ QStatePrivate::get(forState)->emitFinished();
+}
+
+void QStateMachinePrivate::startupHook()
+{
+}
+
+/*
+ This function is called when the state machine is performing no
+ microstep because no transition is enabled (i.e. an event is ignored).
+
+ The default implementation does nothing.
+*/
+void QStateMachinePrivate::noMicrostep()
+{ }
+
+/*
+ This function is called when the state machine has reached a stable
+ state (no pending events), and has not finished yet.
+ For each event the state machine receives it is guaranteed that
+ 1) beginMacrostep is called
+ 2) selectTransition is called at least once
+ 3) begin/endMicrostep is called at least once or noMicrostep is called
+ at least once (possibly both, but at least one)
+ 4) the state machine either enters an infinite loop, or stops (runningChanged(false),
+ and either finished or stopped are emitted), or processedPendingEvents() is called.
+ 5) if the machine is not in an infinite loop endMacrostep is called
+
+ didChange is set to true if at least one microstep was performed, it is possible
+ that the machine returned to exactly the same state as before, but some transitions
+ were triggered.
+
+ The default implementation does nothing.
+*/
+void QStateMachinePrivate::processedPendingEvents(bool didChange)
+{
+ Q_UNUSED(didChange);
+}
+
+void QStateMachinePrivate::beginMacrostep()
+{ }
+
+void QStateMachinePrivate::endMacrostep(bool didChange)
+{
+ Q_UNUSED(didChange);
+}
+
namespace _QStateMachine_Internal{
class GoToStateTransition : public QAbstractTransition
@@ -1629,8 +2164,8 @@ public:
: QAbstractTransition()
{ setTargetState(target); }
protected:
- void onTransition(QEvent *) { deleteLater(); }
- bool eventTest(QEvent *) { return true; }
+ void onTransition(QEvent *) Q_DECL_OVERRIDE { deleteLater(); }
+ bool eventTest(QEvent *) Q_DECL_OVERRIDE { return true; }
};
} // namespace
@@ -2191,14 +2726,18 @@ void QStateMachine::setRunning(bool running)
event queue. Events are processed in the order posted. The state machine
takes ownership of the event and deletes it once it has been processed.
- You can only post events when the state machine is running.
+ You can only post events when the state machine is running or when it is starting up.
\sa postDelayedEvent()
*/
void QStateMachine::postEvent(QEvent *event, EventPriority priority)
{
Q_D(QStateMachine);
- if (d->state != QStateMachinePrivate::Running) {
+ switch (d->state) {
+ case QStateMachinePrivate::Running:
+ case QStateMachinePrivate::Starting:
+ break;
+ default:
qWarning("QStateMachine::postEvent: cannot post event when the state machine is not running");
return;
}
diff --git a/src/corelib/statemachine/qstatemachine.h b/src/corelib/statemachine/qstatemachine.h
index 5f203d5ed4..d6c3b7bfa7 100644
--- a/src/corelib/statemachine/qstatemachine.h
+++ b/src/corelib/statemachine/qstatemachine.h
@@ -1,7 +1,7 @@
/****************************************************************************
**
-** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
-** Contact: http://www.qt-project.org/legal
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
**
@@ -10,9 +10,9 @@
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and Digia. For licensing terms and
-** conditions see http://qt.digia.com/licensing. For further information
-** use the contact form at http://qt.digia.com/contact-us.
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
@@ -23,8 +23,8 @@
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
-** In addition, as a special exception, Digia gives you certain additional
-** rights. These rights are described in the Digia Qt LGPL Exception
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** $QT_END_LICENSE$
@@ -136,7 +136,7 @@ public:
QSet<QAbstractState*> configuration() const;
#ifndef QT_NO_STATEMACHINE_EVENTFILTER
- bool eventFilter(QObject *watched, QEvent *event);
+ bool eventFilter(QObject *watched, QEvent *event) Q_DECL_OVERRIDE;
#endif
public Q_SLOTS:
@@ -145,22 +145,14 @@ public Q_SLOTS:
void setRunning(bool running);
Q_SIGNALS:
- void started(
-#if !defined(Q_QDOC)
- QPrivateSignal
-#endif
- );
- void stopped(
-#if !defined(Q_QDOC)
- QPrivateSignal
-#endif
- );
+ void started(QPrivateSignal);
+ void stopped(QPrivateSignal);
void runningChanged(bool running);
protected:
- void onEntry(QEvent *event);
- void onExit(QEvent *event);
+ void onEntry(QEvent *event) Q_DECL_OVERRIDE;
+ void onExit(QEvent *event) Q_DECL_OVERRIDE;
virtual void beginSelectTransitions(QEvent *event);
virtual void endSelectTransitions(QEvent *event);
@@ -168,7 +160,7 @@ protected:
virtual void beginMicrostep(QEvent *event);
virtual void endMicrostep(QEvent *event);
- bool event(QEvent *e);
+ bool event(QEvent *e) Q_DECL_OVERRIDE;
protected:
QStateMachine(QStateMachinePrivate &dd, QObject *parent);
diff --git a/src/corelib/statemachine/qstatemachine_p.h b/src/corelib/statemachine/qstatemachine_p.h
index 465d8aff0d..426f2732df 100644
--- a/src/corelib/statemachine/qstatemachine_p.h
+++ b/src/corelib/statemachine/qstatemachine_p.h
@@ -1,7 +1,7 @@
/****************************************************************************
**
-** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
-** Contact: http://www.qt-project.org/legal
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
**
@@ -10,9 +10,9 @@
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and Digia. For licensing terms and
-** conditions see http://qt.digia.com/licensing. For further information
-** use the contact form at http://qt.digia.com/contact-us.
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
@@ -23,8 +23,8 @@
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
-** In addition, as a special exception, Digia gives you certain additional
-** rights. These rights are described in the Digia Qt LGPL Exception
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** $QT_END_LICENSE$
@@ -75,6 +75,7 @@ class QState;
class QAbstractAnimation;
#endif
+struct CalculationCache;
class QStateMachine;
class Q_CORE_EXPORT QStateMachinePrivate : public QStatePrivate
{
@@ -100,8 +101,10 @@ public:
static QStateMachinePrivate *get(QStateMachine *q);
- QState *findLCA(const QList<QAbstractState*> &states) const;
+ QState *findLCA(const QList<QAbstractState*> &states, bool onlyCompound = false) const;
+ QState *findLCCA(const QList<QAbstractState*> &states) const;
+ static bool transitionStateEntryLessThan(QAbstractTransition *t1, QAbstractTransition *t2);
static bool stateEntryLessThan(QAbstractState *s1, QAbstractState *s2);
static bool stateExitLessThan(QAbstractState *s1, QAbstractState *s2);
@@ -122,12 +125,18 @@ public:
void clearHistory();
QAbstractTransition *createInitialTransition() const;
- void microstep(QEvent *event, const QList<QAbstractTransition*> &transitionList);
- bool isPreempted(const QAbstractState *s, const QSet<QAbstractTransition*> &transitions) const;
- QSet<QAbstractTransition*> selectTransitions(QEvent *event) const;
+ void removeConflictingTransitions(QList<QAbstractTransition*> &enabledTransitions, CalculationCache *cache);
+ void microstep(QEvent *event, const QList<QAbstractTransition*> &transitionList, CalculationCache *cache);
+ QList<QAbstractTransition *> selectTransitions(QEvent *event, CalculationCache *cache);
+ virtual void noMicrostep();
+ virtual void processedPendingEvents(bool didChange);
+ virtual void beginMacrostep();
+ virtual void endMacrostep(bool didChange);
void exitStates(QEvent *event, const QList<QAbstractState *> &statesToExit_sorted,
const QHash<QAbstractState*, QList<QPropertyAssignment> > &assignmentsForEnteredStates);
- QList<QAbstractState*> computeStatesToExit(const QList<QAbstractTransition*> &enabledTransitions);
+ QList<QAbstractState*> computeExitSet(const QList<QAbstractTransition*> &enabledTransitions, CalculationCache *cache);
+ QSet<QAbstractState*> computeExitSet_Unordered(const QList<QAbstractTransition*> &enabledTransitions, CalculationCache *cache);
+ QSet<QAbstractState*> computeExitSet_Unordered(QAbstractTransition *t, CalculationCache *cache);
void executeTransitionContent(QEvent *event, const QList<QAbstractTransition*> &transitionList);
void enterStates(QEvent *event, const QList<QAbstractState*> &exitedStates_sorted,
const QList<QAbstractState*> &statesToEnter_sorted,
@@ -137,12 +146,18 @@ public:
, const QList<QAbstractAnimation*> &selectedAnimations
#endif
);
- QList<QAbstractState*> computeStatesToEnter(const QList<QAbstractTransition*> &enabledTransitions,
- QSet<QAbstractState*> &statesForDefaultEntry);
+ QList<QAbstractState*> computeEntrySet(const QList<QAbstractTransition*> &enabledTransitions,
+ QSet<QAbstractState*> &statesForDefaultEntry, CalculationCache *cache);
+ QAbstractState *getTransitionDomain(QAbstractTransition *t,
+ const QList<QAbstractState *> &effectiveTargetStates,
+ CalculationCache *cache) const;
+ void addDescendantStatesToEnter(QAbstractState *state,
+ QSet<QAbstractState*> &statesToEnter,
+ QSet<QAbstractState*> &statesForDefaultEntry);
void addStatesToEnter(QAbstractState *s, QState *root,
QSet<QAbstractState*> &statesToEnter,
QSet<QAbstractState*> &statesForDefaultEntry);
- void addAncestorStatesToEnter(QAbstractState *s, QState *root,
+ void addAncestorStatesToEnter(QAbstractState *s, QAbstractState *ancestor,
QSet<QAbstractState*> &statesToEnter,
QSet<QAbstractState*> &statesForDefaultEntry);
@@ -156,8 +171,6 @@ public:
static bool isParallel(const QAbstractState *s);
bool isCompound(const QAbstractState *s) const;
bool isAtomic(const QAbstractState *s) const;
- static bool isDescendantOf(const QAbstractState *s, const QAbstractState *other);
- static QList<QState*> properAncestors(const QAbstractState *s, const QState *upperBound);
void goToState(QAbstractState *targetState);
@@ -188,8 +201,29 @@ public:
void processEvents(EventProcessingMode processingMode);
void cancelAllDelayedEvents();
+ virtual void emitStateFinished(QState *forState, QFinalState *guiltyState);
+ virtual void startupHook();
+
#ifndef QT_NO_PROPERTIES
- typedef QPair<QPointer<QObject>, QByteArray> RestorableId;
+ class RestorableId {
+ QPointer<QObject> guard;
+ QObject *obj;
+ QByteArray prop;
+ // two overloads because friends can't have default arguments
+ friend uint qHash(const RestorableId &key, uint seed)
+ Q_DECL_NOEXCEPT_EXPR(noexcept(qHash(std::declval<QByteArray>())))
+ { return qHash(qMakePair(key.obj, key.prop), seed); }
+ friend uint qHash(const RestorableId &key) Q_DECL_NOEXCEPT_EXPR(noexcept(qHash(key, 0U)))
+ { return qHash(key, 0U); }
+ friend bool operator==(const RestorableId &lhs, const RestorableId &rhs) Q_DECL_NOTHROW
+ { return lhs.obj == rhs.obj && lhs.prop == rhs.prop; }
+ friend bool operator!=(const RestorableId &lhs, const RestorableId &rhs) Q_DECL_NOTHROW
+ { return !operator==(lhs, rhs); }
+ public:
+ explicit RestorableId(QObject *o, QByteArray p) Q_DECL_NOTHROW : guard(o), obj(o), prop(qMove(p)) {}
+ QObject *object() const Q_DECL_NOTHROW { return guard; }
+ QByteArray propertyName() const Q_DECL_NOTHROW { return prop; }
+ };
QHash<QAbstractState*, QHash<RestorableId, QVariant> > registeredRestorablesForState;
bool hasRestorable(QAbstractState *state, QObject *object, const QByteArray &propertyName) const;
QVariant savedValueForRestorable(const QList<QAbstractState*> &exitedStates_sorted,