KDStateMachineEditor API Documentation 2.1
Loading...
Searching...
No Matches
statemachineview.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 "statemachineview.h"
17
18#include "commandcontroller.h"
19#include "command/command_p.h"
26#include "debug.h"
27#include "editcontroller.h"
28#include "layoutimportexport.h"
30#include "quick/quickpen_p.h"
36#include "state.h"
37#include "transition.h"
38#include "elementmodel.h"
39#include "layoutproperties.h"
40#include "semanticzoommanager.h"
41#include "kdsmeconstants.h"
42#include "depthchecker.h"
43#include "runtimecontroller.h"
44#include "statemachinescene.h"
45
46#include <QDir>
47#include <QFileInfo>
48#include <QQmlContext>
49#include <QQmlEngine>
50#include <QQuickItem>
51#include <QQuickView>
52
53using namespace KDSME;
54
55namespace {
56
57QObject *kdsme_global_singletontype_provider(QQmlEngine *engine, QJSEngine *scriptEngine)
58{
59 Q_UNUSED(engine)
60 Q_UNUSED(scriptEngine)
61
62 return new QuickKDSMEGlobal;
63}
64
65QObject *kdsme_commandFactory_singletontype_provider(QQmlEngine *engine, QJSEngine *scriptEngine)
66{
67 Q_UNUSED(engine)
68 Q_UNUSED(scriptEngine)
69
70 return new CommandFactory;
71}
72
73#if !defined(NDEBUG)
74QString kdsme_qmlErrorString(const QList<QQmlError> &errors)
75{
76 QString s;
77 for (const QQmlError &e : errors) {
78 s += e.toString() + u'\n';
79 }
80 return s;
81}
82#endif
83
84} // namespace
85
86struct StateMachineView::Private // NOLINT(clang-analyzer-cplusplus.NewDelete)
87{
88 Private(StateMachineView *q);
89
91
92 QPointer<StateMachineScene> m_scene; // potentially deleted by the QML engine, thus QPointer
93
94 CommandController *m_controller;
95 EditController *m_editController;
96 QString m_themeName;
97 bool m_editModeEnabled;
98
99 [[nodiscard]] QRectF adjustedViewRect() const;
100
101 void onStateMachineChanged(KDSME::StateMachine *stateMachine);
102};
103
104StateMachineView::Private::Private(StateMachineView *q)
105 : q(q)
106 , m_scene(nullptr)
107 , m_controller(nullptr)
108 , m_editController(nullptr)
109 , m_themeName(q->defaultThemeName())
110 , m_editModeEnabled(false)
111{
112}
113
115 : QQuickWidget(parent)
116 , d(new Private(this))
117{
118 qRegisterMetaType<QPainterPath>();
119 qRegisterMetaType<Qt::PenStyle>();
120 qRegisterMetaType<CommandController *>();
121
122 qRegisterMetaType<LayoutProperties *>();
123 qRegisterMetaType<State *>();
124 qRegisterMetaType<Transition *>();
125 qRegisterMetaType<Element *>();
126 qRegisterMetaType<Element::Type>();
127 qRegisterMetaType<State *>();
128 qRegisterMetaType<StateMachine *>();
129 qRegisterMetaType<StateModel *>();
130 qRegisterMetaType<ObjectTreeModel *>();
131 qRegisterMetaType<AbstractScene::ViewState>();
132 qRegisterMetaType<GLenum>();
133 qRegisterMetaType<ObjectTreeModel *>();
134
135 // creatable types
136 qmlRegisterType<DepthChecker>(KDSME_QML_NAMESPACE, 1, 0, "DepthChecker");
137 qmlRegisterType<QuickMaskedMouseArea>(KDSME_QML_NAMESPACE, 1, 0, "MaskedMouseArea");
138 qmlRegisterType<QuickPainterPath>(KDSME_QML_NAMESPACE, 1, 0, "PainterPath");
139 qmlRegisterType<QuickPainterPathGeometryItem>(KDSME_QML_NAMESPACE, 1, 0, "PainterPathGeometry");
140 qmlRegisterType<QuickPainterPathStroker>(KDSME_QML_NAMESPACE, 1, 0, "PainterPathStroker");
141 qmlRegisterType<QuickPen>(KDSME_QML_NAMESPACE, 1, 0, "Pen");
142 qmlRegisterType<QuickGeometryItem>(KDSME_QML_NAMESPACE, 1, 0, "Geometry");
143 qmlRegisterType<QuickPrimitiveItem>(KDSME_QML_NAMESPACE, 1, 0, "Primitive");
144 qmlRegisterType<QuickRecursiveInstantiator>(KDSME_QML_NAMESPACE, 1, 0, "RecursiveInstantiator");
145 qmlRegisterType<QuickSceneItem>(KDSME_QML_NAMESPACE, 1, 0, "SceneItem");
146 qmlRegisterType<QuickStateItem>(KDSME_QML_NAMESPACE, 1, 0, "StateItem");
147 qmlRegisterType<QuickTransitionItem>(KDSME_QML_NAMESPACE, 1, 0, "TransitionItem");
148 qmlRegisterType<PainterPathMask>(KDSME_QML_NAMESPACE, 1, 0, "PainterPathMask");
149 qmlRegisterType<SemanticZoomManager>(KDSME_QML_NAMESPACE, 1, 0, "SemanticZoomManager");
150 qmlRegisterType<StateMachineScene>(KDSME_QML_NAMESPACE, 1, 0, "StateMachineScene");
151
152 qmlRegisterUncreatableType<AbstractMask>(KDSME_QML_NAMESPACE, 1, 0, "AbstractMask", QStringLiteral("Access to object"));
153 qmlRegisterUncreatableType<AbstractScene>(KDSME_QML_NAMESPACE, 1, 0, "AbstractScene", QStringLiteral("Access to object"));
154 qmlRegisterUncreatableType<EditController>(KDSME_QML_NAMESPACE, 1, 0, "EditController", QStringLiteral("Access to object"));
155 qmlRegisterUncreatableType<CommandController>(KDSME_QML_NAMESPACE, 1, 0, "CommandController", QStringLiteral("Access to object"));
156 qmlRegisterUncreatableType<RuntimeController>(KDSME_QML_NAMESPACE, 1, 0, "RuntimeController", QStringLiteral("Access to object"));
157 qmlRegisterUncreatableType<Element>(KDSME_QML_NAMESPACE, 1, 0, "Element", QStringLiteral("Access to object"));
158 qmlRegisterUncreatableType<HistoryState>(KDSME_QML_NAMESPACE, 1, 0, "HistoryState", QStringLiteral("Access to object"));
159 qmlRegisterUncreatableType<PseudoState>(KDSME_QML_NAMESPACE, 1, 0, "PseudoState", QStringLiteral("Access to object"));
160 qmlRegisterUncreatableType<State>(KDSME_QML_NAMESPACE, 1, 0, "State", QStringLiteral("Access to object"));
161 qmlRegisterUncreatableType<Transition>(KDSME_QML_NAMESPACE, 1, 0, "Transition", QStringLiteral("Access to object"));
162
163 // singletons
164 qmlRegisterSingletonType<QuickKDSMEGlobal>(KDSME_QML_NAMESPACE, 1, 0, "Global", kdsme_global_singletontype_provider);
165 qmlRegisterSingletonType<CommandFactory>(KDSME_QML_NAMESPACE, 1, 0, "CommandFactory", kdsme_commandFactory_singletontype_provider);
166
167 d->m_controller = new CommandController(new QUndoStack(this), this);
168 d->m_editController = new EditController(this);
169
170 engine()->rootContext()->setContextProperty(QStringLiteral("_quickView"), this);
171
172#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
173 // Does not seem to work under Qt 6 -- yields a black QML scene if enabled there
174 QSurfaceFormat format;
175 format.setSamples(4);
176 setFormat(format);
177#endif
178
179 setResizeMode(QQuickWidget::SizeRootObjectToView);
180 setSource(QUrl(QStringLiteral("qrc:/kdsme/qml/StateMachineView.qml")));
181#if !defined(NDEBUG)
182 Q_ASSERT_X(errors().isEmpty(), __FUNCTION__, qPrintable(kdsme_qmlErrorString(errors())));
183#endif
184}
185
189
190
192{
193 return d->m_scene;
194}
195
196void StateMachineView::setScene(StateMachineScene *scene)
197{
198 if (d->m_scene == scene)
199 return;
200
201 if (d->m_scene) {
202 disconnect(d->m_scene, nullptr, this, nullptr);
203 }
204 d->m_scene = scene;
205 if (d->m_scene) {
206 // clang-format off
207 connect(d->m_scene, SIGNAL(stateMachineChanged(KDSME::StateMachine*)), // clazy:exclude=old-style-connect
208 this, SLOT(onStateMachineChanged(KDSME::StateMachine*)));
209 // clang-format on
210 }
211
212 Q_EMIT sceneChanged(d->m_scene);
213}
214
216{
217 return d->m_controller;
218}
219
221{
222 return d->m_editController;
223}
224
226{
227 return QStringLiteral("DarkTheme");
228}
229
231{
232 return d->m_themeName;
233}
234
235void StateMachineView::setThemeName(const QString &themeName)
236{
237 if (d->m_themeName == themeName)
238 return;
239
240 QString selectedThemeName = themeName;
241 if (themeName.isEmpty()) {
242 selectedThemeName = defaultThemeName();
243 } else {
244 const QString themeFile = QStringLiteral(":/kdsme/qml/themes/%1.qml").arg(themeName);
245 if (!QFileInfo::exists(themeFile)) {
246 qCWarning(KDSME_VIEW) << "Theme file" << themeFile << "does not exist, using fallback";
247 selectedThemeName = defaultThemeName();
248 }
249 }
250
251 d->m_themeName = std::move(selectedThemeName);
252 Q_EMIT themeNameChanged(d->m_themeName);
253}
254
256{
257 auto *item = rootObject()->findChild<QQuickItem *>(QStringLiteral("stateMachineViewport"));
258 Q_ASSERT(item);
259 return item;
260}
261
263{
264 auto *item = rootObject()->findChild<QQuickItem *>(QStringLiteral("stateMachineScene"));
265 Q_ASSERT(item);
266 return item;
267}
268
269void StateMachineView::Private::onStateMachineChanged(KDSME::StateMachine *stateMachine)
270{
271 Q_UNUSED(stateMachine);
272}
273
275{
276 Q_ASSERT(d->m_scene);
277 auto *cmd = new ChangeStateMachineCommand(d->m_scene);
278 cmd->setStateMachine(stateMachine);
279 if (d->m_scene->rootState()) {
280 commandController()->push(cmd);
281 } else {
282 cmd->redo();
283 delete cmd;
284 }
285}
286
288{
289 auto *cmd = new DeleteElementCommand(d->m_scene, element);
290 commandController()->push(cmd);
291}
292
293QRectF StateMachineView::Private::adjustedViewRect() const
294{
295 static const int margin = 10;
296
297 const QQuickItem *viewPort = q->rootObject()->findChild<QQuickItem *>(QStringLiteral("scrollView"));
298 const QRectF viewRect(viewPort->x(), viewPort->y(), viewPort->width(), viewPort->height());
299 if (viewRect.isEmpty())
300 return QRectF();
301
302 return viewRect.adjusted(margin, margin, -margin, -margin);
303}
304
306{
307 const QRectF sceneRect = scene()->rootState()->boundingRect();
308 const QRectF viewRect = d->adjustedViewRect();
309 if (sceneRect.isEmpty() || viewRect.isEmpty())
310 return;
311
312 const qreal horizontalScale = viewRect.width() / sceneRect.width();
313 const qreal verticalScale = viewRect.height() / sceneRect.height();
314 const qreal uniformScale = qMin(horizontalScale, verticalScale);
315 scene()->zoomBy(uniformScale);
316}
317
319{
320 Q_ASSERT(commandController());
321 commandController()->undoStack()->push(cmd);
322}
323
324#include "moc_statemachineview.cpp"
Changes the state machine of a KDSME::StateMachineScene and records the old state machine the scene w...
Q_INVOKABLE void push(KDSME::Command *command)
This is the inverse operation to the KDSME::CreateElementCommand command.
virtual QRectF boundingRect() const
Definition element.cpp:199
Widget for displaying a KDSME::StateMachine in a Qt Quick based view.
void setThemeName(const QString &themeName)
KDSME::StateMachineScene * scene
QQuickItem * sceneObject() const
QQuickItem * viewPortObject() const
Q_INVOKABLE void deleteElement(KDSME::Element *element)
Q_INVOKABLE void changeStateMachine(KDSME::StateMachine *stateMachine)
KDSME::CommandController * commandController
Q_INVOKABLE void fitInView()
StateMachineView(QWidget *parent=nullptr)
KDSME::EditController * editController
void sceneChanged(KDSME::StateMachineScene *scene)
Q_INVOKABLE void sendCommand(KDSME::Command *cmd) const
void themeNameChanged(const QString &themeName)
static const char KDSME_QML_NAMESPACE[]

© 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