Files
qt-creator/src/plugins/scxmleditor/plugin_interface/graphicsscene.cpp
Eike Ziller ed5e6a4999 Add some additional shortcuts for actions
Add Cmd+Shift+- for decreasing font size on macOS.
Do not add Cmd+= for increasing size, because it conflicts with the
existing shortcut for "Replace and Find Next".

Sprinkle some Backspace shortcuts in addition to Delete for removing
items. There are (laptop) keyboards that either do not have a designated
Delete key (requiring Fn+Backspace) or where the Delete key is not
conveniently located/sized, and there is no benefit in making the
distinction in that case anyhow.

Fixes: QTCREATORBUG-706
Fixes: QTCREATORBUG-13733
Change-Id: I06274a9810b82800ec6158a883c95d2a7ae2465e
Reviewed-by: David Schulz <david.schulz@qt.io>
2020-03-17 09:39:37 +00:00

956 lines
28 KiB
C++

/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "graphicsscene.h"
#include "actionhandler.h"
#include "actionprovider.h"
#include "finalstateitem.h"
#include "initialstateitem.h"
#include "parallelitem.h"
#include "sceneutils.h"
#include "scxmleditorconstants.h"
#include "scxmltagutils.h"
#include "scxmluifactory.h"
#include "snapline.h"
#include "stateitem.h"
#include "transitionitem.h"
#include "utilsprovider.h"
#include "warning.h"
#include "warningitem.h"
#include <utils/qtcassert.h>
#include <QAction>
#include <QGuiApplication>
#include <QClipboard>
#include <QMenu>
#include <QMimeData>
#include <QThread>
#include <QUndoStack>
using namespace ScxmlEditor::PluginInterface;
GraphicsScene::GraphicsScene(QObject *parent)
: QGraphicsScene(parent)
{
//setMinimumRenderSize(5);
setItemIndexMethod(QGraphicsScene::NoIndex);
}
GraphicsScene::~GraphicsScene()
{
clear();
}
void GraphicsScene::unselectAll()
{
const QList<QGraphicsItem*> selectedItems = this->selectedItems();
foreach (QGraphicsItem *it, selectedItems)
it->setSelected(false);
if (m_document)
m_document->setCurrentTag(nullptr);
}
void GraphicsScene::unhighlightAll()
{
foreach (BaseItem *it, m_baseItems)
it->setHighlight(false);
}
void GraphicsScene::highlightItems(const QVector<ScxmlTag*> &lstIds)
{
foreach (BaseItem *it, m_baseItems)
it->setHighlight(lstIds.contains(it->tag()));
}
QRectF GraphicsScene::selectedBoundingRect() const
{
QRectF r;
foreach (BaseItem *item, m_baseItems) {
if (item->isSelected())
r = r.united(item->sceneBoundingRect());
}
return r;
}
qreal GraphicsScene::selectedMaxWidth() const
{
qreal maxw = 0;
foreach (BaseItem *item, m_baseItems) {
if (item->isSelected() && item->type() >= InitialStateType)
maxw = qMax(maxw, item->sceneBoundingRect().width());
}
return maxw;
}
qreal GraphicsScene::selectedMaxHeight() const
{
qreal maxh = 0;
foreach (BaseItem *item, m_baseItems) {
if (item->isSelected() && item->type() >= InitialStateType)
maxh = qMax(maxh, item->sceneBoundingRect().height());
}
return maxh;
}
void GraphicsScene::alignStates(int alignType)
{
if (alignType >= ActionAlignLeft && alignType <= ActionAlignVertical) {
m_document->undoStack()->beginMacro(tr("Align states"));
QRectF r = selectedBoundingRect();
if (r.isValid()) {
switch (alignType) {
case ActionAlignLeft:
foreach (BaseItem *item, m_baseItems) {
if (item->isSelected() && item->type() >= InitialStateType)
item->moveStateBy(r.left() - item->sceneBoundingRect().left(), 0);
}
break;
case ActionAlignRight:
foreach (BaseItem *item, m_baseItems) {
if (item->isSelected() && item->type() >= InitialStateType)
item->moveStateBy(r.right() - item->sceneBoundingRect().right(), 0);
}
break;
case ActionAlignTop:
foreach (BaseItem *item, m_baseItems) {
if (item->isSelected() && item->type() >= InitialStateType)
item->moveStateBy(0, r.top() - item->sceneBoundingRect().top());
}
break;
case ActionAlignBottom:
foreach (BaseItem *item, m_baseItems) {
if (item->isSelected() && item->type() >= InitialStateType)
item->moveStateBy(0, r.bottom() - item->sceneBoundingRect().bottom());
}
break;
case ActionAlignHorizontal:
foreach (BaseItem *item, m_baseItems) {
if (item->isSelected() && item->type() >= InitialStateType)
item->moveStateBy(0, r.center().y() - item->sceneBoundingRect().center().y());
}
break;
case ActionAlignVertical:
foreach (BaseItem *item, m_baseItems) {
if (item->isSelected() && item->type() >= InitialStateType)
item->moveStateBy(r.center().x() - item->sceneBoundingRect().center().x(), 0);
}
break;
default:
break;
}
}
m_document->undoStack()->endMacro();
}
}
void GraphicsScene::adjustStates(int adjustType)
{
if (adjustType >= ActionAdjustWidth && adjustType <= ActionAdjustSize) {
m_document->undoStack()->beginMacro(tr("Adjust states"));
qreal maxw = selectedMaxWidth();
qreal maxh = selectedMaxHeight();
foreach (BaseItem *item, m_baseItems) {
if (item->isSelected() && item->type() >= InitialStateType) {
QRectF rr = item->boundingRect();
if ((adjustType == ActionAdjustWidth || adjustType == ActionAdjustSize) && !qFuzzyCompare(rr.width(), maxw))
rr.setWidth(maxw);
if ((adjustType == ActionAdjustHeight || adjustType == ActionAdjustSize) && !qFuzzyCompare(rr.height(), maxh))
rr.setHeight(maxh);
item->setItemBoundingRect(rr);
qgraphicsitem_cast<ConnectableItem*>(item)->updateTransitions(true);
}
}
m_document->undoStack()->endMacro();
}
}
void GraphicsScene::cut()
{
m_document->undoStack()->beginMacro(tr("Cut"));
copy();
removeSelectedItems();
m_document->undoStack()->endMacro();
}
void GraphicsScene::removeSelectedItems()
{
QVector<ScxmlTag*> tags = SceneUtils::findRemovedTags(m_baseItems);
if (!tags.isEmpty()) {
m_document->undoStack()->beginMacro(tr("Remove items"));
// Then remove found tags
for (int i = tags.count(); i--;) {
m_document->setCurrentTag(tags[i]);
m_document->removeTag(tags[i]);
}
m_document->setCurrentTag(nullptr);
m_document->undoStack()->endMacro();
}
}
void GraphicsScene::copy()
{
if (!m_document->currentTag())
return;
QPointF minPos;
QVector<ScxmlTag*> tags;
if (m_document->currentTag()->tagType() == Scxml) {
QVector<BaseItem*> items;
foreach (BaseItem *item, m_baseItems) {
if (!item->parentItem())
items << item;
}
tags = SceneUtils::findCopyTags(items, minPos);
} else {
tags = SceneUtils::findCopyTags(m_baseItems, minPos);
}
if (tags.isEmpty() && m_document->currentTag())
tags << m_document->currentTag();
if (!tags.isEmpty()) {
auto mime = new QMimeData;
QByteArray result = m_document->content(tags);
mime->setText(QLatin1String(result));
mime->setData("StateChartEditor/StateData", result);
QStringList strTypes;
foreach (const ScxmlTag *tag, tags) {
strTypes << tag->tagName(false);
}
mime->setData("StateChartEditor/CopiedTagTypes", strTypes.join(",").toLocal8Bit());
mime->setData("StateChartEditor/CopiedMinPos", QString::fromLatin1("%1:%2").arg(minPos.x()).arg(minPos.y()).toLocal8Bit());
QGuiApplication::clipboard()->setMimeData(mime);
}
checkPaste();
}
void GraphicsScene::checkPaste()
{
const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData();
const QString copiedTagTypes = QLatin1String(mimeData->data("StateChartEditor/CopiedTagTypes"));
emit pasteAvailable(TagUtils::checkPaste(copiedTagTypes, m_document->currentTag()));
}
void GraphicsScene::paste(const QPointF &targetPos)
{
const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData();
QPointF startPos(targetPos);
BaseItem *targetItem = nullptr;
foreach (BaseItem *item, m_baseItems) {
if (item->isSelected() && item->type() >= StateType) {
targetItem = item;
break;
}
}
if (m_lastPasteTargetItem != targetItem)
m_pasteCounter = 0;
m_lastPasteTargetItem = targetItem;
if (m_lastPasteTargetItem)
startPos = m_lastPasteTargetItem->boundingRect().topLeft();
QPointF pastedPos = startPos + QPointF(m_pasteCounter * 30, m_pasteCounter * 30);
m_pasteCounter++;
QString strMinPos = QLatin1String(mimeData->data("StateChartEditor/CopiedMinPos"));
QPointF minPos(0, 0);
if (!strMinPos.isEmpty()) {
QStringList coords = strMinPos.split(":", QString::SkipEmptyParts);
if (coords.count() == 2)
minPos = QPointF(coords[0].toDouble(), coords[1].toDouble());
}
m_document->pasteData(mimeData->data("StateChartEditor/StateData"), minPos, pastedPos);
}
void GraphicsScene::setEditorInfo(const QString &key, const QString &value)
{
foreach (BaseItem *item, m_baseItems) {
if (item->isSelected() && item->type() >= TransitionType)
item->setEditorInfo(key, value);
}
}
void GraphicsScene::setDocument(ScxmlDocument *document)
{
if (m_document)
disconnect(m_document, nullptr, this, nullptr);
m_document = document;
init();
connectDocument();
}
void GraphicsScene::connectDocument()
{
if (m_document) {
connect(m_document.data(), &ScxmlDocument::beginTagChange, this, &GraphicsScene::beginTagChange);
connect(m_document.data(), &ScxmlDocument::endTagChange, this, &GraphicsScene::endTagChange);
}
}
void GraphicsScene::disconnectDocument()
{
if (m_document)
m_document->disconnect(this);
}
void GraphicsScene::init()
{
m_initializing = true;
disconnectDocument();
clear();
addItem(m_lineX = new SnapLine);
addItem(m_lineY = new SnapLine);
if (m_document) {
const ScxmlTag *rootTag = m_document->rootTag();
if (rootTag) {
for (int i = 0; i < rootTag->childCount(); ++i) {
ScxmlTag *child = rootTag->child(i);
ConnectableItem *newItem = SceneUtils::createItemByTagType(child->tagType());
if (newItem) {
addItem(newItem);
newItem->init(child);
}
}
const QList<QGraphicsItem*> items = this->items();
for (int i = 0; i < items.count(); ++i) {
if (items[i]->type() >= TransitionType) {
auto item = qgraphicsitem_cast<BaseItem*>(items[i]);
if (item)
item->finalizeCreation();
}
}
}
}
m_initializing = false;
warningVisibilityChanged(0, nullptr);
emit selectedStateCountChanged(0);
emit selectedBaseItemCountChanged(0);
}
void GraphicsScene::runLayoutToSelectedStates()
{
m_document->undoStack()->beginMacro(tr("Re-layout"));
QVector<BaseItem*> selectedItems;
foreach (BaseItem *node, m_baseItems) {
if (node->isSelected()) {
int index = 0;
for (int i = 0; i < selectedItems.count(); ++i) {
if (node->depth() <= selectedItems[i]->depth()) {
index = i;
break;
}
}
selectedItems.insert(index, node);
}
}
// Layout selected items
for (int i = 0; i < selectedItems.count(); ++i)
selectedItems[i]->doLayout(selectedItems[i]->depth());
// Layout scene items if necessary
if (selectedItems.isEmpty()) {
QList<QGraphicsItem*> sceneItems;
foreach (BaseItem *item, m_baseItems) {
if (item->type() >= InitialStateType && !item->parentItem())
sceneItems << item;
}
SceneUtils::layout(sceneItems);
foreach (QGraphicsItem *item, sceneItems) {
if (item->type() >= StateType)
static_cast<StateItem*>(item)->shrink();
}
}
// Update properties
foreach (BaseItem *node, selectedItems) {
node->updateUIProperties();
}
m_document->undoStack()->endMacro();
}
void GraphicsScene::runAutomaticLayout()
{
m_autoLayoutRunning = true;
// 1. Find max depth
int maxDepth = 0;
foreach (BaseItem *node, m_baseItems) {
maxDepth = qMax(maxDepth, node->depth());
node->setBlockUpdates(true);
}
// 2. Layout every depth-level separately
for (int d = (maxDepth + 1); d--;) {
foreach (BaseItem *node, m_baseItems)
node->doLayout(d);
}
// 3. Layout scene items
QList<QGraphicsItem*> sceneItems;
foreach (BaseItem *item, m_baseItems) {
if (item->type() >= InitialStateType && !item->parentItem())
sceneItems << item;
}
SceneUtils::layout(sceneItems);
foreach (QGraphicsItem *item, sceneItems) {
if (item->type() >= StateType)
static_cast<StateItem*>(item)->shrink();
}
foreach (BaseItem *node, m_baseItems) {
node->updateUIProperties();
node->setBlockUpdates(false);
}
m_autoLayoutRunning = false;
}
void GraphicsScene::beginTagChange(ScxmlDocument::TagChange change, ScxmlTag *tag, const QVariant &value)
{
switch (change) {
case ScxmlDocument::TagRemoveChild: {
if (tag)
removeItems(tag->child(value.toInt()));
break;
}
default:
break;
}
}
void GraphicsScene::endTagChange(ScxmlDocument::TagChange change, ScxmlTag *tag, const QVariant &value)
{
Q_UNUSED(value)
switch (change) {
case ScxmlDocument::TagAttributesChanged: {
foreach (BaseItem *item, m_baseItems) {
if (item->tag() == tag)
item->updateAttributes();
}
break;
}
case ScxmlDocument::TagEditorInfoChanged: {
foreach (BaseItem *item, m_baseItems) {
if (item->tag() == tag)
item->updateEditorInfo();
}
break;
}
case ScxmlDocument::TagCurrentChanged: {
foreach (BaseItem *item, m_baseItems) {
if (!item->isSelected() && item->tag() == tag)
item->setSelected(true);
}
checkPaste();
break;
}
case ScxmlDocument::TagChangeParent: {
auto childItem = qobject_cast<ConnectableItem*>(findItem(tag));
if (childItem) {
QTC_ASSERT(tag, break);
BaseItem *newParentItem = findItem(tag->parentTag());
BaseItem *oldParentItem = childItem->parentBaseItem();
QPointF sPos = childItem->scenePos();
if (oldParentItem) {
childItem->setParentItem(nullptr);
childItem->setPos(sPos);
}
if (newParentItem)
childItem->setPos(newParentItem->mapFromScene(childItem->sceneBoundingRect().center()) - childItem->boundingRect().center());
childItem->setParentItem(newParentItem);
childItem->updateUIProperties();
childItem->updateTransitions(true);
childItem->updateTransitionAttributes(true);
childItem->checkWarnings();
childItem->checkInitial();
if (newParentItem) {
newParentItem->checkInitial();
newParentItem->updateAttributes();
newParentItem->checkWarnings();
newParentItem->checkOverlapping();
newParentItem->updateUIProperties();
}
if (oldParentItem)
oldParentItem->checkInitial();
if (!oldParentItem || !newParentItem)
checkInitialState();
}
break;
}
case ScxmlDocument::TagAddTags: {
// Finalize transitions
if (!tag)
break;
QVector<ScxmlTag*> childTransitionTags;
if (tag->tagName(false) == "transition")
childTransitionTags << tag;
TagUtils::findAllTransitionChildren(tag, childTransitionTags);
for (int i = 0; i < childTransitionTags.count(); ++i) {
BaseItem *item = findItem(childTransitionTags[i]);
if (item)
item->finalizeCreation();
}
}
break;
case ScxmlDocument::TagAddChild: {
ScxmlTag *childTag = tag ? tag->child(value.toInt()) : nullptr;
if (childTag) {
// Check that there is no any item with this tag
BaseItem *childItem = findItem(childTag);
BaseItem *parentItem = findItem(tag);
if (!childItem) {
if (childTag->tagType() == Transition || childTag->tagType() == InitialTransition) {
auto transition = new TransitionItem;
addItem(transition);
transition->setStartItem(qgraphicsitem_cast<ConnectableItem*>(parentItem));
transition->init(childTag, nullptr, false, false);
transition->updateAttributes();
} else {
childItem = SceneUtils::createItemByTagType(childTag->tagType(), QPointF());
if (childItem) {
childItem->init(childTag, parentItem, false);
if (!parentItem)
addItem(childItem);
childItem->finalizeCreation();
childItem->updateUIProperties();
}
}
}
if (parentItem) {
parentItem->updateAttributes();
parentItem->updateUIProperties();
parentItem->checkInitial();
} else
checkInitialState();
}
break;
}
case ScxmlDocument::TagRemoveChild: {
if (tag) {
BaseItem *parentItem = findItem(tag);
if (parentItem) {
parentItem->updateAttributes();
parentItem->checkInitial();
} else {
checkInitialState();
}
}
break;
}
case ScxmlDocument::TagChangeOrder: {
if (tag) {
BaseItem *parentItem = findItem(tag->parentTag());
if (parentItem)
parentItem->updateAttributes();
else
checkInitialState();
}
break;
}
default:
break;
}
}
void GraphicsScene::setTopMostScene(bool topmost)
{
m_topMostScene = topmost;
}
bool GraphicsScene::topMostScene() const
{
return m_topMostScene;
}
void GraphicsScene::setActionHandler(ActionHandler *mgr)
{
m_actionHandler = mgr;
}
void GraphicsScene::setWarningModel(ScxmlEditor::OutputPane::WarningModel *model)
{
m_warningModel = model;
}
void GraphicsScene::setUiFactory(ScxmlUiFactory *uifactory)
{
m_uiFactory = uifactory;
}
ActionHandler *GraphicsScene::actionHandler() const
{
return m_actionHandler;
}
ScxmlEditor::OutputPane::WarningModel *GraphicsScene::warningModel() const
{
return m_warningModel;
}
ScxmlUiFactory *GraphicsScene::uiFactory() const
{
return m_uiFactory;
}
void GraphicsScene::addConnectableItem(ItemType type, const QPointF &pos, BaseItem *parentItem)
{
m_document->undoStack()->beginMacro(tr("Add new state"));
ConnectableItem *newItem = SceneUtils::createItem(type, pos);
if (newItem) {
ScxmlTag *newTag = SceneUtils::createTag(type, m_document);
ScxmlTag *parentTag = parentItem ? parentItem->tag() : m_document->rootTag();
newItem->setTag(newTag);
newItem->setParentItem(parentItem);
if (!parentItem)
addItem(newItem);
newItem->updateAttributes();
newItem->updateEditorInfo();
newItem->updateUIProperties();
if (parentItem)
parentItem->updateUIProperties();
m_document->addTag(parentTag, newTag);
unselectAll();
newItem->setSelected(true);
}
m_document->undoStack()->endMacro();
}
void GraphicsScene::keyPressEvent(QKeyEvent *event)
{
QGraphicsItem *focusItem = this->focusItem();
if (!focusItem || focusItem->type() != TextType) {
if (event->key() == Qt::Key_Delete || event->key() == Qt::Key_Backspace)
removeSelectedItems();
}
QGraphicsScene::keyPressEvent(event);
}
void GraphicsScene::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
QGraphicsItem *it = itemAt(event->scenePos(), QTransform());
if (!it || it->type() == LayoutType) {
if (event->button() == Qt::LeftButton) {
QGraphicsScene::mousePressEvent(event);
m_document->setCurrentTag(m_document->rootTag());
return;
} else if (m_actionHandler && event->button() == Qt::RightButton) {
event->accept();
QMenu menu;
menu.addAction(m_actionHandler->action(ActionCopy));
menu.addAction(m_actionHandler->action(ActionPaste));
menu.addAction(m_actionHandler->action(ActionScreenshot));
menu.addAction(m_actionHandler->action(ActionExportToImage));
menu.addSeparator();
menu.addAction(m_actionHandler->action(ActionZoomIn));
menu.addAction(m_actionHandler->action(ActionZoomOut));
menu.addAction(m_actionHandler->action(ActionFitToView));
if (m_uiFactory) {
auto actionProvider = static_cast<ActionProvider*>(m_uiFactory->object(Constants::C_UI_FACTORY_OBJECT_ACTIONPROVIDER));
if (actionProvider) {
menu.addSeparator();
actionProvider->initStateMenu(m_document->rootTag(), &menu);
}
}
menu.exec(event->screenPos());
return;
}
}
QGraphicsScene::mousePressEvent(event);
}
BaseItem *GraphicsScene::findItem(const ScxmlTag *tag) const
{
if (!tag)
return nullptr;
foreach (BaseItem *it, m_baseItems) {
if (it->tag() == tag)
return it;
}
return nullptr;
}
void GraphicsScene::removeItems(const ScxmlTag *tag)
{
if (tag) {
// Find right items
QVector<BaseItem*> items;
foreach (BaseItem *it, m_baseItems) {
if (it->tag() == tag)
items << it;
}
// Then delete them
for (int i = items.count(); i--;) {
items[i]->setTag(nullptr);
delete items[i];
}
}
}
QPair<bool, bool> GraphicsScene::checkSnapToItem(BaseItem *item, const QPointF &p, QPointF &pp)
{
if (m_selectedStateCount > 1)
return QPair<bool, bool>(false, false);
QGraphicsItem *parentItem = item->parentItem();
qreal diffX = 8;
qreal diffXdY = 2000;
qreal diffY = 8;
qreal diffYdX = 2000;
foreach (BaseItem *it, m_baseItems) {
if (!it->isSelected() && it != item && it->parentItem() == parentItem && it->type() >= InitialStateType) {
QPointF c = it->sceneCenter();
qreal dX = qAbs(c.x() - p.x());
qreal dY = qAbs(c.y() - p.y());
if (dX < 7 && dY < diffXdY) {
pp.setX(c.x());
diffX = dX;
diffXdY = dY;
m_lineY->show(c.x(), c.y(), c.x(), p.y());
}
if (dY < 7 && dX < diffYdX) {
pp.setY(c.y());
diffY = dY;
diffYdX = dX;
m_lineX->show(c.x(), c.y(), p.x(), c.y());
}
}
}
if (qFuzzyCompare(diffX, 8))
m_lineY->hideLine();
if (qFuzzyCompare(diffY, 8))
m_lineX->hideLine();
return QPair<bool, bool>(diffX < 8, diffY < 8);
}
void GraphicsScene::selectionChanged(bool para)
{
Q_UNUSED(para)
int count = 0;
int baseCount = 0;
int stateTypeCount = 0;
foreach (BaseItem *item, m_baseItems) {
if (item->isSelected()) {
if (item->type() >= TransitionType)
baseCount++;
if (item->type() >= InitialStateType)
count++;
if (item->type() >= StateType)
stateTypeCount++;
}
}
m_selectedStateTypeCount = stateTypeCount;
if (count != m_selectedStateCount) {
m_selectedStateCount = count;
emit selectedStateCountChanged(m_selectedStateCount);
}
if (baseCount != m_selectedBaseItemCount) {
m_selectedBaseItemCount = baseCount;
emit selectedBaseItemCountChanged(m_selectedBaseItemCount);
}
}
void GraphicsScene::addWarningItem(WarningItem *item)
{
if (!m_allWarnings.contains(item)) {
m_allWarnings << item;
if (!m_autoLayoutRunning && !m_initializing)
QMetaObject::invokeMethod(this, "warningVisibilityChanged", Qt::QueuedConnection, Q_ARG(int, 0));
}
}
void GraphicsScene::removeWarningItem(WarningItem *item)
{
m_allWarnings.removeAll(item);
if (!m_autoLayoutRunning && !m_initializing)
QMetaObject::invokeMethod(this, "warningVisibilityChanged", Qt::QueuedConnection, Q_ARG(int, 0));
}
void GraphicsScene::warningVisibilityChanged(int type, WarningItem *item)
{
if (!m_autoLayoutRunning && !m_initializing) {
foreach (WarningItem *it, m_allWarnings) {
if (it != item && (type == 0 || it->type() == type))
it->check();
}
}
}
ScxmlTag *GraphicsScene::tagByWarning(const ScxmlEditor::OutputPane::Warning *w) const
{
ScxmlTag *tag = nullptr;
foreach (WarningItem *it, m_allWarnings) {
if (it->warning() == w) {
tag = it->tag();
break;
}
}
return tag;
}
void GraphicsScene::highlightWarningItem(const ScxmlEditor::OutputPane::Warning *w)
{
ScxmlTag *tag = tagByWarning(w);
if (tag)
highlightItems({tag});
else
unhighlightAll();
}
void GraphicsScene::selectWarningItem(const ScxmlEditor::OutputPane::Warning *w)
{
ScxmlTag *tag = tagByWarning(w);
if (tag) {
unselectAll();
m_document->setCurrentTag(tag);
}
}
QList<QGraphicsItem*> GraphicsScene::sceneItems(Qt::SortOrder order) const
{
QList<QGraphicsItem*> children;
QList<QGraphicsItem*> items = this->items(order);
for (int i = 0; i < items.count(); ++i) {
if (!items[i]->parentItem() && items[i]->type() >= InitialStateType)
children << items[i];
}
return children;
}
void GraphicsScene::addChild(BaseItem *item)
{
if (!m_baseItems.contains(item)) {
connect(item, &BaseItem::selectedStateChanged, this, &GraphicsScene::selectionChanged);
connect(item, &BaseItem::openToDifferentView, this, [=](BaseItem *item){
emit openStateView(item);
}, Qt::QueuedConnection);
m_baseItems << item;
}
}
void GraphicsScene::removeChild(BaseItem *item)
{
if (item)
disconnect(item, nullptr, this, nullptr);
m_baseItems.removeAll(item);
selectionChanged(false);
}
void GraphicsScene::checkItemsVisibility(double scaleFactor)
{
foreach (BaseItem *item, m_baseItems) {
item->checkVisibility(scaleFactor);
}
}
void GraphicsScene::checkInitialState()
{
if (m_document) {
QList<QGraphicsItem*> sceneItems;
foreach (BaseItem *item, m_baseItems) {
if (item->type() >= InitialStateType && !item->parentItem())
sceneItems << item;
}
if (m_uiFactory) {
auto utilsProvider = static_cast<UtilsProvider*>(m_uiFactory->object("utilsProvider"));
if (utilsProvider)
utilsProvider->checkInitialState(sceneItems, m_document->rootTag());
}
}
}
void GraphicsScene::clearAllTags()
{
foreach (BaseItem *it, m_baseItems) {
it->setTag(nullptr);
}
}
void GraphicsScene::setBlockUpdates(bool block)
{
foreach (BaseItem *it, m_baseItems) {
it->setBlockUpdates(block);
}
}