ModelEditor: Introduce swimlanes

Change-Id: I9ac9c51eabc00c6912fd47fbf51b50b2938846ae
Reviewed-by: Leena Miettinen <riitta-leena.miettinen@qt.io>
Reviewed-by: Tobias Hunger <tobias.hunger@qt.io>
This commit is contained in:
Jochen Becher
2017-07-15 15:37:19 +02:00
parent c562dce322
commit 4c469e0111
50 changed files with 852 additions and 28 deletions

View File

@@ -119,9 +119,18 @@
// Toolbar {
// id: <id>
// title: <a Ui title. Defaults to the id of the toolbar>
// element: <List of elements the toolbar is assigned to. Each element can be one of package, component,
// class, item or any Icon definition. Default to nothing which defines an object toolbar for
// diagrams.>
// priority: <priority number which decides about the position of toolbar in toolbox. Defaults to 0>
// Tools {
// Tool { title: <Ui title>; element: <element type>; stereotype: <stereotype, defaults to nothing> }
// Tool {
// title: <Ui title>;
// element: <element type; one of package, class, component, item, annotation, boundary or swimlane
// for object toolbars. One of dependency, inheritance or association for element toolbars.
// Must be given>;
// stereotype: <stereotype, defaults to nothing>
// }
// Separator
// }
// }
@@ -465,6 +474,7 @@ Toolbar {
Separator
Tool { title: "Annotation"; element: annotation }
Tool { title: "Boundary"; element: boundary }
Tool { title: "Swimlane"; element: swimlane }
}
}
@@ -477,6 +487,7 @@ Toolbar {
Separator
Tool { title: "Annotation"; element: annotation }
Tool { title: "Boundary"; element: boundary }
Tool { title: "Swimlane"; element: swimlane }
}
}
@@ -489,6 +500,7 @@ Toolbar {
Separator
Tool { title: "Annotation"; element: annotation }
Tool { title: "Boundary"; element: boundary }
Tool { title: "Swimlane"; element: swimlane }
}
}
@@ -504,5 +516,6 @@ Toolbar {
Separator
Tool { title: "Annotation"; element: annotation }
Tool { title: "Boundary"; element: boundary }
Tool { title: "Swimlane"; element: swimlane }
}
}

View File

@@ -74,6 +74,8 @@ QtcLibrary {
"diagram/dpackage.h",
"diagram/drelation.cpp",
"diagram/drelation.h",
"diagram/dswimlane.cpp",
"diagram/dswimlane.h",
"diagram/dvisitor.h",
"diagram_controller/dclonevisitor.cpp",
"diagram_controller/dclonevisitor.h",
@@ -130,6 +132,8 @@ QtcLibrary {
"diagram_scene/items/relationitem.h",
"diagram_scene/items/stereotypedisplayvisitor.cpp",
"diagram_scene/items/stereotypedisplayvisitor.h",
"diagram_scene/items/swimlaneitem.cpp",
"diagram_scene/items/swimlaneitem.h",
"diagram_scene/latchcontroller.cpp",
"diagram_scene/latchcontroller.h",
"diagram_scene/parts/alignbuttonsitem.cpp",

View File

@@ -36,7 +36,6 @@
#include <QHash>
#include <QSet>
#include <QPair>
#include <QDebug>
namespace qmt {
@@ -884,7 +883,8 @@ void StereotypeDefinitionParser::parseToolbarTool(const Toolbar *toolbar, Toolba
<< QStringLiteral("class")
<< QStringLiteral("item")
<< QStringLiteral("annotation")
<< QStringLiteral("boundary");
<< QStringLiteral("boundary")
<< QStringLiteral("swimlane");
QString elementName = element.toLower();
if (!elementNames.contains(elementName))
throw StereotypeDefinitionParserError(QString(QStringLiteral("Unexpected value \"%1\" for element.")).arg(element), token.sourcePos());

View File

@@ -41,6 +41,7 @@ class DAssociation;
class DConnection;
class DAnnotation;
class DBoundary;
class DSwimlane;
class DConstVisitor
{
@@ -61,6 +62,7 @@ public:
virtual void visitDConnection(const DConnection *connection) = 0;
virtual void visitDAnnotation(const DAnnotation *annotation) = 0;
virtual void visitDBoundary(const DBoundary *boundary) = 0;
virtual void visitDSwimlane(const DSwimlane *swimlane) = 0;
};
} // namespace qmt

View File

@@ -0,0 +1,86 @@
/****************************************************************************
**
** Copyright (C) 2017 Jochen Becher
** 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 "dswimlane.h"
#include "dvisitor.h"
#include "dconstvisitor.h"
namespace qmt {
DSwimlane::DSwimlane()
: DElement()
{
}
DSwimlane::DSwimlane(const DSwimlane &rhs)
: DElement(rhs),
m_text(rhs.m_text),
m_horizontal(rhs.m_horizontal),
m_pos(rhs.m_pos)
{
}
DSwimlane::~DSwimlane()
{
}
DSwimlane &DSwimlane::operator=(const DSwimlane &rhs)
{
if (this != &rhs) {
DElement::operator=(rhs);
m_text = rhs.m_text;
m_horizontal = rhs.m_horizontal;
m_pos = rhs.m_pos;
}
return *this;
}
void DSwimlane::setText(const QString &text)
{
m_text = text;
}
void DSwimlane::setHorizontal(bool horizontal)
{
m_horizontal = horizontal;
}
void DSwimlane::setPos(qreal pos)
{
m_pos = pos;
}
void DSwimlane::accept(DVisitor *visitor)
{
visitor->visitDSwimlane(this);
}
void DSwimlane::accept(DConstVisitor *visitor) const
{
visitor->visitDSwimlane(this);
}
} // namespoace qmt

View File

@@ -0,0 +1,58 @@
/****************************************************************************
**
** Copyright (C) 2017 Jochen Becher
** 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.
**
****************************************************************************/
#pragma once
#include "delement.h"
namespace qmt {
class QMT_EXPORT DSwimlane : public DElement
{
public:
DSwimlane();
DSwimlane(const DSwimlane &rhs);
~DSwimlane();
DSwimlane &operator=(const DSwimlane &rhs);
Uid modelUid() const override { return Uid::invalidUid(); }
QString text() const { return m_text; }
void setText(const QString &text);
bool isHorizontal() const { return m_horizontal; }
void setHorizontal(bool horizontal);
qreal pos() const { return m_pos; }
void setPos(qreal pos);
void accept(DVisitor *visitor) override;
void accept(DConstVisitor *visitor) const override;
private:
QString m_text;
bool m_horizontal = false; // false: vertical, true: horizontal
qreal m_pos = 0.0;
};
} // namespace qmt

View File

@@ -41,6 +41,7 @@ class DAssociation;
class DConnection;
class DAnnotation;
class DBoundary;
class DSwimlane;
class DVisitor
{
@@ -61,6 +62,7 @@ public:
virtual void visitDConnection(DConnection *connection) = 0;
virtual void visitDAnnotation(DAnnotation *annotation) = 0;
virtual void visitDBoundary(DBoundary *boundary) = 0;
virtual void visitDSwimlane(DSwimlane *swimlane) = 0;
};
} // namespace qmt

View File

@@ -39,6 +39,7 @@
#include "qmt/diagram/dconnection.h"
#include "qmt/diagram/dannotation.h"
#include "qmt/diagram/dboundary.h"
#include "qmt/diagram/dswimlane.h"
#include "qmt/infrastructure/qmtassert.h"
namespace qmt {
@@ -144,6 +145,14 @@ void DCloneVisitor::visitDBoundary(const DBoundary *boundary)
visitDElement(boundary);
}
void DCloneVisitor::visitDSwimlane(const DSwimlane *swimlane)
{
if (!m_cloned)
m_cloned = new DSwimlane(*swimlane);
visitDElement(swimlane);
}
DCloneDeepVisitor::DCloneDeepVisitor()
: m_cloned(0)
{
@@ -244,4 +253,11 @@ void DCloneDeepVisitor::visitDBoundary(const DBoundary *boundary)
visitDElement(boundary);
}
void DCloneDeepVisitor::visitDSwimlane(const DSwimlane *swimlane)
{
if (!m_cloned)
m_cloned = new DSwimlane(*swimlane);
visitDElement(swimlane);
}
} // namespace qmt

View File

@@ -51,6 +51,7 @@ public:
void visitDConnection(const DConnection *connection) override;
void visitDAnnotation(const DAnnotation *annotation) override;
void visitDBoundary(const DBoundary *boundary) override;
void visitDSwimlane(const DSwimlane *swimlane) override;
private:
DElement *m_cloned;
@@ -77,6 +78,7 @@ public:
void visitDConnection(const DConnection *connection) override;
void visitDAnnotation(const DAnnotation *annotation) override;
void visitDBoundary(const DBoundary *boundary) override;
void visitDSwimlane(const DSwimlane *swimlane) override;
private:
DElement *m_cloned;

View File

@@ -39,6 +39,7 @@
#include "qmt/diagram/dconnection.h"
#include "qmt/diagram/dannotation.h"
#include "qmt/diagram/dboundary.h"
#include "qmt/diagram/dswimlane.h"
#include "qmt/infrastructure/qmtassert.h"
namespace qmt {
@@ -178,4 +179,14 @@ void DFlatAssignmentVisitor::visitDBoundary(const DBoundary *boundary)
target->setRect(boundary->rect());
}
void DFlatAssignmentVisitor::visitDSwimlane(const DSwimlane *swimlane)
{
visitDElement(swimlane);
auto target = dynamic_cast<DSwimlane *>(m_target);
QMT_ASSERT(target, return);
target->setText(swimlane->text());
target->setHorizontal(swimlane->isHorizontal());
target->setPos(swimlane->pos());
}
} // namespace qmt

