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