source: trunk/src/gui/graphicsview/qgraphicsscene.cpp@ 711

Last change on this file since 711 was 651, checked in by Dmitry A. Kuminov, 16 years ago

trunk: Merged in qt 4.6.2 sources.

File size: 224.8 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** This file is part of the QtGui module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42/*!
43 \class QGraphicsScene
44 \brief The QGraphicsScene class provides a surface for managing a large
45 number of 2D graphical items.
46 \since 4.2
47 \ingroup graphicsview-api
48
49
50 The class serves as a container for QGraphicsItems. It is used together
51 with QGraphicsView for visualizing graphical items, such as lines,
52 rectangles, text, or even custom items, on a 2D surface. QGraphicsScene is
53 part of \l{The Graphics View Framework}.
54
55 QGraphicsScene also provides functionality that lets you efficiently
56 determine both the location of items, and for determining what items are
57 visible within an arbitrary area on the scene. With the QGraphicsView
58 widget, you can either visualize the whole scene, or zoom in and view only
59 parts of the scene.
60
61 Example:
62
63 \snippet doc/src/snippets/code/src_gui_graphicsview_qgraphicsscene.cpp 0
64
65 Note that QGraphicsScene has no visual appearance of its own; it only
66 manages the items. You need to create a QGraphicsView widget to visualize
67 the scene.
68
69 To add items to a scene, you start off by constructing a QGraphicsScene
70 object. Then, you have two options: either add your existing QGraphicsItem
71 objects by calling addItem(), or you can call one of the convenience
72 functions addEllipse(), addLine(), addPath(), addPixmap(), addPolygon(),
73 addRect(), or addText(), which all return a pointer to the newly added item.
74 The dimensions of the items added with these functions are relative to the
75 item's coordinate system, and the items position is initialized to (0,
76 0) in the scene.
77
78 You can then visualize the scene using QGraphicsView. When the scene
79 changes, (e.g., when an item moves or is transformed) QGraphicsScene
80 emits the changed() signal. To remove an item, call removeItem().
81
82 QGraphicsScene uses an indexing algorithm to manage the location of items
83 efficiently. By default, a BSP (Binary Space Partitioning) tree is used; an
84 algorithm suitable for large scenes where most items remain static (i.e.,
85 do not move around). You can choose to disable this index by calling
86 setItemIndexMethod(). For more information about the available indexing
87 algorithms, see the itemIndexMethod property.
88
89 The scene's bounding rect is set by calling setSceneRect(). Items can be
90 placed at any position on the scene, and the size of the scene is by
91 default unlimited. The scene rect is used only for internal bookkeeping,
92 maintaining the scene's item index. If the scene rect is unset,
93 QGraphicsScene will use the bounding area of all items, as returned by
94 itemsBoundingRect(), as the scene rect. However, itemsBoundingRect() is a
95 relatively time consuming function, as it operates by collecting
96 positional information for every item on the scene. Because of this, you
97 should always set the scene rect when operating on large scenes.
98
99 One of QGraphicsScene's greatest strengths is its ability to efficiently
100 determine the location of items. Even with millions of items on the scene,
101 the items() functions can determine the location of an item within few
102 milliseconds. There are several overloads to items(): one that finds items
103 at a certain position, one that finds items inside or intersecting with a
104 polygon or a rectangle, and more. The list of returned items is sorted by
105 stacking order, with the topmost item being the first item in the list.
106 For convenience, there is also an itemAt() function that returns the
107 topmost item at a given position.
108
109 QGraphicsScene maintains selection information for the scene. To select
110 items, call setSelectionArea(), and to clear the current selection, call
111 clearSelection(). Call selectedItems() to get the list of all selected
112 items.
113
114 \section1 Event Handling and Propagation
115
116 Another responsibility that QGraphicsScene has, is to propagate events
117 from QGraphicsView. To send an event to a scene, you construct an event
118 that inherits QEvent, and then send it using, for example,
119 QApplication::sendEvent(). event() is responsible for dispatching
120 the event to the individual items. Some common events are handled by
121 convenience event handlers. For example, key press events are handled by
122 keyPressEvent(), and mouse press events are handled by mousePressEvent().
123
124 Key events are delivered to the \e {focus item}. To set the focus item,
125 you can either call setFocusItem(), passing an item that accepts focus, or
126 the item itself can call QGraphicsItem::setFocus(). Call focusItem() to
127 get the current focus item. For compatibility with widgets, the scene also
128 maintains its own focus information. By default, the scene does not have
129 focus, and all key events are discarded. If setFocus() is called, or if an
130 item on the scene gains focus, the scene automatically gains focus. If the
131 scene has focus, hasFocus() will return true, and key events will be
132 forwarded to the focus item, if any. If the scene loses focus, (i.e.,
133 someone calls clearFocus(),) while an item has focus, the scene will
134 maintain its item focus information, and once the scene regains focus, it
135 will make sure the last focus item regains focus.
136
137 For mouse-over effects, QGraphicsScene dispatches \e {hover
138 events}. If an item accepts hover events (see
139 QGraphicsItem::acceptHoverEvents()), it will receive a \l
140 {QEvent::}{GraphicsSceneHoverEnter} event when the mouse enters
141 its area. As the mouse continues moving inside the item's area,
142 QGraphicsScene will send it \l {QEvent::}{GraphicsSceneHoverMove}
143 events. When the mouse leaves the item's area, the item will
144 receive a \l {QEvent::}{GraphicsSceneHoverLeave} event.
145
146 All mouse events are delivered to the current \e {mouse grabber}
147 item. An item becomes the scene's mouse grabber if it accepts
148 mouse events (see QGraphicsItem::acceptedMouseButtons()) and it
149 receives a mouse press. It stays the mouse grabber until it
150 receives a mouse release when no other mouse buttons are
151 pressed. You can call mouseGrabberItem() to determine what item is
152 currently grabbing the mouse.
153
154 \sa QGraphicsItem, QGraphicsView
155*/
156
157/*!
158 \enum QGraphicsScene::SceneLayer
159 \since 4.3
160
161 This enum describes the rendering layers in a QGraphicsScene. When
162 QGraphicsScene draws the scene contents, it renders each of these layers
163 separately, in order.
164
165 Each layer represents a flag that can be OR'ed together when calling
166 functions such as invalidate() or QGraphicsView::invalidateScene().
167
168 \value ItemLayer The item layer. QGraphicsScene renders all items are in
169 this layer by calling the virtual function drawItems(). The item layer is
170 drawn after the background layer, but before the foreground layer.
171
172 \value BackgroundLayer The background layer. QGraphicsScene renders the
173 scene's background in this layer by calling the virtual function
174 drawBackground(). The background layer is drawn first of all layers.
175
176 \value ForegroundLayer The foreground layer. QGraphicsScene renders the
177 scene's foreground in this layer by calling the virtual function
178 drawForeground(). The foreground layer is drawn last of all layers.
179
180 \value AllLayers All layers; this value represents a combination of all
181 three layers.
182
183 \sa invalidate(), QGraphicsView::invalidateScene()
184*/
185
186/*!
187 \enum QGraphicsScene::ItemIndexMethod
188
189 This enum describes the indexing algorithms QGraphicsScene provides for
190 managing positional information about items on the scene.
191
192 \value BspTreeIndex A Binary Space Partitioning tree is applied. All
193 QGraphicsScene's item location algorithms are of an order close to
194 logarithmic complexity, by making use of binary search. Adding, moving and
195 removing items is logarithmic. This approach is best for static scenes
196 (i.e., scenes where most items do not move).
197
198 \value NoIndex No index is applied. Item location is of linear complexity,
199 as all items on the scene are searched. Adding, moving and removing items,
200 however, is done in constant time. This approach is ideal for dynamic
201 scenes, where many items are added, moved or removed continuously.
202
203 \sa setItemIndexMethod(), bspTreeDepth
204*/
205
206#include "qgraphicsscene.h"
207
208#ifndef QT_NO_GRAPHICSVIEW
209
210#include "qgraphicsitem.h"
211#include "qgraphicsitem_p.h"
212#include "qgraphicslayout.h"
213#include "qgraphicsscene_p.h"
214#include "qgraphicssceneevent.h"
215#include "qgraphicsview.h"
216#include "qgraphicsview_p.h"
217#include "qgraphicswidget.h"
218#include "qgraphicswidget_p.h"
219#include "qgraphicssceneindex_p.h"
220#include "qgraphicsscenebsptreeindex_p.h"
221#include "qgraphicsscenelinearindex_p.h"
222
223#include <QtCore/qdebug.h>
224#include <QtCore/qlist.h>
225#include <QtCore/qmath.h>
226#include <QtCore/qrect.h>
227#include <QtCore/qset.h>
228#include <QtCore/qstack.h>
229#include <QtCore/qtimer.h>
230#include <QtCore/qvarlengtharray.h>
231#include <QtGui/qapplication.h>
232#include <QtGui/qdesktopwidget.h>
233#include <QtGui/qevent.h>
234#include <QtGui/qgraphicslayout.h>
235#include <QtGui/qgraphicsproxywidget.h>
236#include <QtGui/qgraphicswidget.h>
237#include <QtGui/qmatrix.h>
238#include <QtGui/qpaintengine.h>
239#include <QtGui/qpainter.h>
240#include <QtGui/qpixmapcache.h>
241#include <QtGui/qpolygon.h>
242#include <QtGui/qstyleoption.h>
243#include <QtGui/qtooltip.h>
244#include <QtGui/qtransform.h>
245#include <QtGui/qinputcontext.h>
246#include <QtGui/qgraphicseffect.h>
247#include <private/qapplication_p.h>
248#include <private/qobject_p.h>
249#ifdef Q_WS_X11
250#include <private/qt_x11_p.h>
251#endif
252#include <private/qgraphicseffect_p.h>
253#include <private/qgesturemanager_p.h>
254#include <private/qpathclipper_p.h>
255
256// #define GESTURE_DEBUG
257#ifndef GESTURE_DEBUG
258# define DEBUG if (0) qDebug
259#else
260# define DEBUG qDebug
261#endif
262
263QT_BEGIN_NAMESPACE
264
265bool qt_sendSpontaneousEvent(QObject *receiver, QEvent *event);
266
267static void _q_hoverFromMouseEvent(QGraphicsSceneHoverEvent *hover, const QGraphicsSceneMouseEvent *mouseEvent)
268{
269 hover->setWidget(mouseEvent->widget());
270 hover->setPos(mouseEvent->pos());
271 hover->setScenePos(mouseEvent->scenePos());
272 hover->setScreenPos(mouseEvent->screenPos());
273 hover->setLastPos(mouseEvent->lastPos());
274 hover->setLastScenePos(mouseEvent->lastScenePos());
275 hover->setLastScreenPos(mouseEvent->lastScreenPos());
276 hover->setModifiers(mouseEvent->modifiers());
277 hover->setAccepted(mouseEvent->isAccepted());
278}
279
280int QGraphicsScenePrivate::changedSignalIndex;
281
282/*!
283 \internal
284*/
285QGraphicsScenePrivate::QGraphicsScenePrivate()
286 : indexMethod(QGraphicsScene::BspTreeIndex),
287 index(0),
288 lastItemCount(0),
289 hasSceneRect(false),
290 dirtyGrowingItemsBoundingRect(true),
291 updateAll(false),
292 calledEmitUpdated(false),
293 processDirtyItemsEmitted(false),
294 selectionChanging(0),
295 needSortTopLevelItems(true),
296 holesInTopLevelSiblingIndex(false),
297 topLevelSequentialOrdering(true),
298 scenePosDescendantsUpdatePending(false),
299 stickyFocus(false),
300 hasFocus(false),
301 focusItem(0),
302 lastFocusItem(0),
303 tabFocusFirst(0),
304 activePanel(0),
305 lastActivePanel(0),
306 activationRefCount(0),
307 childExplicitActivation(0),
308 lastMouseGrabberItem(0),
309 lastMouseGrabberItemHasImplicitMouseGrab(false),
310 dragDropItem(0),
311 enterWidget(0),
312 lastDropAction(Qt::IgnoreAction),
313 allItemsIgnoreHoverEvents(true),
314 allItemsUseDefaultCursor(true),
315 painterStateProtection(true),
316 sortCacheEnabled(false),
317 style(0),
318 allItemsIgnoreTouchEvents(true)
319{
320}
321
322/*!
323 \internal
324*/
325void QGraphicsScenePrivate::init()
326{
327 Q_Q(QGraphicsScene);
328
329 index = new QGraphicsSceneBspTreeIndex(q);
330
331 // Keep this index so we can check for connected slots later on.
332 if (!changedSignalIndex) {
333 changedSignalIndex = signalIndex("changed(QList<QRectF>)");
334 }
335 qApp->d_func()->scene_list.append(q);
336 q->update();
337}
338
339/*!
340 \internal
341*/
342QGraphicsScenePrivate *QGraphicsScenePrivate::get(QGraphicsScene *q)
343{
344 return q->d_func();
345}
346
347void QGraphicsScenePrivate::_q_emitUpdated()
348{
349 Q_Q(QGraphicsScene);
350 calledEmitUpdated = false;
351
352 if (dirtyGrowingItemsBoundingRect) {
353 if (!hasSceneRect) {
354 const QRectF oldGrowingItemsBoundingRect = growingItemsBoundingRect;
355 growingItemsBoundingRect |= q->itemsBoundingRect();
356 if (oldGrowingItemsBoundingRect != growingItemsBoundingRect)
357 emit q->sceneRectChanged(growingItemsBoundingRect);
358 }
359 dirtyGrowingItemsBoundingRect = false;
360 }
361
362 // Ensure all views are connected if anything is connected. This disables
363 // the optimization that items send updates directly to the views, but it
364 // needs to happen in order to keep compatibility with the behavior from
365 // Qt 4.4 and backward.
366 if (isSignalConnected(changedSignalIndex)) {
367 for (int i = 0; i < views.size(); ++i) {
368 QGraphicsView *view = views.at(i);
369 if (!view->d_func()->connectedToScene) {
370 view->d_func()->connectedToScene = true;
371 q->connect(q, SIGNAL(changed(QList<QRectF>)),
372 views.at(i), SLOT(updateScene(QList<QRectF>)));
373 }
374 }
375 } else {
376 if (views.isEmpty()) {
377 updateAll = false;
378 return;
379 }
380 for (int i = 0; i < views.size(); ++i)
381 views.at(i)->d_func()->processPendingUpdates();
382 // It's important that we update all views before we dispatch, hence two for-loops.
383 for (int i = 0; i < views.size(); ++i)
384 views.at(i)->d_func()->dispatchPendingUpdateRequests();
385 return;
386 }
387
388 // Notify the changes to anybody interested.
389 QList<QRectF> oldUpdatedRects;
390 oldUpdatedRects = updateAll ? (QList<QRectF>() << q->sceneRect()) : updatedRects;
391 updateAll = false;
392 updatedRects.clear();
393 emit q->changed(oldUpdatedRects);
394}
395
396/*!
397 \internal
398
399 ### This function is almost identical to QGraphicsItemPrivate::addChild().
400*/
401void QGraphicsScenePrivate::registerTopLevelItem(QGraphicsItem *item)
402{
403 item->d_ptr->ensureSequentialSiblingIndex();
404 needSortTopLevelItems = true; // ### maybe false
405 item->d_ptr->siblingIndex = topLevelItems.size();
406 topLevelItems.append(item);
407}
408
409/*!
410 \internal
411
412 ### This function is almost identical to QGraphicsItemPrivate::removeChild().
413*/
414void QGraphicsScenePrivate::unregisterTopLevelItem(QGraphicsItem *item)
415{
416 if (!holesInTopLevelSiblingIndex)
417 holesInTopLevelSiblingIndex = item->d_ptr->siblingIndex != topLevelItems.size() - 1;
418 if (topLevelSequentialOrdering && !holesInTopLevelSiblingIndex)
419 topLevelItems.removeAt(item->d_ptr->siblingIndex);
420 else
421 topLevelItems.removeOne(item);
422 // NB! Do not use topLevelItems.removeAt(item->d_ptr->siblingIndex) because
423 // the item is not guaranteed to be at the index after the list is sorted
424 // (see ensureSortedTopLevelItems()).
425 item->d_ptr->siblingIndex = -1;
426 if (topLevelSequentialOrdering)
427 topLevelSequentialOrdering = !holesInTopLevelSiblingIndex;
428}
429
430/*!
431 \internal
432*/
433void QGraphicsScenePrivate::_q_polishItems()
434{
435 if (unpolishedItems.isEmpty())
436 return;
437
438 const QVariant booleanTrueVariant(true);
439 QGraphicsItem *item = 0;
440 QGraphicsItemPrivate *itemd = 0;
441 const int oldUnpolishedCount = unpolishedItems.count();
442
443 for (int i = 0; i < oldUnpolishedCount; ++i) {
444 item = unpolishedItems.at(i);
445 if (!item)
446 continue;
447 itemd = item->d_ptr.data();
448 itemd->pendingPolish = false;
449 if (!itemd->explicitlyHidden) {
450 item->itemChange(QGraphicsItem::ItemVisibleChange, booleanTrueVariant);
451 item->itemChange(QGraphicsItem::ItemVisibleHasChanged, booleanTrueVariant);
452 }
453 if (itemd->isWidget) {
454 QEvent event(QEvent::Polish);
455 QApplication::sendEvent((QGraphicsWidget *)item, &event);
456 }
457 }
458
459 if (unpolishedItems.count() == oldUnpolishedCount) {
460 // No new items were added to the vector.
461 unpolishedItems.clear();
462 } else {
463 // New items were appended; keep them and remove the old ones.
464 unpolishedItems.remove(0, oldUnpolishedCount);
465 unpolishedItems.squeeze();
466 QMetaObject::invokeMethod(q_ptr, "_q_polishItems", Qt::QueuedConnection);
467 }
468}
469
470void QGraphicsScenePrivate::_q_processDirtyItems()
471{
472 processDirtyItemsEmitted = false;
473
474 if (updateAll) {
475 Q_ASSERT(calledEmitUpdated);
476 // No need for further processing (except resetting the dirty states).
477 // The growingItemsBoundingRect is updated in _q_emitUpdated.
478 for (int i = 0; i < topLevelItems.size(); ++i)
479 resetDirtyItem(topLevelItems.at(i), /*recursive=*/true);
480 return;
481 }
482
483 const bool wasPendingSceneUpdate = calledEmitUpdated;
484 const QRectF oldGrowingItemsBoundingRect = growingItemsBoundingRect;
485
486 // Process items recursively.
487 for (int i = 0; i < topLevelItems.size(); ++i)
488 processDirtyItemsRecursive(topLevelItems.at(i));
489
490 dirtyGrowingItemsBoundingRect = false;
491 if (!hasSceneRect && oldGrowingItemsBoundingRect != growingItemsBoundingRect)
492 emit q_func()->sceneRectChanged(growingItemsBoundingRect);
493
494 if (wasPendingSceneUpdate)
495 return;
496
497 for (int i = 0; i < views.size(); ++i)
498 views.at(i)->d_func()->processPendingUpdates();
499
500 if (calledEmitUpdated) {
501 // We did a compatibility QGraphicsScene::update in processDirtyItemsRecursive
502 // and we cannot wait for the control to reach the eventloop before the
503 // changed signal is emitted, so we emit it now.
504 _q_emitUpdated();
505 }
506
507 // Immediately dispatch all pending update requests on the views.
508 for (int i = 0; i < views.size(); ++i)
509 views.at(i)->d_func()->dispatchPendingUpdateRequests();
510}
511
512/*!
513 \internal
514*/
515void QGraphicsScenePrivate::setScenePosItemEnabled(QGraphicsItem *item, bool enabled)
516{
517 QGraphicsItem *p = item->d_ptr->parent;
518 while (p) {
519 p->d_ptr->scenePosDescendants = enabled;
520 p = p->d_ptr->parent;
521 }
522 if (!enabled && !scenePosDescendantsUpdatePending) {
523 scenePosDescendantsUpdatePending = true;
524 QMetaObject::invokeMethod(q_func(), "_q_updateScenePosDescendants", Qt::QueuedConnection);
525 }
526}
527
528/*!
529 \internal
530*/
531void QGraphicsScenePrivate::registerScenePosItem(QGraphicsItem *item)
532{
533 scenePosItems.insert(item);
534 setScenePosItemEnabled(item, true);
535}
536
537/*!
538 \internal
539*/
540void QGraphicsScenePrivate::unregisterScenePosItem(QGraphicsItem *item)
541{
542 scenePosItems.remove(item);
543 setScenePosItemEnabled(item, false);
544}
545
546/*!
547 \internal
548*/
549void QGraphicsScenePrivate::_q_updateScenePosDescendants()
550{
551 foreach (QGraphicsItem *item, scenePosItems) {
552 QGraphicsItem *p = item->d_ptr->parent;
553 while (p) {
554 p->d_ptr->scenePosDescendants = 1;
555 p = p->d_ptr->parent;
556 }
557 }
558 scenePosDescendantsUpdatePending = false;
559}
560
561/*!
562 \internal
563
564 Schedules an item for removal. This function leaves some stale indexes
565 around in the BSP tree if called from the item's destructor; these will
566 be cleaned up the next time someone triggers purgeRemovedItems().
567
568 Note: This function might get called from QGraphicsItem's destructor. \a item is
569 being destroyed, so we cannot call any pure virtual functions on it (such
570 as boundingRect()). Also, it is unnecessary to update the item's own state
571 in any way.
572*/
573void QGraphicsScenePrivate::removeItemHelper(QGraphicsItem *item)
574{
575 Q_Q(QGraphicsScene);
576
577 // Clear focus on the item to remove any reference in the focusWidget chain.
578 item->clearFocus();
579
580 markDirty(item, QRectF(), /*invalidateChildren=*/false, /*force=*/false,
581 /*ignoreOpacity=*/false, /*removingItemFromScene=*/true);
582
583 if (item->d_ptr->inDestructor) {
584 // The item is actually in its destructor, we call the special method in the index.
585 index->deleteItem(item);
586 } else {
587 // Can potentially call item->boundingRect() (virtual function), that's why
588 // we only can call this function if the item is not in its destructor.
589 index->removeItem(item);
590 }
591
592 item->d_ptr->clearSubFocus();
593
594 if (item->flags() & QGraphicsItem::ItemSendsScenePositionChanges)
595 unregisterScenePosItem(item);
596
597 QGraphicsScene *oldScene = item->d_func()->scene;
598 item->d_func()->scene = 0;
599
600 //We need to remove all children first because they might use their parent
601 //attributes (e.g. sceneTransform).
602 if (!item->d_ptr->inDestructor) {
603 // Remove all children recursively
604 for (int i = 0; i < item->d_ptr->children.size(); ++i)
605 q->removeItem(item->d_ptr->children.at(i));
606 }
607
608 if (!item->d_ptr->inDestructor && item == tabFocusFirst) {
609 QGraphicsWidget *widget = static_cast<QGraphicsWidget *>(item);
610 widget->d_func()->fixFocusChainBeforeReparenting(0, oldScene, 0);
611 }
612
613 // Unregister focus proxy.
614 item->d_ptr->resetFocusProxy();
615
616 // Remove from parent, or unregister from toplevels.
617 if (QGraphicsItem *parentItem = item->parentItem()) {
618 if (parentItem->scene()) {
619 Q_ASSERT_X(parentItem->scene() == q, "QGraphicsScene::removeItem",
620 "Parent item's scene is different from this item's scene");
621 item->setParentItem(0);
622 }
623 } else {
624 unregisterTopLevelItem(item);
625 }
626
627 // Reset the mouse grabber and focus item data.
628 if (item == focusItem)
629 focusItem = 0;
630 if (item == lastFocusItem)
631 lastFocusItem = 0;
632 if (item == activePanel) {
633 // ### deactivate...
634 activePanel = 0;
635 }
636 if (item == lastActivePanel)
637 lastActivePanel = 0;
638
639 // Cancel active touches
640 {
641 QMap<int, QGraphicsItem *>::iterator it = itemForTouchPointId.begin();
642 while (it != itemForTouchPointId.end()) {
643 if (it.value() == item) {
644 sceneCurrentTouchPoints.remove(it.key());
645 it = itemForTouchPointId.erase(it);
646 } else {
647 ++it;
648 }
649 }
650 }
651
652 // Disable selectionChanged() for individual items
653 ++selectionChanging;
654 int oldSelectedItemsSize = selectedItems.size();
655
656 // Update selected & hovered item bookkeeping
657 selectedItems.remove(item);
658 hoverItems.removeAll(item);
659 cachedItemsUnderMouse.removeAll(item);
660 if (item->d_ptr->pendingPolish) {
661 const int unpolishedIndex = unpolishedItems.indexOf(item);
662 if (unpolishedIndex != -1)
663 unpolishedItems[unpolishedIndex] = 0;
664 item->d_ptr->pendingPolish = false;
665 }
666 resetDirtyItem(item);
667
668 //We remove all references of item from the sceneEventFilter arrays
669 QMultiMap<QGraphicsItem*, QGraphicsItem*>::iterator iterator = sceneEventFilters.begin();
670 while (iterator != sceneEventFilters.end()) {
671 if (iterator.value() == item || iterator.key() == item)
672 iterator = sceneEventFilters.erase(iterator);
673 else
674 ++iterator;
675 }
676
677 if (item->isPanel() && item->isVisible() && item->panelModality() != QGraphicsItem::NonModal)
678 leaveModal(item);
679
680 // Reset the mouse grabber and focus item data.
681 if (mouseGrabberItems.contains(item))
682 ungrabMouse(item, /* item is dying */ item->d_ptr->inDestructor);
683
684 // Reset the keyboard grabber
685 if (keyboardGrabberItems.contains(item))
686 ungrabKeyboard(item, /* item is dying */ item->d_ptr->inDestructor);
687
688 // Reset the last mouse grabber item
689 if (item == lastMouseGrabberItem)
690 lastMouseGrabberItem = 0;
691
692 // Reenable selectionChanged() for individual items
693 --selectionChanging;
694 if (!selectionChanging && selectedItems.size() != oldSelectedItemsSize)
695 emit q->selectionChanged();
696}
697
698/*!
699 \internal
700*/
701void QGraphicsScenePrivate::setActivePanelHelper(QGraphicsItem *item, bool duringActivationEvent)
702{
703 Q_Q(QGraphicsScene);
704 if (item && item->scene() != q) {
705 qWarning("QGraphicsScene::setActivePanel: item %p must be part of this scene",
706 item);
707 return;
708 }
709
710 // Ensure the scene has focus when we change panel activation.
711 q->setFocus(Qt::ActiveWindowFocusReason);
712
713 // Find the item's panel.
714 QGraphicsItem *panel = item ? item->panel() : 0;
715 lastActivePanel = panel ? activePanel : 0;
716 if (panel == activePanel || (!q->isActive() && !duringActivationEvent))
717 return;
718
719 // Deactivate the last active panel.
720 if (activePanel) {
721 if (QGraphicsItem *fi = activePanel->focusItem()) {
722 // Remove focus from the current focus item.
723 if (fi == q->focusItem())
724 q->setFocusItem(0, Qt::ActiveWindowFocusReason);
725 }
726
727 QEvent event(QEvent::WindowDeactivate);
728 q->sendEvent(activePanel, &event);
729 } else if (panel && !duringActivationEvent) {
730 // Deactivate the scene if changing activation to a panel.
731 QEvent event(QEvent::WindowDeactivate);
732 foreach (QGraphicsItem *item, q->items()) {
733 if (item->isVisible() && !item->isPanel() && !item->parentItem())
734 q->sendEvent(item, &event);
735 }
736 }
737
738 // Update activate state.
739 activePanel = panel;
740 QEvent event(QEvent::ActivationChange);
741 QApplication::sendEvent(q, &event);
742
743 // Activate
744 if (panel) {
745 QEvent event(QEvent::WindowActivate);
746 q->sendEvent(panel, &event);
747
748 // Set focus on the panel's focus item.
749 if (QGraphicsItem *focusItem = panel->focusItem())
750 focusItem->setFocus(Qt::ActiveWindowFocusReason);
751 } else if (q->isActive()) {
752 // Activate the scene
753 QEvent event(QEvent::WindowActivate);
754 foreach (QGraphicsItem *item, q->items()) {
755 if (item->isVisible() && !item->isPanel() && !item->parentItem())
756 q->sendEvent(item, &event);
757 }
758 }
759}
760
761/*!
762 \internal
763*/
764void QGraphicsScenePrivate::setFocusItemHelper(QGraphicsItem *item,
765 Qt::FocusReason focusReason)
766{
767 Q_Q(QGraphicsScene);
768 if (item == focusItem)
769 return;
770
771 // Clear focus if asked to set focus on something that can't
772 // accept input focus.
773 if (item && (!(item->flags() & QGraphicsItem::ItemIsFocusable)
774 || !item->isVisible() || !item->isEnabled())) {
775 item = 0;
776 }
777
778 // Set focus on the scene if an item requests focus.
779 if (item) {
780 q->setFocus(focusReason);
781 if (item == focusItem)
782 return;
783 }
784
785 if (focusItem) {
786 QFocusEvent event(QEvent::FocusOut, focusReason);
787 lastFocusItem = focusItem;
788 focusItem = 0;
789 sendEvent(lastFocusItem, &event);
790
791#ifndef QT_NO_IM
792 if (lastFocusItem
793 && (lastFocusItem->flags() & QGraphicsItem::ItemAcceptsInputMethod)) {
794 // Reset any visible preedit text
795 QInputMethodEvent imEvent;
796 sendEvent(lastFocusItem, &imEvent);
797
798 // Close any external input method panel. This happens
799 // automatically by removing WA_InputMethodEnabled on
800 // the views, but if we are changing focus, we have to
801 // do it ourselves.
802 if (item) {
803 for (int i = 0; i < views.size(); ++i)
804 views.at(i)->inputContext()->reset();
805 }
806 }
807#endif //QT_NO_IM
808 }
809
810 if (item) {
811 focusItem = item;
812 QFocusEvent event(QEvent::FocusIn, focusReason);
813 sendEvent(item, &event);
814 }
815
816 updateInputMethodSensitivityInViews();
817}
818
819/*!
820 \internal
821*/
822void QGraphicsScenePrivate::addPopup(QGraphicsWidget *widget)
823{
824 Q_ASSERT(widget);
825 Q_ASSERT(!popupWidgets.contains(widget));
826 popupWidgets << widget;
827 if (QGraphicsWidget *focusWidget = widget->focusWidget()) {
828 focusWidget->setFocus(Qt::PopupFocusReason);
829 } else {
830 grabKeyboard((QGraphicsItem *)widget);
831 if (focusItem && popupWidgets.size() == 1) {
832 QFocusEvent event(QEvent::FocusOut, Qt::PopupFocusReason);
833 sendEvent(focusItem, &event);
834 }
835 }
836 grabMouse((QGraphicsItem *)widget);
837}
838
839/*!
840 \internal
841
842 Remove \a widget from the popup list. Important notes:
843
844 \a widget is guaranteed to be in the list of popups, but it might not be
845 the last entry; you can hide any item in the pop list before the others,
846 and this must cause all later mouse grabbers to lose the grab.
847*/
848void QGraphicsScenePrivate::removePopup(QGraphicsWidget *widget, bool itemIsDying)
849{
850 Q_ASSERT(widget);
851 int index = popupWidgets.indexOf(widget);
852 Q_ASSERT(index != -1);
853
854 for (int i = popupWidgets.size() - 1; i >= index; --i) {
855 QGraphicsWidget *widget = popupWidgets.takeLast();
856 ungrabMouse(widget, itemIsDying);
857 if (focusItem && popupWidgets.isEmpty()) {
858 QFocusEvent event(QEvent::FocusIn, Qt::PopupFocusReason);
859 sendEvent(focusItem, &event);
860 } else if (keyboardGrabberItems.contains(static_cast<QGraphicsItem *>(widget))) {
861 ungrabKeyboard(static_cast<QGraphicsItem *>(widget), itemIsDying);
862 }
863 if (!itemIsDying && widget->isVisible()) {
864 widget->hide();
865 widget->QGraphicsItem::d_ptr->explicitlyHidden = 0;
866 }
867 }
868}
869
870/*!
871 \internal
872*/
873void QGraphicsScenePrivate::grabMouse(QGraphicsItem *item, bool implicit)
874{
875 // Append to list of mouse grabber items, and send a mouse grab event.
876 if (mouseGrabberItems.contains(item)) {
877 if (mouseGrabberItems.last() == item) {
878 Q_ASSERT(!implicit);
879 if (!lastMouseGrabberItemHasImplicitMouseGrab) {
880 qWarning("QGraphicsItem::grabMouse: already a mouse grabber");
881 } else {
882 // Upgrade to an explicit mouse grab
883 lastMouseGrabberItemHasImplicitMouseGrab = false;
884 }
885 } else {
886 qWarning("QGraphicsItem::grabMouse: already blocked by mouse grabber: %p",
887 mouseGrabberItems.last());
888 }
889 return;
890 }
891
892 // Send ungrab event to the last grabber.
893 if (!mouseGrabberItems.isEmpty()) {
894 QGraphicsItem *last = mouseGrabberItems.last();
895 if (lastMouseGrabberItemHasImplicitMouseGrab) {
896 // Implicit mouse grab is immediately lost.
897 last->ungrabMouse();
898 } else {
899 // Just send ungrab event to current grabber.
900 QEvent ungrabEvent(QEvent::UngrabMouse);
901 sendEvent(last, &ungrabEvent);
902 }
903 }
904
905 mouseGrabberItems << item;
906 lastMouseGrabberItemHasImplicitMouseGrab = implicit;
907
908 // Send grab event to current grabber.
909 QEvent grabEvent(QEvent::GrabMouse);
910 sendEvent(item, &grabEvent);
911}
912
913/*!
914 \internal
915*/
916void QGraphicsScenePrivate::ungrabMouse(QGraphicsItem *item, bool itemIsDying)
917{
918 int index = mouseGrabberItems.indexOf(item);
919 if (index == -1) {
920 qWarning("QGraphicsItem::ungrabMouse: not a mouse grabber");
921 return;
922 }
923
924 if (item != mouseGrabberItems.last()) {
925 // Recursively ungrab the next mouse grabber until we reach this item
926 // to ensure state consistency.
927 ungrabMouse(mouseGrabberItems.at(index + 1), itemIsDying);
928 }
929 if (!popupWidgets.isEmpty() && item == popupWidgets.last()) {
930 // If the item is a popup, go via removePopup to ensure state
931 // consistency and that it gets hidden correctly - beware that
932 // removePopup() reenters this function to continue removing the grab.
933 removePopup((QGraphicsWidget *)item, itemIsDying);
934 return;
935 }
936
937 // Send notification about mouse ungrab.
938 if (!itemIsDying) {
939 QEvent event(QEvent::UngrabMouse);
940 sendEvent(item, &event);
941 }
942
943 // Remove the item from the list of grabbers. Whenever this happens, we
944 // reset the implicitGrab (there can be only ever be one implicit grabber
945 // in a scene, and it is always the latest grabber; if the implicit grab
946 // is lost, it is not automatically regained.
947 mouseGrabberItems.takeLast();
948 lastMouseGrabberItemHasImplicitMouseGrab = false;
949
950 // Send notification about mouse regrab. ### It's unfortunate that all the
951 // items get a GrabMouse event, but this is a rare case with a simple
952 // implementation and it does ensure a consistent state.
953 if (!itemIsDying && !mouseGrabberItems.isEmpty()) {
954 QGraphicsItem *last = mouseGrabberItems.last();
955 QEvent event(QEvent::GrabMouse);
956 sendEvent(last, &event);
957 }
958}
959
960/*!
961 \internal
962*/
963void QGraphicsScenePrivate::clearMouseGrabber()
964{
965 if (!mouseGrabberItems.isEmpty())
966 mouseGrabberItems.first()->ungrabMouse();
967 lastMouseGrabberItem = 0;
968}
969
970/*!
971 \internal
972*/
973void QGraphicsScenePrivate::grabKeyboard(QGraphicsItem *item)
974{
975 if (keyboardGrabberItems.contains(item)) {
976 if (keyboardGrabberItems.last() == item)
977 qWarning("QGraphicsItem::grabKeyboard: already a keyboard grabber");
978 else
979 qWarning("QGraphicsItem::grabKeyboard: already blocked by keyboard grabber: %p",
980 keyboardGrabberItems.last());
981 return;
982 }
983
984 // Send ungrab event to the last grabber.
985 if (!keyboardGrabberItems.isEmpty()) {
986 // Just send ungrab event to current grabber.
987 QEvent ungrabEvent(QEvent::UngrabKeyboard);
988 sendEvent(keyboardGrabberItems.last(), &ungrabEvent);
989 }
990
991 keyboardGrabberItems << item;
992
993 // Send grab event to current grabber.
994 QEvent grabEvent(QEvent::GrabKeyboard);
995 sendEvent(item, &grabEvent);
996}
997
998/*!
999 \internal
1000*/
1001void QGraphicsScenePrivate::ungrabKeyboard(QGraphicsItem *item, bool itemIsDying)
1002{
1003 int index = keyboardGrabberItems.lastIndexOf(item);
1004 if (index == -1) {
1005 qWarning("QGraphicsItem::ungrabKeyboard: not a keyboard grabber");
1006 return;
1007 }
1008 if (item != keyboardGrabberItems.last()) {
1009 // Recursively ungrab the topmost keyboard grabber until we reach this
1010 // item to ensure state consistency.
1011 ungrabKeyboard(keyboardGrabberItems.at(index + 1), itemIsDying);
1012 }
1013
1014 // Send notification about keyboard ungrab.
1015 if (!itemIsDying) {
1016 QEvent event(QEvent::UngrabKeyboard);
1017 sendEvent(item, &event);
1018 }
1019
1020 // Remove the item from the list of grabbers.
1021 keyboardGrabberItems.takeLast();
1022
1023 // Send notification about mouse regrab.
1024 if (!itemIsDying && !keyboardGrabberItems.isEmpty()) {
1025 QGraphicsItem *last = keyboardGrabberItems.last();
1026 QEvent event(QEvent::GrabKeyboard);
1027 sendEvent(last, &event);
1028 }
1029}
1030
1031/*!
1032 \internal
1033*/
1034void QGraphicsScenePrivate::clearKeyboardGrabber()
1035{
1036 if (!keyboardGrabberItems.isEmpty())
1037 ungrabKeyboard(keyboardGrabberItems.first());
1038}
1039
1040void QGraphicsScenePrivate::enableMouseTrackingOnViews()
1041{
1042 foreach (QGraphicsView *view, views)
1043 view->viewport()->setMouseTracking(true);
1044}
1045
1046/*!
1047 Returns all items for the screen position in \a event.
1048*/
1049QList<QGraphicsItem *> QGraphicsScenePrivate::itemsAtPosition(const QPoint &screenPos,
1050 const QPointF &scenePos,
1051 QWidget *widget) const
1052{
1053 Q_Q(const QGraphicsScene);
1054 QGraphicsView *view = widget ? qobject_cast<QGraphicsView *>(widget->parentWidget()) : 0;
1055 if (!view)
1056 return q->items(scenePos, Qt::IntersectsItemShape, Qt::DescendingOrder, QTransform());
1057
1058 const QRectF pointRect(QPointF(widget->mapFromGlobal(screenPos)), QSizeF(1, 1));
1059 if (!view->isTransformed())
1060 return q->items(pointRect, Qt::IntersectsItemShape, Qt::DescendingOrder);
1061
1062 const QTransform viewTransform = view->viewportTransform();
1063 if (viewTransform.type() <= QTransform::TxScale) {
1064 return q->items(viewTransform.inverted().mapRect(pointRect), Qt::IntersectsItemShape,
1065 Qt::DescendingOrder, viewTransform);
1066 }
1067 return q->items(viewTransform.inverted().map(pointRect), Qt::IntersectsItemShape,
1068 Qt::DescendingOrder, viewTransform);
1069}
1070
1071/*!
1072 \internal
1073*/
1074void QGraphicsScenePrivate::storeMouseButtonsForMouseGrabber(QGraphicsSceneMouseEvent *event)
1075{
1076 for (int i = 0x1; i <= 0x10; i <<= 1) {
1077 if (event->buttons() & i) {
1078 mouseGrabberButtonDownPos.insert(Qt::MouseButton(i),
1079 mouseGrabberItems.last()->d_ptr->genericMapFromScene(event->scenePos(),
1080 event->widget()));
1081 mouseGrabberButtonDownScenePos.insert(Qt::MouseButton(i), event->scenePos());
1082 mouseGrabberButtonDownScreenPos.insert(Qt::MouseButton(i), event->screenPos());
1083 }
1084 }
1085}
1086
1087/*!
1088 \internal
1089*/
1090void QGraphicsScenePrivate::installSceneEventFilter(QGraphicsItem *watched, QGraphicsItem *filter)
1091{
1092 sceneEventFilters.insert(watched, filter);
1093}
1094
1095/*!
1096 \internal
1097*/
1098void QGraphicsScenePrivate::removeSceneEventFilter(QGraphicsItem *watched, QGraphicsItem *filter)
1099{
1100 if (!sceneEventFilters.contains(watched))
1101 return;
1102
1103 QMultiMap<QGraphicsItem *, QGraphicsItem *>::Iterator it = sceneEventFilters.lowerBound(watched);
1104 QMultiMap<QGraphicsItem *, QGraphicsItem *>::Iterator end = sceneEventFilters.upperBound(watched);
1105 do {
1106 if (it.value() == filter)
1107 it = sceneEventFilters.erase(it);
1108 else
1109 ++it;
1110 } while (it != end);
1111}
1112
1113/*!
1114 \internal
1115*/
1116bool QGraphicsScenePrivate::filterDescendantEvent(QGraphicsItem *item, QEvent *event)
1117{
1118 if (item && (item->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorFiltersChildEvents)) {
1119 QGraphicsItem *parent = item->parentItem();
1120 while (parent) {
1121 if (parent->d_ptr->filtersDescendantEvents && parent->sceneEventFilter(item, event))
1122 return true;
1123 if (!(parent->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorFiltersChildEvents))
1124 return false;
1125 parent = parent->parentItem();
1126 }
1127 }
1128 return false;
1129}
1130
1131/*!
1132 \internal
1133*/
1134bool QGraphicsScenePrivate::filterEvent(QGraphicsItem *item, QEvent *event)
1135{
1136 if (item && !sceneEventFilters.contains(item))
1137 return false;
1138
1139 QMultiMap<QGraphicsItem *, QGraphicsItem *>::Iterator it = sceneEventFilters.lowerBound(item);
1140 QMultiMap<QGraphicsItem *, QGraphicsItem *>::Iterator end = sceneEventFilters.upperBound(item);
1141 while (it != end) {
1142 // ### The filterer and filteree might both be deleted.
1143 if (it.value()->sceneEventFilter(it.key(), event))
1144 return true;
1145 ++it;
1146 }
1147 return false;
1148}
1149
1150/*!
1151 \internal
1152
1153 This is the final dispatch point for any events from the scene to the
1154 item. It filters the event first - if the filter returns true, the event
1155 is considered to have been eaten by the filter, and is therefore stopped
1156 (the default filter returns false). Then/otherwise, if the item is
1157 enabled, the event is sent; otherwise it is stopped.
1158*/
1159bool QGraphicsScenePrivate::sendEvent(QGraphicsItem *item, QEvent *event)
1160{
1161 if (QGraphicsObject *object = item->toGraphicsObject()) {
1162 QGestureManager *gestureManager = QApplicationPrivate::instance()->gestureManager;
1163 if (gestureManager) {
1164 if (gestureManager->filterEvent(object, event))
1165 return true;
1166 }
1167 }
1168
1169 if (filterEvent(item, event))
1170 return false;
1171 if (filterDescendantEvent(item, event))
1172 return false;
1173 if (!item || !item->isEnabled())
1174 return false;
1175 if (QGraphicsObject *o = item->toGraphicsObject()) {
1176 bool spont = event->spontaneous();
1177 if (spont ? qt_sendSpontaneousEvent(o, event) : QApplication::sendEvent(o, event))
1178 return true;
1179 event->spont = spont;
1180 }
1181 return item->sceneEvent(event);
1182}
1183
1184/*!
1185 \internal
1186*/
1187void QGraphicsScenePrivate::cloneDragDropEvent(QGraphicsSceneDragDropEvent *dest,
1188 QGraphicsSceneDragDropEvent *source)
1189{
1190 dest->setWidget(source->widget());
1191 dest->setPos(source->pos());
1192 dest->setScenePos(source->scenePos());
1193 dest->setScreenPos(source->screenPos());
1194 dest->setButtons(source->buttons());
1195 dest->setModifiers(source->modifiers());
1196 dest->setPossibleActions(source->possibleActions());
1197 dest->setProposedAction(source->proposedAction());
1198 dest->setDropAction(source->dropAction());
1199 dest->setSource(source->source());
1200 dest->setMimeData(source->mimeData());
1201}
1202
1203/*!
1204 \internal
1205*/
1206void QGraphicsScenePrivate::sendDragDropEvent(QGraphicsItem *item,
1207 QGraphicsSceneDragDropEvent *dragDropEvent)
1208{
1209 dragDropEvent->setPos(item->d_ptr->genericMapFromScene(dragDropEvent->scenePos(), dragDropEvent->widget()));
1210 sendEvent(item, dragDropEvent);
1211}
1212
1213/*!
1214 \internal
1215*/
1216void QGraphicsScenePrivate::sendHoverEvent(QEvent::Type type, QGraphicsItem *item,
1217 QGraphicsSceneHoverEvent *hoverEvent)
1218{
1219 QGraphicsSceneHoverEvent event(type);
1220 event.setWidget(hoverEvent->widget());
1221 event.setPos(item->d_ptr->genericMapFromScene(hoverEvent->scenePos(), hoverEvent->widget()));
1222 event.setScenePos(hoverEvent->scenePos());
1223 event.setScreenPos(hoverEvent->screenPos());
1224 event.setLastPos(item->d_ptr->genericMapFromScene(hoverEvent->lastScenePos(), hoverEvent->widget()));
1225 event.setLastScenePos(hoverEvent->lastScenePos());
1226 event.setLastScreenPos(hoverEvent->lastScreenPos());
1227 event.setModifiers(hoverEvent->modifiers());
1228 sendEvent(item, &event);
1229}
1230
1231/*!
1232 \internal
1233*/
1234void QGraphicsScenePrivate::sendMouseEvent(QGraphicsSceneMouseEvent *mouseEvent)
1235{
1236 if (mouseEvent->button() == 0 && mouseEvent->buttons() == 0 && lastMouseGrabberItemHasImplicitMouseGrab) {
1237 // ### This is a temporary fix for until we get proper mouse
1238 // grab events.
1239 clearMouseGrabber();
1240 return;
1241 }
1242
1243 QGraphicsItem *item = mouseGrabberItems.last();
1244 if (item->isBlockedByModalPanel())
1245 return;
1246
1247 for (int i = 0x1; i <= 0x10; i <<= 1) {
1248 Qt::MouseButton button = Qt::MouseButton(i);
1249 mouseEvent->setButtonDownPos(button, mouseGrabberButtonDownPos.value(button, item->d_ptr->genericMapFromScene(mouseEvent->scenePos(), mouseEvent->widget())));
1250 mouseEvent->setButtonDownScenePos(button, mouseGrabberButtonDownScenePos.value(button, mouseEvent->scenePos()));
1251 mouseEvent->setButtonDownScreenPos(button, mouseGrabberButtonDownScreenPos.value(button, mouseEvent->screenPos()));
1252 }
1253 mouseEvent->setPos(item->d_ptr->genericMapFromScene(mouseEvent->scenePos(), mouseEvent->widget()));
1254 mouseEvent->setLastPos(item->d_ptr->genericMapFromScene(mouseEvent->lastScenePos(), mouseEvent->widget()));
1255 sendEvent(item, mouseEvent);
1256}
1257
1258/*!
1259 \internal
1260*/
1261void QGraphicsScenePrivate::mousePressEventHandler(QGraphicsSceneMouseEvent *mouseEvent)
1262{
1263 Q_Q(QGraphicsScene);
1264
1265 // Ignore by default, unless we find a mouse grabber that accepts it.
1266 mouseEvent->ignore();
1267
1268 // Deliver to any existing mouse grabber.
1269 if (!mouseGrabberItems.isEmpty()) {
1270 if (mouseGrabberItems.last()->isBlockedByModalPanel())
1271 return;
1272 // The event is ignored by default, but we disregard the event's
1273 // accepted state after delivery; the mouse is grabbed, after all.
1274 sendMouseEvent(mouseEvent);
1275 return;
1276 }
1277
1278 // Start by determining the number of items at the current position.
1279 // Reuse value from earlier calculations if possible.
1280 if (cachedItemsUnderMouse.isEmpty()) {
1281 cachedItemsUnderMouse = itemsAtPosition(mouseEvent->screenPos(),
1282 mouseEvent->scenePos(),
1283 mouseEvent->widget());
1284 }
1285
1286 // Update window activation.
1287 QGraphicsItem *topItem = cachedItemsUnderMouse.value(0);
1288 QGraphicsWidget *newActiveWindow = topItem ? topItem->window() : 0;
1289 if (newActiveWindow && newActiveWindow->isBlockedByModalPanel(&topItem)) {
1290 // pass activation to the blocking modal window
1291 newActiveWindow = topItem ? topItem->window() : 0;
1292 }
1293
1294 if (newActiveWindow != q->activeWindow())
1295 q->setActiveWindow(newActiveWindow);
1296
1297 // Set focus on the topmost enabled item that can take focus.
1298 bool setFocus = false;
1299 foreach (QGraphicsItem *item, cachedItemsUnderMouse) {
1300 if (item->isBlockedByModalPanel()) {
1301 // Make sure we don't clear focus.
1302 setFocus = true;
1303 break;
1304 }
1305 if (item->isEnabled() && ((item->flags() & QGraphicsItem::ItemIsFocusable) && item->d_ptr->mouseSetsFocus)) {
1306 if (!item->isWidget() || ((QGraphicsWidget *)item)->focusPolicy() & Qt::ClickFocus) {
1307 setFocus = true;
1308 if (item != q->focusItem())
1309 q->setFocusItem(item, Qt::MouseFocusReason);
1310 break;
1311 }
1312 }
1313 if (item->isPanel())
1314 break;
1315 }
1316
1317 // Check for scene modality.
1318 bool sceneModality = false;
1319 for (int i = 0; i < modalPanels.size(); ++i) {
1320 if (modalPanels.at(i)->panelModality() == QGraphicsItem::SceneModal) {
1321 sceneModality = true;
1322 break;
1323 }
1324 }
1325
1326 // If nobody could take focus, clear it.
1327 if (!stickyFocus && !setFocus && !sceneModality)
1328 q->setFocusItem(0, Qt::MouseFocusReason);
1329
1330 // Any item will do.
1331 if (sceneModality && cachedItemsUnderMouse.isEmpty())
1332 cachedItemsUnderMouse << modalPanels.first();
1333
1334 // Find a mouse grabber by sending mouse press events to all mouse grabber
1335 // candidates one at a time, until the event is accepted. It's accepted by
1336 // default, so the receiver has to explicitly ignore it for it to pass
1337 // through.
1338 foreach (QGraphicsItem *item, cachedItemsUnderMouse) {
1339 if (!(item->acceptedMouseButtons() & mouseEvent->button())) {
1340 // Skip items that don't accept the event's mouse button.
1341 continue;
1342 }
1343
1344 // Check if this item is blocked by a modal panel and deliver the mouse event to the
1345 // blocking panel instead of this item if blocked.
1346 (void) item->isBlockedByModalPanel(&item);
1347
1348 grabMouse(item, /* implicit = */ true);
1349 mouseEvent->accept();
1350
1351 // check if the item we are sending to are disabled (before we send the event)
1352 bool disabled = !item->isEnabled();
1353 bool isPanel = item->isPanel();
1354 if (mouseEvent->type() == QEvent::GraphicsSceneMouseDoubleClick
1355 && item != lastMouseGrabberItem && lastMouseGrabberItem) {
1356 // If this item is different from the item that received the last
1357 // mouse event, and mouseEvent is a doubleclick event, then the
1358 // event is converted to a press. Known limitation:
1359 // Triple-clicking will not generate a doubleclick, though.
1360 QGraphicsSceneMouseEvent mousePress(QEvent::GraphicsSceneMousePress);
1361 mousePress.spont = mouseEvent->spont;
1362 mousePress.accept();
1363 mousePress.setButton(mouseEvent->button());
1364 mousePress.setButtons(mouseEvent->buttons());
1365 mousePress.setScreenPos(mouseEvent->screenPos());
1366 mousePress.setScenePos(mouseEvent->scenePos());
1367 mousePress.setModifiers(mouseEvent->modifiers());
1368 mousePress.setWidget(mouseEvent->widget());
1369 mousePress.setButtonDownPos(mouseEvent->button(),
1370 mouseEvent->buttonDownPos(mouseEvent->button()));
1371 mousePress.setButtonDownScenePos(mouseEvent->button(),
1372 mouseEvent->buttonDownScenePos(mouseEvent->button()));
1373 mousePress.setButtonDownScreenPos(mouseEvent->button(),
1374 mouseEvent->buttonDownScreenPos(mouseEvent->button()));
1375 sendMouseEvent(&mousePress);
1376 mouseEvent->setAccepted(mousePress.isAccepted());
1377 } else {
1378 sendMouseEvent(mouseEvent);
1379 }
1380
1381 bool dontSendUngrabEvents = mouseGrabberItems.isEmpty() || mouseGrabberItems.last() != item;
1382 if (disabled) {
1383 ungrabMouse(item, /* itemIsDying = */ dontSendUngrabEvents);
1384 break;
1385 }
1386 if (mouseEvent->isAccepted()) {
1387 if (!mouseGrabberItems.isEmpty())
1388 storeMouseButtonsForMouseGrabber(mouseEvent);
1389 lastMouseGrabberItem = item;
1390 return;
1391 }
1392 ungrabMouse(item, /* itemIsDying = */ dontSendUngrabEvents);
1393
1394 // Don't propagate through panels.
1395 if (isPanel)
1396 break;
1397 }
1398
1399 // Is the event still ignored? Then the mouse press goes to the scene.
1400 // Reset the mouse grabber, clear the selection, clear focus, and leave
1401 // the event ignored so that it can propagate through the originating
1402 // view.
1403 if (!mouseEvent->isAccepted()) {
1404 clearMouseGrabber();
1405
1406 QGraphicsView *view = mouseEvent->widget() ? qobject_cast<QGraphicsView *>(mouseEvent->widget()->parentWidget()) : 0;
1407 bool dontClearSelection = view && view->dragMode() == QGraphicsView::ScrollHandDrag;
1408 if (!dontClearSelection) {
1409 // Clear the selection if the originating view isn't in scroll
1410 // hand drag mode. The view will clear the selection if no drag
1411 // happened.
1412 q->clearSelection();
1413 }
1414 }
1415}
1416
1417/*!
1418 \internal
1419
1420 Ensures that the list of toplevels is sorted by insertion order, and that
1421 the siblingIndexes are packed (no gaps), and start at 0.
1422
1423 ### This function is almost identical to
1424 QGraphicsItemPrivate::ensureSequentialSiblingIndex().
1425*/
1426void QGraphicsScenePrivate::ensureSequentialTopLevelSiblingIndexes()
1427{
1428 if (!topLevelSequentialOrdering) {
1429 qSort(topLevelItems.begin(), topLevelItems.end(), QGraphicsItemPrivate::insertionOrder);
1430 topLevelSequentialOrdering = true;
1431 needSortTopLevelItems = 1;
1432 }
1433 if (holesInTopLevelSiblingIndex) {
1434 holesInTopLevelSiblingIndex = 0;
1435 for (int i = 0; i < topLevelItems.size(); ++i)
1436 topLevelItems[i]->d_ptr->siblingIndex = i;
1437 }
1438}
1439
1440/*!
1441 \internal
1442
1443 Set the font and propagate the changes if the font is different from the
1444 current font.
1445*/
1446void QGraphicsScenePrivate::setFont_helper(const QFont &font)
1447{
1448 if (this->font == font && this->font.resolve() == font.resolve())
1449 return;
1450 updateFont(font);
1451}
1452
1453/*!
1454 \internal
1455
1456 Resolve the scene's font against the application font, and propagate the
1457 changes too all items in the scene.
1458*/
1459void QGraphicsScenePrivate::resolveFont()
1460{
1461 QFont naturalFont = QApplication::font();
1462 naturalFont.resolve(0);
1463 QFont resolvedFont = font.resolve(naturalFont);
1464 updateFont(resolvedFont);
1465}
1466
1467/*!
1468 \internal
1469
1470 Update the font, and whether or not it has changed, reresolve all fonts in
1471 the scene.
1472*/
1473void QGraphicsScenePrivate::updateFont(const QFont &font)
1474{
1475 Q_Q(QGraphicsScene);
1476
1477 // Update local font setting.
1478 this->font = font;
1479
1480 // Resolve the fonts of all top-level widget items, or widget items
1481 // whose parent is not a widget.
1482 foreach (QGraphicsItem *item, q->items()) {
1483 if (!item->parentItem()) {
1484 // Resolvefont for an item is a noop operation, but
1485 // every item can be a widget, or can have a widget
1486 // childre.
1487 item->d_ptr->resolveFont(font.resolve());
1488 }
1489 }
1490
1491 // Send the scene a FontChange event.
1492 QEvent event(QEvent::FontChange);
1493 QApplication::sendEvent(q, &event);
1494}
1495
1496/*!
1497 \internal
1498
1499 Set the palette and propagate the changes if the palette is different from
1500 the current palette.
1501*/
1502void QGraphicsScenePrivate::setPalette_helper(const QPalette &palette)
1503{
1504 if (this->palette == palette && this->palette.resolve() == palette.resolve())
1505 return;
1506 updatePalette(palette);
1507}
1508
1509/*!
1510 \internal
1511
1512 Resolve the scene's palette against the application palette, and propagate
1513 the changes too all items in the scene.
1514*/
1515void QGraphicsScenePrivate::resolvePalette()
1516{
1517 QPalette naturalPalette = QApplication::palette();
1518 naturalPalette.resolve(0);
1519 QPalette resolvedPalette = palette.resolve(naturalPalette);
1520 updatePalette(resolvedPalette);
1521}
1522
1523/*!
1524 \internal
1525
1526 Update the palette, and whether or not it has changed, reresolve all
1527 palettes in the scene.
1528*/
1529void QGraphicsScenePrivate::updatePalette(const QPalette &palette)
1530{
1531 Q_Q(QGraphicsScene);
1532
1533 // Update local palette setting.
1534 this->palette = palette;
1535
1536 // Resolve the palettes of all top-level widget items, or widget items
1537 // whose parent is not a widget.
1538 foreach (QGraphicsItem *item, q->items()) {
1539 if (!item->parentItem()) {
1540 // Resolvefont for an item is a noop operation, but
1541 // every item can be a widget, or can have a widget
1542 // childre.
1543 item->d_ptr->resolvePalette(palette.resolve());
1544 }
1545 }
1546
1547 // Send the scene a PaletteChange event.
1548 QEvent event(QEvent::PaletteChange);
1549 QApplication::sendEvent(q, &event);
1550}
1551
1552/*!
1553 Constructs a QGraphicsScene object. The \a parent parameter is
1554 passed to QObject's constructor.
1555*/
1556QGraphicsScene::QGraphicsScene(QObject *parent)
1557 : QObject(*new QGraphicsScenePrivate, parent)
1558{
1559 d_func()->init();
1560}
1561
1562/*!
1563 Constructs a QGraphicsScene object, using \a sceneRect for its
1564 scene rectangle. The \a parent parameter is passed to QObject's
1565 constructor.
1566
1567 \sa sceneRect
1568*/
1569QGraphicsScene::QGraphicsScene(const QRectF &sceneRect, QObject *parent)
1570 : QObject(*new QGraphicsScenePrivate, parent)
1571{
1572 d_func()->init();
1573 setSceneRect(sceneRect);
1574}
1575
1576/*!
1577 Constructs a QGraphicsScene object, using the rectangle specified
1578 by (\a x, \a y), and the given \a width and \a height for its
1579 scene rectangle. The \a parent parameter is passed to QObject's
1580 constructor.
1581
1582 \sa sceneRect
1583*/
1584QGraphicsScene::QGraphicsScene(qreal x, qreal y, qreal width, qreal height, QObject *parent)
1585 : QObject(*new QGraphicsScenePrivate, parent)
1586{
1587 d_func()->init();
1588 setSceneRect(x, y, width, height);
1589}
1590
1591/*!
1592 Removes and deletes all items from the scene object
1593 before destroying the scene object. The scene object
1594 is removed from the application's global scene list,
1595 and it is removed from all associated views.
1596*/
1597QGraphicsScene::~QGraphicsScene()
1598{
1599 Q_D(QGraphicsScene);
1600
1601 // Remove this scene from qApp's global scene list.
1602 qApp->d_func()->scene_list.removeAll(this);
1603
1604 clear();
1605
1606 // Remove this scene from all associated views.
1607 for (int j = 0; j < d->views.size(); ++j)
1608 d->views.at(j)->setScene(0);
1609}
1610
1611/*!
1612 \property QGraphicsScene::sceneRect
1613 \brief the scene rectangle; the bounding rectangle of the scene
1614
1615 The scene rectangle defines the extent of the scene. It is
1616 primarily used by QGraphicsView to determine the view's default
1617 scrollable area, and by QGraphicsScene to manage item indexing.
1618
1619 If unset, or if set to a null QRectF, sceneRect() will return the largest
1620 bounding rect of all items on the scene since the scene was created (i.e.,
1621 a rectangle that grows when items are added to or moved in the scene, but
1622 never shrinks).
1623
1624 \sa width(), height(), QGraphicsView::sceneRect
1625*/
1626QRectF QGraphicsScene::sceneRect() const
1627{
1628 Q_D(const QGraphicsScene);
1629 if (d->hasSceneRect)
1630 return d->sceneRect;
1631
1632 if (d->dirtyGrowingItemsBoundingRect) {
1633 // Lazily update the growing items bounding rect
1634 QGraphicsScenePrivate *thatd = const_cast<QGraphicsScenePrivate *>(d);
1635 QRectF oldGrowingBoundingRect = thatd->growingItemsBoundingRect;
1636 thatd->growingItemsBoundingRect |= itemsBoundingRect();
1637 thatd->dirtyGrowingItemsBoundingRect = false;
1638 if (oldGrowingBoundingRect != thatd->growingItemsBoundingRect)
1639 emit const_cast<QGraphicsScene *>(this)->sceneRectChanged(thatd->growingItemsBoundingRect);
1640 }
1641 return d->growingItemsBoundingRect;
1642}
1643void QGraphicsScene::setSceneRect(const QRectF &rect)
1644{
1645 Q_D(QGraphicsScene);
1646 if (rect != d->sceneRect) {
1647 d->hasSceneRect = !rect.isNull();
1648 d->sceneRect = rect;
1649 emit sceneRectChanged(d->hasSceneRect ? rect : d->growingItemsBoundingRect);
1650 }
1651}
1652
1653/*!
1654 \fn qreal QGraphicsScene::width() const
1655
1656 This convenience function is equivalent to calling sceneRect().width().
1657
1658 \sa height()
1659*/
1660
1661/*!
1662 \fn qreal QGraphicsScene::height() const
1663
1664 This convenience function is equivalent to calling \c sceneRect().height().
1665
1666 \sa width()
1667*/
1668
1669/*!
1670 Renders the \a source rect from scene into \a target, using \a painter. This
1671 function is useful for capturing the contents of the scene onto a paint
1672 device, such as a QImage (e.g., to take a screenshot), or for printing
1673 with QPrinter. For example:
1674
1675 \snippet doc/src/snippets/code/src_gui_graphicsview_qgraphicsscene.cpp 1
1676
1677 If \a source is a null rect, this function will use sceneRect() to
1678 determine what to render. If \a target is a null rect, the dimensions of \a
1679 painter's paint device will be used.
1680
1681 The source rect contents will be transformed according to \a
1682 aspectRatioMode to fit into the target rect. By default, the aspect ratio
1683 is kept, and \a source is scaled to fit in \a target.
1684
1685 \sa QGraphicsView::render()
1686*/
1687void QGraphicsScene::render(QPainter *painter, const QRectF &target, const QRectF &source,
1688 Qt::AspectRatioMode aspectRatioMode)
1689{
1690 // ### Switch to using the recursive rendering algorithm instead.
1691
1692 // Default source rect = scene rect
1693 QRectF sourceRect = source;
1694 if (sourceRect.isNull())
1695 sourceRect = sceneRect();
1696
1697 // Default target rect = device rect
1698 QRectF targetRect = target;
1699 if (targetRect.isNull()) {
1700 if (painter->device()->devType() == QInternal::Picture)
1701 targetRect = sourceRect;
1702 else
1703 targetRect.setRect(0, 0, painter->device()->width(), painter->device()->height());
1704 }
1705
1706 // Find the ideal x / y scaling ratio to fit \a source into \a target.
1707 qreal xratio = targetRect.width() / sourceRect.width();
1708 qreal yratio = targetRect.height() / sourceRect.height();
1709
1710 // Scale according to the aspect ratio mode.
1711 switch (aspectRatioMode) {
1712 case Qt::KeepAspectRatio:
1713 xratio = yratio = qMin(xratio, yratio);
1714 break;
1715 case Qt::KeepAspectRatioByExpanding:
1716 xratio = yratio = qMax(xratio, yratio);
1717 break;
1718 case Qt::IgnoreAspectRatio:
1719 break;
1720 }
1721
1722 // Find all items to draw, and reverse the list (we want to draw
1723 // in reverse order).
1724 QList<QGraphicsItem *> itemList = items(sourceRect, Qt::IntersectsItemBoundingRect);
1725 QGraphicsItem **itemArray = new QGraphicsItem *[itemList.size()];
1726 int numItems = itemList.size();
1727 for (int i = 0; i < numItems; ++i)
1728 itemArray[numItems - i - 1] = itemList.at(i);
1729 itemList.clear();
1730
1731 painter->save();
1732
1733 // Transform the painter.
1734 painter->setClipRect(targetRect);
1735 QTransform painterTransform;
1736 painterTransform *= QTransform()
1737 .translate(targetRect.left(), targetRect.top())
1738 .scale(xratio, yratio)
1739 .translate(-sourceRect.left(), -sourceRect.top());
1740 painter->setWorldTransform(painterTransform, true);
1741
1742 // Two unit vectors.
1743 QLineF v1(0, 0, 1, 0);
1744 QLineF v2(0, 0, 0, 1);
1745
1746 // Generate the style options
1747 QStyleOptionGraphicsItem *styleOptionArray = new QStyleOptionGraphicsItem[numItems];
1748 for (int i = 0; i < numItems; ++i)
1749 itemArray[i]->d_ptr->initStyleOption(&styleOptionArray[i], painterTransform, targetRect.toRect());
1750
1751 // Render the scene.
1752 drawBackground(painter, sourceRect);
1753 drawItems(painter, numItems, itemArray, styleOptionArray);
1754 drawForeground(painter, sourceRect);
1755
1756 delete [] itemArray;
1757 delete [] styleOptionArray;
1758
1759 painter->restore();
1760}
1761
1762/*!
1763 \property QGraphicsScene::itemIndexMethod
1764 \brief the item indexing method.
1765
1766 QGraphicsScene applies an indexing algorithm to the scene, to speed up
1767 item discovery functions like items() and itemAt(). Indexing is most
1768 efficient for static scenes (i.e., where items don't move around). For
1769 dynamic scenes, or scenes with many animated items, the index bookkeeping
1770 can outweight the fast lookup speeds.
1771
1772 For the common case, the default index method BspTreeIndex works fine. If
1773 your scene uses many animations and you are experiencing slowness, you can
1774 disable indexing by calling \c setItemIndexMethod(NoIndex).
1775
1776 \sa bspTreeDepth
1777*/
1778QGraphicsScene::ItemIndexMethod QGraphicsScene::itemIndexMethod() const
1779{
1780 Q_D(const QGraphicsScene);
1781 return d->indexMethod;
1782}
1783void QGraphicsScene::setItemIndexMethod(ItemIndexMethod method)
1784{
1785 Q_D(QGraphicsScene);
1786 if (d->indexMethod == method)
1787 return;
1788
1789 d->indexMethod = method;
1790
1791 QList<QGraphicsItem *> oldItems = d->index->items(Qt::DescendingOrder);
1792 delete d->index;
1793 if (method == BspTreeIndex)
1794 d->index = new QGraphicsSceneBspTreeIndex(this);
1795 else
1796 d->index = new QGraphicsSceneLinearIndex(this);
1797 for (int i = oldItems.size() - 1; i >= 0; --i)
1798 d->index->addItem(oldItems.at(i));
1799}
1800
1801/*!
1802 \property QGraphicsScene::bspTreeDepth
1803 \brief the depth of QGraphicsScene's BSP index tree
1804 \since 4.3
1805
1806 This property has no effect when NoIndex is used.
1807
1808 This value determines the depth of QGraphicsScene's BSP tree. The depth
1809 directly affects QGraphicsScene's performance and memory usage; the latter
1810 growing exponentially with the depth of the tree. With an optimal tree
1811 depth, QGraphicsScene can instantly determine the locality of items, even
1812 for scenes with thousands or millions of items. This also greatly improves
1813 rendering performance.
1814
1815 By default, the value is 0, in which case Qt will guess a reasonable
1816 default depth based on the size, location and number of items in the
1817 scene. If these parameters change frequently, however, you may experience
1818 slowdowns as QGraphicsScene retunes the depth internally. You can avoid
1819 potential slowdowns by fixating the tree depth through setting this
1820 property.
1821
1822 The depth of the tree and the size of the scene rectangle decide the
1823 granularity of the scene's partitioning. The size of each scene segment is
1824 determined by the following algorithm:
1825
1826 \snippet doc/src/snippets/code/src_gui_graphicsview_qgraphicsscene.cpp 2
1827
1828 The BSP tree has an optimal size when each segment contains between 0 and
1829 10 items.
1830
1831 \sa itemIndexMethod
1832*/
1833int QGraphicsScene::bspTreeDepth() const
1834{
1835 Q_D(const QGraphicsScene);
1836 QGraphicsSceneBspTreeIndex *bspTree = qobject_cast<QGraphicsSceneBspTreeIndex *>(d->index);
1837 return bspTree ? bspTree->bspTreeDepth() : 0;
1838}
1839void QGraphicsScene::setBspTreeDepth(int depth)
1840{
1841 Q_D(QGraphicsScene);
1842 if (depth < 0) {
1843 qWarning("QGraphicsScene::setBspTreeDepth: invalid depth %d ignored; must be >= 0", depth);
1844 return;
1845 }
1846
1847 QGraphicsSceneBspTreeIndex *bspTree = qobject_cast<QGraphicsSceneBspTreeIndex *>(d->index);
1848 if (!bspTree) {
1849 qWarning("QGraphicsScene::setBspTreeDepth: can not apply if indexing method is not BSP");
1850 return;
1851 }
1852 bspTree->setBspTreeDepth(depth);
1853}
1854
1855/*!
1856 \property QGraphicsScene::sortCacheEnabled
1857 \brief whether sort caching is enabled
1858 \since 4.5
1859 \obsolete
1860
1861 Since Qt 4.6, this property has no effect.
1862*/
1863bool QGraphicsScene::isSortCacheEnabled() const
1864{
1865 Q_D(const QGraphicsScene);
1866 return d->sortCacheEnabled;
1867}
1868void QGraphicsScene::setSortCacheEnabled(bool enabled)
1869{
1870 Q_D(QGraphicsScene);
1871 if (d->sortCacheEnabled == enabled)
1872 return;
1873 d->sortCacheEnabled = enabled;
1874}
1875
1876/*!
1877 Calculates and returns the bounding rect of all items on the scene. This
1878 function works by iterating over all items, and because if this, it can
1879 be slow for large scenes.
1880
1881 \sa sceneRect()
1882*/
1883QRectF QGraphicsScene::itemsBoundingRect() const
1884{
1885 // Does not take untransformable items into account.
1886 QRectF boundingRect;
1887 foreach (QGraphicsItem *item, items())
1888 boundingRect |= item->sceneBoundingRect();
1889 return boundingRect;
1890}
1891
1892/*!
1893 Returns a list of all items in the scene in descending stacking order.
1894
1895 \sa addItem(), removeItem(), {QGraphicsItem#Sorting}{Sorting}
1896*/
1897QList<QGraphicsItem *> QGraphicsScene::items() const
1898{
1899 Q_D(const QGraphicsScene);
1900 return d->index->items(Qt::DescendingOrder);
1901}
1902
1903/*!
1904 Returns an ordered list of all items on the scene. \a order decides the
1905 stacking order.
1906
1907 \sa addItem(), removeItem(), {QGraphicsItem#Sorting}{Sorting}
1908*/
1909QList<QGraphicsItem *> QGraphicsScene::items(Qt::SortOrder order) const
1910{
1911 Q_D(const QGraphicsScene);
1912 return d->index->items(order);
1913}
1914
1915/*!
1916 \obsolete
1917
1918 Returns all visible items at position \a pos in the scene. The items are
1919 listed in descending stacking order (i.e., the first item in the list is the
1920 top-most item, and the last item is the bottom-most item).
1921
1922 This function is deprecated and returns incorrect results if the scene
1923 contains items that ignore transformations. Use the overload that takes
1924 a QTransform instead.
1925
1926 \sa itemAt(), {QGraphicsItem#Sorting}{Sorting}
1927*/
1928QList<QGraphicsItem *> QGraphicsScene::items(const QPointF &pos) const
1929{
1930 Q_D(const QGraphicsScene);
1931 return d->index->items(pos, Qt::IntersectsItemShape, Qt::DescendingOrder);
1932}
1933
1934/*!
1935 \overload
1936 \obsolete
1937
1938 Returns all visible items that, depending on \a mode, are either inside or
1939 intersect with the specified \a rectangle.
1940
1941 The default value for \a mode is Qt::IntersectsItemShape; all items whose
1942 exact shape intersects with or is contained by \a rectangle are returned.
1943
1944 This function is deprecated and returns incorrect results if the scene
1945 contains items that ignore transformations. Use the overload that takes
1946 a QTransform instead.
1947
1948 \sa itemAt(), {QGraphicsItem#Sorting}{Sorting}
1949*/
1950QList<QGraphicsItem *> QGraphicsScene::items(const QRectF &rectangle, Qt::ItemSelectionMode mode) const
1951{
1952 Q_D(const QGraphicsScene);
1953 return d->index->items(rectangle, mode, Qt::DescendingOrder);
1954}
1955
1956/*!
1957 \fn QList<QGraphicsItem *> QGraphicsScene::items(qreal x, qreal y, qreal w, qreal h, Qt::ItemSelectionMode mode) const
1958 \obsolete
1959 \since 4.3
1960
1961 This convenience function is equivalent to calling items(QRectF(\a x, \a y, \a w, \a h), \a mode).
1962
1963 This function is deprecated and returns incorrect results if the scene
1964 contains items that ignore transformations. Use the overload that takes
1965 a QTransform instead.
1966*/
1967
1968/*!
1969 \fn QList<QGraphicsItem *> QGraphicsScene::items(qreal x, qreal y, qreal w, qreal h, Qt::ItemSelectionMode mode, Qt::SortOrder order, const QTransform &deviceTransform) const
1970 \overload
1971 \since 4.6
1972
1973 \brief Returns all visible items that, depending on \a mode, are
1974 either inside or intersect with the rectangle defined by \a x, \a y,
1975 \a w and \a h, in a list sorted using \a order.
1976
1977 \a deviceTransform is the transformation that applies to the view, and needs to
1978 be provided if the scene contains items that ignore transformations.
1979*/
1980
1981/*!
1982 \fn QList<QGraphicsItem *> QGraphicsScene::items(const QPolygonF &polygon, Qt::ItemSelectionMode mode) const
1983 \overload
1984 \obsolete
1985
1986 Returns all visible items that, depending on \a mode, are either inside or
1987 intersect with the polygon \a polygon.
1988
1989 The default value for \a mode is Qt::IntersectsItemShape; all items whose
1990 exact shape intersects with or is contained by \a polygon are returned.
1991
1992 This function is deprecated and returns incorrect results if the scene
1993 contains items that ignore transformations. Use the overload that takes
1994 a QTransform instead.
1995
1996 \sa itemAt(), {QGraphicsItem#Sorting}{Sorting}
1997*/
1998QList<QGraphicsItem *> QGraphicsScene::items(const QPolygonF &polygon, Qt::ItemSelectionMode mode) const
1999{
2000 Q_D(const QGraphicsScene);
2001 return d->index->items(polygon, mode, Qt::DescendingOrder);
2002}
2003
2004/*!
2005 \fn QList<QGraphicsItem *> QGraphicsScene::items(const QPainterPath &path, Qt::ItemSelectionMode mode) const
2006 \overload
2007 \obsolete
2008
2009 Returns all visible items that, depending on \a path, are either inside or
2010 intersect with the path \a path.
2011
2012 The default value for \a mode is Qt::IntersectsItemShape; all items whose
2013 exact shape intersects with or is contained by \a path are returned.
2014
2015 This function is deprecated and returns incorrect results if the scene
2016 contains items that ignore transformations. Use the overload that takes
2017 a QTransform instead.
2018
2019 \sa itemAt(), {QGraphicsItem#Sorting}{Sorting}
2020*/
2021QList<QGraphicsItem *> QGraphicsScene::items(const QPainterPath &path, Qt::ItemSelectionMode mode) const
2022{
2023 Q_D(const QGraphicsScene);
2024 return d->index->items(path, mode, Qt::DescendingOrder);
2025}
2026
2027/*!
2028 \fn QList<QGraphicsItem *> QGraphicsScene::items(const QPointF &pos, Qt::ItemSelectionMode mode, Qt::SortOrder order, const QTransform &deviceTransform) const
2029 \since 4.6
2030
2031 \brief Returns all visible items that, depending on \a mode, are at
2032 the specified \a pos in a list sorted using \a order.
2033
2034 The default value for \a mode is Qt::IntersectsItemShape; all items whose
2035 exact shape intersects with \a pos are returned.
2036
2037 \a deviceTransform is the transformation that applies to the view, and needs to
2038 be provided if the scene contains items that ignore transformations.
2039
2040 \sa itemAt(), {QGraphicsItem#Sorting}{Sorting}
2041*/
2042QList<QGraphicsItem *> QGraphicsScene::items(const QPointF &pos, Qt::ItemSelectionMode mode,
2043 Qt::SortOrder order, const QTransform &deviceTransform) const
2044{
2045 Q_D(const QGraphicsScene);
2046 return d->index->items(pos, mode, order, deviceTransform);
2047}
2048
2049/*!
2050 \fn QList<QGraphicsItem *> QGraphicsScene::items(const QRectF &rect, Qt::ItemSelectionMode mode, Qt::SortOrder order, const QTransform &deviceTransform) const
2051 \overload
2052 \since 4.6
2053
2054 \brief Returns all visible items that, depending on \a mode, are
2055 either inside or intersect with the specified \a rect and return a
2056 list sorted using \a order.
2057
2058 The default value for \a mode is Qt::IntersectsItemShape; all items whose
2059 exact shape intersects with or is contained by \a rect are returned.
2060
2061 \a deviceTransform is the transformation that applies to the view, and needs to
2062 be provided if the scene contains items that ignore transformations.
2063
2064 \sa itemAt(), {QGraphicsItem#Sorting}{Sorting}
2065*/
2066QList<QGraphicsItem *> QGraphicsScene::items(const QRectF &rect, Qt::ItemSelectionMode mode,
2067 Qt::SortOrder order, const QTransform &deviceTransform) const
2068{
2069 Q_D(const QGraphicsScene);
2070 return d->index->items(rect, mode, order, deviceTransform);
2071}
2072
2073/*!
2074 \fn QList<QGraphicsItem *> QGraphicsScene::items(const QPolygonF &polygon, Qt::ItemSelectionMode mode, Qt::SortOrder order, const QTransform &deviceTransform) const
2075 \overload
2076 \since 4.6
2077
2078 \brief Returns all visible items that, depending on \a mode, are
2079 either inside or intersect with the specified \a polygon and return
2080 a list sorted using \a order.
2081
2082 The default value for \a mode is Qt::IntersectsItemShape; all items whose
2083 exact shape intersects with or is contained by \a polygon are returned.
2084
2085 \a deviceTransform is the transformation that applies to the view, and needs to
2086 be provided if the scene contains items that ignore transformations.
2087
2088 \sa itemAt(), {QGraphicsItem#Sorting}{Sorting}
2089*/
2090QList<QGraphicsItem *> QGraphicsScene::items(const QPolygonF &polygon, Qt::ItemSelectionMode mode,
2091 Qt::SortOrder order, const QTransform &deviceTransform) const
2092{
2093 Q_D(const QGraphicsScene);
2094 return d->index->items(polygon, mode, order, deviceTransform);
2095}
2096
2097/*!
2098 \fn QList<QGraphicsItem *> QGraphicsScene::items(const QPainterPath &path, Qt::ItemSelectionMode mode, Qt::SortOrder order, const QTransform &deviceTransform) const
2099 \overload
2100 \since 4.6
2101
2102 \brief Returns all visible items that, depending on \a mode, are
2103 either inside or intersect with the specified \a path and return a
2104 list sorted using \a order.
2105
2106 The default value for \a mode is Qt::IntersectsItemShape; all items whose
2107 exact shape intersects with or is contained by \a path are returned.
2108
2109 \a deviceTransform is the transformation that applies to the view, and needs to
2110 be provided if the scene contains items that ignore transformations.
2111
2112 \sa itemAt(), {QGraphicsItem#Sorting}{Sorting}
2113*/
2114QList<QGraphicsItem *> QGraphicsScene::items(const QPainterPath &path, Qt::ItemSelectionMode mode,
2115 Qt::SortOrder order, const QTransform &deviceTransform) const
2116{
2117 Q_D(const QGraphicsScene);
2118 return d->index->items(path, mode, order, deviceTransform);
2119}
2120
2121/*!
2122 Returns a list of all items that collide with \a item. Collisions are
2123 determined by calling QGraphicsItem::collidesWithItem(); the collision
2124 detection is determined by \a mode. By default, all items whose shape
2125 intersects \a item or is contained inside \a item's shape are returned.
2126
2127 The items are returned in descending stacking order (i.e., the first item
2128 in the list is the uppermost item, and the last item is the lowermost
2129 item).
2130
2131 \sa items(), itemAt(), QGraphicsItem::collidesWithItem(), {QGraphicsItem#Sorting}{Sorting}
2132*/
2133QList<QGraphicsItem *> QGraphicsScene::collidingItems(const QGraphicsItem *item,
2134 Qt::ItemSelectionMode mode) const
2135{
2136 Q_D(const QGraphicsScene);
2137 if (!item) {
2138 qWarning("QGraphicsScene::collidingItems: cannot find collisions for null item");
2139 return QList<QGraphicsItem *>();
2140 }
2141
2142 // Does not support ItemIgnoresTransformations.
2143 QList<QGraphicsItem *> tmp;
2144 foreach (QGraphicsItem *itemInVicinity, d->index->estimateItems(item->sceneBoundingRect(), Qt::DescendingOrder)) {
2145 if (item != itemInVicinity && item->collidesWithItem(itemInVicinity, mode))
2146 tmp << itemInVicinity;
2147 }
2148 return tmp;
2149}
2150
2151/*!
2152 \overload
2153 \obsolete
2154
2155 Returns the topmost visible item at the specified \a position, or 0 if
2156 there are no items at this position.
2157
2158 This function is deprecated and returns incorrect results if the scene
2159 contains items that ignore transformations. Use the overload that takes
2160 a QTransform instead.
2161
2162 \sa items(), collidingItems(), {QGraphicsItem#Sorting}{Sorting}
2163*/
2164QGraphicsItem *QGraphicsScene::itemAt(const QPointF &position) const
2165{
2166 QList<QGraphicsItem *> itemsAtPoint = items(position);
2167 return itemsAtPoint.isEmpty() ? 0 : itemsAtPoint.first();
2168}
2169
2170/*!
2171 \since 4.6
2172
2173 Returns the topmost visible item at the specified \a position, or 0
2174 if there are no items at this position.
2175
2176 \a deviceTransform is the transformation that applies to the view, and needs to
2177 be provided if the scene contains items that ignore transformations.
2178
2179 \sa items(), collidingItems(), {QGraphicsItem#Sorting}{Sorting}
2180*/
2181QGraphicsItem *QGraphicsScene::itemAt(const QPointF &position, const QTransform &deviceTransform) const
2182{
2183 QList<QGraphicsItem *> itemsAtPoint = items(position, Qt::IntersectsItemShape,
2184 Qt::DescendingOrder, deviceTransform);
2185 return itemsAtPoint.isEmpty() ? 0 : itemsAtPoint.first();
2186}
2187
2188/*!
2189 \fn QGraphicsScene::itemAt(qreal x, qreal y, const QTransform &deviceTransform) const
2190 \overload
2191 \since 4.6
2192
2193 Returns the topmost item at the position specified by (\a x, \a
2194 y), or 0 if there are no items at this position.
2195
2196 \a deviceTransform is the transformation that applies to the view, and needs to
2197 be provided if the scene contains items that ignore transformations.
2198
2199 This convenience function is equivalent to calling \c
2200 {itemAt(QPointF(x, y), deviceTransform)}.
2201*/
2202
2203/*!
2204 \fn QGraphicsScene::itemAt(qreal x, qreal y) const
2205 \overload
2206 \obsolete
2207
2208 Returns the topmost item at the position specified by (\a x, \a
2209 y), or 0 if there are no items at this position.
2210
2211 This convenience function is equivalent to calling \c
2212 {itemAt(QPointF(x, y))}.
2213
2214 This function is deprecated and returns incorrect results if the scene
2215 contains items that ignore transformations. Use the overload that takes
2216 a QTransform instead.
2217*/
2218
2219/*!
2220 Returns a list of all currently selected items. The items are
2221 returned in no particular order.
2222
2223 \sa setSelectionArea()
2224*/
2225QList<QGraphicsItem *> QGraphicsScene::selectedItems() const
2226{
2227 Q_D(const QGraphicsScene);
2228
2229 // Optimization: Lazily removes items that are not selected.
2230 QGraphicsScene *that = const_cast<QGraphicsScene *>(this);
2231 QSet<QGraphicsItem *> actuallySelectedSet;
2232 foreach (QGraphicsItem *item, that->d_func()->selectedItems) {
2233 if (item->isSelected())
2234 actuallySelectedSet << item;
2235 }
2236
2237 that->d_func()->selectedItems = actuallySelectedSet;
2238
2239 return d->selectedItems.values();
2240}
2241
2242/*!
2243 Returns the selection area that was previously set with
2244 setSelectionArea(), or an empty QPainterPath if no selection area has been
2245 set.
2246
2247 \sa setSelectionArea()
2248*/
2249QPainterPath QGraphicsScene::selectionArea() const
2250{
2251 Q_D(const QGraphicsScene);
2252 return d->selectionArea;
2253}
2254
2255/*!
2256 \since 4.6
2257
2258 Sets the selection area to \a path. All items within this area are
2259 immediately selected, and all items outside are unselected. You can get
2260 the list of all selected items by calling selectedItems().
2261
2262 \a deviceTransform is the transformation that applies to the view, and needs to
2263 be provided if the scene contains items that ignore transformations.
2264
2265 For an item to be selected, it must be marked as \e selectable
2266 (QGraphicsItem::ItemIsSelectable).
2267
2268 \sa clearSelection(), selectionArea()
2269*/
2270void QGraphicsScene::setSelectionArea(const QPainterPath &path, const QTransform &deviceTransform)
2271{
2272 setSelectionArea(path, Qt::IntersectsItemShape, deviceTransform);
2273}
2274
2275/*!
2276 \obsolete
2277 \overload
2278
2279 Sets the selection area to \a path.
2280
2281 This function is deprecated and leads to incorrect results if the scene
2282 contains items that ignore transformations. Use the overload that takes
2283 a QTransform instead.
2284*/
2285void QGraphicsScene::setSelectionArea(const QPainterPath &path)
2286{
2287 setSelectionArea(path, Qt::IntersectsItemShape, QTransform());
2288}
2289
2290/*!
2291 \obsolete
2292 \overload
2293 \since 4.3
2294
2295 Sets the selection area to \a path using \a mode to determine if items are
2296 included in the selection area.
2297
2298 \sa clearSelection(), selectionArea()
2299*/
2300void QGraphicsScene::setSelectionArea(const QPainterPath &path, Qt::ItemSelectionMode mode)
2301{
2302 setSelectionArea(path, mode, QTransform());
2303}
2304
2305/*!
2306 \overload
2307 \since 4.6
2308
2309 Sets the selection area to \a path using \a mode to determine if items are
2310 included in the selection area.
2311
2312 \a deviceTransform is the transformation that applies to the view, and needs to
2313 be provided if the scene contains items that ignore transformations.
2314
2315 \sa clearSelection(), selectionArea()
2316*/
2317void QGraphicsScene::setSelectionArea(const QPainterPath &path, Qt::ItemSelectionMode mode,
2318 const QTransform &deviceTransform)
2319{
2320 Q_D(QGraphicsScene);
2321
2322 // Note: with boolean path operations, we can improve performance here
2323 // quite a lot by "growing" the old path instead of replacing it. That
2324 // allows us to only check the intersect area for changes, instead of
2325 // reevaluating the whole path over again.
2326 d->selectionArea = path;
2327
2328 QSet<QGraphicsItem *> unselectItems = d->selectedItems;
2329
2330 // Disable emitting selectionChanged() for individual items.
2331 ++d->selectionChanging;
2332 bool changed = false;
2333
2334 // Set all items in path to selected.
2335 foreach (QGraphicsItem *item, items(path, mode, Qt::DescendingOrder, deviceTransform)) {
2336 if (item->flags() & QGraphicsItem::ItemIsSelectable) {
2337 if (!item->isSelected())
2338 changed = true;
2339 unselectItems.remove(item);
2340 item->setSelected(true);
2341 }
2342 }
2343
2344 // Unselect all items outside path.
2345 foreach (QGraphicsItem *item, unselectItems) {
2346 item->setSelected(false);
2347 changed = true;
2348 }
2349
2350 // Reenable emitting selectionChanged() for individual items.
2351 --d->selectionChanging;
2352
2353 if (!d->selectionChanging && changed)
2354 emit selectionChanged();
2355}
2356
2357/*!
2358 Clears the current selection.
2359
2360 \sa setSelectionArea(), selectedItems()
2361*/
2362void QGraphicsScene::clearSelection()
2363{
2364 Q_D(QGraphicsScene);
2365
2366 // Disable emitting selectionChanged
2367 ++d->selectionChanging;
2368 bool changed = !d->selectedItems.isEmpty();
2369
2370 foreach (QGraphicsItem *item, d->selectedItems)
2371 item->setSelected(false);
2372 d->selectedItems.clear();
2373
2374 // Reenable emitting selectionChanged() for individual items.
2375 --d->selectionChanging;
2376
2377 if (!d->selectionChanging && changed)
2378 emit selectionChanged();
2379}
2380
2381/*!
2382 \since 4.4
2383
2384 Removes and deletes all items from the scene, but otherwise leaves the
2385 state of the scene unchanged.
2386
2387 \sa addItem()
2388*/
2389void QGraphicsScene::clear()
2390{
2391 Q_D(QGraphicsScene);
2392 // NB! We have to clear the index before deleting items; otherwise the
2393 // index might try to access dangling item pointers.
2394 d->index->clear();
2395 // NB! QGraphicsScenePrivate::unregisterTopLevelItem() removes items
2396 while (!d->topLevelItems.isEmpty())
2397 delete d->topLevelItems.first();
2398 Q_ASSERT(d->topLevelItems.isEmpty());
2399 d->lastItemCount = 0;
2400 d->allItemsIgnoreHoverEvents = true;
2401 d->allItemsUseDefaultCursor = true;
2402 d->allItemsIgnoreTouchEvents = true;
2403}
2404
2405/*!
2406 Groups all items in \a items into a new QGraphicsItemGroup, and returns a
2407 pointer to the group. The group is created with the common ancestor of \a
2408 items as its parent, and with position (0, 0). The items are all
2409 reparented to the group, and their positions and transformations are
2410 mapped to the group. If \a items is empty, this function will return an
2411 empty top-level QGraphicsItemGroup.
2412
2413 QGraphicsScene has ownership of the group item; you do not need to delete
2414 it. To dismantle (ungroup) a group, call destroyItemGroup().
2415
2416 \sa destroyItemGroup(), QGraphicsItemGroup::addToGroup()
2417*/
2418QGraphicsItemGroup *QGraphicsScene::createItemGroup(const QList<QGraphicsItem *> &items)
2419{
2420 // Build a list of the first item's ancestors
2421 QList<QGraphicsItem *> ancestors;
2422 int n = 0;
2423 if (!items.isEmpty()) {
2424 QGraphicsItem *parent = items.at(n++);
2425 while ((parent = parent->parentItem()))
2426 ancestors.append(parent);
2427 }
2428
2429 // Find the common ancestor for all items
2430 QGraphicsItem *commonAncestor = 0;
2431 if (!ancestors.isEmpty()) {
2432 while (n < items.size()) {
2433 int commonIndex = -1;
2434 QGraphicsItem *parent = items.at(n++);
2435 do {
2436 int index = ancestors.indexOf(parent, qMax(0, commonIndex));
2437 if (index != -1) {
2438 commonIndex = index;
2439 break;
2440 }
2441 } while ((parent = parent->parentItem()));
2442
2443 if (commonIndex == -1) {
2444 commonAncestor = 0;
2445 break;
2446 }
2447
2448 commonAncestor = ancestors.at(commonIndex);
2449 }
2450 }
2451
2452 // Create a new group at that level
2453 QGraphicsItemGroup *group = new QGraphicsItemGroup(commonAncestor);
2454 if (!commonAncestor)
2455 addItem(group);
2456 foreach (QGraphicsItem *item, items)
2457 group->addToGroup(item);
2458 return group;
2459}
2460
2461/*!
2462 Reparents all items in \a group to \a group's parent item, then removes \a
2463 group from the scene, and finally deletes it. The items' positions and
2464 transformations are mapped from the group to the group's parent.
2465
2466 \sa createItemGroup(), QGraphicsItemGroup::removeFromGroup()
2467*/
2468void QGraphicsScene::destroyItemGroup(QGraphicsItemGroup *group)
2469{
2470 foreach (QGraphicsItem *item, group->children())
2471 group->removeFromGroup(item);
2472 removeItem(group);
2473 delete group;
2474}
2475
2476/*!
2477 Adds or moves the \a item and all its childen to this scene.
2478 This scene takes ownership of the \a item.
2479
2480 If the item is visible (i.e., QGraphicsItem::isVisible() returns
2481 true), QGraphicsScene will emit changed() once control goes back
2482 to the event loop.
2483
2484 If the item is already in a different scene, it will first be
2485 removed from its old scene, and then added to this scene as a
2486 top-level.
2487
2488 QGraphicsScene will send ItemSceneChange notifications to \a item
2489 while it is added to the scene. If item does not currently belong
2490 to a scene, only one notification is sent. If it does belong to
2491 scene already (i.e., it is moved to this scene), QGraphicsScene
2492 will send an addition notification as the item is removed from its
2493 previous scene.
2494
2495 If the item is a panel, the scene is active, and there is no
2496 active panel in the scene, then the item will be activated.
2497
2498 \sa removeItem(), addEllipse(), addLine(), addPath(), addPixmap(),
2499 addRect(), addText(), addWidget(), {QGraphicsItem#Sorting}{Sorting}
2500*/
2501void QGraphicsScene::addItem(QGraphicsItem *item)
2502{
2503 Q_D(QGraphicsScene);
2504 if (!item) {
2505 qWarning("QGraphicsScene::addItem: cannot add null item");
2506 return;
2507 }
2508 if (item->d_ptr->scene == this) {
2509 qWarning("QGraphicsScene::addItem: item has already been added to this scene");
2510 return;
2511 }
2512 // Remove this item from its existing scene
2513 if (QGraphicsScene *oldScene = item->d_ptr->scene)
2514 oldScene->removeItem(item);
2515
2516 // Notify the item that its scene is changing, and allow the item to
2517 // react.
2518 const QVariant newSceneVariant(item->itemChange(QGraphicsItem::ItemSceneChange,
2519 qVariantFromValue<QGraphicsScene *>(this)));
2520 QGraphicsScene *targetScene = qVariantValue<QGraphicsScene *>(newSceneVariant);
2521 if (targetScene != this) {
2522 if (targetScene && item->d_ptr->scene != targetScene)
2523 targetScene->addItem(item);
2524 return;
2525 }
2526
2527 if (d->unpolishedItems.isEmpty())
2528 QMetaObject::invokeMethod(this, "_q_polishItems", Qt::QueuedConnection);
2529 d->unpolishedItems.append(item);
2530 item->d_ptr->pendingPolish = true;
2531
2532 // Detach this item from its parent if the parent's scene is different
2533 // from this scene.
2534 if (QGraphicsItem *itemParent = item->d_ptr->parent) {
2535 if (itemParent->d_ptr->scene != this)
2536 item->setParentItem(0);
2537 }
2538
2539 // Add the item to this scene
2540 item->d_func()->scene = targetScene;
2541
2542 // Add the item in the index
2543 d->index->addItem(item);
2544
2545 // Add to list of toplevels if this item is a toplevel.
2546 if (!item->d_ptr->parent)
2547 d->registerTopLevelItem(item);
2548
2549 // Add to list of items that require an update. We cannot assume that the
2550 // item is fully constructed, so calling item->update() can lead to a pure
2551 // virtual function call to boundingRect().
2552 d->markDirty(item);
2553 d->dirtyGrowingItemsBoundingRect = true;
2554
2555 // Disable selectionChanged() for individual items
2556 ++d->selectionChanging;
2557 int oldSelectedItemSize = d->selectedItems.size();
2558
2559 // Enable mouse tracking if the item accepts hover events or has a cursor set.
2560 if (d->allItemsIgnoreHoverEvents && d->itemAcceptsHoverEvents_helper(item)) {
2561 d->allItemsIgnoreHoverEvents = false;
2562 d->enableMouseTrackingOnViews();
2563 }
2564#ifndef QT_NO_CURSOR
2565 if (d->allItemsUseDefaultCursor && item->d_ptr->hasCursor) {
2566 d->allItemsUseDefaultCursor = false;
2567 if (d->allItemsIgnoreHoverEvents) // already enabled otherwise
2568 d->enableMouseTrackingOnViews();
2569 }
2570#endif //QT_NO_CURSOR
2571
2572 // Enable touch events if the item accepts touch events.
2573 if (d->allItemsIgnoreTouchEvents && item->d_ptr->acceptTouchEvents) {
2574 d->allItemsIgnoreTouchEvents = false;
2575 d->enableTouchEventsOnViews();
2576 }
2577
2578 // Update selection lists
2579 if (item->isSelected())
2580 d->selectedItems << item;
2581 if (item->isWidget() && item->isVisible() && static_cast<QGraphicsWidget *>(item)->windowType() == Qt::Popup)
2582 d->addPopup(static_cast<QGraphicsWidget *>(item));
2583 if (item->isPanel() && item->isVisible() && item->panelModality() != QGraphicsItem::NonModal)
2584 d->enterModal(item);
2585
2586 // Update creation order focus chain. Make sure to leave the widget's
2587 // internal tab order intact.
2588 if (item->isWidget()) {
2589 QGraphicsWidget *widget = static_cast<QGraphicsWidget *>(item);
2590 if (!d->tabFocusFirst) {
2591 // No first tab focus widget - make this the first tab focus
2592 // widget.
2593 d->tabFocusFirst = widget;
2594 } else if (!widget->parentWidget()) {
2595 // Adding a widget that is not part of a tab focus chain.
2596 QGraphicsWidget *last = d->tabFocusFirst->d_func()->focusPrev;
2597 QGraphicsWidget *lastNew = widget->d_func()->focusPrev;
2598 last->d_func()->focusNext = widget;
2599 widget->d_func()->focusPrev = last;
2600 d->tabFocusFirst->d_func()->focusPrev = lastNew;
2601 lastNew->d_func()->focusNext = d->tabFocusFirst;
2602 }
2603 }
2604
2605 // Add all children recursively
2606 item->d_ptr->ensureSortedChildren();
2607 for (int i = 0; i < item->d_ptr->children.size(); ++i)
2608 addItem(item->d_ptr->children.at(i));
2609
2610 // Resolve font and palette.
2611 item->d_ptr->resolveFont(d->font.resolve());
2612 item->d_ptr->resolvePalette(d->palette.resolve());
2613
2614
2615 // Reenable selectionChanged() for individual items
2616 --d->selectionChanging;
2617 if (!d->selectionChanging && d->selectedItems.size() != oldSelectedItemSize)
2618 emit selectionChanged();
2619
2620 // Deliver post-change notification
2621 item->itemChange(QGraphicsItem::ItemSceneHasChanged, newSceneVariant);
2622
2623 // Update explicit activation
2624 bool autoActivate = true;
2625 if (!d->childExplicitActivation && item->d_ptr->explicitActivate)
2626 d->childExplicitActivation = item->d_ptr->wantsActive ? 1 : 2;
2627 if (d->childExplicitActivation && item->isPanel()) {
2628 if (d->childExplicitActivation == 1)
2629 setActivePanel(item);
2630 else
2631 autoActivate = false;
2632 d->childExplicitActivation = 0;
2633 } else if (!item->d_ptr->parent) {
2634 d->childExplicitActivation = 0;
2635 }
2636
2637 // Auto-activate this item's panel if nothing else has been activated
2638 if (autoActivate) {
2639 if (!d->lastActivePanel && !d->activePanel && item->isPanel()) {
2640 if (isActive())
2641 setActivePanel(item);
2642 else
2643 d->lastActivePanel = item;
2644 }
2645 }
2646
2647 if (item->d_ptr->flags & QGraphicsItem::ItemSendsScenePositionChanges)
2648 d->registerScenePosItem(item);
2649
2650 // Ensure that newly added items that have subfocus set, gain
2651 // focus automatically if there isn't a focus item already.
2652 if (!d->focusItem && item != d->lastFocusItem && item->focusItem() == item)
2653 item->focusItem()->setFocus();
2654
2655 d->updateInputMethodSensitivityInViews();
2656}
2657
2658/*!
2659 Creates and adds an ellipse item to the scene, and returns the item
2660 pointer. The geometry of the ellipse is defined by \a rect, and its pen
2661 and brush are initialized to \a pen and \a brush.
2662
2663 Note that the item's geometry is provided in item coordinates, and its
2664 position is initialized to (0, 0).
2665
2666 If the item is visible (i.e., QGraphicsItem::isVisible() returns true),
2667 QGraphicsScene will emit changed() once control goes back to the event
2668 loop.
2669
2670 \sa addLine(), addPath(), addPixmap(), addRect(), addText(), addItem(),
2671 addWidget()
2672*/
2673QGraphicsEllipseItem *QGraphicsScene::addEllipse(const QRectF &rect, const QPen &pen, const QBrush &brush)
2674{
2675 QGraphicsEllipseItem *item = new QGraphicsEllipseItem(rect);
2676 item->setPen(pen);
2677 item->setBrush(brush);
2678 addItem(item);
2679 return item;
2680}
2681
2682/*!
2683 \fn QGraphicsEllipseItem *QGraphicsScene::addEllipse(qreal x, qreal y, qreal w, qreal h, const QPen &pen, const QBrush &brush)
2684 \since 4.3
2685
2686 This convenience function is equivalent to calling addEllipse(QRectF(\a x,
2687 \a y, \a w, \a h), \a pen, \a brush).
2688*/
2689
2690/*!
2691 Creates and adds a line item to the scene, and returns the item
2692 pointer. The geometry of the line is defined by \a line, and its pen
2693 is initialized to \a pen.
2694
2695 Note that the item's geometry is provided in item coordinates, and its
2696 position is initialized to (0, 0).
2697
2698 If the item is visible (i.e., QGraphicsItem::isVisible() returns true),
2699 QGraphicsScene will emit changed() once control goes back to the event
2700 loop.
2701
2702 \sa addEllipse(), addPath(), addPixmap(), addRect(), addText(), addItem(),
2703 addWidget()
2704*/
2705QGraphicsLineItem *QGraphicsScene::addLine(const QLineF &line, const QPen &pen)
2706{
2707 QGraphicsLineItem *item = new QGraphicsLineItem(line);
2708 item->setPen(pen);
2709 addItem(item);
2710 return item;
2711}
2712
2713/*!
2714 \fn QGraphicsLineItem *QGraphicsScene::addLine(qreal x1, qreal y1, qreal x2, qreal y2, const QPen &pen)
2715 \since 4.3
2716
2717 This convenience function is equivalent to calling addLine(QLineF(\a x1,
2718 \a y1, \a x2, \a y2), \a pen).
2719*/
2720
2721/*!
2722 Creates and adds a path item to the scene, and returns the item
2723 pointer. The geometry of the path is defined by \a path, and its pen and
2724 brush are initialized to \a pen and \a brush.
2725
2726 Note that the item's geometry is provided in item coordinates, and its
2727 position is initialized to (0, 0).
2728
2729 If the item is visible (i.e., QGraphicsItem::isVisible() returns true),
2730 QGraphicsScene will emit changed() once control goes back to the event
2731 loop.
2732
2733 \sa addEllipse(), addLine(), addPixmap(), addRect(), addText(), addItem(),
2734 addWidget()
2735*/
2736QGraphicsPathItem *QGraphicsScene::addPath(const QPainterPath &path, const QPen &pen, const QBrush &brush)
2737{
2738 QGraphicsPathItem *item = new QGraphicsPathItem(path);
2739 item->setPen(pen);
2740 item->setBrush(brush);
2741 addItem(item);
2742 return item;
2743}
2744
2745/*!
2746 Creates and adds a pixmap item to the scene, and returns the item
2747 pointer. The pixmap is defined by \a pixmap.
2748
2749 Note that the item's geometry is provided in item coordinates, and its
2750 position is initialized to (0, 0).
2751
2752 If the item is visible (i.e., QGraphicsItem::isVisible() returns true),
2753 QGraphicsScene will emit changed() once control goes back to the event
2754 loop.
2755
2756 \sa addEllipse(), addLine(), addPath(), addRect(), addText(), addItem(),
2757 addWidget()
2758*/
2759QGraphicsPixmapItem *QGraphicsScene::addPixmap(const QPixmap &pixmap)
2760{
2761 QGraphicsPixmapItem *item = new QGraphicsPixmapItem(pixmap);
2762 addItem(item);
2763 return item;
2764}
2765
2766/*!
2767 Creates and adds a polygon item to the scene, and returns the item
2768 pointer. The polygon is defined by \a polygon, and its pen and
2769 brush are initialized to \a pen and \a brush.
2770
2771 Note that the item's geometry is provided in item coordinates, and its
2772 position is initialized to (0, 0).
2773
2774 If the item is visible (i.e., QGraphicsItem::isVisible() returns true),
2775 QGraphicsScene will emit changed() once control goes back to the event
2776 loop.
2777
2778 \sa addEllipse(), addLine(), addPath(), addRect(), addText(), addItem(),
2779 addWidget()
2780*/
2781QGraphicsPolygonItem *QGraphicsScene::addPolygon(const QPolygonF &polygon,
2782 const QPen &pen, const QBrush &brush)
2783{
2784 QGraphicsPolygonItem *item = new QGraphicsPolygonItem(polygon);
2785 item->setPen(pen);
2786 item->setBrush(brush);
2787 addItem(item);
2788 return item;
2789}
2790
2791/*!
2792 Creates and adds a rectangle item to the scene, and returns the item
2793 pointer. The geometry of the rectangle is defined by \a rect, and its pen
2794 and brush are initialized to \a pen and \a brush.
2795
2796 Note that the item's geometry is provided in item coordinates, and its
2797 position is initialized to (0, 0). For example, if a QRect(50, 50, 100,
2798 100) is added, its top-left corner will be at (50, 50) relative to the
2799 origin in the items coordinate system.
2800
2801 If the item is visible (i.e., QGraphicsItem::isVisible() returns true),
2802 QGraphicsScene will emit changed() once control goes back to the event
2803 loop.
2804
2805 \sa addEllipse(), addLine(), addPixmap(), addPixmap(), addText(),
2806 addItem(), addWidget()
2807*/
2808QGraphicsRectItem *QGraphicsScene::addRect(const QRectF &rect, const QPen &pen, const QBrush &brush)
2809{
2810 QGraphicsRectItem *item = new QGraphicsRectItem(rect);
2811 item->setPen(pen);
2812 item->setBrush(brush);
2813 addItem(item);
2814 return item;
2815}
2816
2817/*!
2818 \fn QGraphicsRectItem *QGraphicsScene::addRect(qreal x, qreal y, qreal w, qreal h, const QPen &pen, const QBrush &brush)
2819 \since 4.3
2820
2821 This convenience function is equivalent to calling addRect(QRectF(\a x,
2822 \a y, \a w, \a h), \a pen, \a brush).
2823*/
2824
2825/*!
2826 Creates and adds a text item to the scene, and returns the item
2827 pointer. The text string is initialized to \a text, and its font
2828 is initialized to \a font.
2829
2830 The item's position is initialized to (0, 0).
2831
2832 If the item is visible (i.e., QGraphicsItem::isVisible() returns true),
2833 QGraphicsScene will emit changed() once control goes back to the event
2834 loop.
2835
2836 \sa addEllipse(), addLine(), addPixmap(), addPixmap(), addRect(),
2837 addItem(), addWidget()
2838*/
2839QGraphicsTextItem *QGraphicsScene::addText(const QString &text, const QFont &font)
2840{
2841 QGraphicsTextItem *item = new QGraphicsTextItem(text);
2842 item->setFont(font);
2843 addItem(item);
2844 return item;
2845}
2846
2847/*!
2848 Creates and adds a QGraphicsSimpleTextItem to the scene, and returns the
2849 item pointer. The text string is initialized to \a text, and its font is
2850 initialized to \a font.
2851
2852 The item's position is initialized to (0, 0).
2853
2854 If the item is visible (i.e., QGraphicsItem::isVisible() returns true),
2855 QGraphicsScene will emit changed() once control goes back to the event
2856 loop.
2857
2858 \sa addEllipse(), addLine(), addPixmap(), addPixmap(), addRect(),
2859 addItem(), addWidget()
2860*/
2861QGraphicsSimpleTextItem *QGraphicsScene::addSimpleText(const QString &text, const QFont &font)
2862{
2863 QGraphicsSimpleTextItem *item = new QGraphicsSimpleTextItem(text);
2864 item->setFont(font);
2865 addItem(item);
2866 return item;
2867}
2868
2869/*!
2870 Creates a new QGraphicsProxyWidget for \a widget, adds it to the scene,
2871 and returns a pointer to the proxy. \a wFlags set the default window flags
2872 for the embedding proxy widget.
2873
2874 The item's position is initialized to (0, 0).
2875
2876 If the item is visible (i.e., QGraphicsItem::isVisible() returns true),
2877 QGraphicsScene will emit changed() once control goes back to the event
2878 loop.
2879
2880 Note that widgets with the Qt::WA_PaintOnScreen widget attribute
2881 set and widgets that wrap an external application or controller
2882 are not supported. Examples are QGLWidget and QAxWidget.
2883
2884 \sa addEllipse(), addLine(), addPixmap(), addPixmap(), addRect(),
2885 addText(), addSimpleText(), addItem()
2886*/
2887QGraphicsProxyWidget *QGraphicsScene::addWidget(QWidget *widget, Qt::WindowFlags wFlags)
2888{
2889 QGraphicsProxyWidget *proxy = new QGraphicsProxyWidget(0, wFlags);
2890 proxy->setWidget(widget);
2891 addItem(proxy);
2892 return proxy;
2893}
2894
2895/*!
2896 Removes the item \a item and all its children from the scene. The
2897 ownership of \a item is passed on to the caller (i.e.,
2898 QGraphicsScene will no longer delete \a item when destroyed).
2899
2900 \sa addItem()
2901*/
2902void QGraphicsScene::removeItem(QGraphicsItem *item)
2903{
2904 // ### Refactoring: This function shares much functionality with _q_removeItemLater()
2905 Q_D(QGraphicsScene);
2906 if (!item) {
2907 qWarning("QGraphicsScene::removeItem: cannot remove 0-item");
2908 return;
2909 }
2910 if (item->scene() != this) {
2911 qWarning("QGraphicsScene::removeItem: item %p's scene (%p)"
2912 " is different from this scene (%p)",
2913 item, item->scene(), this);
2914 return;
2915 }
2916
2917 // Notify the item that it's scene is changing to 0, allowing the item to
2918 // react.
2919 const QVariant newSceneVariant(item->itemChange(QGraphicsItem::ItemSceneChange,
2920 qVariantFromValue<QGraphicsScene *>(0)));
2921 QGraphicsScene *targetScene = qVariantValue<QGraphicsScene *>(newSceneVariant);
2922 if (targetScene != 0 && targetScene != this) {
2923 targetScene->addItem(item);
2924 return;
2925 }
2926
2927 d->removeItemHelper(item);
2928
2929 // Deliver post-change notification
2930 item->itemChange(QGraphicsItem::ItemSceneHasChanged, newSceneVariant);
2931
2932 d->updateInputMethodSensitivityInViews();
2933}
2934
2935/*!
2936 When the scene is active, this functions returns the scene's current focus
2937 item, or 0 if no item currently has focus. When the scene is inactive, this
2938 functions returns the item that will gain input focus when the scene becomes
2939 active.
2940
2941 The focus item receives keyboard input when the scene receives a
2942 key event.
2943
2944 \sa setFocusItem(), QGraphicsItem::hasFocus(), isActive()
2945*/
2946QGraphicsItem *QGraphicsScene::focusItem() const
2947{
2948 Q_D(const QGraphicsScene);
2949 return isActive() ? d->focusItem : d->lastFocusItem;
2950}
2951
2952/*!
2953 Sets the scene's focus item to \a item, with the focus reason \a
2954 focusReason, after removing focus from any previous item that may have had
2955 focus.
2956
2957 If \a item is 0, or if it either does not accept focus (i.e., it does not
2958 have the QGraphicsItem::ItemIsFocusable flag enabled), or is not visible
2959 or not enabled, this function only removes focus from any previous
2960 focusitem.
2961
2962 If item is not 0, and the scene does not currently have focus (i.e.,
2963 hasFocus() returns false), this function will call setFocus()
2964 automatically.
2965
2966 \sa focusItem(), hasFocus(), setFocus()
2967*/
2968void QGraphicsScene::setFocusItem(QGraphicsItem *item, Qt::FocusReason focusReason)
2969{
2970 Q_D(QGraphicsScene);
2971 if (item)
2972 item->setFocus(focusReason);
2973 else
2974 d->setFocusItemHelper(item, focusReason);
2975}
2976
2977/*!
2978 Returns true if the scene has focus; otherwise returns false. If the scene
2979 has focus, it will will forward key events from QKeyEvent to any item that
2980 has focus.
2981
2982 \sa setFocus(), setFocusItem()
2983*/
2984bool QGraphicsScene::hasFocus() const
2985{
2986 Q_D(const QGraphicsScene);
2987 return d->hasFocus;
2988}
2989
2990/*!
2991 Sets focus on the scene by sending a QFocusEvent to the scene, passing \a
2992 focusReason as the reason. If the scene regains focus after having
2993 previously lost it while an item had focus, the last focus item will
2994 receive focus with \a focusReason as the reason.
2995
2996 If the scene already has focus, this function does nothing.
2997
2998 \sa hasFocus(), clearFocus(), setFocusItem()
2999*/
3000void QGraphicsScene::setFocus(Qt::FocusReason focusReason)
3001{
3002 Q_D(QGraphicsScene);
3003 if (d->hasFocus || !isActive())
3004 return;
3005 QFocusEvent event(QEvent::FocusIn, focusReason);
3006 QCoreApplication::sendEvent(this, &event);
3007}
3008
3009/*!
3010 Clears focus from the scene. If any item has focus when this function is
3011 called, it will lose focus, and regain focus again once the scene regains
3012 focus.
3013
3014 A scene that does not have focus ignores key events.
3015
3016 \sa hasFocus(), setFocus(), setFocusItem()
3017*/
3018void QGraphicsScene::clearFocus()
3019{
3020 Q_D(QGraphicsScene);
3021 if (d->hasFocus) {
3022 d->hasFocus = false;
3023 setFocusItem(0, Qt::OtherFocusReason);
3024 }
3025}
3026
3027/*!
3028 \property QGraphicsScene::stickyFocus
3029 \brief whether clicking into the scene background will clear focus
3030
3031 \since 4.6
3032
3033 In a QGraphicsScene with stickyFocus set to true, focus will remain
3034 unchanged when the user clicks into the scene background or on an item
3035 that does not accept focus. Otherwise, focus will be cleared.
3036
3037 By default, this property is false.
3038
3039 Focus changes in response to a mouse press. You can reimplement
3040 mousePressEvent() in a subclass of QGraphicsScene to toggle this property
3041 based on where the user has clicked.
3042
3043 \sa clearFocus(), setFocusItem()
3044*/
3045void QGraphicsScene::setStickyFocus(bool enabled)
3046{
3047 Q_D(QGraphicsScene);
3048 d->stickyFocus = enabled;
3049}
3050bool QGraphicsScene::stickyFocus() const
3051{
3052 Q_D(const QGraphicsScene);
3053 return d->stickyFocus;
3054}
3055
3056/*!
3057 Returns the current mouse grabber item, or 0 if no item is currently
3058 grabbing the mouse. The mouse grabber item is the item that receives all
3059 mouse events sent to the scene.
3060
3061 An item becomes a mouse grabber when it receives and accepts a
3062 mouse press event, and it stays the mouse grabber until either of
3063 the following events occur:
3064
3065 \list
3066 \o If the item receives a mouse release event when there are no other
3067 buttons pressed, it loses the mouse grab.
3068 \o If the item becomes invisible (i.e., someone calls \c {item->setVisible(false))},
3069 or if it becomes disabled (i.e., someone calls \c {item->setEnabled(false))},
3070 it loses the mouse grab.
3071 \o If the item is removed from the scene, it loses the mouse grab.
3072 \endlist
3073
3074 If the item loses its mouse grab, the scene will ignore all mouse events
3075 until a new item grabs the mouse (i.e., until a new item receives a mouse
3076 press event).
3077*/
3078QGraphicsItem *QGraphicsScene::mouseGrabberItem() const
3079{
3080 Q_D(const QGraphicsScene);
3081 return !d->mouseGrabberItems.isEmpty() ? d->mouseGrabberItems.last() : 0;
3082}
3083
3084/*!
3085 \property QGraphicsScene::backgroundBrush
3086 \brief the background brush of the scene.
3087
3088 Set this property to changes the scene's background to a different color,
3089 gradient or texture. The default background brush is Qt::NoBrush. The
3090 background is drawn before (behind) the items.
3091
3092 Example:
3093
3094 \snippet doc/src/snippets/code/src_gui_graphicsview_qgraphicsscene.cpp 3
3095
3096 QGraphicsScene::render() calls drawBackground() to draw the scene
3097 background. For more detailed control over how the background is drawn,
3098 you can reimplement drawBackground() in a subclass of QGraphicsScene.
3099*/
3100QBrush QGraphicsScene::backgroundBrush() const
3101{
3102 Q_D(const QGraphicsScene);
3103 return d->backgroundBrush;
3104}
3105void QGraphicsScene::setBackgroundBrush(const QBrush &brush)
3106{
3107 Q_D(QGraphicsScene);
3108 d->backgroundBrush = brush;
3109 foreach (QGraphicsView *view, d->views) {
3110 view->resetCachedContent();
3111 view->viewport()->update();
3112 }
3113 update();
3114}
3115
3116/*!
3117 \property QGraphicsScene::foregroundBrush
3118 \brief the foreground brush of the scene.
3119
3120 Change this property to set the scene's foreground to a different
3121 color, gradient or texture.
3122
3123 The foreground is drawn after (on top of) the items. The default
3124 foreground brush is Qt::NoBrush ( i.e. the foreground is not
3125 drawn).
3126
3127 Example:
3128
3129 \snippet doc/src/snippets/code/src_gui_graphicsview_qgraphicsscene.cpp 4
3130
3131 QGraphicsScene::render() calls drawForeground() to draw the scene
3132 foreground. For more detailed control over how the foreground is
3133 drawn, you can reimplement the drawForeground() function in a
3134 QGraphicsScene subclass.
3135*/
3136QBrush QGraphicsScene::foregroundBrush() const
3137{
3138 Q_D(const QGraphicsScene);
3139 return d->foregroundBrush;
3140}
3141void QGraphicsScene::setForegroundBrush(const QBrush &brush)
3142{
3143 Q_D(QGraphicsScene);
3144 d->foregroundBrush = brush;
3145 foreach (QGraphicsView *view, views())
3146 view->viewport()->update();
3147 update();
3148}
3149
3150/*!
3151 This method is used by input methods to query a set of properties of
3152 the scene to be able to support complex input method operations as support
3153 for surrounding text and reconversions.
3154
3155 The \a query parameter specifies which property is queried.
3156
3157 \sa QWidget::inputMethodQuery()
3158*/
3159QVariant QGraphicsScene::inputMethodQuery(Qt::InputMethodQuery query) const
3160{
3161 Q_D(const QGraphicsScene);
3162 if (!d->focusItem || !(d->focusItem->flags() & QGraphicsItem::ItemAcceptsInputMethod))
3163 return QVariant();
3164 const QTransform matrix = d->focusItem->sceneTransform();
3165 QVariant value = d->focusItem->inputMethodQuery(query);
3166 if (value.type() == QVariant::RectF)
3167 value = matrix.mapRect(value.toRectF());
3168 else if (value.type() == QVariant::PointF)
3169 value = matrix.map(value.toPointF());
3170 else if (value.type() == QVariant::Rect)
3171 value = matrix.mapRect(value.toRect());
3172 else if (value.type() == QVariant::Point)
3173 value = matrix.map(value.toPoint());
3174 return value;
3175}
3176
3177/*!
3178 \fn void QGraphicsScene::update(const QRectF &rect)
3179 Schedules a redraw of the area \a rect on the scene.
3180
3181 \sa sceneRect(), changed()
3182*/
3183void QGraphicsScene::update(const QRectF &rect)
3184{
3185 Q_D(QGraphicsScene);
3186 if (d->updateAll || (rect.isEmpty() && !rect.isNull()))
3187 return;
3188
3189 // Check if anyone's connected; if not, we can send updates directly to
3190 // the views. Otherwise or if there are no views, use old behavior.
3191 bool directUpdates = !(d->isSignalConnected(d->changedSignalIndex)) && !d->views.isEmpty();
3192 if (rect.isNull()) {
3193 d->updateAll = true;
3194 d->updatedRects.clear();
3195 if (directUpdates) {
3196 // Update all views.
3197 for (int i = 0; i < d->views.size(); ++i)
3198 d->views.at(i)->d_func()->fullUpdatePending = true;
3199 }
3200 } else {
3201 if (directUpdates) {
3202 // Update all views.
3203 for (int i = 0; i < d->views.size(); ++i) {
3204 QGraphicsView *view = d->views.at(i);
3205 view->d_func()->updateRegion(QRegion(view->mapFromScene(rect).boundingRect()));
3206 }
3207 } else {
3208 d->updatedRects << rect;
3209 }
3210 }
3211
3212 if (!d->calledEmitUpdated) {
3213 d->calledEmitUpdated = true;
3214 QMetaObject::invokeMethod(this, "_q_emitUpdated", Qt::QueuedConnection);
3215 }
3216}
3217
3218/*!
3219 \fn void QGraphicsScene::update(qreal x, qreal y, qreal w, qreal h)
3220 \overload
3221 \since 4.3
3222
3223 This function is equivalent to calling update(QRectF(\a x, \a y, \a w,
3224 \a h));
3225*/
3226
3227/*!
3228 Invalidates and schedules a redraw of the \a layers in \a rect on the
3229 scene. Any cached content in \a layers is unconditionally invalidated and
3230 redrawn.
3231
3232 You can use this function overload to notify QGraphicsScene of changes to
3233 the background or the foreground of the scene. This function is commonly
3234 used for scenes with tile-based backgrounds to notify changes when
3235 QGraphicsView has enabled
3236 \l{QGraphicsView::CacheBackground}{CacheBackground}.
3237
3238 Example:
3239
3240 \snippet doc/src/snippets/code/src_gui_graphicsview_qgraphicsscene.cpp 5
3241
3242 Note that QGraphicsView currently supports background caching only (see
3243 QGraphicsView::CacheBackground). This function is equivalent to calling
3244 update() if any layer but BackgroundLayer is passed.
3245
3246 \sa QGraphicsView::resetCachedContent()
3247*/
3248void QGraphicsScene::invalidate(const QRectF &rect, SceneLayers layers)
3249{
3250 foreach (QGraphicsView *view, views())
3251 view->invalidateScene(rect, layers);
3252 update(rect);
3253}
3254
3255/*!
3256 \fn void QGraphicsScene::invalidate(qreal x, qreal y, qreal w, qreal h, SceneLayers layers)
3257 \overload
3258 \since 4.3
3259
3260 This convenience function is equivalent to calling invalidate(QRectF(\a x, \a
3261 y, \a w, \a h), \a layers);
3262*/
3263
3264/*!
3265 Returns a list of all the views that display this scene.
3266
3267 \sa QGraphicsView::scene()
3268*/
3269QList <QGraphicsView *> QGraphicsScene::views() const
3270{
3271 Q_D(const QGraphicsScene);
3272 return d->views;
3273}
3274
3275/*!
3276 This slot \e advances the scene by one step, by calling
3277 QGraphicsItem::advance() for all items on the scene. This is done in two
3278 phases: in the first phase, all items are notified that the scene is about
3279 to change, and in the second phase all items are notified that they can
3280 move. In the first phase, QGraphicsItem::advance() is called passing a
3281 value of 0 as an argument, and 1 is passed in the second phase.
3282
3283 \sa QGraphicsItem::advance(), QGraphicsItemAnimation, QTimeLine
3284*/
3285void QGraphicsScene::advance()
3286{
3287 for (int i = 0; i < 2; ++i) {
3288 foreach (QGraphicsItem *item, items())
3289 item->advance(i);
3290 }
3291}
3292
3293/*!
3294 Processes the event \a event, and dispatches it to the respective
3295 event handlers.
3296
3297 In addition to calling the convenience event handlers, this
3298 function is responsible for converting mouse move events to hover
3299 events for when there is no mouse grabber item. Hover events are
3300 delivered directly to items; there is no convenience function for
3301 them.
3302
3303 Unlike QWidget, QGraphicsScene does not have the convenience functions
3304 \l{QWidget::}{enterEvent()} and \l{QWidget::}{leaveEvent()}. Use this
3305 function to obtain those events instead.
3306
3307 \sa contextMenuEvent(), keyPressEvent(), keyReleaseEvent(),
3308 mousePressEvent(), mouseMoveEvent(), mouseReleaseEvent(),
3309 mouseDoubleClickEvent(), focusInEvent(), focusOutEvent()
3310*/
3311bool QGraphicsScene::event(QEvent *event)
3312{
3313 Q_D(QGraphicsScene);
3314
3315 switch (event->type()) {
3316 case QEvent::GraphicsSceneMousePress:
3317 case QEvent::GraphicsSceneMouseMove:
3318 case QEvent::GraphicsSceneMouseRelease:
3319 case QEvent::GraphicsSceneMouseDoubleClick:
3320 case QEvent::GraphicsSceneHoverEnter:
3321 case QEvent::GraphicsSceneHoverLeave:
3322 case QEvent::GraphicsSceneHoverMove:
3323 case QEvent::TouchBegin:
3324 case QEvent::TouchUpdate:
3325 case QEvent::TouchEnd:
3326 // Reset the under-mouse list to ensure that this event gets fresh
3327 // item-under-mouse data. Be careful about this list; if people delete
3328 // items from inside event handlers, this list can quickly end up
3329 // having stale pointers in it. We need to clear it before dispatching
3330 // events that use it.
3331 // ### this should only be cleared if we received a new mouse move event,
3332 // which relies on us fixing the replay mechanism in QGraphicsView.
3333 d->cachedItemsUnderMouse.clear();
3334 default:
3335 break;
3336 }
3337
3338 switch (event->type()) {
3339 case QEvent::GraphicsSceneDragEnter:
3340 dragEnterEvent(static_cast<QGraphicsSceneDragDropEvent *>(event));
3341 break;
3342 case QEvent::GraphicsSceneDragMove:
3343 dragMoveEvent(static_cast<QGraphicsSceneDragDropEvent *>(event));
3344 break;
3345 case QEvent::GraphicsSceneDragLeave:
3346 dragLeaveEvent(static_cast<QGraphicsSceneDragDropEvent *>(event));
3347 break;
3348 case QEvent::GraphicsSceneDrop:
3349 dropEvent(static_cast<QGraphicsSceneDragDropEvent *>(event));
3350 break;
3351 case QEvent::GraphicsSceneContextMenu:
3352 contextMenuEvent(static_cast<QGraphicsSceneContextMenuEvent *>(event));
3353 break;
3354 case QEvent::KeyPress:
3355 if (!d->focusItem) {
3356 QKeyEvent *k = static_cast<QKeyEvent *>(event);
3357 if (k->key() == Qt::Key_Tab || k->key() == Qt::Key_Backtab) {
3358 if (!(k->modifiers() & (Qt::ControlModifier | Qt::AltModifier))) { //### Add MetaModifier?
3359 bool res = false;
3360 if (k->key() == Qt::Key_Backtab
3361 || (k->key() == Qt::Key_Tab && (k->modifiers() & Qt::ShiftModifier))) {
3362 res = focusNextPrevChild(false);
3363 } else if (k->key() == Qt::Key_Tab) {
3364 res = focusNextPrevChild(true);
3365 }
3366 if (!res)
3367 event->ignore();
3368 return true;
3369 }
3370 }
3371 }
3372 keyPressEvent(static_cast<QKeyEvent *>(event));
3373 break;
3374 case QEvent::KeyRelease:
3375 keyReleaseEvent(static_cast<QKeyEvent *>(event));
3376 break;
3377 case QEvent::ShortcutOverride: {
3378 QGraphicsItem *parent = focusItem();
3379 while (parent) {
3380 d->sendEvent(parent, event);
3381 if (event->isAccepted())
3382 return true;
3383 parent = parent->parentItem();
3384 }
3385 }
3386 return false;
3387 case QEvent::GraphicsSceneMouseMove:
3388 {
3389 QGraphicsSceneMouseEvent *mouseEvent = static_cast<QGraphicsSceneMouseEvent *>(event);
3390 d->lastSceneMousePos = mouseEvent->scenePos();
3391 mouseMoveEvent(mouseEvent);
3392 break;
3393 }
3394 case QEvent::GraphicsSceneMousePress:
3395 mousePressEvent(static_cast<QGraphicsSceneMouseEvent *>(event));
3396 break;
3397 case QEvent::GraphicsSceneMouseRelease:
3398 mouseReleaseEvent(static_cast<QGraphicsSceneMouseEvent *>(event));
3399 break;
3400 case QEvent::GraphicsSceneMouseDoubleClick:
3401 mouseDoubleClickEvent(static_cast<QGraphicsSceneMouseEvent *>(event));
3402 break;
3403 case QEvent::GraphicsSceneWheel:
3404 wheelEvent(static_cast<QGraphicsSceneWheelEvent *>(event));
3405 break;
3406 case QEvent::FocusIn:
3407 focusInEvent(static_cast<QFocusEvent *>(event));
3408 break;
3409 case QEvent::FocusOut:
3410 focusOutEvent(static_cast<QFocusEvent *>(event));
3411 break;
3412 case QEvent::GraphicsSceneHoverEnter:
3413 case QEvent::GraphicsSceneHoverLeave:
3414 case QEvent::GraphicsSceneHoverMove:
3415 {
3416 QGraphicsSceneHoverEvent *hoverEvent = static_cast<QGraphicsSceneHoverEvent *>(event);
3417 d->lastSceneMousePos = hoverEvent->scenePos();
3418 d->dispatchHoverEvent(hoverEvent);
3419 break;
3420 }
3421 case QEvent::Leave:
3422 d->leaveScene();
3423 break;
3424 case QEvent::GraphicsSceneHelp:
3425 helpEvent(static_cast<QGraphicsSceneHelpEvent *>(event));
3426 break;
3427 case QEvent::InputMethod:
3428 inputMethodEvent(static_cast<QInputMethodEvent *>(event));
3429 break;
3430 case QEvent::WindowActivate:
3431 if (!d->activationRefCount++) {
3432 if (d->lastActivePanel) {
3433 // Activate the last panel.
3434 d->setActivePanelHelper(d->lastActivePanel, true);
3435 } else if (d->tabFocusFirst && d->tabFocusFirst->isPanel()) {
3436 // Activate the panel of the first item in the tab focus
3437 // chain.
3438 d->setActivePanelHelper(d->tabFocusFirst, true);
3439 } else {
3440 // Activate all toplevel items.
3441 QEvent event(QEvent::WindowActivate);
3442 foreach (QGraphicsItem *item, items()) {
3443 if (item->isVisible() && !item->isPanel() && !item->parentItem())
3444 sendEvent(item, &event);
3445 }
3446 }
3447 }
3448 break;
3449 case QEvent::WindowDeactivate:
3450 if (!--d->activationRefCount) {
3451 if (d->activePanel) {
3452 // Deactivate the active panel (but keep it so we can
3453 // reactivate it later).
3454 QGraphicsItem *lastActivePanel = d->activePanel;
3455 d->setActivePanelHelper(0, true);
3456 d->lastActivePanel = lastActivePanel;
3457 } else {
3458 // Activate all toplevel items.
3459 QEvent event(QEvent::WindowDeactivate);
3460 foreach (QGraphicsItem *item, items()) {
3461 if (item->isVisible() && !item->isPanel() && !item->parentItem())
3462 sendEvent(item, &event);
3463 }
3464 }
3465 }
3466 break;
3467 case QEvent::ApplicationFontChange: {
3468 // Resolve the existing scene font.
3469 d->resolveFont();
3470 break;
3471 }
3472 case QEvent::FontChange:
3473 // Update the entire scene when the font changes.
3474 update();
3475 break;
3476 case QEvent::ApplicationPaletteChange: {
3477 // Resolve the existing scene palette.
3478 d->resolvePalette();
3479 break;
3480 }
3481 case QEvent::PaletteChange:
3482 // Update the entire scene when the palette changes.
3483 update();
3484 break;
3485 case QEvent::StyleChange:
3486 // Reresolve all widgets' styles. Update all top-level widgets'
3487 // geometries that do not have an explicit style set.
3488 update();
3489 break;
3490 case QEvent::TouchBegin:
3491 case QEvent::TouchUpdate:
3492 case QEvent::TouchEnd:
3493 d->touchEventHandler(static_cast<QTouchEvent *>(event));
3494 break;
3495 case QEvent::Gesture:
3496 case QEvent::GestureOverride:
3497 d->gestureEventHandler(static_cast<QGestureEvent *>(event));
3498 break;
3499 default:
3500 return QObject::event(event);
3501 }
3502 return true;
3503}
3504
3505/*!
3506 \reimp
3507
3508 QGraphicsScene filters QApplication's events to detect palette and font
3509 changes.
3510*/
3511bool QGraphicsScene::eventFilter(QObject *watched, QEvent *event)
3512{
3513 if (watched != qApp)
3514 return false;
3515
3516 switch (event->type()) {
3517 case QEvent::ApplicationPaletteChange:
3518 QApplication::postEvent(this, new QEvent(QEvent::ApplicationPaletteChange));
3519 break;
3520 case QEvent::ApplicationFontChange:
3521 QApplication::postEvent(this, new QEvent(QEvent::ApplicationFontChange));
3522 break;
3523 default:
3524 break;
3525 }
3526 return false;
3527}
3528
3529/*!
3530 This event handler, for event \a contextMenuEvent, can be reimplemented in
3531 a subclass to receive context menu events. The default implementation
3532 forwards the event to the topmost item that accepts context menu events at
3533 the position of the event. If no items accept context menu events at this
3534 position, the event is ignored.
3535
3536 \sa QGraphicsItem::contextMenuEvent()
3537*/
3538void QGraphicsScene::contextMenuEvent(QGraphicsSceneContextMenuEvent *contextMenuEvent)
3539{
3540 Q_D(QGraphicsScene);
3541 // Ignore by default.
3542 contextMenuEvent->ignore();
3543
3544 // Send the event to all items at this position until one item accepts the
3545 // event.
3546 foreach (QGraphicsItem *item, d->itemsAtPosition(contextMenuEvent->screenPos(),
3547 contextMenuEvent->scenePos(),
3548 contextMenuEvent->widget())) {
3549 contextMenuEvent->setPos(item->d_ptr->genericMapFromScene(contextMenuEvent->scenePos(),
3550 contextMenuEvent->widget()));
3551 contextMenuEvent->accept();
3552 if (!d->sendEvent(item, contextMenuEvent))
3553 break;
3554
3555 if (contextMenuEvent->isAccepted())
3556 break;
3557 }
3558}
3559
3560/*!
3561 This event handler, for event \a event, can be reimplemented in a subclass
3562 to receive drag enter events for the scene.
3563
3564 The default implementation accepts the event and prepares the scene to
3565 accept drag move events.
3566
3567 \sa QGraphicsItem::dragEnterEvent(), dragMoveEvent(), dragLeaveEvent(),
3568 dropEvent()
3569*/
3570void QGraphicsScene::dragEnterEvent(QGraphicsSceneDragDropEvent *event)
3571{
3572 Q_D(QGraphicsScene);
3573 d->dragDropItem = 0;
3574 d->lastDropAction = Qt::IgnoreAction;
3575 event->accept();
3576}
3577
3578/*!
3579 This event handler, for event \a event, can be reimplemented in a subclass
3580 to receive drag move events for the scene.
3581
3582 \sa QGraphicsItem::dragMoveEvent(), dragEnterEvent(), dragLeaveEvent(),
3583 dropEvent()
3584*/
3585void QGraphicsScene::dragMoveEvent(QGraphicsSceneDragDropEvent *event)
3586{
3587 Q_D(QGraphicsScene);
3588 event->ignore();
3589
3590 if (!d->mouseGrabberItems.isEmpty()) {
3591 // Mouse grabbers that start drag events lose the mouse grab.
3592 d->clearMouseGrabber();
3593 d->mouseGrabberButtonDownPos.clear();
3594 d->mouseGrabberButtonDownScenePos.clear();
3595 d->mouseGrabberButtonDownScreenPos.clear();
3596 }
3597
3598 bool eventDelivered = false;
3599
3600 // Find the topmost enabled items under the cursor. They are all
3601 // candidates for accepting drag & drop events.
3602 foreach (QGraphicsItem *item, d->itemsAtPosition(event->screenPos(),
3603 event->scenePos(),
3604 event->widget())) {
3605 if (!item->isEnabled() || !item->acceptDrops())
3606 continue;
3607
3608 if (item != d->dragDropItem) {
3609 // Enter the new drag drop item. If it accepts the event, we send
3610 // the leave to the parent item.
3611 QGraphicsSceneDragDropEvent dragEnter(QEvent::GraphicsSceneDragEnter);
3612 d->cloneDragDropEvent(&dragEnter, event);
3613 dragEnter.setDropAction(event->proposedAction());
3614 d->sendDragDropEvent(item, &dragEnter);
3615 event->setAccepted(dragEnter.isAccepted());
3616 event->setDropAction(dragEnter.dropAction());
3617 if (!event->isAccepted()) {
3618 // Propagate to the item under
3619 continue;
3620 }
3621
3622 d->lastDropAction = event->dropAction();
3623
3624 if (d->dragDropItem) {
3625 // Leave the last drag drop item. A perfect implementation
3626 // would set the position of this event to the point where
3627 // this event and the last event intersect with the item's
3628 // shape, but that's not easy to do. :-)
3629 QGraphicsSceneDragDropEvent dragLeave(QEvent::GraphicsSceneDragLeave);
3630 d->cloneDragDropEvent(&dragLeave, event);
3631 d->sendDragDropEvent(d->dragDropItem, &dragLeave);
3632 }
3633
3634 // We've got a new drag & drop item
3635 d->dragDropItem = item;
3636 }
3637
3638 // Send the move event.
3639 event->setDropAction(d->lastDropAction);
3640 event->accept();
3641 d->sendDragDropEvent(item, event);
3642 if (event->isAccepted())
3643 d->lastDropAction = event->dropAction();
3644 eventDelivered = true;
3645 break;
3646 }
3647
3648 if (!eventDelivered) {
3649 if (d->dragDropItem) {
3650 // Leave the last drag drop item
3651 QGraphicsSceneDragDropEvent dragLeave(QEvent::GraphicsSceneDragLeave);
3652 d->cloneDragDropEvent(&dragLeave, event);
3653 d->sendDragDropEvent(d->dragDropItem, &dragLeave);
3654 d->dragDropItem = 0;
3655 }
3656 // Propagate
3657 event->setDropAction(Qt::IgnoreAction);
3658 }
3659}
3660
3661/*!
3662 This event handler, for event \a event, can be reimplemented in a subclass
3663 to receive drag leave events for the scene.
3664
3665 \sa QGraphicsItem::dragLeaveEvent(), dragEnterEvent(), dragMoveEvent(),
3666 dropEvent()
3667*/
3668void QGraphicsScene::dragLeaveEvent(QGraphicsSceneDragDropEvent *event)
3669{
3670 Q_D(QGraphicsScene);
3671 if (d->dragDropItem) {
3672 // Leave the last drag drop item
3673 d->sendDragDropEvent(d->dragDropItem, event);
3674 d->dragDropItem = 0;
3675 }
3676}
3677
3678/*!
3679 This event handler, for event \a event, can be reimplemented in a subclass
3680 to receive drop events for the scene.
3681
3682 \sa QGraphicsItem::dropEvent(), dragEnterEvent(), dragMoveEvent(),
3683 dragLeaveEvent()
3684*/
3685void QGraphicsScene::dropEvent(QGraphicsSceneDragDropEvent *event)
3686{
3687 Q_UNUSED(event);
3688 Q_D(QGraphicsScene);
3689 if (d->dragDropItem) {
3690 // Drop on the last drag drop item
3691 d->sendDragDropEvent(d->dragDropItem, event);
3692 d->dragDropItem = 0;
3693 }
3694}
3695
3696/*!
3697 This event handler, for event \a focusEvent, can be reimplemented in a
3698 subclass to receive focus in events.
3699
3700 The default implementation sets focus on the scene, and then on the last
3701 focus item.
3702
3703 \sa QGraphicsItem::focusOutEvent()
3704*/
3705void QGraphicsScene::focusInEvent(QFocusEvent *focusEvent)
3706{
3707 Q_D(QGraphicsScene);
3708
3709 d->hasFocus = true;
3710 switch (focusEvent->reason()) {
3711 case Qt::TabFocusReason:
3712 if (!focusNextPrevChild(true))
3713 focusEvent->ignore();
3714 break;
3715 case Qt::BacktabFocusReason:
3716 if (!focusNextPrevChild(false))
3717 focusEvent->ignore();
3718 break;
3719 default:
3720 if (d->lastFocusItem) {
3721 // Set focus on the last focus item
3722 setFocusItem(d->lastFocusItem, focusEvent->reason());
3723 }
3724 break;
3725 }
3726}
3727
3728/*!
3729 This event handler, for event \a focusEvent, can be reimplemented in a
3730 subclass to receive focus out events.
3731
3732 The default implementation removes focus from any focus item, then removes
3733 focus from the scene.
3734
3735 \sa QGraphicsItem::focusInEvent()
3736*/
3737void QGraphicsScene::focusOutEvent(QFocusEvent *focusEvent)
3738{
3739 Q_D(QGraphicsScene);
3740 d->hasFocus = false;
3741 setFocusItem(0, focusEvent->reason());
3742
3743 // Remove all popups when the scene loses focus.
3744 if (!d->popupWidgets.isEmpty())
3745 d->removePopup(d->popupWidgets.first());
3746}
3747
3748/*!
3749 This event handler, for event \a helpEvent, can be
3750 reimplemented in a subclass to receive help events. The events
3751 are of type QEvent::ToolTip, which are created when a tooltip is
3752 requested.
3753
3754 The default implementation shows the tooltip of the topmost
3755 item, i.e., the item with the highest z-value, at the mouse
3756 cursor position. If no item has a tooltip set, this function
3757 does nothing.
3758
3759 \sa QGraphicsItem::toolTip(), QGraphicsSceneHelpEvent
3760*/
3761void QGraphicsScene::helpEvent(QGraphicsSceneHelpEvent *helpEvent)
3762{
3763#ifdef QT_NO_TOOLTIP
3764 Q_UNUSED(helpEvent);
3765#else
3766 // Find the first item that does tooltips
3767 Q_D(QGraphicsScene);
3768 QList<QGraphicsItem *> itemsAtPos = d->itemsAtPosition(helpEvent->screenPos(),
3769 helpEvent->scenePos(),
3770 helpEvent->widget());
3771 QGraphicsItem *toolTipItem = 0;
3772 for (int i = 0; i < itemsAtPos.size(); ++i) {
3773 QGraphicsItem *tmp = itemsAtPos.at(i);
3774 if (!tmp->toolTip().isEmpty()) {
3775 toolTipItem = tmp;
3776 break;
3777 }
3778 }
3779
3780 // Show or hide the tooltip
3781 QString text;
3782 QPoint point;
3783 if (toolTipItem && !toolTipItem->toolTip().isEmpty()) {
3784 text = toolTipItem->toolTip();
3785 point = helpEvent->screenPos();
3786 }
3787 QToolTip::showText(point, text, helpEvent->widget());
3788 helpEvent->setAccepted(!text.isEmpty());
3789#endif
3790}
3791
3792bool QGraphicsScenePrivate::itemAcceptsHoverEvents_helper(const QGraphicsItem *item) const
3793{
3794 return (item->d_ptr->acceptsHover
3795 || (item->d_ptr->isWidget
3796 && static_cast<const QGraphicsWidget *>(item)->d_func()->hasDecoration()))
3797 && !item->isBlockedByModalPanel();
3798}
3799
3800/*!
3801 This event handler, for event \a hoverEvent, can be reimplemented in a
3802 subclass to receive hover enter events. The default implementation
3803 forwards the event to the topmost item that accepts hover events at the
3804 scene position from the event.
3805
3806 \sa QGraphicsItem::hoverEvent(), QGraphicsItem::setAcceptHoverEvents()
3807*/
3808bool QGraphicsScenePrivate::dispatchHoverEvent(QGraphicsSceneHoverEvent *hoverEvent)
3809{
3810 if (allItemsIgnoreHoverEvents)
3811 return false;
3812
3813 // Find the first item that accepts hover events, reusing earlier
3814 // calculated data is possible.
3815 if (cachedItemsUnderMouse.isEmpty()) {
3816 cachedItemsUnderMouse = itemsAtPosition(hoverEvent->screenPos(),
3817 hoverEvent->scenePos(),
3818 hoverEvent->widget());
3819 }
3820
3821 QGraphicsItem *item = 0;
3822 for (int i = 0; i < cachedItemsUnderMouse.size(); ++i) {
3823 QGraphicsItem *tmp = cachedItemsUnderMouse.at(i);
3824 if (itemAcceptsHoverEvents_helper(tmp)) {
3825 item = tmp;
3826 break;
3827 }
3828 }
3829
3830 // Find the common ancestor item for the new topmost hoverItem and the
3831 // last item in the hoverItem list.
3832 QGraphicsItem *commonAncestorItem = (item && !hoverItems.isEmpty()) ? item->commonAncestorItem(hoverItems.last()) : 0;
3833 while (commonAncestorItem && !itemAcceptsHoverEvents_helper(commonAncestorItem))
3834 commonAncestorItem = commonAncestorItem->parentItem();
3835 if (commonAncestorItem && commonAncestorItem->panel() != item->panel()) {
3836 // The common ancestor isn't in the same panel as the two hovered
3837 // items.
3838 commonAncestorItem = 0;
3839 }
3840
3841 // Check if the common ancestor item is known.
3842 int index = commonAncestorItem ? hoverItems.indexOf(commonAncestorItem) : -1;
3843 // Send hover leaves to any existing hovered children of the common
3844 // ancestor item.
3845 for (int i = hoverItems.size() - 1; i > index; --i) {
3846 QGraphicsItem *lastItem = hoverItems.takeLast();
3847 if (itemAcceptsHoverEvents_helper(lastItem))
3848 sendHoverEvent(QEvent::GraphicsSceneHoverLeave, lastItem, hoverEvent);
3849 }
3850
3851 // Item is a child of a known item. Generate enter events for the
3852 // missing links.
3853 QList<QGraphicsItem *> parents;
3854 QGraphicsItem *parent = item;
3855 while (parent && parent != commonAncestorItem) {
3856 parents.prepend(parent);
3857 if (parent->isPanel()) {
3858 // Stop at the panel - we don't deliver beyond this point.
3859 break;
3860 }
3861 parent = parent->parentItem();
3862 }
3863 for (int i = 0; i < parents.size(); ++i) {
3864 parent = parents.at(i);
3865 hoverItems << parent;
3866 if (itemAcceptsHoverEvents_helper(parent))
3867 sendHoverEvent(QEvent::GraphicsSceneHoverEnter, parent, hoverEvent);
3868 }
3869
3870 // Generate a move event for the item itself
3871 if (item
3872 && !hoverItems.isEmpty()
3873 && item == hoverItems.last()) {
3874 sendHoverEvent(QEvent::GraphicsSceneHoverMove, item, hoverEvent);
3875 return true;
3876 }
3877 return false;
3878}
3879
3880/*!
3881 \internal
3882
3883 Handles all actions necessary to clean up the scene when the mouse leaves
3884 the view.
3885*/
3886void QGraphicsScenePrivate::leaveScene()
3887{
3888 Q_Q(QGraphicsScene);
3889#ifndef QT_NO_TOOLTIP
3890 QToolTip::hideText();
3891#endif
3892 // Send HoverLeave events to all existing hover items, topmost first.
3893 QGraphicsView *senderWidget = qobject_cast<QGraphicsView *>(q->sender());
3894 QGraphicsSceneHoverEvent hoverEvent;
3895 hoverEvent.setWidget(senderWidget);
3896
3897 if (senderWidget) {
3898 QPoint cursorPos = QCursor::pos();
3899 hoverEvent.setScenePos(senderWidget->mapToScene(senderWidget->mapFromGlobal(cursorPos)));
3900 hoverEvent.setLastScenePos(hoverEvent.scenePos());
3901 hoverEvent.setScreenPos(cursorPos);
3902 hoverEvent.setLastScreenPos(hoverEvent.screenPos());
3903 }
3904
3905 while (!hoverItems.isEmpty()) {
3906 QGraphicsItem *lastItem = hoverItems.takeLast();
3907 if (itemAcceptsHoverEvents_helper(lastItem))
3908 sendHoverEvent(QEvent::GraphicsSceneHoverLeave, lastItem, &hoverEvent);
3909 }
3910}
3911
3912/*!
3913 This event handler, for event \a keyEvent, can be reimplemented in a
3914 subclass to receive keypress events. The default implementation forwards
3915 the event to current focus item.
3916
3917 \sa QGraphicsItem::keyPressEvent(), focusItem()
3918*/
3919void QGraphicsScene::keyPressEvent(QKeyEvent *keyEvent)
3920{
3921 // ### Merge this function with keyReleaseEvent; they are identical
3922 // ### (except this comment).
3923 Q_D(QGraphicsScene);
3924 QGraphicsItem *item = !d->keyboardGrabberItems.isEmpty() ? d->keyboardGrabberItems.last() : 0;
3925 if (!item)
3926 item = focusItem();
3927 if (item) {
3928 QGraphicsItem *p = item;
3929 do {
3930 // Accept the event by default
3931 keyEvent->accept();
3932 // Send it; QGraphicsItem::keyPressEvent ignores it. If the event
3933 // is filtered out, stop propagating it.
3934 if (p->isBlockedByModalPanel())
3935 break;
3936 if (!d->sendEvent(p, keyEvent))
3937 break;
3938 } while (!keyEvent->isAccepted() && !p->isPanel() && (p = p->parentItem()));
3939 } else {
3940 keyEvent->ignore();
3941 }
3942}
3943
3944/*!
3945 This event handler, for event \a keyEvent, can be reimplemented in a
3946 subclass to receive key release events. The default implementation
3947 forwards the event to current focus item.
3948
3949 \sa QGraphicsItem::keyReleaseEvent(), focusItem()
3950*/
3951void QGraphicsScene::keyReleaseEvent(QKeyEvent *keyEvent)
3952{
3953 // ### Merge this function with keyPressEvent; they are identical (except
3954 // ### this comment).
3955 Q_D(QGraphicsScene);
3956 QGraphicsItem *item = !d->keyboardGrabberItems.isEmpty() ? d->keyboardGrabberItems.last() : 0;
3957 if (!item)
3958 item = focusItem();
3959 if (item) {
3960 QGraphicsItem *p = item;
3961 do {
3962 // Accept the event by default
3963 keyEvent->accept();
3964 // Send it; QGraphicsItem::keyPressEvent ignores it. If the event
3965 // is filtered out, stop propagating it.
3966 if (p->isBlockedByModalPanel())
3967 break;
3968 if (!d->sendEvent(p, keyEvent))
3969 break;
3970 } while (!keyEvent->isAccepted() && !p->isPanel() && (p = p->parentItem()));
3971 } else {
3972 keyEvent->ignore();
3973 }
3974}
3975
3976/*!
3977 This event handler, for event \a mouseEvent, can be reimplemented
3978 in a subclass to receive mouse press events for the scene.
3979
3980 The default implementation depends on the state of the scene. If
3981 there is a mouse grabber item, then the event is sent to the mouse
3982 grabber. Otherwise, it is forwarded to the topmost item that
3983 accepts mouse events at the scene position from the event, and
3984 that item promptly becomes the mouse grabber item.
3985
3986 If there is no item at the given position on the scene, the
3987 selection area is reset, any focus item loses its input focus, and
3988 the event is then ignored.
3989
3990 \sa QGraphicsItem::mousePressEvent(),
3991 QGraphicsItem::setAcceptedMouseButtons()
3992*/
3993void QGraphicsScene::mousePressEvent(QGraphicsSceneMouseEvent *mouseEvent)
3994{
3995 Q_D(QGraphicsScene);
3996 if (d->mouseGrabberItems.isEmpty()) {
3997 // Dispatch hover events
3998 QGraphicsSceneHoverEvent hover;