View File

@@ -49,6 +49,7 @@ public:
void visitDConnection(const DConnection *connection) override;
void visitDAnnotation(const DAnnotation *annotation) override;
void visitDBoundary(const DBoundary *boundary) override;
void visitDSwimlane(const DSwimlane *swimlane) override;
private:
DElement *m_target;

View File

@@ -39,6 +39,7 @@
#include "qmt/diagram/dconnection.h"
#include "qmt/diagram/dannotation.h"
#include "qmt/diagram/dboundary.h"
#include "qmt/diagram/dswimlane.h"
namespace qmt {
@@ -116,6 +117,11 @@ void DVoidVisitor::visitDBoundary(DBoundary *boundary)
visitDElement(boundary);
}
void DVoidVisitor::visitDSwimlane(DSwimlane *swimlane)
{
visitDElement(swimlane);
}
DConstVoidVisitor::DConstVoidVisitor()
{
}
@@ -190,4 +196,9 @@ void DConstVoidVisitor::visitDBoundary(const DBoundary *boundary)
visitDElement(boundary);
}
void DConstVoidVisitor::visitDSwimlane(const DSwimlane *swimlane)
{
visitDElement(swimlane);
}
} // namespace qmt

View File

@@ -50,6 +50,7 @@ public:
void visitDConnection(DConnection *connection) override;
void visitDAnnotation(DAnnotation *annotation) override;
void visitDBoundary(DBoundary *boundary) override;
void visitDSwimlane(DSwimlane *swimlane) override;
};
class QMT_EXPORT DConstVoidVisitor : public DConstVisitor
@@ -71,6 +72,7 @@ public:
void visitDConnection(const DConnection *connection) override;
void visitDAnnotation(const DAnnotation *annotation) override;
void visitDBoundary(const DBoundary *boundary) override;
void visitDSwimlane(const DSwimlane *swimlane) override;
};
} // namespace qmt

View File

@@ -25,6 +25,8 @@
#pragma once
#include <QRectF>
namespace qmt {
class ISelectable
@@ -36,6 +38,8 @@ public:
virtual void setSecondarySelected(bool secondarySelected) = 0;
virtual bool isFocusSelected() const = 0;
virtual void setFocusSelected(bool focusSelected) = 0;
virtual QRectF getSecondarySelectionBoundary() = 0;
virtual void setBoundarySelected(const QRectF &boundary, bool secondary) = 0;
};
} // namespace qmt

View File

