KDStateMachineEditor API Documentation 2.1
Loading...
Searching...
No Matches
statemachinescene.cpp
Go to the documentation of this file.
1/*
2 This file is part of the KDAB State Machine Editor Library.
3
4 SPDX-FileCopyrightText: 2014 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
5 Author: Kevin Funk <kevin.funk@kdab.com>
6
7 SPDX-License-Identifier: LGPL-2.1-only OR LicenseRef-KDAB-KDStateMachineEditor
8
9 Licensees holding valid commercial KDAB State Machine Editor Library
10 licenses may use this file in accordance with the KDAB State Machine Editor
11 Library License Agreement provided with the Software.
12
13 Contact info@kdab.com if any conditions of this licensing are not clear to you.
14*/
15
16#include <config-kdsme.h>
17
18#include "statemachinescene.h"
19#include "statemachinescene_p.h"
20
21#include "debug.h"
22#include "state.h"
23#include "transition.h"
24#include "layouter.h"
25#include "layoutproperties.h"
26#include "layoututils.h"
27#include "elementmodel.h"
28#include "elementwalker.h"
29#include "objecthelper.h"
30
31#if HAVE_GRAPHVIZ
33#else
34#include "layerwiselayouter.h"
35#endif
36
37#include <QDir>
38#include <QElapsedTimer>
39#include <QItemSelectionModel>
40#include <QPainterPath>
41#include <QSortFilterProxyModel>
42#include <QTransform>
43#include <QQmlEngine>
44
45using namespace KDSME;
46
47StateMachineScene::Private::Private(StateMachineScene *view)
48 : q(view)
49 , m_rootState(nullptr)
50#if HAVE_GRAPHVIZ
51 , m_layouter(new GraphvizLayouter(q))
52#else
53 , m_layouter(new LayerwiseLayouter(q))
54#endif
55 , m_properties(new LayoutProperties(q))
56 , m_zoom(1.0)
57 , m_maximumDepth(3)
58{
59}
60
62 : AbstractScene(parent)
63 , d(new Private(this))
64{
65 setModel(new StateModel(this)); // NOLINT(clang-analyzer-optin.cplusplus.VirtualCall)
66}
67
71
73{
74 return d->m_properties;
75}
76
78{
79 if (!state)
80 return;
81
82 state->setExpanded(false);
83 d->updateChildItemVisibility(state, false);
84}
85
87{
88 if (!state)
89 return;
90
91 state->setExpanded(true);
92 d->updateChildItemVisibility(state, true);
93}
94
96{
97 return state ? state->isExpanded() : false;
98}
99
101{
102 if (expand) {
103 expandItem(state);
104 } else {
105 collapseItem(state);
106 }
107}
108
110{
111 if (!stateModel() || !item)
112 return false;
113
114 const QModelIndex index = stateModel()->indexForObject(item);
115 return selectionModel()->isSelected(index);
116}
117
119{
120 if (!stateModel() || !item)
121 return;
122
123 const QModelIndex index = stateModel()->indexForObject(item);
124 selectionModel()->select(index, (selected ? QItemSelectionModel::Select : QItemSelectionModel::Deselect));
125}
126
131
133{
134 if (!stateModel() || !item)
135 return;
136
137 const QModelIndex index = stateModel()->indexForObject(item);
138 setCurrentIndex(index);
139}
140
142{
143 auto *element = selectionModel()->currentIndex().data(StateModel::ElementRole).value<Element *>();
144 if (!element || element->type() == Element::ElementType)
145 return nullptr;
146
147 if (element->type() == Element::SignalTransitionType || element->type() == Element::TimeoutTransitionType)
148 element = static_cast<Transition *>(element)->sourceState();
149
150 QQmlEngine::setObjectOwnership(element, QQmlEngine::CppOwnership);
151 return element;
152}
153
155{
156 return d->m_rootState;
157}
158
160{
161 if (d->m_rootState == rootState)
162 return;
163
164 // reset properties
165 setZoom(1.0);
166
167 Q_ASSERT(stateModel());
169
170 d->m_rootState = rootState;
171 Q_EMIT rootStateChanged(d->m_rootState);
172
173 d->updateItemVisibilities();
174}
175
177{
178 return d->m_layouter;
179}
180
182{
183 if (d->m_layouter == layouter)
184 return;
185
186 delete d->m_layouter;
187
188 d->m_layouter = layouter;
189
190 if (d->m_layouter) {
191 d->m_layouter->setParent(this);
192 }
193 layout();
194}
195
197{
198 return d->m_zoom;
199}
200
202{
203 if (qFuzzyCompare(d->m_zoom, zoom))
204 return;
205
206 const auto delta = zoom / d->m_zoom;
207 d->zoomByInternal(delta);
208
209 d->m_zoom = zoom;
210 Q_EMIT zoomChanged(d->m_zoom);
211}
212
214{
215 setZoom(d->m_zoom * scale);
216}
217
219{
220 return d->m_maximumDepth;
221}
222
224{
225 if (maximumDepth <= 0 || d->m_maximumDepth == maximumDepth)
226 return;
227
228 d->m_maximumDepth = maximumDepth;
229 Q_EMIT maximumDepthChanged(d->m_maximumDepth);
230
231 auto oldViewState = viewState();
233
234 d->updateItemVisibilities();
235 layout();
236
237 setViewState(oldViewState);
238}
239
240void StateMachineScene::Private::zoomByInternal(qreal scale) const
241{
242 auto root = q->rootState();
243
244 QTransform matrix;
245 matrix.scale(scale, scale);
246
247 auto oldViewState = q->viewState();
248 q->setViewState(RefreshState);
249
251 walker.walkItems(root, [&](Element *element) -> ElementWalker::VisitResult {
252 element->setPos(matrix.map(element->pos()));
253 element->setWidth(element->width() * scale);
254 element->setHeight(element->height() * scale);
255 if (auto transition = qobject_cast<Transition *>(element)) {
256 transition->setShape(matrix.map(transition->shape()));
257 }
259 });
260
261 q->setViewState(oldViewState);
262}
263
265{
266 qCDebug(KDSME_VIEW) << d->m_layouter << d->m_rootState;
267
268 if (!d->m_layouter || !d->m_rootState) {
269 return;
270 }
271
272 auto oldViewState = viewState();
274
275 // reset
276 setZoom(1.0);
277
278 QElapsedTimer timer;
279 timer.start();
280
281 d->m_layouter->layout(d->m_rootState, layoutProperties());
282
283 qCDebug(KDSME_VIEW) << "Layouting took" << timer.elapsed() << "ms";
284
285 setViewState(oldViewState);
286}
287
289{
290 return qobject_cast<StateModel *>(model());
291}
292
293void StateMachineScene::setModel(QAbstractItemModel *model)
294{
295 auto *stateModel = qobject_cast<StateModel *>(model);
296 if (!stateModel) {
297 qCWarning(KDSME_VIEW) << "Invalid model class type, expected StateModel instance";
298 return;
299 }
300
302}
303
304void StateMachineScene::Private::updateItemVisibilities() const
305{
307 walker.walkItems(m_rootState, [&](Element *element) -> ElementWalker::VisitResult {
308 if (auto state = qobject_cast<State *>(element)) {
309 const bool expand = (m_maximumDepth > 0 ? ObjectHelper::depth(m_rootState, state) < m_maximumDepth : true);
310
311 q->setItemExpanded(state, expand);
312 }
313
315 });
316}
317
318void StateMachineScene::Private::updateChildItemVisibility(State *state, bool expand)
319{
320 if (!state)
321 return;
322
324 walker.walkChildren(state, [&](Element *i) -> ElementWalker::VisitResult {
325 if (auto *transition = qobject_cast<Transition *>(i)) {
326 // Avoid hiding transitions from states that are collapsed but still visible
327 // which have a sibling state as their target
328 auto sourceState = transition->sourceState();
329 auto targetState = transition->targetState();
330 if (sourceState->isVisible()
331 && (sourceState->parentState() ? sourceState->parentState()->children().contains(targetState) : false)) {
332 i->setVisible(true);
334 }
335 }
336
337 i->setVisible(expand);
339 });
340}
341
342void StateMachineScene::currentChanged(const QModelIndex &current, const QModelIndex &previous)
343{
344 AbstractScene::currentChanged(current, previous);
345
346 auto *currentItem = current.data(StateModel::ElementRole).value<Element *>();
347 auto *previousItem = previous.data(StateModel::ElementRole).value<Element *>();
348 if (!currentItem && !previousItem) {
349 // something went wrong
350 return;
351 }
352
353 if (currentItem) {
355 }
356 if (previousItem) {
357 previousItem->setSelected(false);
358 }
359
361}
362
363void StateMachineScene::rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end)
364{
365 AbstractScene::rowsAboutToBeRemoved(parent, start, end);
366}
367
368void StateMachineScene::rowsInserted(const QModelIndex &parent, int start, int end)
369{
370 AbstractScene::rowsInserted(parent, start, end);
371}
372
377
378#include "moc_statemachinescene.cpp"
QItemSelectionModel * selectionModel() const
void setViewState(KDSME::AbstractScene::ViewState state)
QAbstractItemModel * model
void setCurrentIndex(const QModelIndex &index)
virtual void setModel(QAbstractItemModel *model)
virtual void currentChanged(const QModelIndex &current, const QModelIndex &previous)
virtual void rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end)
virtual void layoutChanged()
QModelIndex currentIndex() const
virtual void rowsInserted(const QModelIndex &parent, int start, int end)
qreal width
Definition element.h:43
void setPos(const QPointF &pos)
Definition element.cpp:97
void setSelected(bool selected)
Definition element.cpp:164
qreal height
Definition element.h:44
void setVisible(bool visible)
Definition element.cpp:150
QPointF pos
The position of the element from the top-left corner.
Definition element.h:42
void setWidth(qreal width)
Definition element.cpp:111
@ TimeoutTransitionType
Definition element.h:58
@ SignalTransitionType
Definition element.h:57
void setHeight(qreal height)
Definition element.cpp:125
QModelIndex indexForObject(QObject *object) const
void rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end) override
void setModel(QAbstractItemModel *model) override
Q_INVOKABLE void collapseItem(KDSME::State *state)
StateModel * stateModel() const
StateMachineScene(QQuickItem *parent=nullptr)
void zoomChanged(qreal zoom)
Q_INVOKABLE bool isItemSelected(KDSME::Element *item)
void currentChanged(const QModelIndex &current, const QModelIndex &previous) override
void maximumDepthChanged(int depth)
void currentItemChanged(KDSME::Element *currentItem)
Q_INVOKABLE void expandItem(KDSME::State *state)
void rowsInserted(const QModelIndex &parent, int start, int end) override
KDSME::Element * currentState() const
void setCurrentItem(KDSME::Element *item)
Q_INVOKABLE void setItemSelected(KDSME::Element *item, bool selected)
Q_INVOKABLE void setItemExpanded(KDSME::State *state, bool expand)
void rootStateChanged(KDSME::State *state)
void setRootState(State *rootState)
Q_INVOKABLE bool isItemExpanded(KDSME::State *state) const
void setMaximumDepth(int maximumDepth)
KDSME::LayoutProperties * layoutProperties
void setLayouter(Layouter *layouter)
Ownership is transferred.
@ ElementRole
return Element*
void setState(State *state)
void setExpanded(bool expanded)
Definition state.cpp:186
bool isExpanded() const
Definition state.cpp:181
KDSME::State * sourceState
Definition transition.h:26
@ RecursiveWalk
Traverse the children of this item.
Definition treewalker.h:49
KDSME_CORE_EXPORT int depth(const QObject *root, const QObject *object)

© Klarälvdalens Datakonsult AB (KDAB)
"The Qt, C++ and OpenGL Experts"
https://www.kdab.com/
KDStateMachineEditor
Create Qt State Machine metacode using a graphical user interface
https://github.com/KDAB/KDStateMachineEditor
Generated on Tue Jul 15 2025 15:21:47 for KDStateMachineEditor API Documentation by doxygen 1.9.8