1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the examples of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:BSD$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** BSD License Usage
18** Alternatively, you may use this file under the terms of the BSD license
19** as follows:
20**
21** "Redistribution and use in source and binary forms, with or without
22** modification, are permitted provided that the following conditions are
23** met:
24** * Redistributions of source code must retain the above copyright
25** notice, this list of conditions and the following disclaimer.
26** * Redistributions in binary form must reproduce the above copyright
27** notice, this list of conditions and the following disclaimer in
28** the documentation and/or other materials provided with the
29** distribution.
30** * Neither the name of The Qt Company Ltd nor the names of its
31** contributors may be used to endorse or promote products derived
32** from this software without specific prior written permission.
33**
34**
35** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
36** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
37** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
38** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
39** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
41** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
42** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
43** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
44** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
45** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
46**
47** $QT_END_LICENSE$
48**
49****************************************************************************/
50
51#include "diagramscene.h"
52#include "arrow.h"
53
54#include <QGraphicsSceneMouseEvent>
55#include <QTextCursor>
56
57//! [0]
58DiagramScene::DiagramScene(QMenu *itemMenu, QObject *parent)
59 : QGraphicsScene(parent)
60{
61 myItemMenu = itemMenu;
62 myMode = MoveItem;
63 myItemType = DiagramItem::Step;
64 line = nullptr;
65 textItem = nullptr;
66 myItemColor = Qt::white;
67 myTextColor = Qt::black;
68 myLineColor = Qt::black;
69}
70//! [0]
71
72//! [1]
73void DiagramScene::setLineColor(const QColor &color)
74{
75 myLineColor = color;
76 if (isItemChange(Arrow::Type)) {
77 Arrow *item = qgraphicsitem_cast<Arrow *>(selectedItems().first());
78 item->setColor(myLineColor);
79 update();
80 }
81}
82//! [1]
83
84//! [2]
85void DiagramScene::setTextColor(const QColor &color)
86{
87 myTextColor = color;
88 if (isItemChange(DiagramTextItem::Type)) {
89 DiagramTextItem *item = qgraphicsitem_cast<DiagramTextItem *>(selectedItems().first());
90 item->setDefaultTextColor(myTextColor);
91 }
92}
93//! [2]
94
95//! [3]
96void DiagramScene::setItemColor(const QColor &color)
97{
98 myItemColor = color;
99 if (isItemChange(DiagramItem::Type)) {
100 DiagramItem *item = qgraphicsitem_cast<DiagramItem *>(selectedItems().first());
101 item->setBrush(myItemColor);
102 }
103}
104//! [3]
105
106//! [4]
107void DiagramScene::setFont(const QFont &font)
108{
109 myFont = font;
110
111 if (isItemChange(DiagramTextItem::Type)) {
112 QGraphicsTextItem *item = qgraphicsitem_cast<DiagramTextItem *>(selectedItems().first());
113 //At this point the selection can change so the first selected item might not be a DiagramTextItem
114 if (item)
115 item->setFont(myFont);
116 }
117}
118//! [4]
119
120void DiagramScene::setMode(Mode mode)
121{
122 myMode = mode;
123}
124
125void DiagramScene::setItemType(DiagramItem::DiagramType type)
126{
127 myItemType = type;
128}
129
130//! [5]
131void DiagramScene::editorLostFocus(DiagramTextItem *item)
132{
133 QTextCursor cursor = item->textCursor();
134 cursor.clearSelection();
135 item->setTextCursor(cursor);
136
137 if (item->toPlainText().isEmpty()) {
138 removeItem(item);
139 item->deleteLater();
140 }
141}
142//! [5]
143
144//! [6]
145void DiagramScene::mousePressEvent(QGraphicsSceneMouseEvent *mouseEvent)
146{
147 if (mouseEvent->button() != Qt::LeftButton)
148 return;
149
150 DiagramItem *item;
151 switch (myMode) {
152 case InsertItem:
153 item = new DiagramItem(myItemType, myItemMenu);
154 item->setBrush(myItemColor);
155 addItem(item);
156 item->setPos(mouseEvent->scenePos());
157 emit itemInserted(item);
158 break;
159//! [6] //! [7]
160 case InsertLine:
161 line = new QGraphicsLineItem(QLineF(mouseEvent->scenePos(),
162 mouseEvent->scenePos()));
163 line->setPen(QPen(myLineColor, 2));
164 addItem(line);
165 break;
166//! [7] //! [8]
167 case InsertText:
168 textItem = new DiagramTextItem();
169 textItem->setFont(myFont);
170 textItem->setTextInteractionFlags(Qt::TextEditorInteraction);
171 textItem->setZValue(1000.0);
172 connect(textItem, &DiagramTextItem::lostFocus,
173 this, &DiagramScene::editorLostFocus);
174 connect(textItem, &DiagramTextItem::selectedChange,
175 this, &DiagramScene::itemSelected);
176 addItem(textItem);
177 textItem->setDefaultTextColor(myTextColor);
178 textItem->setPos(mouseEvent->scenePos());
179 emit textInserted(textItem);
180//! [8] //! [9]
181 default:
182 ;
183 }
184 QGraphicsScene::mousePressEvent(mouseEvent);
185}
186//! [9]
187
188//! [10]
189void DiagramScene::mouseMoveEvent(QGraphicsSceneMouseEvent *mouseEvent)
190{
191 if (myMode == InsertLine && line != nullptr) {
192 QLineF newLine(line->line().p1(), mouseEvent->scenePos());
193 line->setLine(newLine);
194 } else if (myMode == MoveItem) {
195 QGraphicsScene::mouseMoveEvent(mouseEvent);
196 }
197}
198//! [10]
199
200//! [11]
201void DiagramScene::mouseReleaseEvent(QGraphicsSceneMouseEvent *mouseEvent)
202{
203 if (line != nullptr && myMode == InsertLine) {
204 QList<QGraphicsItem *> startItems = items(line->line().p1());
205 if (startItems.count() && startItems.first() == line)
206 startItems.removeFirst();
207 QList<QGraphicsItem *> endItems = items(line->line().p2());
208 if (endItems.count() && endItems.first() == line)
209 endItems.removeFirst();
210
211 removeItem(line);
212 delete line;
213//! [11] //! [12]
214
215 if (startItems.count() > 0 && endItems.count() > 0 &&
216 startItems.first()->type() == DiagramItem::Type &&
217 endItems.first()->type() == DiagramItem::Type &&
218 startItems.first() != endItems.first()) {
219 DiagramItem *startItem = qgraphicsitem_cast<DiagramItem *>(startItems.first());
220 DiagramItem *endItem = qgraphicsitem_cast<DiagramItem *>(endItems.first());
221 Arrow *arrow = new Arrow(startItem, endItem);
222 arrow->setColor(myLineColor);
223 startItem->addArrow(arrow);
224 endItem->addArrow(arrow);
225 arrow->setZValue(-1000.0);
226 addItem(arrow);
227 arrow->updatePosition();
228 }
229 }
230//! [12] //! [13]
231 line = nullptr;
232 QGraphicsScene::mouseReleaseEvent(mouseEvent);
233}
234//! [13]
235
236//! [14]
237bool DiagramScene::isItemChange(int type) const
238{
239 const QList<QGraphicsItem *> items = selectedItems();
240 const auto cb = [type](const QGraphicsItem *item) { return item->type() == type; };
241 return std::find_if(items.begin(), items.end(), cb) != items.end();
242}
243//! [14]
244