@@ -27,6 +27,7 @@
namespace qmt {
const int SWIMLANE_ITEMS_ZVALUE = -1100;
const int BOUNDARY_ITEMS_ZVALUE = -1000;
// all model objects have z-values from -500 to 500 depending on their depth in the model tree
const int RELATION_ITEMS_ZVALUE = 1000;

View File

@@ -39,6 +39,7 @@
#include "qmt/diagram_controller/diagramcontroller.h"
#include "qmt/diagram_controller/dselection.h"
#include "qmt/diagram_scene/items/objectitem.h"
#include "qmt/diagram_scene/items/swimlaneitem.h"
#include "qmt/model/mdiagram.h"
#include "qmt/model/mobject.h"
#include "qmt/model/mpackage.h"
@@ -48,6 +49,8 @@
#include "qmt/tasks/diagramscenecontroller.h"
#include "qmt/tasks/ielementtasks.h"
#include "utils/asconst.h"
#include <QSet>
#include <QGraphicsItem>
#include <QGraphicsSceneMouseEvent>
@@ -241,7 +244,7 @@ ObjectItem *DiagramSceneModel::findTopmostObjectItem(const QPointF &scenePos) co
{
// fetch affected items from scene in correct drawing order to find topmost element
const QList<QGraphicsItem *> items = m_graphicsScene->items(scenePos);
for (QGraphicsItem *item : items) {
for (QGraphicsItem *item : Utils::asConst(items)) {
if (m_graphicsItems.contains(item)) {
DObject *object = dynamic_cast<DObject *>(m_itemToElementMap.value(item));
if (object)
@@ -705,6 +708,7 @@ void DiagramSceneModel::onEndResetDiagram(const MDiagram *diagram)
// update graphics items again so every item gets a correct list of colliding items
foreach (DElement *element, diagram->diagramElements())
updateGraphicsItem(m_elementToItemMap.value(element), element);
recalcSceneRectSize();
}
m_busyState = NotBusy;
}
@@ -724,6 +728,7 @@ void DiagramSceneModel::onEndUpdateElement(int row, const MDiagram *diagram)
if (diagram == m_diagram) {
QGraphicsItem *item = m_graphicsItems.at(row);
updateGraphicsItem(item, diagram->diagramElements().at(row));
recalcSceneRectSize();
}
m_busyState = NotBusy;
}
@@ -747,6 +752,7 @@ void DiagramSceneModel::onEndInsertElement(int row, const MDiagram *diagram)
updateGraphicsItem(item, element);
m_graphicsScene->invalidate();
updateGraphicsItem(item, element);
recalcSceneRectSize();
}
m_busyState = NotBusy;
}
@@ -757,6 +763,7 @@ void DiagramSceneModel::onBeginRemoveElement(int row, const MDiagram *diagram)
if (diagram == m_diagram) {
QGraphicsItem *item = m_graphicsItems.takeAt(row);
deleteGraphicsItem(item, diagram->diagramElements().at(row));
recalcSceneRectSize();
}
m_busyState = RemoveElement;
}
@@ -807,6 +814,27 @@ void DiagramSceneModel::onSelectionChanged()
}
}
// select more items secondarily
for (QGraphicsItem *selectedItem : Utils::asConst(m_selectedItems)) {
if (auto selectable = dynamic_cast<ISelectable *>(selectedItem)) {
QRectF boundary = selectable->getSecondarySelectionBoundary();
if (!boundary.isEmpty()) {
for (QGraphicsItem *item : Utils::asConst(m_graphicsItems)) {
if (auto secondarySelectable = dynamic_cast<ISelectable *>(item)) {
if (!item->isSelected() && !secondarySelectable->isSecondarySelected()) {
secondarySelectable->setBoundarySelected(boundary, true);
QMT_CHECK(!m_selectedItems.contains(item));
QMT_CHECK(!m_secondarySelectedItems.contains(item));
if (secondarySelectable->isSecondarySelected())
newSecondarySelectedItems.insert(item);
}
}
}
}
}
}
// select all relations where both ends are primary or secondary selected
foreach (DElement *element, m_diagram->diagramElements()) {
auto relation = dynamic_cast<DRelation *>(element);
@@ -882,6 +910,17 @@ void DiagramSceneModel::addExtraSceneItems()
m_latchController->addToGraphicsScene(m_graphicsScene);
}
void DiagramSceneModel::recalcSceneRectSize()
{
QRectF sceneRect = m_originItem->mapRectToScene(m_originItem->boundingRect());
for (QGraphicsItem *item : Utils::asConst(m_graphicsItems)) {
// TODO use an interface to update sceneRect by item
if (!dynamic_cast<SwimlaneItem *>(item))
sceneRect |= item->mapRectToScene(item->boundingRect());
}
emit sceneRectChanged(sceneRect);
}
QGraphicsItem *DiagramSceneModel::createGraphicsItem(DElement *element)
{
QMT_ASSERT(element, return nullptr);

View File

@@ -80,6 +80,7 @@ public:
signals:
void diagramSceneActivated(const MDiagram *diagram);
void selectionHasChanged(const MDiagram *diagram);
void sceneRectChanged(const QRectF &sceneRect);
public:
DiagramController *diagramController() const { return m_diagramController; }
@@ -152,6 +153,7 @@ private:
void clearGraphicsScene();
void removeExtraSceneItems();
void addExtraSceneItems();
void recalcSceneRectSize();
QGraphicsItem *createGraphicsItem(DElement *element);
void updateGraphicsItem(QGraphicsItem *item, DElement *element);
void deleteGraphicsItem(QGraphicsItem *item, DElement *element);

View File

@@ -35,6 +35,7 @@
#include "items/connectionitem.h"
#include "items/annotationitem.h"
#include "items/boundaryitem.h"
#include "items/swimlaneitem.h"
#include "qmt/diagram/delement.h"
#include "qmt/diagram/dobject.h"
@@ -50,6 +51,7 @@
#include "qmt/diagram/dconnection.h"
#include "qmt/diagram/dannotation.h"
#include "qmt/diagram/dboundary.h"
#include "qmt/diagram/dswimlane.h"
#include "qmt/infrastructure/qmtassert.h"
namespace qmt {
@@ -142,6 +144,12 @@ void DiagramSceneModel::CreationVisitor::visitDBoundary(DBoundary *boundary)
m_graphicsItem = new BoundaryItem(boundary, m_diagramSceneModel);
}
void DiagramSceneModel::CreationVisitor::visitDSwimlane(DSwimlane *swimlane)
{
QMT_CHECK(!m_graphicsItem);
m_graphicsItem = new SwimlaneItem(swimlane, m_diagramSceneModel);
}
DiagramSceneModel::UpdateVisitor::UpdateVisitor(QGraphicsItem *item, DiagramSceneModel *diagramSceneModel,
DElement *relatedElement)
: m_graphicsItem(item),
@@ -297,4 +305,15 @@ void DiagramSceneModel::UpdateVisitor::visitDBoundary(DBoundary *boundary)
boundaryItem->update();
}
void DiagramSceneModel::UpdateVisitor::visitDSwimlane(DSwimlane *swimlane)
{
Q_UNUSED(swimlane); // avoid warning in release mode
QMT_ASSERT(m_graphicsItem, return);
SwimlaneItem *swimlaneItem = qgraphicsitem_cast<SwimlaneItem *>(m_graphicsItem);
QMT_ASSERT(swimlaneItem, return);
QMT_CHECK(swimlaneItem->swimlane() == swimlane);
swimlaneItem->update();
}
} // namespace qmt

View File

@@ -52,6 +52,7 @@ public:
void visitDConnection(DConnection *connection) override;
void visitDAnnotation(DAnnotation *annotation) override;
void visitDBoundary(DBoundary *boundary) override;
void visitDSwimlane(DSwimlane *swimlane) override;
private:
DiagramSceneModel *m_diagramSceneModel;
@@ -78,6 +79,7 @@ public:
void visitDConnection(DConnection *connection) override;
void visitDAnnotation(DAnnotation *annotation) override;
void visitDBoundary(DBoundary *boundary) override;
void visitDSwimlane(DSwimlane *swimlane) override;
private:
QGraphicsItem *m_graphicsItem;

View File

