1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtCore module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include "qhistorystate.h"
41#include "qhistorystate_p.h"
42
43QT_BEGIN_NAMESPACE
44
45/*!
46 \class QHistoryState
47 \inmodule QtCore
48
49 \brief The QHistoryState class provides a means of returning to a previously active substate.
50
51 \since 4.6
52 \ingroup statemachine
53
54 A history state is a pseudo-state that represents the child state that the
55 parent state was in the last time the parent state was exited. A transition
56 with a history state as its target is in fact a transition to one or more
57 other child states of the parent state. QHistoryState is part of \l{The
58 State Machine Framework}.
59
60 Use the setDefaultState() function to set the state that should be entered
61 if the parent state has never been entered. Example:
62
63 \code
64 QStateMachine machine;
65
66 QState *s1 = new QState();
67 QState *s11 = new QState(s1);
68 QState *s12 = new QState(s1);
69
70 QHistoryState *s1h = new QHistoryState(s1);
71 s1h->setDefaultState(s11);
72
73 machine.addState(s1);
74
75 QState *s2 = new QState();
76 machine.addState(s2);
77
78 QPushButton *button = new QPushButton();
79 // Clicking the button will cause the state machine to enter the child state
80 // that s1 was in the last time s1 was exited, or the history state's default
81 // state if s1 has never been entered.
82 s1->addTransition(button, SIGNAL(clicked()), s1h);
83 \endcode
84
85 If more than one default state has to be entered, or if the transition to the default state(s)
86 has to be acted upon, the defaultTransition should be set instead. Note that the eventTest()
87 method of that transition will never be called: the selection and execution of the transition is
88 done automatically when entering the history state.
89
90 By default a history state is shallow, meaning that it won't remember nested
91 states. This can be configured through the historyType property.
92*/
93
94/*!
95 \property QHistoryState::defaultTransition
96
97 \brief the default transition of this history state
98*/
99
100/*!
101 \property QHistoryState::defaultState
102
103 \brief the default state of this history state
104*/
105
106/*!
107 \property QHistoryState::historyType
108
109 \brief the type of history that this history state records
110
111 The default value of this property is QHistoryState::ShallowHistory.
112*/
113
114/*!
115 \enum QHistoryState::HistoryType
116
117 This enum specifies the type of history that a QHistoryState records.
118
119 \value ShallowHistory Only the immediate child states of the parent state
120 are recorded. In this case a transition with the history state as its
121 target will end up in the immediate child state that the parent was in the
122 last time it was exited. This is the default.
123
124 \value DeepHistory Nested states are recorded. In this case a transition
125 with the history state as its target will end up in the most deeply nested
126 descendant state the parent was in the last time it was exited.
127*/
128
129namespace {
130class DefaultStateTransition: public QAbstractTransition
131{
132 Q_OBJECT
133
134public:
135 DefaultStateTransition(QHistoryState *source, QAbstractState *target);
136
137protected:
138 // It doesn't matter whether this transition matches any event or not. It is always associated
139 // with a QHistoryState, and as soon as the state-machine detects that it enters a history
140 // state, it will handle this transition as a special case. The history state itself is never
141 // entered either: either the stored configuration will be used, or the target(s) of this
142 // transition are used.
143 bool eventTest(QEvent *event) override { Q_UNUSED(event); return false; }
144 void onTransition(QEvent *event) override { Q_UNUSED(event); }
145};
146}
147
148QHistoryStatePrivate::QHistoryStatePrivate()
149 : QAbstractStatePrivate(HistoryState)
150 , defaultTransition(nullptr)
151 , historyType(QHistoryState::ShallowHistory)
152{
153}
154
155DefaultStateTransition::DefaultStateTransition(QHistoryState *source, QAbstractState *target)
156 : QAbstractTransition()
157{
158 setParent(source);
159 setTargetState(target);
160}
161
162/*!
163 Constructs a new shallow history state with the given \a parent state.
164*/
165QHistoryState::QHistoryState(QState *parent)
166 : QAbstractState(*new QHistoryStatePrivate, parent)
167{
168}
169/*!
170 Constructs a new history state of the given \a type, with the given \a
171 parent state.
172*/
173QHistoryState::QHistoryState(HistoryType type, QState *parent)
174 : QAbstractState(*new QHistoryStatePrivate, parent)
175{
176 Q_D(QHistoryState);
177 d->historyType = type;
178}
179
180/*!
181 Destroys this history state.
182*/
183QHistoryState::~QHistoryState()
184{
185}
186
187/*!
188 Returns this history state's default transition. The default transition is
189 taken when the history state has never been entered before. The target states
190 of the default transition therefore make up the default state.
191
192 \since 5.6
193*/
194QAbstractTransition *QHistoryState::defaultTransition() const
195{
196 Q_D(const QHistoryState);
197 return d->defaultTransition;
198}
199
200/*!
201 Sets this history state's default transition to be the given \a transition.
202 This will set the source state of the \a transition to the history state.
203
204 Note that the eventTest method of the \a transition will never be called.
205
206 \since 5.6
207*/
208void QHistoryState::setDefaultTransition(QAbstractTransition *transition)
209{
210 Q_D(QHistoryState);
211 if (d->defaultTransition != transition) {
212 d->defaultTransition = transition;
213 transition->setParent(this);
214 emit defaultTransitionChanged(QHistoryState::QPrivateSignal());
215 }
216}
217
218/*!
219 Returns this history state's default state. The default state indicates the
220 state to transition to if the parent state has never been entered before.
221*/
222QAbstractState *QHistoryState::defaultState() const
223{
224 Q_D(const QHistoryState);
225 return d->defaultTransition ? d->defaultTransition->targetState() : nullptr;
226}
227
228static inline bool isSoleEntry(const QList<QAbstractState*> &states, const QAbstractState * state)
229{
230 return states.size() == 1 && states.first() == state;
231}
232
233/*!
234 Sets this history state's default state to be the given \a state.
235 \a state must be a sibling of this history state.
236
237 Note that this function does not set \a state as the initial state
238 of its parent.
239*/
240void QHistoryState::setDefaultState(QAbstractState *state)
241{
242 Q_D(QHistoryState);
243 if (state && state->parentState() != parentState()) {
244 qWarning(msg: "QHistoryState::setDefaultState: state %p does not belong "
245 "to this history state's group (%p)", state, parentState());
246 return;
247 }
248 if (!d->defaultTransition || !isSoleEntry(states: d->defaultTransition->targetStates(), state)) {
249 if (!d->defaultTransition || !qobject_cast<DefaultStateTransition*>(object: d->defaultTransition)) {
250 d->defaultTransition = new DefaultStateTransition(this, state);
251 emit defaultTransitionChanged(QHistoryState::QPrivateSignal());
252 } else {
253 d->defaultTransition->setTargetState(state);
254 }
255 emit defaultStateChanged(QHistoryState::QPrivateSignal());
256 }
257}
258
259/*!
260 Returns the type of history that this history state records.
261*/
262QHistoryState::HistoryType QHistoryState::historyType() const
263{
264 Q_D(const QHistoryState);
265 return d->historyType;
266}
267
268/*!
269 Sets the \a type of history that this history state records.
270*/
271void QHistoryState::setHistoryType(HistoryType type)
272{
273 Q_D(QHistoryState);
274 if (d->historyType != type) {
275 d->historyType = type;
276 emit historyTypeChanged(QHistoryState::QPrivateSignal());
277 }
278}
279
280/*!
281 \reimp
282*/
283void QHistoryState::onEntry(QEvent *event)
284{
285 Q_UNUSED(event);
286}
287
288/*!
289 \reimp
290*/
291void QHistoryState::onExit(QEvent *event)
292{
293 Q_UNUSED(event);
294}
295
296/*!
297 \reimp
298*/
299bool QHistoryState::event(QEvent *e)
300{
301 return QAbstractState::event(e);
302}
303
304/*!
305 \fn QHistoryState::defaultStateChanged()
306 \since 5.4
307
308 This signal is emitted when the defaultState property is changed.
309
310 \sa QHistoryState::defaultState
311*/
312
313/*!
314 \fn QHistoryState::historyTypeChanged()
315 \since 5.4
316
317 This signal is emitted when the historyType property is changed.
318
319 \sa QHistoryState::historyType
320*/
321
322/*!
323 \fn QHistoryState::defaultTransitionChanged()
324 \since 5.6
325
326 This signal is emitted when the defaultTransition property is changed.
327
328 \sa QHistoryState::defaultTransition
329*/
330
331QT_END_NAMESPACE
332
333#include "moc_qhistorystate.cpp"
334#include "qhistorystate.moc"
335

source code of qtbase/src/corelib/statemachine/qhistorystate.cpp