1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 Jochen Becher
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of Qt Creator.
7 **
8 ** Commercial License Usage
9 ** Licensees holding valid commercial Qt licenses may use this file in
10 ** accordance with the commercial license agreement provided with the
11 ** Software or, alternatively, in accordance with the terms contained in
12 ** a written agreement between you and The Qt Company. For licensing terms
13 ** and conditions see https://www.qt.io/terms-conditions. For further
14 ** information use the contact form at https://www.qt.io/contact-us.
15 **
16 ** GNU General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU
18 ** General Public License version 3 as published by the Free Software
19 ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
20 ** included in the packaging of this file. Please review the following
21 ** information to ensure the GNU General Public License requirements will
22 ** be met: https://www.gnu.org/licenses/gpl-3.0.html.
23 **
24 ****************************************************************************/
25
26 #include "relationstarter.h"
27
28 #include "qmt/diagram_scene/diagramscenemodel.h"
29 #include "qmt/diagram_scene/diagramsceneconstants.h"
30 #include "qmt/diagram_scene/capabilities/relationable.h"
31 #include "qmt/infrastructure/qmtassert.h"
32 #include "qmt/style/stylecontroller.h"
33
34 #include <QGraphicsSceneMouseEvent>
35 #include <QKeyEvent>
36 #include <QGraphicsScene>
37 #include <QPainter>
38
39 namespace qmt {
40
RelationStarter(IRelationable * owner,DiagramSceneModel * diagramSceneModel,QGraphicsItem * parent)41 RelationStarter::RelationStarter(IRelationable *owner, DiagramSceneModel *diagramSceneModel, QGraphicsItem *parent)
42 : QGraphicsRectItem(parent),
43 m_owner(owner),
44 m_diagramSceneModel(diagramSceneModel)
45 {
46 setBrush(QBrush(QColor(192, 192, 192)));
47 setPen(QPen(QColor(64, 64, 64)));
48 setFlag(QGraphicsItem::ItemIsFocusable);
49 }
50
~RelationStarter()51 RelationStarter::~RelationStarter()
52 {
53 }
54
boundingRect() const55 QRectF RelationStarter::boundingRect() const
56 {
57 return rect();
58 }
59
paint(QPainter * painter,const QStyleOptionGraphicsItem * option,QWidget * widget)60 void RelationStarter::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
61 {
62 Q_UNUSED(option)
63 Q_UNUSED(widget)
64
65 painter->save();
66 painter->setPen(pen());
67 painter->setBrush(brush());
68 painter->drawRoundedRect(rect(), 3, 3);
69 painter->restore();
70 }
71
addArrow(const QString & id,ArrowItem::Shaft shaft,ArrowItem::Head startHead,ArrowItem::Head endHead,const QString & toolTip)72 void RelationStarter::addArrow(const QString &id, ArrowItem::Shaft shaft,
73 ArrowItem::Head startHead, ArrowItem::Head endHead,
74 const QString &toolTip)
75 {
76 QMT_CHECK(!id.isEmpty());
77 prepareGeometryChange();
78 auto arrow = new ArrowItem(this);
79 arrow->setArrowSize(10.0);
80 arrow->setDiamondSize(8.0);
81 arrow->setShaft(shaft);
82 arrow->setStartHead(startHead);
83 arrow->setEndHead(endHead);
84 arrow->setToolTip(toolTip.isEmpty() ? id : toolTip);
85 arrow->setPoints(QList<QPointF>() << QPointF(0.0, 10.0) << QPointF(15.0, 0.0));
86 arrow->setPos(6.0, m_arrows.size() * 20.0 + 8.0);
87 arrow->update(m_diagramSceneModel->styleController()->relationStarterStyle());
88 m_arrows.append(arrow);
89 m_arrowIds.insert(arrow, id);
90 setRect(0.0, 0.0, 26.0, m_arrows.size() * 20.0 + 6.0);
91 }
92
mousePressEvent(QGraphicsSceneMouseEvent * event)93 void RelationStarter::mousePressEvent(QGraphicsSceneMouseEvent *event)
94 {
95 if (m_currentPreviewArrow)
96 return;
97 foreach (ArrowItem *item, m_arrows) {
98 if (item->boundingRect().contains(mapToItem(item, event->pos()))) {
99 prepareGeometryChange();
100 m_currentPreviewArrowIntermediatePoints.clear();
101 m_currentPreviewArrowId = m_arrowIds.value(item);
102 QMT_CHECK(!m_currentPreviewArrowId.isEmpty());
103 m_currentPreviewArrow = new ArrowItem(*item);
104 // TODO use constants for sizes (in relationitem.h also)
105 m_currentPreviewArrow->setArrowSize(12.0);
106 m_currentPreviewArrow->setDiamondSize(12.0);
107 m_currentPreviewArrow->setPoints(QList<QPointF>() << m_owner->relationStartPos() << mapToScene(event->pos()));
108 m_currentPreviewArrow->update(m_diagramSceneModel->styleController()->relationStarterStyle());
109 m_currentPreviewArrow->setZValue(PREVIEW_RELATION_ZVALUE);
110 scene()->addItem(m_currentPreviewArrow);
111 setFocus(); // receive keyboard events
112 break;
113 }
114 }
115 }
116
mouseMoveEvent(QGraphicsSceneMouseEvent * event)117 void RelationStarter::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
118 {
119 if (!m_currentPreviewArrow)
120 return;
121 updateCurrentPreviewArrow(mapToScene(event->pos()));
122 }
123
mouseReleaseEvent(QGraphicsSceneMouseEvent * event)124 void RelationStarter::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
125 {
126 if (m_currentPreviewArrow) {
127 m_owner->relationDrawn(m_currentPreviewArrowId, mapToScene(event->pos()),
128 m_currentPreviewArrowIntermediatePoints);
129 m_currentPreviewArrow->scene()->removeItem(m_currentPreviewArrow);
130 delete m_currentPreviewArrow;
131 m_currentPreviewArrow = nullptr;
132 m_currentPreviewArrowIntermediatePoints.clear();
133 }
134 }
135
keyPressEvent(QKeyEvent * event)136 void RelationStarter::keyPressEvent(QKeyEvent *event)
137 {
138 if (!m_currentPreviewArrow)
139 return;
140 if (event->key() == Qt::Key_Shift) {
141 QPointF p = m_currentPreviewArrow->lastLineSegment().p1();
142 if (m_currentPreviewArrowIntermediatePoints.isEmpty() || m_currentPreviewArrowIntermediatePoints.last() != p) {
143 m_currentPreviewArrowIntermediatePoints.append(p);
144 // Do not update the preview arrow here because last two points are now identical which looks wired
145 }
146 } else if (event->key() == Qt::Key_Control) {
147 if (!m_currentPreviewArrowIntermediatePoints.isEmpty()) {
148 m_currentPreviewArrowIntermediatePoints.removeLast();
149 updateCurrentPreviewArrow(m_currentPreviewArrow->lastLineSegment().p1());
150 }
151 }
152 }
153
focusOutEvent(QFocusEvent * event)154 void RelationStarter::focusOutEvent(QFocusEvent *event)
155 {
156 Q_UNUSED(event)
157 if (m_currentPreviewArrow) {
158 m_currentPreviewArrow->scene()->removeItem(m_currentPreviewArrow);
159 delete m_currentPreviewArrow;
160 m_currentPreviewArrow = nullptr;
161 m_currentPreviewArrowIntermediatePoints.clear();
162 }
163 }
164
updateCurrentPreviewArrow(const QPointF & headPoint)165 void RelationStarter::updateCurrentPreviewArrow(const QPointF &headPoint)
166 {
167 prepareGeometryChange();
168 m_currentPreviewArrow->setPoints(QList<QPointF>() << m_owner->relationStartPos()
169 << m_currentPreviewArrowIntermediatePoints << headPoint);
170 m_currentPreviewArrow->update(m_diagramSceneModel->styleController()->relationStarterStyle());
171 }
172
173 } // namespace qmt
174