@@ -213,6 +213,21 @@ void AnnotationItem::setFocusSelected(bool focusSelected)
}
}
QRectF AnnotationItem::getSecondarySelectionBoundary()
{
return QRectF();
}
void AnnotationItem::setBoundarySelected(const QRectF &boundary, bool secondary)
{
if (boundary.contains(mapRectToScene(boundingRect()))) {
if (secondary)
setSecondarySelected(true);
else
setSelected(true);
}
}
bool AnnotationItem::isEditable() const
{
return true;

View File

@@ -77,6 +77,8 @@ public:
void setSecondarySelected(bool secondarySelected) override;
bool isFocusSelected() const override;
void setFocusSelected(bool focusSelected) override;
QRectF getSecondarySelectionBoundary() override;
void setBoundarySelected(const QRectF &boundary, bool secondary) override;
bool isEditable() const override;
void edit() override;

View File

@@ -264,6 +264,21 @@ void BoundaryItem::setFocusSelected(bool focusSelected)
}
}
QRectF BoundaryItem::getSecondarySelectionBoundary()
{
return QRectF();
}
void BoundaryItem::setBoundarySelected(const QRectF &boundary, bool secondary)
{
if (boundary.contains(mapRectToScene(boundingRect()))) {
if (secondary)
setSecondarySelected(true);
else
setSelected(true);
}
}
bool BoundaryItem::isEditable() const
{
return true;

View File

@@ -76,6 +76,8 @@ public:
void setSecondarySelected(bool secondarySelected) override;
bool isFocusSelected() const override;
void setFocusSelected(bool focusSelected) override;
QRectF getSecondarySelectionBoundary() override;
void setBoundarySelected(const QRectF &boundary, bool secondary) override;
bool isEditable() const override;
void edit() override;

View File

@@ -208,6 +208,21 @@ void ObjectItem::setFocusSelected(bool focusSelected)
}
}
QRectF ObjectItem::getSecondarySelectionBoundary()
{
return QRectF();
}
void ObjectItem::setBoundarySelected(const QRectF &boundary, bool secondary)
{
if (boundary.contains(mapRectToScene(boundingRect()))) {
if (secondary)
setSecondarySelected(true);
else
setSelected(true);
}
}
ILatchable::Action ObjectItem::horizontalLatchAction() const
{
if (!m_selectionMarker)

View File

@@ -113,6 +113,8 @@ public:
void setSecondarySelected(bool secondarySelected) override;
bool isFocusSelected() const override;
void setFocusSelected(bool focusSelected) override;
QRectF getSecondarySelectionBoundary() override;
void setBoundarySelected(const QRectF &boundary, bool secondary) override;
Action horizontalLatchAction() const override;
Action verticalLatchAction() const override;

View File

@@ -316,6 +316,18 @@ void RelationItem::setFocusSelected(bool focusSelected)
}
}
QRectF RelationItem::getSecondarySelectionBoundary()
{
return QRectF();
}
void RelationItem::setBoundarySelected(const QRectF &boundary, bool secondary)
{
// TODO make individual intermediate points selectable
Q_UNUSED(boundary)
Q_UNUSED(secondary)
}
QPointF RelationItem::grabHandle(int index)
{
if (index == 0) {

View File

@@ -70,6 +70,8 @@ public:
void setSecondarySelected(bool secondarySelected) override;
bool isFocusSelected() const override;
void setFocusSelected(bool focusSelected) override;
QRectF getSecondarySelectionBoundary() override;
void setBoundarySelected(const QRectF &boundary, bool secondary) override;
QPointF grabHandle(int index) override;
void insertHandle(int beforeIndex, const QPointF &pos, double rasterWidth, double rasterHeight) override;

View File

@@ -0,0 +1,250 @@
/****************************************************************************
**
** Copyright (C) 2017 Jochen Becher
** 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 "swimlaneitem.h"
#include "qmt/diagram_controller/diagramcontroller.h"
#include "qmt/diagram/dswimlane.h"
#include "qmt/diagram_scene/diagramsceneconstants.h"
#include "qmt/diagram_scene/diagramscenemodel.h"
#include "qmt/infrastructure/qmtassert.h"
#include "qmt/style/stylecontroller.h"
#include "qmt/style/style.h"
#include <QBrush>
#include <QGraphicsLineItem>
#include <QGraphicsScene>
#include <QGraphicsSceneMouseEvent>
#include <QPen>
namespace qmt {
static const qreal SWIMLANE_LENGTH = 100000;
static const qreal SWIMLANE_WIDTH = 16;
static const qreal SWIMLANE_MARKER_WIDTH = 8;
SwimlaneItem::SwimlaneItem(DSwimlane *swimlane, DiagramSceneModel *diagramSceneModel,
QGraphicsItem *parent)
: QGraphicsItem (parent),
m_swimlane(swimlane),
m_diagramSceneModel(diagramSceneModel)
{
setFlags(QGraphicsItem::ItemIsSelectable);
}
SwimlaneItem::~SwimlaneItem()
{
}
QRectF SwimlaneItem::boundingRect() const
{
if (m_swimlane->isHorizontal())
return QRectF(-SWIMLANE_LENGTH/2, -SWIMLANE_WIDTH/2, SWIMLANE_LENGTH, SWIMLANE_WIDTH);
else
return QRectF(-SWIMLANE_WIDTH/2, -SWIMLANE_LENGTH/2, SWIMLANE_WIDTH, SWIMLANE_LENGTH);
}
void SwimlaneItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
Q_UNUSED(painter);
Q_UNUSED(option);
Q_UNUSED(widget);
}
void SwimlaneItem::update()
{
QMT_CHECK(!m_isUpdating);
m_isUpdating = true;
prepareGeometryChange();
const Style *style = adaptedStyle();
Q_UNUSED(style);
// swimline line
if (!m_lineItem)
m_lineItem = new QGraphicsLineItem(this);
m_lineItem->setPen(QPen(QBrush(Qt::black), 1, Qt::DashLine));
updateSelectionMarker();
updateGeometry();
setZValue(SWIMLANE_ITEMS_ZVALUE);
m_isUpdating = false;
}
void SwimlaneItem::moveDelta(const QPointF &delta)
{
m_diagramSceneModel->diagramController()->startUpdateElement(m_swimlane, m_diagramSceneModel->diagram(),
DiagramController::UpdateGeometry);
if (m_swimlane->isHorizontal())
m_swimlane->setPos(m_swimlane->pos() + delta.y());
else
m_swimlane->setPos(m_swimlane->pos() + delta.x());
m_diagramSceneModel->diagramController()->finishUpdateElement(m_swimlane, m_diagramSceneModel->diagram(), false);
}
void SwimlaneItem::alignItemPositionToRaster(double rasterWidth, double rasterHeight)
{
if (m_swimlane->isHorizontal()) {
qreal yDelta = qRound(m_swimlane->pos() / rasterHeight) * rasterHeight - m_swimlane->pos();
moveDelta(QPointF(0, yDelta));
} else {
qreal xDelta = qRound(m_swimlane->pos() / rasterWidth) * rasterWidth - m_swimlane->pos();
moveDelta(QPointF(xDelta, 0));
}
}
bool SwimlaneItem::isSecondarySelected() const
{
return m_secondarySelected;
}
void SwimlaneItem::setSecondarySelected(bool secondarySelected)
{
if (m_secondarySelected != secondarySelected) {
m_secondarySelected = secondarySelected;
update();
}
}
bool SwimlaneItem::isFocusSelected() const
{
return false;
}
void SwimlaneItem::setFocusSelected(bool focusSelected)
{
Q_UNUSED(focusSelected);
}
QRectF SwimlaneItem::getSecondarySelectionBoundary()
{
QRectF boundary;
if (m_swimlane->isHorizontal())
boundary = QRectF(-SWIMLANE_LENGTH/2, pos().y(), SWIMLANE_LENGTH, SWIMLANE_LENGTH);
else
boundary = QRectF(pos().x(), -SWIMLANE_LENGTH/2, SWIMLANE_LENGTH, SWIMLANE_LENGTH);
return boundary;
}
void SwimlaneItem::setBoundarySelected(const QRectF &boundary, bool secondary)
{
qreal pos = m_swimlane->pos();
bool c;
if (m_swimlane->isHorizontal())
c = pos >= boundary.top() && pos <= boundary.bottom() && boundary.top() > -SWIMLANE_LENGTH/2;
else
c = pos >= boundary.left() && pos <= boundary.right() && boundary.left() > -SWIMLANE_LENGTH/2;
if (c) {
if (secondary)
setSecondarySelected(true);
else
setSelected(true);
}
}
void SwimlaneItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
if (event->button() == Qt::LeftButton || event->button() == Qt::RightButton) {
bool multiSelect = (event->modifiers() & Qt::ControlModifier) != 0;
m_diagramSceneModel->selectItem(this, multiSelect);
}
}
void SwimlaneItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
if (event->buttons() & Qt::LeftButton) {
QPointF delta = event->scenePos() - event->lastScenePos();
if (m_swimlane->isHorizontal())
delta.setX(0.0);
else
delta.setY(0.0);
m_diagramSceneModel->moveSelectedItems(this, delta);
}
}
void SwimlaneItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
{
if (event->button() == Qt::LeftButton) {
if (event->scenePos() != event->buttonDownScenePos(Qt::LeftButton))
m_diagramSceneModel->alignSelectedItemsPositionOnRaster();
}
}
void SwimlaneItem::updateSelectionMarker()
{
if (isSelected() || m_secondarySelected) {
if (!m_selectionMarker)
m_selectionMarker = new QGraphicsRectItem(this);
m_selectionMarker->setBrush(isSelected() ? Qt::lightGray : Qt::transparent);
m_selectionMarker->setPen(isSelected() ? Qt::NoPen : QPen(Qt::lightGray));
m_selectionMarker->setZValue(-1);
} else if (m_selectionMarker) {
if (m_selectionMarker->scene())
m_selectionMarker->scene()->removeItem(m_selectionMarker);
delete m_selectionMarker;
m_selectionMarker = nullptr;
}
}
const Style *SwimlaneItem::adaptedStyle()
{
return m_diagramSceneModel->styleController()->adaptSwimlaneStyle(m_swimlane);
}
QSizeF SwimlaneItem::calcMinimumGeometry() const
{
if (m_swimlane->isHorizontal())
return QSizeF(SWIMLANE_LENGTH, SWIMLANE_WIDTH);
else
return QSizeF(SWIMLANE_WIDTH, SWIMLANE_LENGTH);
}
void SwimlaneItem::updateGeometry()
{
prepareGeometryChange();
QSizeF geometry = calcMinimumGeometry();
qreal width = geometry.width();
qreal height = geometry.height();
if (m_swimlane->isHorizontal()) {
setPos(0, m_swimlane->pos());
if (m_lineItem)
m_lineItem->setLine(-width / 2, 0, width / 2, 0);
if (m_selectionMarker)
m_selectionMarker->setRect(-width / 2, -SWIMLANE_MARKER_WIDTH / 2, width, SWIMLANE_MARKER_WIDTH);
} else {
setPos(m_swimlane->pos(), 0);
if (m_lineItem)
m_lineItem->setLine(0, -height / 2, 0, height / 2);
if (m_selectionMarker)
m_selectionMarker->setRect(-SWIMLANE_MARKER_WIDTH / 2, -height / 2, SWIMLANE_MARKER_WIDTH, height);
}
}
} // namespace qmt

View File

@@ -0,0 +1,87 @@
/****************************************************************************
**
** Copyright (C) 2017 Jochen Becher
** 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.
**
****************************************************************************/
#pragma once
#include <QGraphicsItem>
#include "qmt/diagram_scene/capabilities/moveable.h"
#include "qmt/diagram_scene/capabilities/selectable.h"
namespace qmt {
class DSwimlane;
class DiagramSceneModel;
class Style;
class SwimlaneItem :
public QGraphicsItem,
public IMoveable,
public ISelectable
{
public:
SwimlaneItem(DSwimlane *swimlane, DiagramSceneModel *diagramSceneModel,
QGraphicsItem *parent = nullptr);
~SwimlaneItem() override;
DSwimlane *swimlane() const { return m_swimlane; }
DiagramSceneModel *diagramSceneModel() const { return m_diagramSceneModel; }
QRectF boundingRect() const override;
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;
virtual void update();
void moveDelta(const QPointF &delta) override;
void alignItemPositionToRaster(double rasterWidth, double rasterHeight) override;
bool isSecondarySelected() const override;
void setSecondarySelected(bool secondarySelected) override;
bool isFocusSelected() const override;
void setFocusSelected(bool focusSelected) override;
QRectF getSecondarySelectionBoundary() override;
void setBoundarySelected(const QRectF &boundary, bool secondary) override;
protected:
void mousePressEvent(QGraphicsSceneMouseEvent *event) override;
void mouseMoveEvent(QGraphicsSceneMouseEvent *event) override;
void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) override;
void updateSelectionMarker();
const Style *adaptedStyle();
private:
QSizeF calcMinimumGeometry() const;
void updateGeometry();
DSwimlane *m_swimlane = nullptr;
DiagramSceneModel *m_diagramSceneModel = nullptr;
QGraphicsLineItem *m_lineItem = nullptr;
QGraphicsRectItem *m_selectionMarker = nullptr;
bool m_isUpdating = false;
bool m_secondarySelected = false;
};
} // namespace qmt

View File

@@ -38,5 +38,6 @@ static const char ELEMENT_TYPE_CLASS[] = "class";
static const char ELEMENT_TYPE_ITEM[] = "item";
static const char ELEMENT_TYPE_ANNOTATION[] = "annotation";
static const char ELEMENT_TYPE_BOUNDARY[] = "boundary";
static const char ELEMENT_TYPE_SWIMLANE[] = "swimlane";
} // namespace qmt

