diff options
author | Artem Sokolovskii <artem.sokolovskii@qt.io> | 2023-04-18 16:46:04 +0200 |
---|---|---|
committer | Artem Sokolovskii <artem.sokolovskii@qt.io> | 2023-05-11 13:59:41 +0000 |
commit | 2d1b8dbc2987e6db76c78d8cb449b47e39dd1597 (patch) | |
tree | f7ebe3a2d9a83e11c929956799db2e07b9092db4 /src/plugins/scxmleditor | |
parent | 56146960029ee843812a5386908d0ea3aaf8ad93 (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')
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; }; |