1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
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 "formeditorscene.h"
27 #include "formeditorview.h"
28 #include "formeditorwidget.h"
29 #include "formeditoritem.h"
30 #include <nodehints.h>
31 #include <qmldesignerconstants.h>
32 #include <qmldesignerplugin.h>
33 #include <designersettings.h>
34
35 #include <QGraphicsSceneDragDropEvent>
36
37 #include <QEvent>
38 #include <QGraphicsSceneMouseEvent>
39 #include <QGraphicsSceneHoverEvent>
40 #include <QGraphicsView>
41
42 #include <QDebug>
43 #include <QElapsedTimer>
44 #include <QList>
45 #include <QTime>
46
47 #include <utils/algorithm.h>
48 #include <utils/qtcassert.h>
49
50 namespace QmlDesigner {
51
FormEditorScene(FormEditorWidget * view,FormEditorView * editorView)52 FormEditorScene::FormEditorScene(FormEditorWidget *view, FormEditorView *editorView)
53 : QGraphicsScene()
54 , m_editorView(editorView)
55 , m_showBoundingRects(false)
56 , m_annotationVisibility(false)
57 {
58 setupScene();
59 view->setScene(this);
60 setItemIndexMethod(QGraphicsScene::NoIndex);
61 }
62
~FormEditorScene()63 FormEditorScene::~FormEditorScene()
64 {
65 clear(); //FormEditorItems have to be cleared before destruction
66 //Reason: FormEditorItems accesses FormEditorScene in destructor
67 }
68
69
setupScene()70 void FormEditorScene::setupScene()
71 {
72 m_formLayerItem = new LayerItem(this);
73 m_manipulatorLayerItem = new LayerItem(this);
74 m_manipulatorLayerItem->setZValue(1.0);
75 m_manipulatorLayerItem->setFlag(QGraphicsItem::ItemClipsChildrenToShape, false);
76 m_formLayerItem->setZValue(0.0);
77 m_formLayerItem->setFlag(QGraphicsItem::ItemClipsChildrenToShape, false);
78 }
79
resetScene()80 void FormEditorScene::resetScene()
81 {
82 foreach (QGraphicsItem *item, m_manipulatorLayerItem->childItems()) {
83 removeItem(item);
84 delete item;
85 }
86
87 setSceneRect(-canvasWidth()/2., -canvasHeight()/2., canvasWidth(), canvasHeight());
88 }
89
itemForQmlItemNode(const QmlItemNode & qmlItemNode) const90 FormEditorItem* FormEditorScene::itemForQmlItemNode(const QmlItemNode &qmlItemNode) const
91 {
92 return m_qmlItemNodeItemHash.value(qmlItemNode);
93 }
94
canvasWidth() const95 double FormEditorScene::canvasWidth() const
96 {
97 return DesignerSettings::getValue(DesignerSettingsKey::CANVASWIDTH).toDouble();
98 }
99
canvasHeight() const100 double FormEditorScene::canvasHeight() const
101 {
102 return DesignerSettings::getValue(DesignerSettingsKey::CANVASHEIGHT).toDouble();
103 }
104
itemsForQmlItemNodes(const QList<QmlItemNode> & nodeList) const105 QList<FormEditorItem*> FormEditorScene::itemsForQmlItemNodes(const QList<QmlItemNode> &nodeList) const
106 {
107 return Utils::filtered(Utils::transform(nodeList, [this](const QmlItemNode &qmlItemNode) {
108 return itemForQmlItemNode(qmlItemNode);
109 }), [] (FormEditorItem* item) { return item; });
110 }
111
allFormEditorItems() const112 QList<FormEditorItem*> FormEditorScene::allFormEditorItems() const
113 {
114 return m_qmlItemNodeItemHash.values();
115 }
116
updateAllFormEditorItems()117 void FormEditorScene::updateAllFormEditorItems()
118 {
119 foreach (FormEditorItem *item, allFormEditorItems())
120 item->update();
121 }
122
removeItemFromHash(FormEditorItem * item)123 void FormEditorScene::removeItemFromHash(FormEditorItem *item)
124 {
125 m_qmlItemNodeItemHash.remove(item->qmlItemNode());
126 }
127
currentTool() const128 AbstractFormEditorTool* FormEditorScene::currentTool() const
129 {
130 return m_editorView->currentTool();
131 }
132
133 //This function calculates the possible parent for reparent
calulateNewParent(FormEditorItem * formEditorItem)134 FormEditorItem* FormEditorScene::calulateNewParent(FormEditorItem *formEditorItem)
135 {
136 if (formEditorItem->qmlItemNode().isValid()) {
137 QList<QGraphicsItem *> list = items(formEditorItem->qmlItemNode().instanceBoundingRect().center());
138 foreach (QGraphicsItem *graphicsItem, list) {
139 if (qgraphicsitem_cast<FormEditorItem*>(graphicsItem) &&
140 graphicsItem->collidesWithItem(formEditorItem, Qt::ContainsItemShape))
141 return qgraphicsitem_cast<FormEditorItem*>(graphicsItem);
142 }
143 }
144
145 return nullptr;
146 }
147
synchronizeTransformation(FormEditorItem * item)148 void FormEditorScene::synchronizeTransformation(FormEditorItem *item)
149 {
150 item->updateGeometry();
151 item->update();
152
153 if (item->qmlItemNode().isRootNode()) {
154 formLayerItem()->update();
155 manipulatorLayerItem()->update();
156 }
157 }
158
synchronizeParent(const QmlItemNode & qmlItemNode)159 void FormEditorScene::synchronizeParent(const QmlItemNode &qmlItemNode)
160 {
161 QmlItemNode parentNode = qmlItemNode.instanceParent().toQmlItemNode();
162 reparentItem(qmlItemNode, parentNode);
163 }
164
synchronizeOtherProperty(FormEditorItem * item,const QByteArray & propertyName)165 void FormEditorScene::synchronizeOtherProperty(FormEditorItem *item, const QByteArray &propertyName)
166 {
167 Q_ASSERT(item);
168
169 item->synchronizeOtherProperty(propertyName);
170 }
171
addFormEditorItem(const QmlItemNode & qmlItemNode,ItemType type)172 FormEditorItem *FormEditorScene::addFormEditorItem(const QmlItemNode &qmlItemNode, ItemType type)
173 {
174 FormEditorItem *formEditorItem = nullptr;
175
176 if (type == Flow)
177 formEditorItem = new FormEditorFlowItem(qmlItemNode, this);
178 else if (type == FlowAction)
179 formEditorItem = new FormEditorFlowActionItem(qmlItemNode, this);
180 else if (type == FlowTransition)
181 formEditorItem = new FormEditorTransitionItem(qmlItemNode, this);
182 else if (type == FlowDecision)
183 formEditorItem = new FormEditorFlowDecisionItem(qmlItemNode, this);
184 else if (type == FlowWildcard)
185 formEditorItem = new FormEditorFlowWildcardItem(qmlItemNode, this);
186 else
187 formEditorItem = new FormEditorItem(qmlItemNode, this);
188
189 QTC_ASSERT(!m_qmlItemNodeItemHash.contains(qmlItemNode), ;);
190
191 m_qmlItemNodeItemHash.insert(qmlItemNode, formEditorItem);
192 if (qmlItemNode.isRootNode()) {
193 setSceneRect(-canvasWidth()/2., -canvasHeight()/2., canvasWidth(), canvasHeight());
194 formLayerItem()->update();
195 manipulatorLayerItem()->update();
196 }
197
198 return formEditorItem;
199 }
200
dropEvent(QGraphicsSceneDragDropEvent * event)201 void FormEditorScene::dropEvent(QGraphicsSceneDragDropEvent * event)
202 {
203 currentTool()->dropEvent(removeLayerItems(itemsAt(event->scenePos())), event);
204
205 if (views().constFirst())
206 views().constFirst()->setFocus();
207 }
208
dragEnterEvent(QGraphicsSceneDragDropEvent * event)209 void FormEditorScene::dragEnterEvent(QGraphicsSceneDragDropEvent * event)
210 {
211 currentTool()->dragEnterEvent(removeLayerItems(itemsAt(event->scenePos())), event);
212 }
213
dragLeaveEvent(QGraphicsSceneDragDropEvent * event)214 void FormEditorScene::dragLeaveEvent(QGraphicsSceneDragDropEvent * event)
215 {
216 currentTool()->dragLeaveEvent(removeLayerItems(itemsAt(event->scenePos())), event);
217
218 return;
219 }
220
dragMoveEvent(QGraphicsSceneDragDropEvent * event)221 void FormEditorScene::dragMoveEvent(QGraphicsSceneDragDropEvent * event)
222 {
223 currentTool()->dragMoveEvent(removeLayerItems(itemsAt(event->scenePos())), event);
224 }
225
removeLayerItems(const QList<QGraphicsItem * > & itemList)226 QList<QGraphicsItem *> FormEditorScene::removeLayerItems(const QList<QGraphicsItem *> &itemList)
227 {
228 QList<QGraphicsItem *> itemListWithoutLayerItems;
229
230 foreach (QGraphicsItem *item, itemList)
231 if (item != manipulatorLayerItem() && item != formLayerItem())
232 itemListWithoutLayerItems.append(item);
233
234 return itemListWithoutLayerItems;
235 }
236
itemsAt(const QPointF & pos)237 QList<QGraphicsItem *> FormEditorScene::itemsAt(const QPointF &pos)
238 {
239 QTransform transform;
240
241 if (!views().isEmpty())
242 transform = views().constFirst()->transform();
243
244 return items(pos,
245 Qt::IntersectsItemShape,
246 Qt::DescendingOrder,
247 transform);
248 }
249
mousePressEvent(QGraphicsSceneMouseEvent * event)250 void FormEditorScene::mousePressEvent(QGraphicsSceneMouseEvent *event)
251 {
252 event->ignore();
253 QGraphicsScene::mousePressEvent(event);
254 if (event->isAccepted())
255 return;
256
257 if (editorView() && editorView()->model())
258 currentTool()->mousePressEvent(removeLayerItems(itemsAt(event->scenePos())), event);
259 }
260
staticTimer()261 static QElapsedTimer staticTimer()
262 {
263 QElapsedTimer timer;
264 timer.start();
265 return timer;
266 }
267
mouseMoveEvent(QGraphicsSceneMouseEvent * event)268 void FormEditorScene::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
269 {
270 static QElapsedTimer time = staticTimer();
271
272 QGraphicsScene::mouseMoveEvent(event);
273
274 if (time.elapsed() > 30) {
275 time.restart();
276 if (event->buttons())
277 currentTool()->mouseMoveEvent(removeLayerItems(itemsAt(event->scenePos())), event);
278 else
279 currentTool()->hoverMoveEvent(removeLayerItems(itemsAt(event->scenePos())), event);
280
281 event->accept();
282 }
283 }
284
mouseReleaseEvent(QGraphicsSceneMouseEvent * event)285 void FormEditorScene::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
286 {
287 event->ignore();
288 QGraphicsScene::mouseReleaseEvent(event);
289 if (event->isAccepted())
290 return;
291
292 if (editorView() && editorView()->model()) {
293 currentTool()->mouseReleaseEvent(removeLayerItems(itemsAt(event->scenePos())), event);
294
295 event->accept();
296 }
297 }
298
mouseDoubleClickEvent(QGraphicsSceneMouseEvent * event)299 void FormEditorScene::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
300 {
301 event->ignore();
302 QGraphicsScene::mousePressEvent(event);
303 if (event->isAccepted())
304 return;
305
306 if (editorView() && editorView()->model()) {
307 currentTool()->mouseDoubleClickEvent(removeLayerItems(itemsAt(event->scenePos())), event);
308
309 event->accept();
310 }
311 }
312
keyPressEvent(QKeyEvent * keyEvent)313 void FormEditorScene::keyPressEvent(QKeyEvent *keyEvent)
314 {
315 if (editorView() && editorView()->model())
316 currentTool()->keyPressEvent(keyEvent);
317 }
318
keyReleaseEvent(QKeyEvent * keyEvent)319 void FormEditorScene::keyReleaseEvent(QKeyEvent *keyEvent)
320 {
321 if (editorView() && editorView()->model())
322 currentTool()->keyReleaseEvent(keyEvent);
323 }
324
focusOutEvent(QFocusEvent * focusEvent)325 void FormEditorScene::focusOutEvent(QFocusEvent *focusEvent)
326 {
327 if (currentTool())
328 currentTool()->focusLost();
329
330 QmlDesignerPlugin::emitUsageStatisticsTime(Constants::EVENT_FORMEDITOR_TIME,
331 m_usageTimer.elapsed());
332
333 QGraphicsScene::focusOutEvent(focusEvent);
334 }
335
focusInEvent(QFocusEvent * focusEvent)336 void FormEditorScene::focusInEvent(QFocusEvent *focusEvent)
337 {
338 m_usageTimer.restart();
339 QGraphicsScene::focusInEvent(focusEvent);
340 }
341
editorView() const342 FormEditorView *FormEditorScene::editorView() const
343 {
344 return m_editorView;
345 }
346
manipulatorLayerItem() const347 LayerItem* FormEditorScene::manipulatorLayerItem() const
348 {
349 return m_manipulatorLayerItem.data();
350 }
351
formLayerItem() const352 LayerItem* FormEditorScene::formLayerItem() const
353 {
354 return m_formLayerItem.data();
355 }
356
event(QEvent * event)357 bool FormEditorScene::event(QEvent * event)
358 {
359 switch (event->type())
360 {
361 case QEvent::GraphicsSceneHoverEnter :
362 hoverEnterEvent(static_cast<QGraphicsSceneHoverEvent *>(event));
363 return QGraphicsScene::event(event);
364 case QEvent::GraphicsSceneHoverMove :
365 hoverMoveEvent(static_cast<QGraphicsSceneHoverEvent *>(event));
366 return QGraphicsScene::event(event);
367 case QEvent::GraphicsSceneHoverLeave :
368 hoverLeaveEvent(static_cast<QGraphicsSceneHoverEvent *>(event));
369 return QGraphicsScene::event(event);
370 case QEvent::ShortcutOverride :
371 if (static_cast<QKeyEvent*>(event)->key() == Qt::Key_Escape) {
372 currentTool()->keyPressEvent(static_cast<QKeyEvent*>(event));
373 return true;
374 }
375 Q_FALLTHROUGH();
376 default: return QGraphicsScene::event(event);
377 }
378
379 }
380
hoverEnterEvent(QGraphicsSceneHoverEvent *)381 void FormEditorScene::hoverEnterEvent(QGraphicsSceneHoverEvent * /*event*/)
382 {
383 qDebug() << __FUNCTION__;
384 }
385
hoverMoveEvent(QGraphicsSceneHoverEvent *)386 void FormEditorScene::hoverMoveEvent(QGraphicsSceneHoverEvent * /*event*/)
387 {
388 qDebug() << __FUNCTION__;
389 }
390
hoverLeaveEvent(QGraphicsSceneHoverEvent *)391 void FormEditorScene::hoverLeaveEvent(QGraphicsSceneHoverEvent * /*event*/)
392 {
393 qDebug() << __FUNCTION__;
394 }
395
reparentItem(const QmlItemNode & node,const QmlItemNode & newParent)396 void FormEditorScene::reparentItem(const QmlItemNode &node, const QmlItemNode &newParent)
397 {
398 if (FormEditorItem *item = itemForQmlItemNode(node)) {
399 item->setParentItem(nullptr);
400 if (newParent.isValid()) {
401 if (FormEditorItem *parentItem = itemForQmlItemNode(newParent))
402 item->setParentItem(parentItem);
403 }
404 } else {
405 Q_ASSERT(itemForQmlItemNode(node));
406 }
407 }
408
rootFormEditorItem() const409 FormEditorItem* FormEditorScene::rootFormEditorItem() const
410 {
411 return itemForQmlItemNode(editorView()->rootModelNode());
412 }
413
clearFormEditorItems()414 void FormEditorScene::clearFormEditorItems()
415 {
416 const QList<QGraphicsItem*> itemList(items());
417
418 const QList<FormEditorItem*> formEditorItemsTransformed =
419 Utils::transform(itemList, [](QGraphicsItem *item) { return qgraphicsitem_cast<FormEditorItem* >(item); });
420
421 const QList<FormEditorItem*> formEditorItems = Utils::filtered(formEditorItemsTransformed,
422 [](FormEditorItem *item) { return item; });
423 foreach (FormEditorItem *item, formEditorItems)
424 item->setParentItem(nullptr);
425
426 foreach (FormEditorItem *item, formEditorItems)
427 delete item;
428 }
429
highlightBoundingRect(FormEditorItem * highlighItem)430 void FormEditorScene::highlightBoundingRect(FormEditorItem *highlighItem)
431 {
432 foreach (FormEditorItem *item, allFormEditorItems()) {
433 if (item == highlighItem)
434 item->setHighlightBoundingRect(true);
435 else
436 item->setHighlightBoundingRect(false);
437 }
438 }
439
setShowBoundingRects(bool show)440 void FormEditorScene::setShowBoundingRects(bool show)
441 {
442 m_showBoundingRects = show;
443 updateAllFormEditorItems();
444 }
445
showBoundingRects() const446 bool FormEditorScene::showBoundingRects() const
447 {
448 return m_showBoundingRects;
449 }
450
annotationVisibility() const451 bool FormEditorScene::annotationVisibility() const
452 {
453 return m_annotationVisibility;
454 }
455
setAnnotationVisibility(bool status)456 void FormEditorScene::setAnnotationVisibility(bool status)
457 {
458 m_annotationVisibility = status;
459 }
460
461 }
462
463