View File

@@ -62,8 +62,11 @@ void DiagramView::setDiagramSceneModel(DiagramSceneModel *diagramSceneModel)
{
setScene(0);
m_diagramSceneModel = diagramSceneModel;
if (diagramSceneModel)
if (diagramSceneModel) {
setScene(m_diagramSceneModel->graphicsScene());
connect(m_diagramSceneModel, &DiagramSceneModel::sceneRectChanged,
this, &DiagramView::onSceneRectChanged, Qt::QueuedConnection);
}
}
void DiagramView::dragEnterEvent(QDragEnterEvent *event)
@@ -110,14 +113,17 @@ void DiagramView::dragMoveEvent(QDragMoveEvent *event)
void DiagramView::dropEvent(QDropEvent *event)
{
event->setDropAction(Qt::MoveAction);
DiagramSceneController *diagramSceneController = m_diagramSceneModel->diagramSceneController();
if (event->mimeData()->hasFormat(QLatin1String(MIME_TYPE_MODEL_ELEMENTS))) {
QDataStream dataStream(event->mimeData()->data(QLatin1String(MIME_TYPE_MODEL_ELEMENTS)));
while (dataStream.status() == QDataStream::Ok) {
QString key;
dataStream >> key;
if (!key.isEmpty()) {
if (m_diagramSceneModel->diagramSceneController()->isAddingAllowed(Uid(key), m_diagramSceneModel->diagram()))
m_diagramSceneModel->diagramSceneController()->addExistingModelElement(Uid(key), mapToScene(event->pos()), m_diagramSceneModel->diagram());
if (diagramSceneController->isAddingAllowed(Uid(key), m_diagramSceneModel->diagram())) {
diagramSceneController->addExistingModelElement(Uid(key), mapToScene(event->pos()),
m_diagramSceneModel->diagram());
}
}
}
event->accept();
@@ -130,7 +136,9 @@ void DiagramView::dropEvent(QDropEvent *event)
dataStream >> newElementId >> name >> stereotype;
if (!newElementId.isEmpty()) {
QPointF pos = mapToScene(event->pos());
m_diagramSceneModel->diagramSceneController()->dropNewElement(newElementId, name, stereotype, m_diagramSceneModel->findTopmostElement(pos), pos, m_diagramSceneModel->diagram());
diagramSceneController->dropNewElement(
newElementId, name, stereotype, m_diagramSceneModel->findTopmostElement(pos),
pos, m_diagramSceneModel->diagram(), event->pos(), size());
}
}
event->accept();
@@ -139,4 +147,10 @@ void DiagramView::dropEvent(QDropEvent *event)
}
}
void DiagramView::onSceneRectChanged(const QRectF &sceneRect)
{
// TODO add some adjustment to all 4 sides?
setSceneRect(sceneRect);
}
} // namespace qmt

