aboutsummaryrefslogtreecommitdiffstats
path: root/src/plugins/scxmleditor
diff options
context:
space:
mode:
authorArtem Sokolovskii <artem.sokolovskii@qt.io>2023-04-18 16:46:04 +0200
committerArtem Sokolovskii <artem.sokolovskii@qt.io>2023-05-11 13:59:41 +0000
commit2d1b8dbc2987e6db76c78d8cb449b47e39dd1597 (patch)
treef7ebe3a2d9a83e11c929956799db2e07b9092db4 /src/plugins/scxmleditor
parent56146960029ee843812a5386908d0ea3aaf8ad93 (diff)
Scxmleditor: Add showing onEntry and on Exit events
This commit enhances the SCXML Editor by adding a new feature that enables the display of onEntry and onExit events in the state item. This feature provides developers with a more comprehensive view of the state machine's behavior, allowing them to better understand the transitions that occur when entering or exiting a particular state. Fixes: QTCREATORBUG-17378 Change-Id: Iaf84af209d9acf13bd4183f7da9acbcd6c1c8214 Reviewed-by: Alessandro Portale <alessandro.portale@qt.io>
Diffstat (limited to 'src/plugins/scxmleditor')
-rw-r--r--src/plugins/scxmleditor/CMakeLists.txt1
-rw-r--r--src/plugins/scxmleditor/plugin_interface/baseitem.cpp3
-rw-r--r--src/plugins/scxmleditor/plugin_interface/baseitem.h1
-rw-r--r--src/plugins/scxmleditor/plugin_interface/eventitem.cpp108
-rw-r--r--src/plugins/scxmleditor/plugin_interface/eventitem.h41
-rw-r--r--src/plugins/scxmleditor/plugin_interface/graphicsscene.cpp15
-rw-r--r--src/plugins/scxmleditor/plugin_interface/stateitem.cpp66
-rw-r--r--src/plugins/scxmleditor/plugin_interface/stateitem.h8
8 files changed, 228 insertions, 15 deletions
diff --git a/src/plugins/scxmleditor/CMakeLists.txt b/src/plugins/scxmleditor/CMakeLists.txt
index fef49a90827..358c407233c 100644
--- a/src/plugins/scxmleditor/CMakeLists.txt
+++ b/src/plugins/scxmleditor/CMakeLists.txt
@@ -42,6 +42,7 @@ add_qtc_plugin(ScxmlEditor
plugin_interface/baseitem.cpp plugin_interface/baseitem.h
plugin_interface/connectableitem.cpp plugin_interface/connectableitem.h
plugin_interface/cornergrabberitem.cpp plugin_interface/cornergrabberitem.h
+ plugin_interface/eventitem.cpp plugin_interface/eventitem.h
plugin_interface/finalstateitem.cpp plugin_interface/finalstateitem.h
plugin_interface/genericscxmlplugin.cpp plugin_interface/genericscxmlplugin.h
plugin_interface/graphicsitemprovider.h
diff --git a/src/plugins/scxmleditor/plugin_interface/baseitem.cpp b/src/plugins/scxmleditor/plugin_interface/baseitem.cpp
index 861094321aa..7d87a68f91c 100644
--- a/src/plugins/scxmleditor/plugin_interface/baseitem.cpp
+++ b/src/plugins/scxmleditor/plugin_interface/baseitem.cpp
@@ -41,7 +41,8 @@ BaseItem::~BaseItem()
void BaseItem::checkParentBoundingRect()
{
BaseItem *parentBaseItem = this->parentBaseItem();
- if (parentBaseItem && type() >= InitialStateType && !parentBaseItem->blockUpdates()) {
+ if ((parentBaseItem && type() >= InitialStateType && !parentBaseItem->blockUpdates())
+ || (parentBaseItem && type() == StateWarningType)) {
auto parentStateItem = qgraphicsitem_cast<StateItem*>(parentBaseItem);
if (parentStateItem && (parentStateItem->type() >= StateType))
parentStateItem->updateBoundingRect();
diff --git a/src/plugins/scxmleditor/plugin_interface/baseitem.h b/src/plugins/scxmleditor/plugin_interface/baseitem.h
index 5c992c632b6..42f09ca3893 100644
--- a/src/plugins/scxmleditor/plugin_interface/baseitem.h
+++ b/src/plugins/scxmleditor/plugin_interface/baseitem.h
@@ -93,6 +93,7 @@ public:
ScxmlUiFactory *uiFactory() const;
virtual void updateUIProperties();
+ virtual void addChild(ScxmlTag */*tag*/) {};
protected:
virtual void updatePolygon();
diff --git a/src/plugins/scxmleditor/plugin_interface/eventitem.cpp b/src/plugins/scxmleditor/plugin_interface/eventitem.cpp
new file mode 100644
index 00000000000..f61517f7cf6
--- /dev/null
+++ b/src/plugins/scxmleditor/plugin_interface/eventitem.cpp
@@ -0,0 +1,108 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#include "eventitem.h"
+
+#include <QColor>
+#include <QFont>
+#include <QGraphicsItem>
+#include <QList>
+#include <QString>
+
+namespace ScxmlEditor {
+
+namespace PluginInterface {
+
+EventItem::EventItem(const QPointF &pos, BaseItem *parent)
+ : BaseItem(parent)
+{
+ m_eventNameItem = new TextItem(this);
+ m_eventNameItem->setParentItem(this);
+ QFont serifFont("Times", 13, QFont::Normal);
+ m_eventNameItem->setFont(serifFont);
+
+ QString color = editorInfo("fontColor");
+ m_eventNameItem->setDefaultTextColor(color.isEmpty() ? QColor(Qt::black) : QColor(color));
+
+ setPos(pos);
+ m_eventNameItem->setTextInteractionFlags(Qt::NoTextInteraction);
+ setItemBoundingRect(m_eventNameItem->boundingRect());
+}
+
+void EventItem::updateAttributes()
+{
+ QString text = " " + tag()->tagName();
+ if (tag()->attributeNames().size() > 0) {
+ for (int i = 0; i < tag()->attributeNames().size(); ++i)
+ if (tag()->attributeNames().at(i) == "event") {
+ if (tag()->attributeValues().size() > i)
+ text += " / " + tag()->attributeValues().at(i);
+ break;
+ }
+ }
+ m_eventNameItem->setText(text);
+ setItemBoundingRect(m_eventNameItem->boundingRect());
+}
+
+OnEntryExitItem::OnEntryExitItem(BaseItem *parent)
+ : BaseItem(parent)
+{
+ m_eventNameItem = new TextItem(this);
+ m_eventNameItem->setParentItem(this);
+ QFont serifFont("Times", 13, QFont::Normal);
+ m_eventNameItem->setFont(serifFont);
+ m_eventNameItem->setDefaultTextColor(Qt::black);
+ m_eventNameItem->setTextInteractionFlags(Qt::NoTextInteraction);
+}
+
+void OnEntryExitItem::updateAttributes()
+{
+ QString text = tag()->tagName();
+
+ m_eventNameItem->setText(text);
+ setItemBoundingRect(childBoundingRect());
+ checkParentBoundingRect();
+}
+
+void OnEntryExitItem::finalizeCreation()
+{
+ auto children = tag()->allChildren();
+ auto pos = m_eventNameItem->boundingRect().bottomLeft();
+ for (auto child : children) {
+ EventItem *item = new EventItem(pos, this);
+ item->setTag(child);
+ item->updateAttributes();
+ pos = item->pos() + item->boundingRect().bottomLeft();
+ }
+
+ setItemBoundingRect(childBoundingRect());
+}
+
+void OnEntryExitItem::addChild(ScxmlTag *tag)
+{
+ auto pos = childBoundingRect().bottomLeft();
+ EventItem *item = new EventItem(pos, this);
+ item->setTag(tag);
+ item->updateAttributes();
+
+ setItemBoundingRect(childBoundingRect());
+ checkParentBoundingRect();
+}
+
+QRectF OnEntryExitItem::childBoundingRect() const
+{
+ QRectF r = m_eventNameItem->boundingRect();
+
+ const QList<QGraphicsItem *> children = childItems();
+
+ for (const QGraphicsItem *child : children) {
+ QRectF br = child->boundingRect();
+ QPointF p = child->pos() + br.topLeft();
+ br.moveTopLeft(p);
+ r = r.united(br);
+ }
+ return r;
+}
+
+} // namespace PluginInterface
+} // namespace ScxmlEditor
diff --git a/src/plugins/scxmleditor/plugin_interface/eventitem.h b/src/plugins/scxmleditor/plugin_interface/eventitem.h
new file mode 100644
index 00000000000..cf8ff3a9e34
--- /dev/null
+++ b/src/plugins/scxmleditor/plugin_interface/eventitem.h
@@ -0,0 +1,41 @@
+// Copyright (C) 2022 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+
+#pragma once
+
+#include "baseitem.h"
+#include "textitem.h"
+
+namespace ScxmlEditor::PluginInterface {
+
+class EventItem : public BaseItem
+{
+public:
+ explicit EventItem(const QPointF &pos = QPointF(), BaseItem *parent = nullptr);
+
+ void updateAttributes() override;
+ void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *) override {}
+
+private:
+ TextItem *m_eventNameItem;
+};
+
+class OnEntryExitItem : public BaseItem
+{
+public:
+ explicit OnEntryExitItem(BaseItem *parent = nullptr);
+
+ int type() const override { return StateWarningType; }
+
+ void updateAttributes() override;
+ void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *) override {}
+ void finalizeCreation() override;
+ void addChild(ScxmlTag *tag) override;
+
+ QRectF childBoundingRect() const;
+
+private:
+ TextItem *m_eventNameItem;
+};
+
+} // namespace ScxmlEditor::PluginInterface
diff --git a/src/plugins/scxmleditor/plugin_interface/graphicsscene.cpp b/src/plugins/scxmleditor/plugin_interface/graphicsscene.cpp
index fb0e8252db9..94bd8b41edb 100644
--- a/src/plugins/scxmleditor/plugin_interface/graphicsscene.cpp
+++ b/src/plugins/scxmleditor/plugin_interface/graphicsscene.cpp
@@ -467,8 +467,7 @@ void GraphicsScene::endTagChange(ScxmlDocument::TagChange change, ScxmlTag *tag,
break;
}
case ScxmlDocument::TagChangeParent: {
- auto childItem = qobject_cast<ConnectableItem*>(findItem(tag));
-
+ auto childItem = findItem(tag);
if (childItem) {
QTC_ASSERT(tag, break);
BaseItem *newParentItem = findItem(tag->parentTag());
@@ -485,8 +484,11 @@ void GraphicsScene::endTagChange(ScxmlDocument::TagChange change, ScxmlTag *tag,
childItem->setParentItem(newParentItem);
childItem->updateUIProperties();
- childItem->updateTransitions(true);
- childItem->updateTransitionAttributes(true);
+ if (auto childConItem = qobject_cast<ConnectableItem*>(findItem(tag))) {
+ childConItem->updateTransitions(true);
+ childConItem->updateTransitionAttributes(true);
+ }
+
childItem->checkWarnings();
childItem->checkInitial();
if (newParentItem) {
@@ -495,6 +497,8 @@ void GraphicsScene::endTagChange(ScxmlDocument::TagChange change, ScxmlTag *tag,
newParentItem->checkWarnings();
newParentItem->checkOverlapping();
newParentItem->updateUIProperties();
+ if (auto newConItem = qobject_cast<StateItem*>(newParentItem))
+ newConItem->updateBoundingRect();
}
if (oldParentItem)
@@ -549,6 +553,9 @@ void GraphicsScene::endTagChange(ScxmlDocument::TagChange change, ScxmlTag *tag,
}
if (parentItem) {
+ if (childItem == nullptr)
+ parentItem->addChild(childTag);
+
parentItem->updateAttributes();
parentItem->updateUIProperties();
parentItem->checkInitial();
diff --git a/src/plugins/scxmleditor/plugin_interface/stateitem.cpp b/src/plugins/scxmleditor/plugin_interface/stateitem.cpp
index dd1015f9d40..e53bd8c894e 100644
--- a/src/plugins/scxmleditor/plugin_interface/stateitem.cpp
+++ b/src/plugins/scxmleditor/plugin_interface/stateitem.cpp
@@ -1,19 +1,18 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
-#include "finalstateitem.h"
+#include "stateitem.h"
+
+#include "eventitem.h"
#include "graphicsitemprovider.h"
#include "graphicsscene.h"
#include "idwarningitem.h"
#include "imageprovider.h"
-#include "initialstateitem.h"
-#include "parallelitem.h"
#include "sceneutils.h"
#include "scxmleditorconstants.h"
#include "scxmleditortr.h"
#include "scxmltagutils.h"
#include "scxmluifactory.h"
-#include "stateitem.h"
#include "statewarningitem.h"
#include "textitem.h"
#include "transitionitem.h"
@@ -28,6 +27,7 @@
#include <QTextOption>
#include <QUndoStack>
#include <QtMath>
+#include <QRubberBand>
using namespace ScxmlEditor::PluginInterface;
@@ -171,6 +171,7 @@ void StateItem::updateBoundingRect()
// Check if we need to increase parent boundingrect
if (!r2.isNull()) {
+ positionOnExitItems();
QRectF r = boundingRect();
QRectF r3 = r.united(r2);
@@ -244,7 +245,6 @@ void StateItem::transitionCountChanged()
QRectF StateItem::childItemsBoundingRect() const
{
QRectF r;
- QRectF rr = boundingRect();
QList<QGraphicsItem*> children = childItems();
for (int i = 0; i < children.count(); ++i) {
@@ -256,15 +256,26 @@ QRectF StateItem::childItemsBoundingRect() const
}
}
+ if (m_onEntryItem) {
+ QRectF br = m_onEntryItem->childBoundingRect();
+ QPointF p = m_onEntryItem->pos() + br.topLeft();
+ br.moveTopLeft(p);
+ r = r.united(br);
+ }
+
+ if (m_onExitItem) {
+ QRectF br = m_onExitItem->childBoundingRect();
+ QPointF p = m_onExitItem->pos() + br.topLeft();
+ br.moveTopLeft(p);
+ r = r.united(br);
+ }
+
if (m_transitionRect.isValid()) {
r.setLeft(r.left() - m_transitionRect.width());
r.setHeight(qMax(r.height(), m_transitionRect.height()));
r.moveBottom(qMax(r.bottom(), m_transitionRect.bottom()));
}
- if (!r.isNull())
- r.adjust(-20, -(rr.height() * 0.06 + 40), 20, 20);
-
return r;
}
@@ -418,11 +429,18 @@ void StateItem::updatePolygon()
<< m_drawingRect.bottomLeft()
<< m_drawingRect.topLeft();
- m_titleRect = QRectF(m_drawingRect.left(), m_drawingRect.top(), m_drawingRect.width(), TEXT_ITEM_HEIGHT + m_drawingRect.height() * 0.06);
+ m_titleRect = QRectF(m_drawingRect.left(),
+ m_drawingRect.top(),
+ m_drawingRect.width(),
+ TEXT_ITEM_HEIGHT + m_drawingRect.height() * 0.06);
QFont f = m_stateNameItem->font();
f.setPixelSize(m_titleRect.height() * 0.65);
m_stateNameItem->setFont(f);
+ if (m_onEntryItem)
+ m_onEntryItem->setPos(m_titleRect.x(), m_titleRect.bottom());
+ positionOnExitItems();
+
updateTextPositions();
}
@@ -517,13 +535,41 @@ void StateItem::init(ScxmlTag *tag, BaseItem *parentItem, bool initChildren, boo
if (newItem) {
newItem->init(child, this, initChildren, blockUpdates);
newItem->finalizeCreation();
- }
+ } else
+ addChild(child);
}
}
if (blockUpdates)
setBlockUpdates(false);
}
+
+void StateItem::addChild(ScxmlTag *child)
+{
+ if (child->tagName() == "onentry") {
+ OnEntryExitItem *item = new OnEntryExitItem(this);
+ m_onEntryItem = item;
+ item->setTag(child);
+ item->finalizeCreation();
+ item->updateAttributes();
+ m_onEntryItem->setPos(m_titleRect.x(), m_titleRect.bottom());
+ } else if (child->tagName() == "onexit") {
+ OnEntryExitItem *item = new OnEntryExitItem(this);
+ m_onExitItem = item;
+ item->setTag(child);
+ item->finalizeCreation();
+ item->updateAttributes();
+ positionOnExitItems();
+ }
+}
+
+void StateItem::positionOnExitItems()
+{
+ int offset = m_onEntryItem ? m_onEntryItem->boundingRect().height() : 0;
+ if (m_onExitItem)
+ m_onExitItem->setPos(m_titleRect.x(), m_titleRect.bottom() + offset);
+}
+
QString StateItem::itemId() const
{
return m_stateNameItem ? m_stateNameItem->toPlainText() : QString();
diff --git a/src/plugins/scxmleditor/plugin_interface/stateitem.h b/src/plugins/scxmleditor/plugin_interface/stateitem.h
index 585992f040e..beaebe9ebd7 100644
--- a/src/plugins/scxmleditor/plugin_interface/stateitem.h
+++ b/src/plugins/scxmleditor/plugin_interface/stateitem.h
@@ -4,7 +4,9 @@
#pragma once
#include "connectableitem.h"
+#include "textitem.h"
#include <QPen>
+#include <QStyleOptionGraphicsItem>
QT_FORWARD_DECLARE_CLASS(QGraphicsSceneMouseEvent)
@@ -16,6 +18,7 @@ class TransitionItem;
class TextItem;
class IdWarningItem;
class StateWarningItem;
+class OnEntryExitItem;
/**
* @brief The StateItem class represents the SCXML-State.
@@ -49,6 +52,8 @@ public:
QRectF childItemsBoundingRect() const;
void connectToParent(BaseItem *parentItem) override;
+ void addChild(ScxmlTag *child) override;
+
protected:
void updatePolygon() override;
void transitionsChanged() override;
@@ -69,6 +74,7 @@ private:
void updateTextPositions();
void checkParentBoundingRect();
void checkWarningItems();
+ void positionOnExitItems();
TextItem *m_stateNameItem;
StateWarningItem *m_stateWarningItem = nullptr;
@@ -76,6 +82,8 @@ private:
QPen m_pen;
bool m_initial = false;
bool m_parallelState = false;
+ QPointer<OnEntryExitItem> m_onEntryItem;
+ QPointer<OnEntryExitItem> m_onExitItem;
QImage m_backgroundImage;
};