View File

@@ -51,6 +51,8 @@ protected:
void dropEvent(QDropEvent *event) override;
private:
void onSceneRectChanged(const QRectF &sceneRect);
QPointer<DiagramSceneModel> m_diagramSceneModel;
};

View File

@@ -59,6 +59,7 @@
#include "qmt/diagram/dconnection.h"
#include "qmt/diagram/dannotation.h"
#include "qmt/diagram/dboundary.h"
#include "qmt/diagram/dswimlane.h"
// TODO move into better place
#include "qmt/diagram_scene/items/stereotypedisplayvisitor.h"
@@ -1183,6 +1184,12 @@ void PropertiesView::MView::visitDBoundary(const DBoundary *boundary)
visitDElement(boundary);
}
void PropertiesView::MView::visitDSwimlane(const DSwimlane *swimlane)
{
setTitle<DSwimlane>(m_diagramElements, tr("Swimlane"), tr("Swimlanes"));
visitDElement(swimlane);
}
void PropertiesView::MView::onStereotypesChanged(const QString &stereotypes)
{
QList<QString> set = m_stereotypesController->fromString(stereotypes);

View File

@@ -94,6 +94,7 @@ public:
void visitDConnection(const DConnection *connection) override;
void visitDAnnotation(const DAnnotation *annotation) override;
void visitDBoundary(const DBoundary *boundary) override;
void visitDSwimlane(const DSwimlane *swimlane) override;
void update(QList<MElement *> &modelElements);
void update(QList<DElement *> &diagramElements, MDiagram *diagram);

View File

@@ -160,6 +160,8 @@ HEADERS += \
$$PWD/tasks/isceneinspector.h \
$$PWD/tasks/voidelementtasks.h \
$$PWD/infrastructure/qmtassert.h \
$$PWD/diagram_scene/items/swimlaneitem.h \
$$PWD/diagram/dswimlane.h
SOURCES += \
$$PWD/config/configcontroller.cpp \
@@ -286,6 +288,8 @@ SOURCES += \
$$PWD/tasks/finddiagramvisitor.cpp \
$$PWD/tasks/findrootdiagramvisitor.cpp \
$$PWD/tasks/voidelementtasks.cpp \
$$PWD/diagram_scene/items/swimlaneitem.cpp \
$$PWD/diagram/dswimlane.cpp
RESOURCES += \
$$PWD/resources/resources.qrc

Binary file not shown.

After

Width:  |  Height:  |  Size: 191 B

View File

@@ -21,5 +21,6 @@
<file>48x48/inheritance.png</file>
<file>48x48/item.png</file>
<file>48x48/package.png</file>
<file>48x48/swimlane.png</file>
</qresource>
</RCC>

View File

@@ -45,6 +45,7 @@
#include "qmt/diagram/dannotation.h"
#include "qmt/diagram/dboundary.h"
#include "qmt/diagram/dswimlane.h"
#include "qark/qxmloutarchive.h"
#include "qark/qxmlinarchive.h"
@@ -403,4 +404,23 @@ inline void Access<Archive, DBoundary>::serialize(Archive &archive, DBoundary &b
QARK_ACCESS_SPECIALIZE(QXmlInArchive, QXmlOutArchive, DBoundary)
// DSwimlane
QARK_REGISTER_TYPE_NAME(DSwimlane, "DSwimlane")
QARK_REGISTER_DERIVED_CLASS(QXmlInArchive, QXmlOutArchive, DSwimlane, DElement)
QARK_ACCESS_SERIALIZE(DSwimlane)
template<class Archive>
inline void Access<Archive, DSwimlane>::serialize(Archive &archive, DSwimlane &swimlane)
{
archive || tag(swimlane)
|| base<DElement>(swimlane)
|| attr(QStringLiteral("text"), swimlane, &DSwimlane::text, &DSwimlane::setText)
|| attr(QStringLiteral("horizontal"), swimlane, &DSwimlane::isHorizontal, &DSwimlane::setHorizontal)
|| attr(QStringLiteral("pos"), swimlane, &DSwimlane::pos, &DSwimlane::setPos)
|| end;
}
QARK_ACCESS_SPECIALIZE(QXmlInArchive, QXmlOutArchive, DSwimlane)
} // namespace qark

View File

@@ -40,7 +40,6 @@
#include <utils/algorithm.h>
#include <QSet>
#include <QDebug>
namespace {
@@ -158,6 +157,26 @@ bool operator==(const BoundaryStyleKey &lhs, const BoundaryStyleKey &rhs)
return true;
}
// TODO remove class if no attributes needed even with future extensions
class SwimlaneStyleKey
{
};
uint qHash(const SwimlaneStyleKey &styleKey)
{
Q_UNUSED(styleKey);
return 1;
}
bool operator==(const SwimlaneStyleKey &lhs, const SwimlaneStyleKey &rhs)
{
Q_UNUSED(lhs);
Q_UNUSED(rhs);
return true;
}
DefaultStyleEngine::DefaultStyleEngine()
{
}
@@ -190,6 +209,8 @@ const Style *DefaultStyleEngine::applyStyle(const Style *baseStyle, StyleEngine:
parameters);
case TypeOther:
break;
case TypeSwimlane:
return applySwimlaneStyle(baseStyle, parameters);
}
return baseStyle;
}
@@ -371,6 +392,13 @@ const Style *DefaultStyleEngine::applyBoundaryStyle(const Style *baseStyle, cons
return applyBoundaryStyle(baseStyle, parameters);
}
const Style *DefaultStyleEngine::applySwimlaneStyle(const Style *baseStyle, const DSwimlane *swimlane, const StyleEngine::Parameters *parameters)
{
Q_UNUSED(swimlane);
return applySwimlaneStyle(baseStyle, parameters);
}
const Style *DefaultStyleEngine::applyAnnotationStyle(const Style *baseStyle, DAnnotation::VisualRole visualRole,
const StyleEngine::Parameters *parameters)
{
@@ -429,6 +457,22 @@ const Style *DefaultStyleEngine::applyBoundaryStyle(const Style *baseStyle, cons
return derivedStyle;
}
const Style *DefaultStyleEngine::applySwimlaneStyle(const Style *baseStyle, const StyleEngine::Parameters *parameters)
{
Q_UNUSED(parameters);
SwimlaneStyleKey key;
const Style *derivedStyle = m_swimlaneStyleMap.value(key);
if (!derivedStyle) {
auto style = new Style(baseStyle->type());
style->setNormalFont(baseStyle->normalFont());
style->setTextBrush(baseStyle->textBrush());
m_swimlaneStyleMap.insert(key, style);
derivedStyle = style;
}
return derivedStyle;
}
DefaultStyleEngine::ElementType DefaultStyleEngine::objectType(const DObject *object)
{
ElementType elementType;
@@ -459,7 +503,6 @@ bool DefaultStyleEngine::areStackingRoles(DObject::VisualPrimaryRole rhsPrimaryR
case DObject::SecondaryRoleLighter:
case DObject::SecondaryRoleDarker:
return lhsPrimaryRole == rhsPrimaryRole;
break;
case DObject::SecondaryRoleSoften:
case DObject::SecondaryRoleOutline:
return false;
@@ -495,7 +538,11 @@ QColor DefaultStyleEngine::baseColor(ElementType elementType, ObjectVisuals obje
case TypeItem:
baseColor = QColor("#B995C6");
break;
default:
case TypeRelation:
case TypeAnnotation:
case TypeBoundary:
case TypeSwimlane:
case TypeOther:
baseColor = QColor("#BF7D65");
break;
}

View File

@@ -42,6 +42,7 @@ class ObjectStyleKey;
class RelationStyleKey;
class AnnotationStyleKey;
class BoundaryStyleKey;
class SwimlaneStyleKey;
class QMT_EXPORT DefaultStyleEngine : public StyleEngine
{
@@ -64,11 +65,14 @@ public:
const Parameters *parameters) override;
const Style *applyBoundaryStyle(const Style *baseStyle, const DBoundary *boundary,
const Parameters *parameters) override;
const Style *applySwimlaneStyle(const Style *baseStyle, const DSwimlane *swimlane,
const Parameters *parameters) override;
private:
const Style *applyAnnotationStyle(const Style *baseStyle, DAnnotation::VisualRole visualRole,
const Parameters *parameters);
const Style *applyBoundaryStyle(const Style *baseStyle, const Parameters *parameters);
const Style *applySwimlaneStyle(const Style *baseStyle, const Parameters *parameters);
ElementType objectType(const DObject *object);
@@ -87,6 +91,7 @@ private:
QHash<RelationStyleKey, const Style *> m_relationStyleMap;
QHash<AnnotationStyleKey, const Style *> m_annotationStyleMap;
QHash<BoundaryStyleKey, const Style *> m_boundaryStyleMap;
QHash<SwimlaneStyleKey, const Style *> m_swimlaneStyleMap;
};
} // namespace qmt

View File

@@ -104,6 +104,12 @@ const Style *StyleController::adaptBoundaryStyle(const DBoundary *boundary)
return m_defaultStyleEngine->applyBoundaryStyle(m_defaultStyle.data(), boundary, &parameters);
}
const Style *StyleController::adaptSwimlaneStyle(const DSwimlane *swimlane)
{
Parameters parameters(this);
return m_defaultStyleEngine->applySwimlaneStyle(m_defaultStyle.data(), swimlane, &parameters);
}
const Style *StyleController::relationStarterStyle()
{
return m_relationStarterStyle.data();

View File

@@ -60,6 +60,7 @@ public:
const Style *adaptRelationStyle(const StyledRelation &relation);
const Style *adaptAnnotationStyle(const DAnnotation *annotation);
const Style *adaptBoundaryStyle(const DBoundary *boundary);
const Style *adaptSwimlaneStyle(const DSwimlane *swimlane);
const Style *relationStarterStyle();
private:

View File

@@ -40,6 +40,7 @@ class StyledRelation;
class DAnnotation;
class DBoundary;
class DSwimlane;
class QMT_EXPORT StyleEngine
{
@@ -52,7 +53,8 @@ public:
TypeItem,
TypeRelation,
TypeAnnotation,
TypeBoundary
TypeBoundary,
TypeSwimlane
};
class Parameters
@@ -77,6 +79,8 @@ public:
const Parameters *) = 0;
virtual const Style *applyBoundaryStyle(const Style *baseStyle, const DBoundary *,
const Parameters *) = 0;
virtual const Style *applySwimlaneStyle(const Style *baseStyle, const DSwimlane *,
const Parameters *) = 0;
};
} // namespace qmt

View File

@@ -40,6 +40,7 @@
#include "qmt/diagram/dobject.h"
#include "qmt/diagram/dpackage.h"
#include "qmt/diagram/drelation.h"
#include "qmt/diagram/dswimlane.h"
#include "qmt/diagram_scene/capabilities/moveable.h"
#include "qmt/diagram_scene/capabilities/resizable.h"
#include "qmt/diagram_scene/diagramsceneconstants.h"
@@ -159,4 +160,11 @@ void AlignOnRasterVisitor::visitDBoundary(DBoundary *boundary)
moveable->alignItemPositionToRaster(RASTER_WIDTH, RASTER_HEIGHT);
}
void AlignOnRasterVisitor::visitDSwimlane(DSwimlane *swimlane)
{
IMoveable *moveable = m_sceneInspector->moveable(swimlane, m_diagram);
if (moveable)
moveable->alignItemPositionToRaster(RASTER_WIDTH, RASTER_HEIGHT);
}
} // namespace qmt

View File

@@ -58,6 +58,7 @@ public:
void visitDConnection(DConnection *connection) override;
void visitDAnnotation(DAnnotation *annotation) override;
void visitDBoundary(DBoundary *boundary) override;
void visitDSwimlane(DSwimlane *swimlane) override;
private:
DiagramController *m_diagramController;

View File

@@ -38,6 +38,7 @@
#include "qmt/diagram/drelation.h"
#include "qmt/diagram/dassociation.h"
#include "qmt/diagram/dconnection.h"
#include "qmt/diagram/dswimlane.h"
#include "qmt/diagram_ui/diagram_mime_types.h"
#include "qmt/model_controller/modelcontroller.h"
#include "qmt/model_controller/mselection.h"
@@ -339,7 +340,8 @@ void DiagramSceneController::addExistingModelElement(const Uid &modelElementKey,
}
void DiagramSceneController::dropNewElement(const QString &newElementId, const QString &name, const QString &stereotype,
DElement *topMostElementAtPos, const QPointF &pos, MDiagram *diagram)
DElement *topMostElementAtPos, const QPointF &pos, MDiagram *diagram,
const QPoint &viewPos, const QSize &viewSize)
{
if (newElementId == QLatin1String(ELEMENT_TYPE_ANNOTATION)) {
auto annotation = new DAnnotation();
@@ -354,6 +356,16 @@ void DiagramSceneController::dropNewElement(const QString &newElementId, const Q
m_diagramController->addElement(boundary, diagram);
alignOnRaster(boundary, diagram);
emit newElementCreated(boundary, diagram);
} else if (newElementId == QLatin1String(ELEMENT_TYPE_SWIMLANE)) {
auto swimlane = new DSwimlane();
qreal x = static_cast<qreal>(viewPos.x()) / viewSize.width();
qreal y = static_cast<qreal>(viewPos.y()) / viewSize.height();
bool horizontal = (y > x && (1-y) > x) || (y <= x && (1-y) <= x);
swimlane->setHorizontal(horizontal);
swimlane->setPos(horizontal ? pos.y() : pos.x());
m_diagramController->addElement(swimlane, diagram);
alignOnRaster(swimlane, diagram);
emit newElementCreated(swimlane, diagram);
} else {
MPackage *parentPackage = findSuitableParentPackage(topMostElementAtPos, diagram);
MObject *newObject = 0;

View File

@@ -97,7 +97,7 @@ public:
bool isAddingAllowed(const Uid &modelElementKey, MDiagram *diagram);
void addExistingModelElement(const Uid &modelElementKey, const QPointF &pos, MDiagram *diagram);
void dropNewElement(const QString &newElementId, const QString &name, const QString &stereotype,
DElement *topMostElementAtPos, const QPointF &pos, MDiagram *diagram);
DElement *topMostElementAtPos, const QPointF &pos, MDiagram *diagram, const QPoint &viewPos, const QSize &viewSize);
void dropNewModelElement(MObject *modelObject, MPackage *parentPackage, const QPointF &pos,
MDiagram *diagram);

View File

@@ -1046,6 +1046,9 @@ void ModelEditor::initToolbars()
} else if (tool.m_elementType == QLatin1String(qmt::ELEMENT_TYPE_BOUNDARY)) {
iconPath = QStringLiteral(":/modelinglib/48x48/boundary.png");
styleEngineElementType = qmt::StyleEngine::TypeBoundary;
} else if (tool.m_elementType == QLatin1String(qmt::ELEMENT_TYPE_SWIMLANE)) {
iconPath = QStringLiteral(":/modelinglib/48x48/swimlane.png");
styleEngineElementType = qmt::StyleEngine::TypeSwimlane;
}
QIcon icon;
if (!tool.m_stereotype.isEmpty() && stereotypeIconElement != qmt::StereotypeIcon::ElementAny) {
@@ -1110,6 +1113,10 @@ void ModelEditor::initToolbars()
new DragTool(QIcon(QStringLiteral(":/modelinglib/48x48/boundary.png")),
tr("Boundary"), QLatin1String(qmt::ELEMENT_TYPE_BOUNDARY),
QString(), toolBar));
toolBarLayout->addWidget(
new DragTool(QIcon(QStringLiteral(":/modelinglib/48x48/swimlane.png")),
tr("Swimlane"), QLatin1String(qmt::ELEMENT_TYPE_SWIMLANE),
QString(), toolBar));
}
// add stretch to all layouts and calculate width of tool bar

View File

@@ -137,6 +137,11 @@ void OpenDiagramElementVisitor::visitDBoundary(const qmt::DBoundary *boundary)
Q_UNUSED(boundary);
}
void OpenDiagramElementVisitor::visitDSwimlane(const qmt::DSwimlane *swimlane)
{
Q_UNUSED(swimlane);
}
void OpenModelElementVisitor::setElementTasks(ElementTasks *elementTasks)
{
m_elementTasks = elementTasks;

View File

@@ -42,20 +42,21 @@ public:
void setModelController(qmt::ModelController *modelController);
void setElementTasks(ElementTasks *elementTasks);
void visitDElement(const qmt::DElement *element);
void visitDObject(const qmt::DObject *object);
void visitDPackage(const qmt::DPackage *package);
void visitDClass(const qmt::DClass *klass);
void visitDComponent(const qmt::DComponent *component);
void visitDDiagram(const qmt::DDiagram *diagram);
void visitDItem(const qmt::DItem *item);
void visitDRelation(const qmt::DRelation *relation);
void visitDInheritance(const qmt::DInheritance *inheritance);
void visitDDependency(const qmt::DDependency *dependency);
void visitDAssociation(const qmt::DAssociation *association);
void visitDConnection(const qmt::DConnection *connection);
void visitDAnnotation(const qmt::DAnnotation *annotation);
void visitDBoundary(const qmt::DBoundary *boundary);
void visitDElement(const qmt::DElement *element) override;
void visitDObject(const qmt::DObject *object) override;
void visitDPackage(const qmt::DPackage *package) override;
void visitDClass(const qmt::DClass *klass) override;
void visitDComponent(const qmt::DComponent *component) override;
void visitDDiagram(const qmt::DDiagram *diagram) override;
void visitDItem(const qmt::DItem *item) override;
void visitDRelation(const qmt::DRelation *relation) override;
void visitDInheritance(const qmt::DInheritance *inheritance) override;
void visitDDependency(const qmt::DDependency *dependency) override;
void visitDAssociation(const qmt::DAssociation *association) override;
void visitDConnection(const qmt::DConnection *connection) override;
void visitDAnnotation(const qmt::DAnnotation *annotation) override;
void visitDBoundary(const qmt::DBoundary *boundary) override;
void visitDSwimlane(const qmt::DSwimlane *swimlane) override;
private:
qmt::ModelController *m_modelController = 0;