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

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

Initially imported qt-all-opensource-src-4.5.1 from Trolltech.

File size: 192.6 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** Contact: Qt Software Information ([email protected])
5**
6** This file is part of the QtGui module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial Usage
10** Licensees holding valid Qt Commercial licenses may use this file in
11** accordance with the Qt Commercial License Agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Nokia.
14**
15** GNU Lesser General Public License Usage
16** Alternatively, this file may be used under the terms of the GNU Lesser
17** General Public License version 2.1 as published by the Free Software
18** Foundation and appearing in the file LICENSE.LGPL included in the
19** packaging of this file. Please review the following information to
20** ensure the GNU Lesser General Public License version 2.1 requirements
21** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
22**
23** In addition, as a special exception, Nokia gives you certain
24** additional rights. These rights are described in the Nokia Qt LGPL
25** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
26** 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 are unsure which license is appropriate for your use, please
37** contact the sales department at [email protected].
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42static const int QGRAPHICSSCENE_INDEXTIMER_TIMEOUT = 2000;
43
44/*!
45 \class QGraphicsScene
46 \brief The QGraphicsScene class provides a surface for managing a large
47 number of 2D graphical items.
48 \since 4.2
49 \ingroup multimedia
50 \ingroup graphicsview-api
51 \mainclass
52
53 The class serves as a container for QGraphicsItems. It is used together
54 with QGraphicsView for visualizing graphical items, such as lines,
55 rectangles, text, or even custom items, on a 2D surface. QGraphicsScene is
56 part of \l{The Graphics View Framework}.
57
58 QGraphicsScene also provides functionality that lets you efficiently
59 determine both the location of items, and for determining what items are
60 visible within an arbitrary area on the scene. With the QGraphicsView
61 widget, you can either visualize the whole scene, or zoom in and view only
62 parts of the scene.
63
64 Example:
65
66 \snippet doc/src/snippets/code/src_gui_graphicsview_qgraphicsscene.cpp 0
67
68 Note that QGraphicsScene has no visual appearance of its own; it only
69 manages the items. You need to create a QGraphicsView widget to visualize
70 the scene.
71
72 To add items to a scene, you start off by constructing a QGraphicsScene
73 object. Then, you have two options: either add your existing QGraphicsItem
74 objects by calling addItem(), or you can call one of the convenience
75 functions addEllipse(), addLine(), addPath(), addPixmap(), addPolygon(),
76 addRect(), or addText(), which all return a pointer to the newly added item.
77 The dimensions of the items added with these functions are relative to the
78 item's coordinate system, and the items position is initialized to (0,
79 0) in the scene.
80
81 You can then visualize the scene using QGraphicsView. When the scene
82 changes, (e.g., when an item moves or is transformed) QGraphicsScene
83 emits the changed() signal. To remove an item, call removeItem().
84
85 QGraphicsScene uses an indexing algorithm to manage the location of items
86 efficiently. By default, a BSP (Binary Space Partitioning) tree is used; an
87 algorithm suitable for large scenes where most items remain static (i.e.,
88 do not move around). You can choose to disable this index by calling
89 setItemIndexMethod(). For more information about the available indexing
90 algorithms, see the itemIndexMethod property.
91
92 The scene's bounding rect is set by calling setSceneRect(). Items can be
93 placed at any position on the scene, and the size of the scene is by
94 default unlimited. The scene rect is used only for internal bookkeeping,
95 maintaining the scene's item index. If the scene rect is unset,
96 QGraphicsScene will use the bounding area of all items, as returned by
97 itemsBoundingRect(), as the scene rect. However, itemsBoundingRect() is a
98 relatively time consuming function, as it operates by collecting
99 positional information for every item on the scene. Because of this, you
100 should always set the scene rect when operating on large scenes.
101
102 One of QGraphicsScene's greatest strengths is its ability to efficiently
103 determine the location of items. Even with millions of items on the scene,
104 the items() functions can determine the location of an item within few
105 milliseconds. There are several overloads to items(): one that finds items
106 at a certain position, one that finds items inside or intersecting with a
107 polygon or a rectangle, and more. The list of returned items is sorted by
108 stacking order, with the topmost item being the first item in the list.
109 For convenience, there is also an itemAt() function that returns the
110 topmost item at a given position.
111
112 QGraphicsScene maintains selection information for the scene. To select
113 items, call setSelectionArea(), and to clear the current selection, call
114 clearSelection(). Call selectedItems() to get the list of all selected
115 items.
116
117 \section1 Event Handling and Propagation
118
119 Another responsibility that QGraphicsScene has, is to propagate events
120 from QGraphicsView. To send an event to a scene, you construct an event
121 that inherits QEvent, and then send it using, for example,
122 QApplication::sendEvent(). event() is responsible for dispatching
123 the event to the individual items. Some common events are handled by
124 convenience event handlers. For example, key press events are handled by
125 keyPressEvent(), and mouse press events are handled by mousePressEvent().
126
127 Key events are delivered to the \e {focus item}. To set the focus item,
128 you can either call setFocusItem(), passing an item that accepts focus, or
129 the item itself can call QGraphicsItem::setFocus(). Call focusItem() to
130 get the current focus item. For compatibility with widgets, the scene also
131 maintains its own focus information. By default, the scene does not have
132 focus, and all key events are discarded. If setFocus() is called, or if an
133 item on the scene gains focus, the scene automatically gains focus. If the
134 scene has focus, hasFocus() will return true, and key events will be
135 forwarded to the focus item, if any. If the scene loses focus, (i.e.,
136 someone calls clearFocus(),) while an item has focus, the scene will
137 maintain its item focus information, and once the scene regains focus, it
138 will make sure the last focus item regains focus.
139
140 For mouse-over effects, QGraphicsScene dispatches \e {hover
141 events}. If an item accepts hover events (see
142 QGraphicsItem::acceptHoverEvents()), it will receive a \l
143 {QEvent::}{GraphicsSceneHoverEnter} event when the mouse enters
144 its area. As the mouse continues moving inside the item's area,
145 QGraphicsScene will send it \l {QEvent::}{GraphicsSceneHoverMove}
146 events. When the mouse leaves the item's area, the item will
147 receive a \l {QEvent::}{GraphicsSceneHoverLeave} event.
148
149 All mouse events are delivered to the current \e {mouse grabber}
150 item. An item becomes the scene's mouse grabber if it accepts
151 mouse events (see QGraphicsItem::acceptedMouseButtons()) and it
152 receives a mouse press. It stays the mouse grabber until it
153 receives a mouse release when no other mouse buttons are
154 pressed. You can call mouseGrabberItem() to determine what item is
155 currently grabbing the mouse.
156
157 \sa QGraphicsItem, QGraphicsView
158*/
159
160/*!
161 \enum QGraphicsScene::SceneLayer
162 \since 4.3
163
164 This enum describes the rendering layers in a QGraphicsScene. When
165 QGraphicsScene draws the scene contents, it renders each of these layers
166 separately, in order.
167
168 Each layer represents a flag that can be OR'ed together when calling
169 functions such as invalidate() or QGraphicsView::invalidateScene().
170
171 \value ItemLayer The item layer. QGraphicsScene renders all items are in
172 this layer by calling the virtual function drawItems(). The item layer is
173 drawn after the background layer, but before the foreground layer.
174
175 \value BackgroundLayer The background layer. QGraphicsScene renders the
176 scene's background in this layer by calling the virtual function
177 drawBackground(). The background layer is drawn first of all layers.
178
179 \value ForegroundLayer The foreground layer. QGraphicsScene renders the
180 scene's foreground in this layer by calling the virtual function
181 drawForeground(). The foreground layer is drawn last of all layers.
182
183 \value AllLayers All layers; this value represents a combination of all
184 three layers.
185
186 \sa invalidate(), QGraphicsView::invalidateScene()
187*/
188
189/*!
190 \enum QGraphicsScene::ItemIndexMethod
191
192 This enum describes the indexing algorithms QGraphicsScene provides for
193 managing positional information about items on the scene.
194
195 \value BspTreeIndex A Binary Space Partitioning tree is applied. All
196 QGraphicsScene's item location algorithms are of an order close to
197 logarithmic complexity, by making use of binary search. Adding, moving and
198 removing items is logarithmic. This approach is best for static scenes
199 (i.e., scenes where most items do not move).
200
201 \value NoIndex No index is applied. Item location is of linear complexity,
202 as all items on the scene are searched. Adding, moving and removing items,
203 however, is done in constant time. This approach is ideal for dynamic
204 scenes, where many items are added, moved or removed continuously.
205
206 \sa setItemIndexMethod(), bspTreeDepth
207*/
208
209#include "qgraphicsscene.h"
210
211#ifndef QT_NO_GRAPHICSVIEW
212
213#include "qgraphicsitem.h"
214#include "qgraphicsitem_p.h"
215#include "qgraphicslayout.h"
216#include "qgraphicsscene_p.h"
217#include "qgraphicssceneevent.h"
218#include "qgraphicsview.h"
219#include "qgraphicsview_p.h"
220#include "qgraphicswidget.h"
221#include "qgraphicswidget_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 <private/qapplication_p.h>
246#include <private/qobject_p.h>
247#ifdef Q_WS_X11
248#include <private/qt_x11_p.h>
249#endif
250
251QT_BEGIN_NAMESPACE
252
253static inline bool QRectF_intersects(const QRectF &s, const QRectF &r)
254{
255 qreal xp = s.left();
256 qreal yp = s.top();
257 qreal w = s.width();
258 qreal h = s.height();
259 qreal l1 = xp;
260 qreal r1 = xp;
261 if (w < 0)
262 l1 += w;
263 else
264 r1 += w;
265
266 qreal l2 = r.left();
267 qreal r2 = r.left();
268 if (w < 0)
269 l2 += r.width();
270 else
271 r2 += r.width();
272
273 if (l1 >= r2 || l2 >= r1)
274 return false;
275
276 qreal t1 = yp;
277 qreal b1 = yp;
278 if (h < 0)
279 t1 += h;
280 else
281 b1 += h;
282
283 qreal t2 = r.top();
284 qreal b2 = r.top();
285 if (r.height() < 0)
286 t2 += r.height();
287 else
288 b2 += r.height();
289
290 return !(t1 >= b2 || t2 >= b1);
291}
292
293// QRectF::intersects() returns false always if either the source or target
294// rectangle's width or height are 0. This works around that problem.
295static inline void _q_adjustRect(QRectF *rect)
296{
297 Q_ASSERT(rect);
298 if (!rect->width())
299 rect->adjust(-0.00001, 0, 0.00001, 0);
300 if (!rect->height())
301 rect->adjust(0, -0.00001, 0, 0.00001);
302}
303
304static inline QRectF adjustedItemBoundingRect(const QGraphicsItem *item)
305{
306 Q_ASSERT(item);
307 QRectF boundingRect(item->boundingRect());
308 _q_adjustRect(&boundingRect);
309 return boundingRect;
310}
311
312static void _q_hoverFromMouseEvent(QGraphicsSceneHoverEvent *hover, const QGraphicsSceneMouseEvent *mouseEvent)
313{
314 hover->setWidget(mouseEvent->widget());
315 hover->setPos(mouseEvent->pos());
316 hover->setScenePos(mouseEvent->scenePos());
317 hover->setScreenPos(mouseEvent->screenPos());
318 hover->setLastPos(mouseEvent->lastPos());
319 hover->setLastScenePos(mouseEvent->lastScenePos());
320 hover->setLastScreenPos(mouseEvent->lastScreenPos());
321 hover->setModifiers(mouseEvent->modifiers());
322 hover->setAccepted(mouseEvent->isAccepted());
323}
324
325/*!
326 \internal
327*/
328QGraphicsScenePrivate::QGraphicsScenePrivate()
329 : changedSignalMask(0),
330 indexMethod(QGraphicsScene::BspTreeIndex),
331 bspTreeDepth(0),
332 lastItemCount(0),
333 hasSceneRect(false),
334 updateAll(false),
335 calledEmitUpdated(false),
336 selectionChanging(0),
337 dirtyItemResetPending(false),
338 regenerateIndex(true),
339 purgePending(false),
340 indexTimerId(0),
341 restartIndexTimer(false),
342 stickyFocus(false),
343 hasFocus(false),
344 focusItem(0),
345 lastFocusItem(0),
346 tabFocusFirst(0),
347 activeWindow(0),
348 activationRefCount(0),
349 lastMouseGrabberItem(0),
350 lastMouseGrabberItemHasImplicitMouseGrab(false),
351 dragDropItem(0),
352 enterWidget(0),
353 lastDropAction(Qt::IgnoreAction),
354 painterStateProtection(true),
355 sortCacheEnabled(false),
356 updatingSortCache(false),
357 style(0)
358{
359}
360
361/*!
362 \internal
363*/
364void QGraphicsScenePrivate::init()
365{
366 Q_Q(QGraphicsScene);
367
368 // Keep this index so we can check for connected slots later on.
369 changedSignalMask = (1 << q->metaObject()->indexOfSignal("changed(QList<QRectF>)"));
370 qApp->d_func()->scene_list.append(q);
371 q->update();
372}
373
374/*!
375 \internal
376*/
377QList<QGraphicsItem *> QGraphicsScenePrivate::estimateItemsInRect(const QRectF &rect) const
378{
379 const_cast<QGraphicsScenePrivate *>(this)->purgeRemovedItems();
380 const_cast<QGraphicsScenePrivate *>(this)->_q_updateSortCache();
381
382 if (indexMethod == QGraphicsScene::BspTreeIndex) {
383 // ### Only do this once in a while.
384 QGraphicsScenePrivate *that = const_cast<QGraphicsScenePrivate *>(this);
385
386 // Get items from BSP tree
387 QList<QGraphicsItem *> items = that->bspTree.items(rect);
388
389 // Fill in with any unindexed items
390 for (int i = 0; i < unindexedItems.size(); ++i) {
391 if (QGraphicsItem *item = unindexedItems.at(i)) {
392 if (!item->d_ptr->itemDiscovered && item->d_ptr->visible && !(item->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren)) {
393 QRectF boundingRect = item->sceneBoundingRect();
394 if (QRectF_intersects(boundingRect, rect)) {
395 item->d_ptr->itemDiscovered = 1;
396 items << item;
397 }
398 }
399 }
400 }
401
402 // Reset the discovered state of all discovered items
403 for (int i = 0; i < items.size(); ++i)
404 items.at(i)->d_func()->itemDiscovered = 0;
405 return items;
406 }
407
408 QList<QGraphicsItem *> itemsInRect;
409 for (int i = 0; i < unindexedItems.size(); ++i) {
410 if (QGraphicsItem *item = unindexedItems.at(i)) {
411 if (item->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren)
412 continue;
413 if (item->d_ptr->visible && item->effectiveOpacity() > qreal(0.0))
414 itemsInRect << item;
415 }
416 }
417 for (int i = 0; i < indexedItems.size(); ++i) {
418 if (QGraphicsItem *item = indexedItems.at(i)) {
419 if (item->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren)
420 continue;
421 if (item->d_ptr->visible && item->effectiveOpacity() > qreal(0.0))
422 itemsInRect << item;
423 }
424 }
425
426 return itemsInRect;
427}
428
429/*!
430 \internal
431*/
432void QGraphicsScenePrivate::addToIndex(QGraphicsItem *item)
433{
434 if (indexMethod == QGraphicsScene::BspTreeIndex) {
435 if (item->d_func()->index != -1) {
436 bspTree.insertItem(item, item->sceneBoundingRect());
437 foreach (QGraphicsItem *child, item->children())
438 child->addToIndex();
439 } else {
440 // The BSP tree is regenerated if the number of items grows to a
441 // certain threshold, or if the bounding rect of the graph doubles in
442 // size.
443 startIndexTimer();
444 }
445 }
446}
447
448/*!
449 \internal
450*/
451void QGraphicsScenePrivate::removeFromIndex(QGraphicsItem *item)
452{
453 if (indexMethod == QGraphicsScene::BspTreeIndex) {
454 int index = item->d_func()->index;
455 if (index != -1) {
456 bspTree.removeItem(item, item->sceneBoundingRect());
457 freeItemIndexes << index;
458 indexedItems[index] = 0;
459 item->d_func()->index = -1;
460 unindexedItems << item;
461
462 foreach (QGraphicsItem *child, item->children())
463 child->removeFromIndex();
464 }
465
466 startIndexTimer();
467 }
468}
469
470/*!
471 \internal
472*/
473void QGraphicsScenePrivate::resetIndex()
474{
475 purgeRemovedItems();
476 if (indexMethod == QGraphicsScene::BspTreeIndex) {
477 for (int i = 0; i < indexedItems.size(); ++i) {
478 if (QGraphicsItem *item = indexedItems.at(i)) {
479 item->d_ptr->index = -1;
480 unindexedItems << item;
481 }
482 }
483 indexedItems.clear();
484 freeItemIndexes.clear();
485 regenerateIndex = true;
486 startIndexTimer();
487 }
488}
489
490static inline int intmaxlog(int n)
491{
492 return (n > 0 ? qMax(qCeil(qLn(qreal(n)) / qLn(qreal(2))), 5) : 0);
493}
494
495/*!
496 \internal
497*/
498void QGraphicsScenePrivate::_q_updateIndex()
499{
500 if (!indexTimerId)
501 return;
502
503 Q_Q(QGraphicsScene);
504 q->killTimer(indexTimerId);
505 indexTimerId = 0;
506
507 purgeRemovedItems();
508
509 // Add unindexedItems to indexedItems
510 QRectF unindexedItemsBoundingRect;
511 for (int i = 0; i < unindexedItems.size(); ++i) {
512 if (QGraphicsItem *item = unindexedItems.at(i)) {
513 unindexedItemsBoundingRect |= item->sceneBoundingRect();
514 if (!freeItemIndexes.isEmpty()) {
515 int freeIndex = freeItemIndexes.takeFirst();
516 item->d_func()->index = freeIndex;
517 indexedItems[freeIndex] = item;
518 } else {
519 item->d_func()->index = indexedItems.size();
520 indexedItems << item;
521 }
522 }
523 }
524
525 // Update growing scene rect.
526 QRectF oldGrowingItemsBoundingRect = growingItemsBoundingRect;
527 growingItemsBoundingRect |= unindexedItemsBoundingRect;
528
529 // Determine whether we should regenerate the BSP tree.
530 if (indexMethod == QGraphicsScene::BspTreeIndex) {
531 int depth = bspTreeDepth;
532 if (depth == 0) {
533 int oldDepth = intmaxlog(lastItemCount);
534 depth = intmaxlog(indexedItems.size());
535 static const int slack = 100;
536 if (bspTree.leafCount() == 0 || (oldDepth != depth && qAbs(lastItemCount - indexedItems.size()) > slack)) {
537 // ### Crude algorithm.
538 regenerateIndex = true;
539 }
540 }
541
542 // Regenerate the tree.
543 if (regenerateIndex) {
544 regenerateIndex = false;
545 bspTree.initialize(q->sceneRect(), depth);
546 unindexedItems = indexedItems;
547 lastItemCount = indexedItems.size();
548 q->update();
549
550 // Take this opportunity to reset our largest-item counter for
551 // untransformable items. When the items are inserted into the BSP
552 // tree, we'll get an accurate calculation.
553 largestUntransformableItem = QRectF();
554 }
555 }
556
557 // Insert all unindexed items into the tree.
558 for (int i = 0; i < unindexedItems.size(); ++i) {
559 if (QGraphicsItem *item = unindexedItems.at(i)) {
560 QRectF rect = item->sceneBoundingRect();
561 if (item->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren)
562 continue;
563 if (indexMethod == QGraphicsScene::BspTreeIndex)
564 bspTree.insertItem(item, rect);
565
566 // If the item ignores view transformations, update our
567 // largest-item-counter to ensure that the view can accurately
568 // discover untransformable items when drawing.
569 if (item->d_ptr->itemIsUntransformable()) {
570 QGraphicsItem *topmostUntransformable = item;
571 while (topmostUntransformable && (topmostUntransformable->d_ptr->ancestorFlags
572 & QGraphicsItemPrivate::AncestorIgnoresTransformations)) {
573 topmostUntransformable = topmostUntransformable->parentItem();
574 }
575 // ### Verify that this is the correct largest untransformable rectangle.
576 largestUntransformableItem |= item->mapToItem(topmostUntransformable, item->boundingRect()).boundingRect();
577 }
578 }
579 }
580 unindexedItems.clear();
581
582 // Notify scene rect changes.
583 if (!hasSceneRect && growingItemsBoundingRect != oldGrowingItemsBoundingRect)
584 emit q->sceneRectChanged(growingItemsBoundingRect);
585}
586
587/*!
588 \internal
589*/
590void QGraphicsScenePrivate::_q_emitUpdated()
591{
592 Q_Q(QGraphicsScene);
593 calledEmitUpdated = false;
594
595 // Ensure all views are connected if anything is connected. This disables
596 // the optimization that items send updates directly to the views, but it
597 // needs to happen in order to keep compatibility with the behavior from
598 // Qt 4.4 and backward.
599 if (!views.isEmpty() && (connectedSignals & changedSignalMask)) {
600 for (int i = 0; i < views.size(); ++i) {
601 QGraphicsView *view = views.at(i);
602 if (!view->d_func()->connectedToScene) {
603 view->d_func()->connectedToScene = true;
604 q->connect(q, SIGNAL(changed(QList<QRectF>)),
605 views.at(i), SLOT(updateScene(QList<QRectF>)));
606 }
607 }
608 }
609
610 // Ensure all dirty items's current positions are recorded in the list of
611 // updated rects.
612 for (int i = 0; i < dirtyItems.size(); ++i)
613 updatedRects += dirtyItems.at(i)->sceneBoundingRect();
614
615 // Notify the changes to anybody interested.
616 QList<QRectF> oldUpdatedRects;
617 oldUpdatedRects = updateAll ? (QList<QRectF>() << q->sceneRect()) : updatedRects;
618 updateAll = false;
619 updatedRects.clear();
620 emit q->changed(oldUpdatedRects);
621}
622
623/*!
624 \internal
625
626 Updates all items in the pending update list. At this point, the list is
627 unlikely to contain partially constructed items.
628*/
629void QGraphicsScenePrivate::_q_updateLater()
630{
631 foreach (QGraphicsItem *item, pendingUpdateItems)
632 item->update();
633 pendingUpdateItems.clear();
634}
635
636/*!
637 \internal
638*/
639void QGraphicsScenePrivate::_q_polishItems()
640{
641 const QVariant booleanTrueVariant(true);
642 foreach (QGraphicsItem *item, unpolishedItems) {
643 if (!item->d_ptr->explicitlyHidden) {
644 item->itemChange(QGraphicsItem::ItemVisibleChange, booleanTrueVariant);
645 item->itemChange(QGraphicsItem::ItemVisibleHasChanged, booleanTrueVariant);
646 }
647 if (item->isWidget()) {
648 QEvent event(QEvent::Polish);
649 QApplication::sendEvent((QGraphicsWidget *)item, &event);
650 }
651 }
652 unpolishedItems.clear();
653}
654
655/*!
656 \internal
657*/
658void QGraphicsScenePrivate::_q_resetDirtyItems()
659{
660 for (int i = 0; i < dirtyItems.size(); ++i) {
661 QGraphicsItem *item = dirtyItems.at(i);
662 item->d_ptr->dirty = 0;
663 item->d_ptr->dirtyChildren = 0;
664 }
665 dirtyItems.clear();
666 dirtyItemResetPending = false;
667}
668
669/*!
670 \internal
671*/
672void QGraphicsScenePrivate::resetDirtyItemsLater()
673{
674 Q_Q(QGraphicsScene);
675 if (dirtyItemResetPending)
676 return;
677 // dirtyItems.reserve(indexedItems.size() + unindexedItems.size());
678 dirtyItemResetPending = true;
679 QMetaObject::invokeMethod(q, "_q_resetDirtyItems", Qt::QueuedConnection);
680}
681
682/*!
683 \internal
684
685 Schedules an item for removal. This function leaves some stale indexes
686 around in the BSP tree; these will be cleaned up the next time someone
687 triggers purgeRemovedItems().
688
689 Note: This function is called from QGraphicsItem's destructor. \a item is
690 being destroyed, so we cannot call any pure virtual functions on it (such
691 as boundingRect()). Also, it is unnecessary to update the item's own state
692 in any way.
693
694 ### Refactoring: This function shares much functionality with removeItem()
695*/
696void QGraphicsScenePrivate::_q_removeItemLater(QGraphicsItem *item)
697{
698 Q_Q(QGraphicsScene);
699
700 // Clear focus on the item to remove any reference in the focusWidget
701 // chain.
702 item->clearFocus();
703
704 int index = item->d_func()->index;
705 if (index != -1) {
706 // Important: The index is useless until purgeRemovedItems() is
707 // called.
708 indexedItems[index] = (QGraphicsItem *)0;
709 if (!purgePending) {
710 purgePending = true;
711 q->update();
712 }
713 removedItems << item;
714 } else {
715 // Recently added items are purged immediately. unindexedItems() never
716 // contains stale items.
717 unindexedItems.removeAll(item);
718 q->update();
719 }
720
721 // Reset the mouse grabber and focus item data.
722 if (item == focusItem)
723 focusItem = 0;
724 if (item == lastFocusItem)
725 lastFocusItem = 0;
726 if (item == activeWindow) {
727 // ### deactivate...
728 activeWindow = 0;
729 }
730
731 // Disable selectionChanged() for individual items
732 ++selectionChanging;
733 int oldSelectedItemsSize = selectedItems.size();
734
735 // Update selected & hovered item bookkeeping
736 selectedItems.remove(item);
737 hoverItems.removeAll(item);
738 pendingUpdateItems.removeAll(item);
739 cachedItemsUnderMouse.removeAll(item);
740 unpolishedItems.removeAll(item);
741 dirtyItems.removeAll(item);
742
743 //We remove all references of item from the sceneEventFilter arrays
744 QMultiMap<QGraphicsItem*, QGraphicsItem*>::iterator iterator = sceneEventFilters.begin();
745 while (iterator != sceneEventFilters.end()) {
746 if (iterator.value() == item || iterator.key() == item)
747 iterator = sceneEventFilters.erase(iterator);
748 else
749 ++iterator;
750 }
751
752 // Remove from scene transform cache
753 int transformIndex = item->d_func()->sceneTransformIndex;
754 if (transformIndex != -1) {
755 validTransforms.setBit(transformIndex, 0);
756 freeSceneTransformSlots.append(transformIndex);
757 }
758
759 // Remove all children recursively.
760 foreach (QGraphicsItem *child, item->children())
761 _q_removeItemLater(child);
762
763 // Reset the mouse grabber
764 if (mouseGrabberItems.contains(item))
765 ungrabMouse(item, /* item is dying */ true);
766
767 // Reset the keyboard grabber
768 if (keyboardGrabberItems.contains(item))
769 ungrabKeyboard(item, /* item is dying */ true);
770
771 // Reset the last mouse grabber item
772 if (item == lastMouseGrabberItem)
773 lastMouseGrabberItem = 0;
774
775 // Reenable selectionChanged() for individual items
776 --selectionChanging;
777 if (!selectionChanging && selectedItems.size() != oldSelectedItemsSize)
778 emit q->selectionChanged();
779}
780
781/*!
782 \internal
783
784 Removes stale pointers from all data structures.
785*/
786void QGraphicsScenePrivate::purgeRemovedItems()
787{
788 Q_Q(QGraphicsScene);
789
790 if (!purgePending && removedItems.isEmpty())
791 return;
792
793 // Remove stale items from the BSP tree.
794 if (indexMethod != QGraphicsScene::NoIndex)
795 bspTree.removeItems(removedItems);
796
797 // Purge this list.
798 removedItems.clear();
799 freeItemIndexes.clear();
800 for (int i = 0; i < indexedItems.size(); ++i) {
801 if (!indexedItems.at(i))
802 freeItemIndexes << i;
803 }
804 purgePending = false;
805
806 // No locality info for the items; update the whole scene.
807 q->update();
808}
809
810/*!
811 \internal
812
813 Starts or restarts the timer used for reindexing unindexed items.
814*/
815void QGraphicsScenePrivate::startIndexTimer()
816{
817 Q_Q(QGraphicsScene);
818 if (indexTimerId) {
819 restartIndexTimer = true;
820 } else {
821 indexTimerId = q->startTimer(QGRAPHICSSCENE_INDEXTIMER_TIMEOUT);
822 }
823}
824
825/*!
826 \internal
827*/
828void QGraphicsScenePrivate::addPopup(QGraphicsWidget *widget)
829{
830 Q_ASSERT(widget);
831 Q_ASSERT(!popupWidgets.contains(widget));
832 popupWidgets << widget;
833 if (QGraphicsWidget *focusWidget = widget->focusWidget()) {
834 focusWidget->setFocus(Qt::PopupFocusReason);
835 } else {
836 grabKeyboard((QGraphicsItem *)widget);
837 if (focusItem && popupWidgets.size() == 1) {
838 QFocusEvent event(QEvent::FocusOut, Qt::PopupFocusReason);
839 sendEvent(focusItem, &event);
840 }
841 }
842 grabMouse((QGraphicsItem *)widget);
843}
844
845/*!
846 \internal
847
848 Remove \a widget from the popup list. Important notes:
849
850 \a widget is guaranteed to be in the list of popups, but it might not be
851 the last entry; you can hide any item in the pop list before the others,
852 and this must cause all later mouse grabbers to lose the grab.
853*/
854void QGraphicsScenePrivate::removePopup(QGraphicsWidget *widget, bool itemIsDying)
855{
856 Q_ASSERT(widget);
857 int index = popupWidgets.indexOf(widget);
858 Q_ASSERT(index != -1);
859
860 for (int i = popupWidgets.size() - 1; i >= index; --i) {
861 QGraphicsWidget *widget = popupWidgets.takeLast();
862 ungrabMouse(widget, itemIsDying);
863 if (focusItem && popupWidgets.isEmpty()) {
864 QFocusEvent event(QEvent::FocusIn, Qt::PopupFocusReason);
865 sendEvent(focusItem, &event);
866 } else {
867 ungrabKeyboard((QGraphicsItem *)widget, itemIsDying);
868 }
869 if (!itemIsDying && widget->isVisible()) {
870 widget->hide();
871 widget->QGraphicsItem::d_ptr->explicitlyHidden = 0;
872 }
873 }
874}
875
876/*!
877 \internal
878*/
879void QGraphicsScenePrivate::grabMouse(QGraphicsItem *item, bool implicit)
880{
881 // Append to list of mouse grabber items, and send a mouse grab event.
882 if (mouseGrabberItems.contains(item)) {
883 if (mouseGrabberItems.last() == item)
884 qWarning("QGraphicsItem::grabMouse: already a mouse grabber");
885 else
886 qWarning("QGraphicsItem::grabMouse: already blocked by mouse grabber: %p",
887 mouseGrabberItems.last());
888 return;
889 }
890
891 // Send ungrab event to the last grabber.
892 if (!mouseGrabberItems.isEmpty()) {
893 QGraphicsItem *last = mouseGrabberItems.last();
894 if (lastMouseGrabberItemHasImplicitMouseGrab) {
895 // Implicit mouse grab is immediately lost.
896 last->ungrabMouse();
897 } else {
898 // Just send ungrab event to current grabber.
899 QEvent ungrabEvent(QEvent::UngrabMouse);
900 sendEvent(last, &ungrabEvent);
901 }
902 }
903
904 mouseGrabberItems << item;
905 lastMouseGrabberItemHasImplicitMouseGrab = implicit;
906
907 // Send grab event to current grabber.
908 QEvent grabEvent(QEvent::GrabMouse);
909 sendEvent(item, &grabEvent);
910}
911
912/*!
913 \internal
914*/
915void QGraphicsScenePrivate::ungrabMouse(QGraphicsItem *item, bool itemIsDying)
916{
917 int index = mouseGrabberItems.indexOf(item);
918 if (index == -1) {
919 qWarning("QGraphicsItem::ungrabMouse: not a mouse grabber");
920 return;
921 }
922
923 if (item != mouseGrabberItems.last()) {
924 // Recursively ungrab the next mouse grabber until we reach this item
925 // to ensure state consistency.
926 ungrabMouse(mouseGrabberItems.at(index + 1), itemIsDying);
927 }
928 if (!popupWidgets.isEmpty() && item == popupWidgets.last()) {
929 // If the item is a popup, go via removePopup to ensure state
930 // consistency and that it gets hidden correctly - beware that
931 // removePopup() reenters this function to continue removing the grab.
932 removePopup((QGraphicsWidget *)item, itemIsDying);
933 return;
934 }
935
936 // Send notification about mouse ungrab.
937 if (!itemIsDying) {
938 QEvent event(QEvent::UngrabMouse);
939 sendEvent(item, &event);
940 }
941
942 // Remove the item from the list of grabbers. Whenever this happens, we
943 // reset the implicitGrab (there can be only ever be one implicit grabber
944 // in a scene, and it is always the latest grabber; if the implicit grab
945 // is lost, it is not automatically regained.
946 mouseGrabberItems.takeLast();
947 lastMouseGrabberItemHasImplicitMouseGrab = false;
948
949 // Send notification about mouse regrab. ### It's unfortunate that all the
950 // items get a GrabMouse event, but this is a rare case with a simple
951 // implementation and it does ensure a consistent state.
952 if (!itemIsDying && !mouseGrabberItems.isEmpty()) {
953 QGraphicsItem *last = mouseGrabberItems.last();
954 QEvent event(QEvent::GrabMouse);
955 sendEvent(last, &event);
956 }
957}
958
959/*!
960 \internal
961*/
962void QGraphicsScenePrivate::clearMouseGrabber()
963{
964 if (!mouseGrabberItems.isEmpty())
965 mouseGrabberItems.first()->ungrabMouse();
966 lastMouseGrabberItem = 0;
967}
968
969/*!
970 \internal
971*/
972void QGraphicsScenePrivate::grabKeyboard(QGraphicsItem *item)
973{
974 if (keyboardGrabberItems.contains(item)) {
975 if (keyboardGrabberItems.last() == item)
976 qWarning("QGraphicsItem::grabKeyboard: already a keyboard grabber");
977 else
978 qWarning("QGraphicsItem::grabKeyboard: already blocked by keyboard grabber: %p",
979 keyboardGrabberItems.last());
980 return;
981 }
982
983 // Send ungrab event to the last grabber.
984 if (!keyboardGrabberItems.isEmpty()) {
985 // Just send ungrab event to current grabber.
986 QEvent ungrabEvent(QEvent::UngrabKeyboard);
987 sendEvent(keyboardGrabberItems.last(), &ungrabEvent);
988 }
989
990 keyboardGrabberItems << item;
991
992 // Send grab event to current grabber.
993 QEvent grabEvent(QEvent::GrabKeyboard);
994 sendEvent(item, &grabEvent);
995}
996
997/*!
998 \internal
999*/
1000void QGraphicsScenePrivate::ungrabKeyboard(QGraphicsItem *item, bool itemIsDying)
1001{
1002 int index = keyboardGrabberItems.lastIndexOf(item);
1003 if (index == -1) {
1004 qWarning("QGraphicsItem::ungrabKeyboard: not a keyboard grabber");
1005 return;
1006 }
1007 if (item != keyboardGrabberItems.last()) {
1008 // Recursively ungrab the topmost keyboard grabber until we reach this
1009 // item to ensure state consistency.
1010 ungrabKeyboard(keyboardGrabberItems.at(index + 1), itemIsDying);
1011 }
1012
1013 // Send notification about keyboard ungrab.
1014 if (!itemIsDying) {
1015 QEvent event(QEvent::UngrabKeyboard);
1016 sendEvent(item, &event);
1017 }
1018
1019 // Remove the item from the list of grabbers.
1020 keyboardGrabberItems.takeLast();
1021
1022 // Send notification about mouse regrab.
1023 if (!itemIsDying && !keyboardGrabberItems.isEmpty()) {
1024 QGraphicsItem *last = keyboardGrabberItems.last();
1025 QEvent event(QEvent::GrabKeyboard);
1026 sendEvent(last, &event);
1027 }
1028}
1029
1030/*!
1031 \internal
1032*/
1033void QGraphicsScenePrivate::clearKeyboardGrabber()
1034{
1035 if (!keyboardGrabberItems.isEmpty())
1036 ungrabKeyboard(keyboardGrabberItems.first());
1037}
1038
1039/*!
1040 Returns all items for the screen position in \a event.
1041*/
1042QList<QGraphicsItem *> QGraphicsScenePrivate::itemsAtPosition(const QPoint &screenPos,
1043 const QPointF &scenePos,
1044 QWidget *widget) const
1045{
1046 Q_Q(const QGraphicsScene);
1047 QGraphicsView *view = widget ? qobject_cast<QGraphicsView *>(widget->parentWidget()) : 0;
1048 QList<QGraphicsItem *> items;
1049 if (view)
1050 items = view->items(view->viewport()->mapFromGlobal(screenPos));
1051 else
1052 items = q->items(scenePos);
1053 return items;
1054}
1055
1056/*!
1057 \internal
1058
1059 Checks if item collides with the path and mode, but also checks that if it
1060 doesn't collide, maybe its frame rect will.
1061*/
1062bool QGraphicsScenePrivate::itemCollidesWithPath(QGraphicsItem *item,
1063 const QPainterPath &path,
1064 Qt::ItemSelectionMode mode)
1065{
1066 if (item->collidesWithPath(path, mode))
1067 return true;
1068 if (item->isWidget()) {
1069 // Check if this is a window, and if its frame rect collides.
1070 QGraphicsWidget *widget = static_cast<QGraphicsWidget *>(item);
1071 if (widget->isWindow()) {
1072 QRectF frameRect = widget->windowFrameRect();
1073 QPainterPath framePath;
1074 framePath.addRect(frameRect);
1075 bool intersects = path.intersects(frameRect);
1076 if (mode == Qt::IntersectsItemShape || mode == Qt::IntersectsItemBoundingRect)
1077 return intersects || path.contains(frameRect.topLeft())
1078 || framePath.contains(path.elementAt(0));
1079 return !intersects && path.contains(frameRect.topLeft());
1080 }
1081 }
1082 return false;
1083}
1084
1085/*!
1086 \internal
1087*/
1088void QGraphicsScenePrivate::storeMouseButtonsForMouseGrabber(QGraphicsSceneMouseEvent *event)
1089{
1090 for (int i = 0x1; i <= 0x10; i <<= 1) {
1091 if (event->buttons() & i) {
1092 mouseGrabberButtonDownPos.insert(Qt::MouseButton(i),
1093 mouseGrabberItems.last()->d_ptr->genericMapFromScene(event->scenePos(),
1094 event->widget()));
1095 mouseGrabberButtonDownScenePos.insert(Qt::MouseButton(i), event->scenePos());
1096 mouseGrabberButtonDownScreenPos.insert(Qt::MouseButton(i), event->screenPos());
1097 }
1098 }
1099}
1100
1101/*!
1102 \internal
1103*/
1104void QGraphicsScenePrivate::installSceneEventFilter(QGraphicsItem *watched, QGraphicsItem *filter)
1105{
1106 sceneEventFilters.insert(watched, filter);
1107}
1108
1109/*!
1110 \internal
1111*/
1112void QGraphicsScenePrivate::removeSceneEventFilter(QGraphicsItem *watched, QGraphicsItem *filter)
1113{
1114 if (!sceneEventFilters.contains(watched))
1115 return;
1116
1117 QMultiMap<QGraphicsItem *, QGraphicsItem *>::Iterator it = sceneEventFilters.lowerBound(watched);
1118 QMultiMap<QGraphicsItem *, QGraphicsItem *>::Iterator end = sceneEventFilters.upperBound(watched);
1119 do {
1120 if (it.value() == filter)
1121 it = sceneEventFilters.erase(it);
1122 else
1123 ++it;
1124 } while (it != end);
1125}
1126
1127/*!
1128 \internal
1129*/
1130bool QGraphicsScenePrivate::filterEvent(QGraphicsItem *item, QEvent *event)
1131{
1132 if (item && !sceneEventFilters.contains(item))
1133 return false;
1134
1135 QMultiMap<QGraphicsItem *, QGraphicsItem *>::Iterator it = sceneEventFilters.lowerBound(item);
1136 QMultiMap<QGraphicsItem *, QGraphicsItem *>::Iterator end = sceneEventFilters.upperBound(item);
1137 while (it != end) {
1138 // ### The filterer and filteree might both be deleted.
1139 if (it.value()->sceneEventFilter(it.key(), event))
1140 return true;
1141 ++it;
1142 }
1143 return false;
1144}
1145
1146/*!
1147 \internal
1148
1149 This is the final dispatch point for any events from the scene to the
1150 item. It filters the event first - if the filter returns true, the event
1151 is considered to have been eaten by the filter, and is therefore stopped
1152 (the default filter returns false). Then/otherwise, if the item is
1153 enabled, the event is sent; otherwise it is stopped.
1154*/
1155bool QGraphicsScenePrivate::sendEvent(QGraphicsItem *item, QEvent *event)
1156{
1157 if (filterEvent(item, event))
1158 return false;
1159 return (item && item->isEnabled()) ? item->sceneEvent(event) : false;
1160}
1161
1162/*!
1163 \internal
1164*/
1165void QGraphicsScenePrivate::cloneDragDropEvent(QGraphicsSceneDragDropEvent *dest,
1166 QGraphicsSceneDragDropEvent *source)
1167{
1168 dest->setWidget(source->widget());
1169 dest->setPos(source->pos());
1170 dest->setScenePos(source->scenePos());
1171 dest->setScreenPos(source->screenPos());
1172 dest->setButtons(source->buttons());
1173 dest->setModifiers(source->modifiers());
1174 dest->setPossibleActions(source->possibleActions());
1175 dest->setProposedAction(source->proposedAction());
1176 dest->setDropAction(source->dropAction());
1177 dest->setSource(source->source());
1178 dest->setMimeData(source->mimeData());
1179}
1180
1181/*!
1182 \internal
1183*/
1184void QGraphicsScenePrivate::sendDragDropEvent(QGraphicsItem *item,
1185 QGraphicsSceneDragDropEvent *dragDropEvent)
1186{
1187 dragDropEvent->setPos(item->d_ptr->genericMapFromScene(dragDropEvent->scenePos(), dragDropEvent->widget()));
1188 sendEvent(item, dragDropEvent);
1189}
1190
1191/*!
1192 \internal
1193*/
1194void QGraphicsScenePrivate::sendHoverEvent(QEvent::Type type, QGraphicsItem *item,
1195 QGraphicsSceneHoverEvent *hoverEvent)
1196{
1197 QGraphicsSceneHoverEvent event(type);
1198 event.setWidget(hoverEvent->widget());
1199 event.setPos(item->d_ptr->genericMapFromScene(hoverEvent->scenePos(), hoverEvent->widget()));
1200 event.setScenePos(hoverEvent->scenePos());
1201 event.setScreenPos(hoverEvent->screenPos());
1202 event.setLastPos(item->d_ptr->genericMapFromScene(hoverEvent->lastScenePos(), hoverEvent->widget()));
1203 event.setLastScenePos(hoverEvent->lastScenePos());
1204 event.setLastScreenPos(hoverEvent->lastScreenPos());
1205 event.setModifiers(hoverEvent->modifiers());
1206 sendEvent(item, &event);
1207}
1208
1209/*!
1210 \internal
1211*/
1212void QGraphicsScenePrivate::sendMouseEvent(QGraphicsSceneMouseEvent *mouseEvent)
1213{
1214 if (mouseEvent->button() == 0 && mouseEvent->buttons() == 0 && lastMouseGrabberItemHasImplicitMouseGrab) {
1215 // ### This is a temporary fix for until we get proper mouse
1216 // grab events.
1217 clearMouseGrabber();
1218 return;
1219 }
1220
1221 QGraphicsItem *item = mouseGrabberItems.last();
1222 for (int i = 0x1; i <= 0x10; i <<= 1) {
1223 Qt::MouseButton button = Qt::MouseButton(i);
1224 mouseEvent->setButtonDownPos(button, mouseGrabberButtonDownPos.value(button, item->d_ptr->genericMapFromScene(mouseEvent->scenePos(), mouseEvent->widget())));
1225 mouseEvent->setButtonDownScenePos(button, mouseGrabberButtonDownScenePos.value(button, mouseEvent->scenePos()));
1226 mouseEvent->setButtonDownScreenPos(button, mouseGrabberButtonDownScreenPos.value(button, mouseEvent->screenPos()));
1227 }
1228 mouseEvent->setPos(item->d_ptr->genericMapFromScene(mouseEvent->scenePos(), mouseEvent->widget()));
1229 mouseEvent->setLastPos(item->d_ptr->genericMapFromScene(mouseEvent->lastScenePos(), mouseEvent->widget()));
1230 sendEvent(item, mouseEvent);
1231}
1232
1233/*!
1234 \internal
1235*/
1236void QGraphicsScenePrivate::mousePressEventHandler(QGraphicsSceneMouseEvent *mouseEvent)
1237{
1238 Q_Q(QGraphicsScene);
1239
1240 // Ignore by default, unless we find a mouse grabber that accepts it.
1241 mouseEvent->ignore();
1242
1243 // Deliver to any existing mouse grabber.
1244 if (!mouseGrabberItems.isEmpty()) {
1245 // The event is ignored by default, but we disregard the event's
1246 // accepted state after delivery; the mouse is grabbed, after all.
1247 sendMouseEvent(mouseEvent);
1248 return;
1249 }
1250
1251 // Start by determining the number of items at the current position.
1252 // Reuse value from earlier calculations if possible.
1253 if (cachedItemsUnderMouse.isEmpty()) {
1254 cachedItemsUnderMouse = itemsAtPosition(mouseEvent->screenPos(),
1255 mouseEvent->scenePos(),
1256 mouseEvent->widget());
1257 }
1258
1259 // Update window activation.
1260 QGraphicsWidget *newActiveWindow = windowForItem(cachedItemsUnderMouse.value(0));
1261 if (newActiveWindow != activeWindow)
1262 q->setActiveWindow(newActiveWindow);
1263
1264 // Set focus on the topmost enabled item that can take focus.
1265 bool setFocus = false;
1266 foreach (QGraphicsItem *item, cachedItemsUnderMouse) {
1267 if (item->isEnabled() && (item->flags() & QGraphicsItem::ItemIsFocusable)) {
1268 if (!item->isWidget() || ((QGraphicsWidget *)item)->focusPolicy() & Qt::ClickFocus) {
1269 setFocus = true;
1270 if (item != q->focusItem())
1271 q->setFocusItem(item, Qt::MouseFocusReason);
1272 break;
1273 }
1274 }
1275 }
1276
1277 // If nobody could take focus, clear it.
1278 if (!stickyFocus && !setFocus)
1279 q->setFocusItem(0, Qt::MouseFocusReason);
1280
1281 // Find a mouse grabber by sending mouse press events to all mouse grabber
1282 // candidates one at a time, until the event is accepted. It's accepted by
1283 // default, so the receiver has to explicitly ignore it for it to pass
1284 // through.
1285 foreach (QGraphicsItem *item, cachedItemsUnderMouse) {
1286 if (!(item->acceptedMouseButtons() & mouseEvent->button())) {
1287 // Skip items that don't accept the event's mouse button.
1288 continue;
1289 }
1290
1291 grabMouse(item, /* implicit = */ true);
1292 mouseEvent->accept();
1293
1294 // check if the item we are sending to are disabled (before we send the event)
1295 bool disabled = !item->isEnabled();
1296 bool isWindow = item->isWindow();
1297 if (mouseEvent->type() == QEvent::GraphicsSceneMouseDoubleClick && item != lastMouseGrabberItem) {
1298 // If this item is different from the item that received the last
1299 // mouse event, and mouseEvent is a doubleclick event, then the
1300 // event is converted to a press. Known limitation:
1301 // Triple-clicking will not generate a doubleclick, though.
1302 QGraphicsSceneMouseEvent mousePress(QEvent::GraphicsSceneMousePress);
1303 mousePress.accept();
1304 mousePress.setButton(mouseEvent->button());
1305 mousePress.setButtons(mouseEvent->buttons());
1306 mousePress.setScreenPos(mouseEvent->screenPos());
1307 mousePress.setScenePos(mouseEvent->scenePos());
1308 mousePress.setModifiers(mouseEvent->modifiers());
1309 mousePress.setWidget(mouseEvent->widget());
1310 mousePress.setButtonDownPos(mouseEvent->button(),
1311 mouseEvent->buttonDownPos(mouseEvent->button()));
1312 mousePress.setButtonDownScenePos(mouseEvent->button(),
1313 mouseEvent->buttonDownScenePos(mouseEvent->button()));
1314 mousePress.setButtonDownScreenPos(mouseEvent->button(),
1315 mouseEvent->buttonDownScreenPos(mouseEvent->button()));
1316 sendMouseEvent(&mousePress);
1317 mouseEvent->setAccepted(mousePress.isAccepted());
1318 } else {
1319 sendMouseEvent(mouseEvent);
1320 }
1321
1322 bool dontSendUngrabEvents = mouseGrabberItems.isEmpty() || mouseGrabberItems.last() != item;
1323 if (disabled) {
1324 ungrabMouse(item, /* itemIsDying = */ dontSendUngrabEvents);
1325 break;
1326 }
1327 if (mouseEvent->isAccepted()) {
1328 if (!mouseGrabberItems.isEmpty())
1329 storeMouseButtonsForMouseGrabber(mouseEvent);
1330 lastMouseGrabberItem = item;
1331 return;
1332 }
1333 ungrabMouse(item, /* itemIsDying = */ dontSendUngrabEvents);
1334
1335 // Don't propagate through windows.
1336 if (isWindow)
1337 break;
1338 }
1339
1340 // Is the event still ignored? Then the mouse press goes to the scene.
1341 // Reset the mouse grabber, clear the selection, clear focus, and leave
1342 // the event ignored so that it can propagate through the originating
1343 // view.
1344 if (!mouseEvent->isAccepted()) {
1345 clearMouseGrabber();
1346
1347 QGraphicsView *view = mouseEvent->widget() ? qobject_cast<QGraphicsView *>(mouseEvent->widget()->parentWidget()) : 0;
1348 bool dontClearSelection = view && view->dragMode() == QGraphicsView::ScrollHandDrag;
1349 if (!dontClearSelection) {
1350 // Clear the selection if the originating view isn't in scroll
1351 // hand drag mode. The view will clear the selection if no drag
1352 // happened.
1353 q->clearSelection();
1354 }
1355 }
1356}
1357
1358QGraphicsWidget *QGraphicsScenePrivate::windowForItem(const QGraphicsItem *item) const
1359{
1360 if (!item)
1361 return 0;
1362 do {
1363 if (item->isWidget())
1364 return static_cast<const QGraphicsWidget *>(item)->window();
1365 item = item->parentItem();
1366 } while (item);
1367 return 0;
1368}
1369
1370
1371QList<QGraphicsItem *> QGraphicsScenePrivate::items_helper(const QPointF &pos) const
1372{
1373 QList<QGraphicsItem *> items;
1374
1375 // The index returns a rough estimate of what items are inside the rect.
1376 // Refine it by iterating through all returned items.
1377 QRectF adjustedRect = QRectF(pos, QSize(1,1));
1378 foreach (QGraphicsItem *item, estimateItemsInRect(adjustedRect)) {
1379 // Find the item's scene transform in a clever way.
1380 QTransform x = item->sceneTransform();
1381 bool keep = false;
1382
1383 // ### _q_adjustedRect is only needed because QRectF::intersects,
1384 // QRectF::contains and QTransform::map() and friends don't work with
1385 // flat rectangles.
1386 const QRectF br(adjustedItemBoundingRect(item));
1387 // Rect intersects/contains item's shape
1388 if (QRectF_intersects(adjustedRect, x.mapRect(br))) {
1389 bool ok;
1390 QTransform xinv = x.inverted(&ok);
1391 if (ok) {
1392 if (item->contains(xinv.map(pos))) {
1393 items << item;
1394 keep = true;
1395 }
1396 }
1397 }
1398
1399 if (keep && (item->flags() & QGraphicsItem::ItemClipsChildrenToShape)) {
1400 // Recurse into children that clip children.
1401 bool ok;
1402 QTransform xinv = x.inverted(&ok);
1403 if (ok)
1404 childItems_helper(&items, item, xinv.map(pos));
1405 }
1406 }
1407
1408 sortItems(&items, Qt::AscendingOrder, sortCacheEnabled);
1409 return items;
1410}
1411
1412QList<QGraphicsItem *> QGraphicsScenePrivate::items_helper(const QRectF &rect,
1413 Qt::ItemSelectionMode mode,
1414 Qt::SortOrder order) const
1415{
1416 QList<QGraphicsItem *> items;
1417
1418 QPainterPath path;
1419
1420 // The index returns a rough estimate of what items are inside the rect.
1421 // Refine it by iterating through all returned items.
1422 QRectF adjustedRect(rect);
1423 _q_adjustRect(&adjustedRect);
1424 foreach (QGraphicsItem *item, estimateItemsInRect(adjustedRect)) {
1425 // Find the item's scene transform in a clever way.
1426 QTransform x = item->sceneTransform();
1427 bool keep = false;
1428
1429 // ### _q_adjustedRect is only needed because QRectF::intersects,
1430 // QRectF::contains and QTransform::map() and friends don't work with
1431 // flat rectangles.
1432 const QRectF br(adjustedItemBoundingRect(item));
1433 if (mode >= Qt::ContainsItemBoundingRect) {
1434 // Rect intersects/contains item's bounding rect
1435 QRectF mbr = x.mapRect(br);
1436 if ((mode == Qt::IntersectsItemBoundingRect && QRectF_intersects(rect, mbr))
1437 || (mode == Qt::ContainsItemBoundingRect && rect != mbr && rect.contains(mbr))) {
1438 items << item;
1439 keep = true;
1440 }
1441 } else {
1442 // Rect intersects/contains item's shape
1443 if (QRectF_intersects(adjustedRect, x.mapRect(br))) {
1444 bool ok;
1445 QTransform xinv = x.inverted(&ok);
1446 if (ok) {
1447 if (path.isEmpty())
1448 path.addRect(rect);
1449 if (itemCollidesWithPath(item, xinv.map(path), mode)) {
1450 items << item;
1451 keep = true;
1452 }
1453 }
1454 }
1455 }
1456
1457 if (keep && (item->flags() & QGraphicsItem::ItemClipsChildrenToShape)) {
1458 // Recurse into children that clip children.
1459 bool ok;
1460 QTransform xinv = x.inverted(&ok);
1461 if (ok) {
1462 if (x.type() <= QTransform::TxScale) {
1463 // Rect
1464 childItems_helper(&items, item, xinv.mapRect(rect), mode);
1465 } else {
1466 // Polygon
1467 childItems_helper(&items, item, xinv.map(rect), mode);
1468 }
1469 }
1470 }
1471 }
1472
1473 if (order != Qt::SortOrder(-1))
1474 sortItems(&items, order, sortCacheEnabled);
1475 return items;
1476}
1477
1478QList<QGraphicsItem *> QGraphicsScenePrivate::items_helper(const QPolygonF &polygon,
1479 Qt::ItemSelectionMode mode,
1480 Qt::SortOrder order) const
1481{
1482 QList<QGraphicsItem *> items;
1483
1484 QRectF polyRect(polygon.boundingRect());
1485 _q_adjustRect(&polyRect);
1486 QPainterPath path;
1487
1488 // The index returns a rough estimate of what items are inside the rect.
1489 // Refine it by iterating through all returned items.
1490 foreach (QGraphicsItem *item, estimateItemsInRect(polyRect)) {
1491 // Find the item's scene transform in a clever way.
1492 QTransform x = item->sceneTransform();
1493 bool keep = false;
1494
1495 // ### _q_adjustedRect is only needed because QRectF::intersects,
1496 // QRectF::contains and QTransform::map() and friends don't work with
1497 // flat rectangles.
1498 const QRectF br(adjustedItemBoundingRect(item));
1499 if (mode >= Qt::ContainsItemBoundingRect) {
1500 // Polygon contains/intersects item's bounding rect
1501 if (path == QPainterPath())
1502 path.addPolygon(polygon);
1503 if ((mode == Qt::IntersectsItemBoundingRect && path.intersects(x.mapRect(br)))
1504 || (mode == Qt::ContainsItemBoundingRect && path.contains(x.mapRect(br)))) {
1505 items << item;
1506 keep = true;
1507 }
1508 } else {
1509 // Polygon contains/intersects item's shape
1510 if (QRectF_intersects(polyRect, x.mapRect(br))) {
1511 bool ok;
1512 QTransform xinv = x.inverted(&ok);
1513 if (ok) {
1514 if (path == QPainterPath())
1515 path.addPolygon(polygon);
1516 if (itemCollidesWithPath(item, xinv.map(path), mode)) {
1517 items << item;
1518 keep = true;
1519 }
1520 }
1521 }
1522 }
1523
1524 if (keep && (item->flags() & QGraphicsItem::ItemClipsChildrenToShape)) {
1525 // Recurse into children that clip children.
1526 bool ok;
1527 QTransform xinv = x.inverted(&ok);
1528 if (ok)
1529 childItems_helper(&items, item, xinv.map(polygon), mode);
1530 }
1531 }
1532
1533 if (order != Qt::SortOrder(-1))
1534 sortItems(&items, order, sortCacheEnabled);
1535 return items;
1536}
1537
1538QList<QGraphicsItem *> QGraphicsScenePrivate::items_helper(const QPainterPath &path,
1539 Qt::ItemSelectionMode mode,
1540 Qt::SortOrder order) const
1541{
1542 QList<QGraphicsItem *> items;
1543 QRectF pathRect(path.controlPointRect());
1544 _q_adjustRect(&pathRect);
1545
1546 // The index returns a rough estimate of what items are inside the rect.
1547 // Refine it by iterating through all returned items.
1548 foreach (QGraphicsItem *item, estimateItemsInRect(pathRect)) {
1549 // Find the item's scene transform in a clever way.
1550 QTransform x = item->sceneTransform();
1551 bool keep = false;
1552
1553 // ### _q_adjustedRect is only needed because QRectF::intersects,
1554 // QRectF::contains and QTransform::map() and friends don't work with
1555 // flat rectangles.
1556 const QRectF br(adjustedItemBoundingRect(item));
1557 if (mode >= Qt::ContainsItemBoundingRect) {
1558 // Path contains/intersects item's bounding rect
1559 if ((mode == Qt::IntersectsItemBoundingRect && path.intersects(x.mapRect(br)))
1560 || (mode == Qt::ContainsItemBoundingRect && path.contains(x.mapRect(br)))) {
1561 items << item;
1562 keep = true;
1563 }
1564 } else {
1565 // Path contains/intersects item's shape
1566 if (QRectF_intersects(pathRect, x.mapRect(br))) {
1567 bool ok;
1568 QTransform xinv = x.inverted(&ok);
1569 if (ok) {
1570 if (itemCollidesWithPath(item, xinv.map(path), mode)) {
1571 items << item;
1572 keep = true;
1573 }
1574 }
1575 }
1576 }
1577
1578 if (keep && (item->flags() & QGraphicsItem::ItemClipsChildrenToShape)) {
1579 bool ok;
1580 QTransform xinv = x.inverted(&ok);
1581 if (ok)
1582 childItems_helper(&items, item, xinv.map(path), mode);
1583 }
1584 }
1585
1586 if (order != Qt::SortOrder(-1))
1587 sortItems(&items, order, sortCacheEnabled);
1588 return items;
1589}
1590
1591void QGraphicsScenePrivate::childItems_helper(QList<QGraphicsItem *> *items,
1592 const QGraphicsItem *parent,
1593 const QPointF &pos) const
1594{
1595 bool parentClip = (parent->flags() & QGraphicsItem::ItemClipsChildrenToShape);
1596 if (parentClip && parent->d_ptr->isClippedAway())
1597 return;
1598 // ### is this needed?
1599 if (parentClip && !parent->boundingRect().contains(pos))
1600 return;
1601
1602 QList<QGraphicsItem *> &children = parent->d_ptr->children;
1603 for (int i = 0; i < children.size(); ++i) {
1604 QGraphicsItem *item = children.at(i);
1605 if (item->d_ptr->hasTransform && !item->transform().isInvertible())
1606 continue;
1607
1608 // Skip invisible items and all their children.
1609 if (item->d_ptr->isInvisible())
1610 continue;
1611
1612 bool keep = false;
1613 if (!item->d_ptr->isClippedAway()) {
1614 if (item->contains(item->mapFromParent(pos))) {
1615 items->append(item);
1616 keep = true;
1617 }
1618 }
1619
1620 if ((keep || !(item->flags() & QGraphicsItem::ItemClipsChildrenToShape)) && !item->d_ptr->children.isEmpty())
1621 // Recurse into children.
1622 childItems_helper(items, item, item->mapFromParent(pos));
1623 }
1624}
1625
1626
1627void QGraphicsScenePrivate::childItems_helper(QList<QGraphicsItem *> *items,
1628 const QGraphicsItem *parent,
1629 const QRectF &rect,
1630 Qt::ItemSelectionMode mode) const
1631{
1632 bool parentClip = (parent->flags() & QGraphicsItem::ItemClipsChildrenToShape);
1633 if (parentClip && parent->d_ptr->isClippedAway())
1634 return;
1635 QRectF adjustedRect(rect);
1636 _q_adjustRect(&adjustedRect);
1637 QRectF r = !parentClip ? adjustedRect : adjustedRect.intersected(adjustedItemBoundingRect(parent));
1638 if (r.isEmpty())
1639 return;
1640
1641 QPainterPath path;
1642 QList<QGraphicsItem *> &children = parent->d_ptr->children;
1643 for (int i = 0; i < children.size(); ++i) {
1644 QGraphicsItem *item = children.at(i);
1645 if (item->d_ptr->hasTransform && !item->transform().isInvertible())
1646 continue;
1647
1648 // Skip invisible items and all their children.
1649 if (item->d_ptr->isInvisible())
1650 continue;
1651
1652 bool keep = false;
1653 if (!item->d_ptr->isClippedAway()) {
1654 // ### _q_adjustedRect is only needed because QRectF::intersects,
1655 // QRectF::contains and QTransform::map() and friends don't work with
1656 // flat rectangles.
1657 const QRectF br(adjustedItemBoundingRect(item));
1658 QRectF mbr = item->mapRectToParent(br);
1659 if (mode >= Qt::ContainsItemBoundingRect) {
1660 // Rect intersects/contains item's bounding rect
1661 if ((mode == Qt::IntersectsItemBoundingRect && QRectF_intersects(rect, mbr))
1662 || (mode == Qt::ContainsItemBoundingRect && rect != mbr && rect.contains(br))) {
1663 items->append(item);
1664 keep = true;
1665 }
1666 } else {
1667 // Rect intersects/contains item's shape
1668 if (QRectF_intersects(rect, mbr)) {
1669 if (path == QPainterPath())
1670 path.addRect(rect);
1671 if (itemCollidesWithPath(item, item->mapFromParent(path), mode)) {
1672 items->append(item);
1673 keep = true;
1674 }
1675 }
1676 }
1677 }
1678
1679 if ((keep || !(item->flags() & QGraphicsItem::ItemClipsChildrenToShape)) && !item->d_ptr->children.isEmpty()) {
1680 // Recurse into children.
1681 if (!item->d_ptr->hasTransform || item->transform().type() <= QTransform::TxScale) {
1682 // Rect
1683 childItems_helper(items, item, item->mapRectFromParent(rect), mode);
1684 } else {
1685 // Polygon
1686 childItems_helper(items, item, item->mapFromParent(rect), mode);
1687 }
1688 }
1689 }
1690}
1691
1692
1693void QGraphicsScenePrivate::childItems_helper(QList<QGraphicsItem *> *items,
1694 const QGraphicsItem *parent,
1695 const QPolygonF &polygon,
1696 Qt::ItemSelectionMode mode) const
1697{
1698 bool parentClip = (parent->flags() & QGraphicsItem::ItemClipsChildrenToShape);
1699 if (parentClip && parent->d_ptr->isClippedAway())
1700 return;
1701 QRectF polyRect(polygon.boundingRect());
1702 _q_adjustRect(&polyRect);
1703 QRectF r = !parentClip ? polyRect : polyRect.intersected(adjustedItemBoundingRect(parent));
1704 if (r.isEmpty())
1705 return;
1706
1707 QPainterPath path;
1708 QList<QGraphicsItem *> &children = parent->d_ptr->children;
1709 for (int i = 0; i < children.size(); ++i) {
1710 QGraphicsItem *item = children.at(i);
1711 if (item->d_ptr->hasTransform && !item->transform().isInvertible())
1712 continue;
1713
1714 // Skip invisible items.
1715 if (item->d_ptr->isInvisible())
1716 continue;
1717
1718 bool keep = false;
1719 if (!item->d_ptr->isClippedAway()) {
1720 // ### _q_adjustedRect is only needed because QRectF::intersects,
1721 // QRectF::contains and QTransform::map() and friends don't work with
1722 // flat rectangles.
1723 const QRectF br(adjustedItemBoundingRect(item));
1724 if (mode >= Qt::ContainsItemBoundingRect) {
1725 // Polygon contains/intersects item's bounding rect
1726 if (path == QPainterPath())
1727 path.addPolygon(polygon);
1728 if ((mode == Qt::IntersectsItemBoundingRect && path.intersects(item->mapRectToParent(br)))
1729 || (mode == Qt::ContainsItemBoundingRect && path.contains(item->mapRectToParent(br)))) {
1730 items->append(item);
1731 keep = true;
1732 }
1733 } else {
1734 // Polygon contains/intersects item's shape
1735 if (QRectF_intersects(polyRect, item->mapRectToParent(br))) {
1736 if (path == QPainterPath())
1737 path.addPolygon(polygon);
1738 if (itemCollidesWithPath(item, item->mapFromParent(path), mode)) {
1739 items->append(item);
1740 keep = true;
1741 }
1742 }
1743 }
1744 }
1745
1746 if ((keep || !(item->flags() & QGraphicsItem::ItemClipsChildrenToShape)) && !item->d_ptr->children.isEmpty()) {
1747 // Recurse into children that clip children.
1748 childItems_helper(items, item, item->mapFromParent(polygon), mode);
1749 }
1750 }
1751}
1752
1753void QGraphicsScenePrivate::childItems_helper(QList<QGraphicsItem *> *items,
1754 const QGraphicsItem *parent,
1755 const QPainterPath &path,
1756 Qt::ItemSelectionMode mode) const
1757{
1758 bool parentClip = (parent->flags() & QGraphicsItem::ItemClipsChildrenToShape);
1759 if (parentClip && parent->d_ptr->isClippedAway())
1760 return;
1761 QRectF pathRect(path.boundingRect());
1762 _q_adjustRect(&pathRect);
1763 QRectF r = !parentClip ? pathRect : pathRect.intersected(adjustedItemBoundingRect(parent));
1764 if (r.isEmpty())
1765 return;
1766
1767 QList<QGraphicsItem *> &children = parent->d_ptr->children;
1768 for (int i = 0; i < children.size(); ++i) {
1769 QGraphicsItem *item = children.at(i);
1770 if (item->d_ptr->hasTransform && !item->transform().isInvertible())
1771 continue;
1772
1773 // Skip invisible items.
1774 if (item->d_ptr->isInvisible())
1775 continue;
1776
1777 bool keep = false;
1778 if (!item->d_ptr->isClippedAway()) {
1779 // ### _q_adjustedRect is only needed because QRectF::intersects,
1780 // QRectF::contains and QTransform::map() and friends don't work with
1781 // flat rectangles.
1782 const QRectF br(adjustedItemBoundingRect(item));
1783 if (mode >= Qt::ContainsItemBoundingRect) {
1784 // Polygon contains/intersects item's bounding rect
1785 if ((mode == Qt::IntersectsItemBoundingRect && path.intersects(item->mapRectToParent(br)))
1786 || (mode == Qt::ContainsItemBoundingRect && path.contains(item->mapRectToParent(br)))) {
1787 items->append(item);
1788 keep = true;
1789 }
1790 } else {
1791 // Path contains/intersects item's shape
1792 if (QRectF_intersects(pathRect, item->mapRectToParent(br))) {
1793 if (itemCollidesWithPath(item, item->mapFromParent(path), mode)) {
1794 items->append(item);
1795 keep = true;
1796 }
1797 }
1798 }
1799 }
1800
1801 if ((keep || !(item->flags() & QGraphicsItem::ItemClipsChildrenToShape)) && !item->d_ptr->children.isEmpty()) {
1802 // Recurse into children that clip children.
1803 childItems_helper(items, item, item->mapFromParent(path), mode);
1804 }
1805 }
1806}
1807
1808void QGraphicsScenePrivate::invalidateSortCache()
1809{
1810 Q_Q(QGraphicsScene);
1811 if (!sortCacheEnabled || updatingSortCache)
1812 return;
1813
1814 updatingSortCache = true;
1815 QMetaObject::invokeMethod(q, "_q_updateSortCache", Qt::QueuedConnection);
1816}
1817
1818/*!
1819 \internal
1820
1821 Should not be exported, but we can't change that now.
1822 ### Qt 5: Remove symbol / make static
1823*/
1824inline bool qt_closestLeaf(const QGraphicsItem *item1, const QGraphicsItem *item2)
1825{
1826 // Return true if sibling item1 is on top of item2.
1827 const QGraphicsItemPrivate *d1 = item1->d_ptr;
1828 const QGraphicsItemPrivate *d2 = item2->d_ptr;
1829 bool f1 = d1->flags & QGraphicsItem::ItemStacksBehindParent;
1830 bool f2 = d2->flags & QGraphicsItem::ItemStacksBehindParent;
1831 if (f1 != f2) return f2;
1832 qreal z1 = d1->z;
1833 qreal z2 = d2->z;
1834 return z1 != z2 ? z1 > z2 : item1 > item2;
1835}
1836
1837/*!
1838 \internal
1839
1840 Should not be exported, but we can't change that now.
1841*/
1842inline bool qt_closestItemFirst(const QGraphicsItem *item1, const QGraphicsItem *item2)
1843{
1844 return QGraphicsScenePrivate::closestItemFirst_withoutCache(item1, item2);
1845}
1846
1847/*!
1848 Returns true if \a item1 is on top of \a item2.
1849
1850 \internal
1851*/
1852bool QGraphicsScenePrivate::closestItemFirst_withoutCache(const QGraphicsItem *item1, const QGraphicsItem *item2)
1853{
1854 // Siblings? Just check their z-values.
1855 const QGraphicsItemPrivate *d1 = item1->d_ptr;
1856 const QGraphicsItemPrivate *d2 = item2->d_ptr;
1857 if (d1->parent == d2->parent)
1858 return qt_closestLeaf(item1, item2);
1859
1860 // Find common ancestor, and each item's ancestor closest to the common
1861 // ancestor.
1862 int item1Depth = d1->depth;
1863 int item2Depth = d2->depth;
1864 const QGraphicsItem *p = item1;
1865 const QGraphicsItem *t1 = item1;
1866 while (item1Depth > item2Depth && (p = p->d_ptr->parent)) {
1867 if (p == item2) {
1868 // item2 is one of item1's ancestors; item1 is on top
1869 return !(t1->d_ptr->flags & QGraphicsItem::ItemStacksBehindParent);
1870 }
1871 t1 = p;
1872 --item1Depth;
1873 }
1874 p = item2;
1875 const QGraphicsItem *t2 = item2;
1876 while (item2Depth > item1Depth && (p = p->d_ptr->parent)) {
1877 if (p == item1) {
1878 // item1 is one of item2's ancestors; item1 is not on top
1879 return (t2->d_ptr->flags & QGraphicsItem::ItemStacksBehindParent);
1880 }
1881 t2 = p;
1882 --item2Depth;
1883 }
1884
1885 // item1Ancestor is now at the same level as item2Ancestor, but not the same.
1886 const QGraphicsItem *a1 = t1;
1887 const QGraphicsItem *a2 = t2;
1888 while (a1) {
1889 const QGraphicsItem *p1 = a1;
1890 const QGraphicsItem *p2 = a2;
1891 a1 = a1->parentItem();
1892 a2 = a2->parentItem();
1893 if (a1 && a1 == a2)
1894 return qt_closestLeaf(p1, p2);
1895 }
1896
1897 // No common ancestor? Then just compare the items' toplevels directly.
1898 return qt_closestLeaf(t1->topLevelItem(), t2->topLevelItem());
1899}
1900
1901/*!
1902 Returns true if \a item2 is on top of \a item1.
1903
1904 \internal
1905*/
1906bool QGraphicsScenePrivate::closestItemLast_withoutCache(const QGraphicsItem *item1, const QGraphicsItem *item2)
1907{
1908 return closestItemFirst_withoutCache(item2, item1);
1909}
1910
1911void QGraphicsScenePrivate::climbTree(QGraphicsItem *item, int *stackingOrder)
1912{
1913 if (!item->d_ptr->children.isEmpty()) {
1914 QList<QGraphicsItem *> childList = item->d_ptr->children;
1915 qSort(childList.begin(), childList.end(), qt_closestLeaf);
1916 for (int i = 0; i < childList.size(); ++i) {
1917 QGraphicsItem *item = childList.at(i);
1918 if (!(item->flags() & QGraphicsItem::ItemStacksBehindParent))
1919 climbTree(childList.at(i), stackingOrder);
1920 }
1921 item->d_ptr->globalStackingOrder = (*stackingOrder)++;
1922 for (int i = 0; i < childList.size(); ++i) {
1923 QGraphicsItem *item = childList.at(i);
1924 if (item->flags() & QGraphicsItem::ItemStacksBehindParent)
1925 climbTree(childList.at(i), stackingOrder);
1926 }
1927 } else {
1928 item->d_ptr->globalStackingOrder = (*stackingOrder)++;
1929 }
1930}
1931
1932void QGraphicsScenePrivate::_q_updateSortCache()
1933{
1934 _q_updateIndex();
1935
1936 if (!sortCacheEnabled || !updatingSortCache)
1937 return;
1938
1939 updatingSortCache = false;
1940 int stackingOrder = 0;
1941
1942 QList<QGraphicsItem *> topLevels;
1943
1944 for (int i = 0; i < indexedItems.size(); ++i) {
1945 QGraphicsItem *item = indexedItems.at(i);
1946 if (item && item->parentItem() == 0)
1947 topLevels << item;
1948 }
1949 for (int i = 0; i < unindexedItems.size(); ++i) {
1950 QGraphicsItem *item = unindexedItems.at(i);
1951 if (item->parentItem() == 0)
1952 topLevels << item;
1953 }
1954
1955 qSort(topLevels.begin(), topLevels.end(), qt_closestLeaf);
1956 for (int i = 0; i < topLevels.size(); ++i)
1957 climbTree(topLevels.at(i), &stackingOrder);
1958}
1959
1960void QGraphicsScenePrivate::sortItems(QList<QGraphicsItem *> *itemList, Qt::SortOrder order,
1961 bool sortCacheEnabled)
1962{
1963 if (sortCacheEnabled) {
1964 if (order == Qt::AscendingOrder) {
1965 qSort(itemList->begin(), itemList->end(), closestItemFirst_withCache);
1966 } else if (order == Qt::DescendingOrder) {
1967 qSort(itemList->begin(), itemList->end(), closestItemLast_withCache);
1968 }
1969 } else {
1970 if (order == Qt::AscendingOrder) {
1971 qSort(itemList->begin(), itemList->end(), closestItemFirst_withoutCache);
1972 } else if (order == Qt::DescendingOrder) {
1973 qSort(itemList->begin(), itemList->end(), closestItemLast_withoutCache);
1974 }
1975 }
1976}
1977
1978/*!
1979 \internal
1980
1981 Set the font and propagate the changes if the font is different from the
1982 current font.
1983*/
1984void QGraphicsScenePrivate::setFont_helper(const QFont &font)
1985{
1986 if (this->font == font && this->font.resolve() == font.resolve())
1987 return;
1988 updateFont(font);
1989}
1990
1991/*!
1992 \internal
1993
1994 Resolve the scene's font against the application font, and propagate the
1995 changes too all items in the scene.
1996*/
1997void QGraphicsScenePrivate::resolveFont()
1998{
1999 QFont naturalFont = qApp->font();
2000 naturalFont.resolve(0);
2001 QFont resolvedFont = font.resolve(naturalFont);
2002 updateFont(resolvedFont);
2003}
2004
2005/*!
2006 \internal
2007
2008 Update the font, and whether or not it has changed, reresolve all fonts in
2009 the scene.
2010*/
2011void QGraphicsScenePrivate::updateFont(const QFont &font)
2012{
2013 Q_Q(QGraphicsScene);
2014
2015 // Update local font setting.
2016 this->font = font;
2017
2018 // Resolve the fonts of all top-level widget items, or widget items
2019 // whose parent is not a widget.
2020 foreach (QGraphicsItem *item, q->items()) {
2021 if (!item->parentItem()) {
2022 // Resolvefont for an item is a noop operation, but
2023 // every item can be a widget, or can have a widget
2024 // childre.
2025 item->d_ptr->resolveFont(font.resolve());
2026 }
2027 }
2028
2029 // Send the scene a FontChange event.
2030 QEvent event(QEvent::FontChange);
2031 QApplication::sendEvent(q, &event);
2032}
2033
2034/*!
2035 \internal
2036
2037 Set the palette and propagate the changes if the palette is different from
2038 the current palette.
2039*/
2040void QGraphicsScenePrivate::setPalette_helper(const QPalette &palette)
2041{
2042 if (this->palette == palette && this->palette.resolve() == palette.resolve())
2043 return;
2044 updatePalette(palette);
2045}
2046
2047/*!
2048 \internal
2049
2050 Resolve the scene's palette against the application palette, and propagate
2051 the changes too all items in the scene.
2052*/
2053void QGraphicsScenePrivate::resolvePalette()
2054{
2055 QPalette naturalPalette = qApp->palette();
2056 naturalPalette.resolve(0);
2057 QPalette resolvedPalette = palette.resolve(naturalPalette);
2058 updatePalette(resolvedPalette);
2059}
2060
2061/*!
2062 \internal
2063
2064 Update the palette, and whether or not it has changed, reresolve all
2065 palettes in the scene.
2066*/
2067void QGraphicsScenePrivate::updatePalette(const QPalette &palette)
2068{
2069 Q_Q(QGraphicsScene);
2070
2071 // Update local palette setting.
2072 this->palette = palette;
2073
2074 // Resolve the palettes of all top-level widget items, or widget items
2075 // whose parent is not a widget.
2076 foreach (QGraphicsItem *item, q->items()) {
2077 if (!item->parentItem()) {
2078 // Resolvefont for an item is a noop operation, but
2079 // every item can be a widget, or can have a widget
2080 // childre.
2081 item->d_ptr->resolvePalette(palette.resolve());
2082 }
2083 }
2084
2085 // Send the scene a PaletteChange event.
2086 QEvent event(QEvent::PaletteChange);
2087 QApplication::sendEvent(q, &event);
2088}
2089
2090/*!
2091 Constructs a QGraphicsScene object. The \a parent parameter is
2092 passed to QObject's constructor.
2093*/
2094QGraphicsScene::QGraphicsScene(QObject *parent)
2095 : QObject(*new QGraphicsScenePrivate, parent)
2096{
2097 d_func()->init();
2098}
2099
2100/*!
2101 Constructs a QGraphicsScene object, using \a sceneRect for its
2102 scene rectangle. The \a parent parameter is passed to QObject's
2103 constructor.
2104
2105 \sa sceneRect
2106*/
2107QGraphicsScene::QGraphicsScene(const QRectF &sceneRect, QObject *parent)
2108 : QObject(*new QGraphicsScenePrivate, parent)
2109{
2110 setSceneRect(sceneRect);
2111 d_func()->init();
2112}
2113
2114/*!
2115 Constructs a QGraphicsScene object, using the rectangle specified
2116 by (\a x, \a y), and the given \a width and \a height for its
2117 scene rectangle. The \a parent parameter is passed to QObject's
2118 constructor.
2119
2120 \sa sceneRect
2121*/
2122QGraphicsScene::QGraphicsScene(qreal x, qreal y, qreal width, qreal height, QObject *parent)
2123 : QObject(*new QGraphicsScenePrivate, parent)
2124{
2125 setSceneRect(x, y, width, height);
2126 d_func()->init();
2127}
2128
2129/*!
2130 Destroys the QGraphicsScene object.
2131*/
2132QGraphicsScene::~QGraphicsScene()
2133{
2134 Q_D(QGraphicsScene);
2135 // Remove this scene from qApp's global scene list.
2136 qApp->d_func()->scene_list.removeAll(this);
2137
2138 clear();
2139
2140 // Remove this scene from all associated views.
2141 for (int j = 0; j < d->views.size(); ++j)
2142 d->views.at(j)->setScene(0);
2143}
2144
2145/*!
2146 \property QGraphicsScene::sceneRect
2147 \brief the scene rectangle; the bounding rectangle of the scene
2148
2149 The scene rectangle defines the extent of the scene. It is
2150 primarily used by QGraphicsView to determine the view's default
2151 scrollable area, and by QGraphicsScene to manage item indexing.
2152
2153 If unset, or if set to a null QRectF, sceneRect() will return the largest
2154 bounding rect of all items on the scene since the scene was created (i.e.,
2155 a rectangle that grows when items are added to or moved in the scene, but
2156 never shrinks).
2157
2158 \sa width(), height(), QGraphicsView::sceneRect
2159*/
2160QRectF QGraphicsScene::sceneRect() const
2161{
2162 Q_D(const QGraphicsScene);
2163 const_cast<QGraphicsScenePrivate *>(d)->_q_updateIndex();
2164 return d->hasSceneRect ? d->sceneRect : d->growingItemsBoundingRect;
2165}
2166void QGraphicsScene::setSceneRect(const QRectF &rect)
2167{
2168 Q_D(QGraphicsScene);
2169 if (rect != d->sceneRect) {
2170 d->hasSceneRect = !rect.isNull();
2171 d->sceneRect = rect;
2172 d->resetIndex();
2173 emit sceneRectChanged(rect);
2174 }
2175}
2176
2177/*!
2178 \fn qreal QGraphicsScene::width() const
2179
2180 This convenience function is equivalent to calling sceneRect().width().
2181
2182 \sa height()
2183*/
2184
2185/*!
2186 \fn qreal QGraphicsScene::height() const
2187
2188 This convenience function is equivalent to calling \c sceneRect().height().
2189
2190 \sa width()
2191*/
2192
2193/*!
2194 Renders the \a source rect from scene into \a target, using \a painter. This
2195 function is useful for capturing the contents of the scene onto a paint
2196 device, such as a QImage (e.g., to take a screenshot), or for printing
2197 with QPrinter. For example:
2198
2199 \snippet doc/src/snippets/code/src_gui_graphicsview_qgraphicsscene.cpp 1
2200
2201 If \a source is a null rect, this function will use sceneRect() to
2202 determine what to render. If \a target is a null rect, the dimensions of \a
2203 painter's paint device will be used.
2204
2205 The source rect contents will be transformed according to \a
2206 aspectRatioMode to fit into the target rect. By default, the aspect ratio
2207 is kept, and \a source is scaled to fit in \a target.
2208
2209 \sa QGraphicsView::render()
2210*/
2211void QGraphicsScene::render(QPainter *painter, const QRectF &target, const QRectF &source,
2212 Qt::AspectRatioMode aspectRatioMode)
2213{
2214 Q_D(QGraphicsScene);
2215
2216 // Default source rect = scene rect
2217 QRectF sourceRect = source;
2218 if (sourceRect.isNull())
2219 sourceRect = sceneRect();
2220
2221 // Default target rect = device rect
2222 QRectF targetRect = target;
2223 if (targetRect.isNull()) {
2224 if (painter->device()->devType() == QInternal::Picture)
2225 targetRect = sourceRect;
2226 else
2227 targetRect.setRect(0, 0, painter->device()->width(), painter->device()->height());
2228 }
2229
2230 // Find the ideal x / y scaling ratio to fit \a source into \a target.
2231 qreal xratio = targetRect.width() / sourceRect.width();
2232 qreal yratio = targetRect.height() / sourceRect.height();
2233
2234 // Scale according to the aspect ratio mode.
2235 switch (aspectRatioMode) {
2236 case Qt::KeepAspectRatio:
2237 xratio = yratio = qMin(xratio, yratio);
2238 break;
2239 case Qt::KeepAspectRatioByExpanding:
2240 xratio = yratio = qMax(xratio, yratio);
2241 break;
2242 case Qt::IgnoreAspectRatio:
2243 break;
2244 }
2245
2246 // Find all items to draw, and reverse the list (we want to draw
2247 // in reverse order).
2248 QList<QGraphicsItem *> itemList = items(sourceRect, Qt::IntersectsItemBoundingRect);
2249 QGraphicsItem **itemArray = new QGraphicsItem *[itemList.size()];
2250 int numItems = itemList.size();
2251 for (int i = 0; i < numItems; ++i)
2252 itemArray[numItems - i - 1] = itemList.at(i);
2253 itemList.clear();
2254
2255 painter->save();
2256
2257 // Transform the painter.
2258 painter->setClipRect(targetRect);
2259 QTransform painterTransform;
2260 painterTransform *= QTransform()
2261 .translate(targetRect.left(), targetRect.top())
2262 .scale(xratio, yratio)
2263 .translate(-sourceRect.left(), -sourceRect.top());
2264 painter->setWorldTransform(painterTransform, true);
2265
2266 // Two unit vectors.
2267 QLineF v1(0, 0, 1, 0);
2268 QLineF v2(0, 0, 0, 1);
2269
2270 // Generate the style options
2271 QStyleOptionGraphicsItem *styleOptionArray = new QStyleOptionGraphicsItem[numItems];
2272 for (int i = 0; i < numItems; ++i) {
2273 QGraphicsItem *item = itemArray[i];
2274
2275 QStyleOptionGraphicsItem option;
2276 option.state = QStyle::State_None;
2277 option.rect = item->boundingRect().toRect();
2278 if (item->isSelected())
2279 option.state |= QStyle::State_Selected;
2280 if (item->isEnabled())
2281 option.state |= QStyle::State_Enabled;
2282 if (item->hasFocus())
2283 option.state |= QStyle::State_HasFocus;
2284 if (d->hoverItems.contains(item))
2285 option.state |= QStyle::State_MouseOver;
2286 if (item == mouseGrabberItem())
2287 option.state |= QStyle::State_Sunken;
2288
2289 // Calculate a simple level-of-detail metric.
2290 // ### almost identical code in QGraphicsView::paintEvent()
2291 // and QGraphicsView::render() - consider refactoring
2292 QTransform itemToDeviceTransform;
2293 if (item->d_ptr->itemIsUntransformable()) {
2294 itemToDeviceTransform = item->deviceTransform(painterTransform);
2295 } else {
2296 itemToDeviceTransform = item->sceneTransform() * painterTransform;
2297 }
2298
2299 option.levelOfDetail = qSqrt(itemToDeviceTransform.map(v1).length() * itemToDeviceTransform.map(v2).length());
2300 option.matrix = itemToDeviceTransform.toAffine(); //### discards perspective
2301
2302 option.exposedRect = item->boundingRect();
2303 option.exposedRect &= itemToDeviceTransform.inverted().mapRect(targetRect);
2304
2305 styleOptionArray[i] = option;
2306 }
2307
2308 // Render the scene.
2309 drawBackground(painter, sourceRect);
2310 drawItems(painter, numItems, itemArray, styleOptionArray);
2311 drawForeground(painter, sourceRect);
2312
2313 delete [] itemArray;
2314 delete [] styleOptionArray;
2315
2316 painter->restore();
2317}
2318
2319/*!
2320 \property QGraphicsScene::itemIndexMethod
2321 \brief the item indexing method.
2322
2323 QGraphicsScene applies an indexing algorithm to the scene, to speed up
2324 item discovery functions like items() and itemAt(). Indexing is most
2325 efficient for static scenes (i.e., where items don't move around). For
2326 dynamic scenes, or scenes with many animated items, the index bookkeeping
2327 can outweight the fast lookup speeds.
2328
2329 For the common case, the default index method BspTreeIndex works fine. If
2330 your scene uses many animations and you are experiencing slowness, you can
2331 disable indexing by calling \c setItemIndexMethod(NoIndex).
2332
2333 \sa bspTreeDepth
2334*/
2335QGraphicsScene::ItemIndexMethod QGraphicsScene::itemIndexMethod() const
2336{
2337 Q_D(const QGraphicsScene);
2338 return d->indexMethod;
2339}
2340void QGraphicsScene::setItemIndexMethod(ItemIndexMethod method)
2341{
2342 Q_D(QGraphicsScene);
2343 d->resetIndex();
2344 d->indexMethod = method;
2345}
2346
2347/*!
2348 \property QGraphicsScene::bspTreeDepth
2349 \brief the depth of QGraphicsScene's BSP index tree
2350 \since 4.3
2351
2352 This property has no effect when NoIndex is used.
2353
2354 This value determines the depth of QGraphicsScene's BSP tree. The depth
2355 directly affects QGraphicsScene's performance and memory usage; the latter
2356 growing exponentially with the depth of the tree. With an optimal tree
2357 depth, QGraphicsScene can instantly determine the locality of items, even
2358 for scenes with thousands or millions of items. This also greatly improves
2359 rendering performance.
2360
2361 By default, the value is 0, in which case Qt will guess a reasonable
2362 default depth based on the size, location and number of items in the
2363 scene. If these parameters change frequently, however, you may experience
2364 slowdowns as QGraphicsScene retunes the depth internally. You can avoid
2365 potential slowdowns by fixating the tree depth through setting this
2366 property.
2367
2368 The depth of the tree and the size of the scene rectangle decide the
2369 granularity of the scene's partitioning. The size of each scene segment is
2370 determined by the following algorithm:
2371
2372 \snippet doc/src/snippets/code/src_gui_graphicsview_qgraphicsscene.cpp 2
2373
2374 The BSP tree has an optimal size when each segment contains between 0 and
2375 10 items.
2376
2377 \sa itemIndexMethod
2378*/
2379int QGraphicsScene::bspTreeDepth() const
2380{
2381 Q_D(const QGraphicsScene);
2382 return d->bspTreeDepth;
2383}
2384void QGraphicsScene::setBspTreeDepth(int depth)
2385{
2386 Q_D(QGraphicsScene);
2387 if (d->bspTreeDepth == depth)
2388 return;
2389
2390 if (depth < 0) {
2391 qWarning("QGraphicsScene::setBspTreeDepth: invalid depth %d ignored; must be >= 0", depth);
2392 return;
2393 }
2394
2395 d->bspTreeDepth = depth;
2396 d->resetIndex();
2397}
2398
2399/*!
2400 \property QGraphicsScene::sortCacheEnabled
2401 \brief whether sort caching is enabled
2402 \since 4.5
2403
2404 When enabled, this property adds a cache that speeds up sorting and
2405 transformations for scenes with deep hierarchies (i.e., items with many
2406 levels of descendents), at the cost of using more memory (approx. 100 more
2407 bytes of memory per item).
2408
2409 Items that are not part of a deep hierarchy suffer no penalty from this
2410 cache.
2411*/
2412bool QGraphicsScene::isSortCacheEnabled() const
2413{
2414 Q_D(const QGraphicsScene);
2415 return d->sortCacheEnabled;
2416}
2417void QGraphicsScene::setSortCacheEnabled(bool enabled)
2418{
2419 Q_D(QGraphicsScene);
2420 if (enabled == d->sortCacheEnabled)
2421 return;
2422 if ((d->sortCacheEnabled = enabled))
2423 d->invalidateSortCache();
2424}
2425
2426/*!
2427 Calculates and returns the bounding rect of all items on the scene. This
2428 function works by iterating over all items, and because if this, it can
2429 be slow for large scenes.
2430
2431 \sa sceneRect()
2432*/
2433QRectF QGraphicsScene::itemsBoundingRect() const
2434{
2435 QRectF boundingRect;
2436 foreach (QGraphicsItem *item, items())
2437 boundingRect |= item->sceneBoundingRect();
2438 return boundingRect;
2439}
2440
2441/*!
2442 Returns a list of all items on the scene, in no particular order.
2443
2444 \sa addItem(), removeItem()
2445*/
2446QList<QGraphicsItem *> QGraphicsScene::items() const
2447{
2448 Q_D(const QGraphicsScene);
2449 const_cast<QGraphicsScenePrivate *>(d)->purgeRemovedItems();
2450
2451 // If freeItemIndexes is empty, we know there are no holes in indexedItems and
2452 // unindexedItems.
2453 if (d->freeItemIndexes.isEmpty()) {
2454 if (d->unindexedItems.isEmpty())
2455 return d->indexedItems;
2456 return d->indexedItems + d->unindexedItems;
2457 }
2458
2459 // Rebuild the list of items to avoid holes. ### We could also just
2460 // compress the item lists at this point.
2461 QList<QGraphicsItem *> itemList;
2462 foreach (QGraphicsItem *item, d->indexedItems + d->unindexedItems) {
2463 if (item)
2464 itemList << item;
2465 }
2466 return itemList;
2467}
2468
2469/*!
2470 Returns all visible items at position \a pos in the scene. The items are
2471 listed in descending Z order (i.e., the first item in the list is the
2472 top-most item, and the last item is the bottom-most item).
2473
2474 \sa itemAt()
2475*/
2476QList<QGraphicsItem *> QGraphicsScene::items(const QPointF &pos) const
2477{
2478 Q_D(const QGraphicsScene);
2479 return d->items_helper(pos);
2480}
2481
2482
2483/*!
2484 \fn QList<QGraphicsItem *> QGraphicsScene::items(const QRectF &rectangle, Qt::ItemSelectionMode mode) const
2485
2486 \overload
2487
2488 Returns all visible items that, depending on \a mode, are either inside or
2489 intersect with the specified \a rectangle.
2490
2491 The default value for \a mode is Qt::IntersectsItemShape; all items whose
2492 exact shape intersects with or is contained by \a rectangle are returned.
2493
2494 \sa itemAt()
2495*/
2496QList<QGraphicsItem *> QGraphicsScene::items(const QRectF &rect, Qt::ItemSelectionMode mode) const
2497{
2498 Q_D(const QGraphicsScene);
2499 return d->items_helper(rect, mode, Qt::AscendingOrder);
2500}
2501
2502/*!
2503 \fn QList<QGraphicsItem *> QGraphicsScene::items(qreal x, qreal y, qreal w, qreal h, Qt::ItemSelectionMode mode) const
2504 \since 4.3
2505
2506 This convenience function is equivalent to calling items(QRectF(\a x, \a y, \a w, \a h), \a mode).
2507*/
2508
2509/*!
2510 \overload
2511
2512 Returns all visible items that, depending on \a mode, are either inside or
2513 intersect with the polygon \a polygon.
2514
2515 The default value for \a mode is Qt::IntersectsItemShape; all items whose
2516 exact shape intersects with or is contained by \a polygon are returned.
2517
2518 \sa itemAt()
2519*/
2520QList<QGraphicsItem *> QGraphicsScene::items(const QPolygonF &polygon, Qt::ItemSelectionMode mode) const
2521{
2522 Q_D(const QGraphicsScene);
2523 return d->items_helper(polygon, mode, Qt::AscendingOrder);
2524}
2525
2526/*!
2527 \overload
2528
2529 Returns all visible items that, depending on \a path, are either inside or
2530 intersect with the path \a path.
2531
2532 The default value for \a mode is Qt::IntersectsItemShape; all items whose
2533 exact shape intersects with or is contained by \a path are returned.
2534
2535 \sa itemAt()
2536*/
2537QList<QGraphicsItem *> QGraphicsScene::items(const QPainterPath &path, Qt::ItemSelectionMode mode) const
2538{
2539 Q_D(const QGraphicsScene);
2540 return d->items_helper(path, mode, Qt::AscendingOrder);
2541}
2542
2543/*!
2544 Returns a list of all items that collide with \a item. Collisions are
2545 determined by calling QGraphicsItem::collidesWithItem(); the collision
2546 detection is determined by \a mode. By default, all items whose shape
2547 intersects \a item or is contained inside \a item's shape are returned.
2548
2549 The items are returned in descending Z order (i.e., the first item in the
2550 list is the top-most item, and the last item is the bottom-most item).
2551
2552 \sa items(), itemAt(), QGraphicsItem::collidesWithItem()
2553*/
2554QList<QGraphicsItem *> QGraphicsScene::collidingItems(const QGraphicsItem *item,
2555 Qt::ItemSelectionMode mode) const
2556{
2557 Q_D(const QGraphicsScene);
2558 if (!item) {
2559 qWarning("QGraphicsScene::collidingItems: cannot find collisions for null item");
2560 return QList<QGraphicsItem *>();
2561 }
2562
2563 QList<QGraphicsItem *> tmp;
2564 foreach (QGraphicsItem *itemInVicinity, d->estimateItemsInRect(item->sceneBoundingRect())) {
2565 if (item != itemInVicinity && item->collidesWithItem(itemInVicinity, mode))
2566 tmp << itemInVicinity;
2567 }
2568 d->sortItems(&tmp, Qt::AscendingOrder, d->sortCacheEnabled);
2569 return tmp;
2570}
2571
2572/*!
2573 \fn QGraphicsItem *QGraphicsScene::itemAt(const QPointF &position) const
2574
2575 Returns the topmost visible item at the specified \a position, or 0 if
2576 there are no items at this position.
2577
2578 \note The topmost item is the one with the highest Z-value.
2579
2580 \sa items(), collidingItems(), QGraphicsItem::setZValue()
2581*/
2582QGraphicsItem *QGraphicsScene::itemAt(const QPointF &pos) const
2583{
2584 QList<QGraphicsItem *> itemsAtPoint = items(pos);
2585 return itemsAtPoint.isEmpty() ? 0 : itemsAtPoint.first();
2586}
2587
2588/*!
2589 \fn QGraphicsScene::itemAt(qreal x, qreal y) const
2590 \overload
2591
2592 Returns the topmost item at the position specified by (\a x, \a
2593 y), or 0 if there are no items at this position.
2594
2595 This convenience function is equivalent to calling \c
2596 {itemAt(QPointF(x, y))}.
2597
2598 \note The topmost item is the one with the highest Z-value.
2599*/
2600
2601/*!
2602 Returns a list of all currently selected items. The items are
2603 returned in no particular order.
2604
2605 \sa setSelectionArea()
2606*/
2607QList<QGraphicsItem *> QGraphicsScene::selectedItems() const
2608{
2609 Q_D(const QGraphicsScene);
2610
2611 // Optimization: Lazily removes items that are not selected.
2612 QGraphicsScene *that = const_cast<QGraphicsScene *>(this);
2613 QSet<QGraphicsItem *> actuallySelectedSet;
2614 foreach (QGraphicsItem *item, that->d_func()->selectedItems) {
2615 if (item->isSelected())
2616 actuallySelectedSet << item;
2617 }
2618
2619 that->d_func()->selectedItems = actuallySelectedSet;
2620
2621 return d->selectedItems.values();
2622}
2623
2624/*!
2625 Returns the selection area that was previously set with
2626 setSelectionArea(), or an empty QPainterPath if no selection area has been
2627 set.
2628
2629 \sa setSelectionArea()
2630*/
2631QPainterPath QGraphicsScene::selectionArea() const
2632{
2633 Q_D(const QGraphicsScene);
2634 return d->selectionArea;
2635}
2636
2637/*!
2638 Sets the selection area to \a path. All items within this area are
2639 immediately selected, and all items outside are unselected. You can get
2640 the list of all selected items by calling selectedItems().
2641
2642 For an item to be selected, it must be marked as \e selectable
2643 (QGraphicsItem::ItemIsSelectable).
2644
2645 \sa clearSelection(), selectionArea()
2646*/
2647void QGraphicsScene::setSelectionArea(const QPainterPath &path)
2648{
2649 setSelectionArea(path, Qt::IntersectsItemShape);
2650}
2651
2652/*!
2653 \overload
2654 \since 4.3
2655
2656 Sets the selection area to \a path using \a mode to determine if items are
2657 included in the selection area.
2658
2659 \sa clearSelection(), selectionArea()
2660*/
2661void QGraphicsScene::setSelectionArea(const QPainterPath &path, Qt::ItemSelectionMode mode)
2662{
2663 Q_D(QGraphicsScene);
2664
2665 // Note: with boolean path operations, we can improve performance here
2666 // quite a lot by "growing" the old path instead of replacing it. That
2667 // allows us to only check the intersect area for changes, instead of
2668 // reevaluating the whole path over again.
2669 d->selectionArea = path;
2670
2671 QSet<QGraphicsItem *> unselectItems = d->selectedItems;
2672
2673 // Disable emitting selectionChanged() for individual items.
2674 ++d->selectionChanging;
2675 bool changed = false;
2676
2677 // Set all items in path to selected.
2678 foreach (QGraphicsItem *item, items(path, mode)) {
2679 if (item->flags() & QGraphicsItem::ItemIsSelectable) {
2680 if (!item->isSelected())
2681 changed = true;
2682 unselectItems.remove(item);
2683 item->setSelected(true);
2684 }
2685 }
2686
2687 // Unselect all items outside path.
2688 foreach (QGraphicsItem *item, unselectItems) {
2689 item->setSelected(false);
2690 changed = true;
2691 }
2692
2693 // Reenable emitting selectionChanged() for individual items.
2694 --d->selectionChanging;
2695
2696 if (!d->selectionChanging && changed)
2697 emit selectionChanged();
2698}
2699
2700/*!
2701 Clears the current selection.
2702
2703 \sa setSelectionArea(), selectedItems()
2704*/
2705void QGraphicsScene::clearSelection()
2706{
2707 Q_D(QGraphicsScene);
2708
2709 // Disable emitting selectionChanged
2710 ++d->selectionChanging;
2711 bool changed = !d->selectedItems.isEmpty();
2712
2713 foreach (QGraphicsItem *item, d->selectedItems)
2714 item->setSelected(false);
2715 d->selectedItems.clear();
2716
2717 // Reenable emitting selectionChanged() for individual items.
2718 --d->selectionChanging;
2719
2720 if (!d->selectionChanging && changed)
2721 emit selectionChanged();
2722}
2723
2724/*!
2725 \since 4.4
2726
2727 Removes and deletes all items from the scene, but otherwise leaves the
2728 state of the scene unchanged.
2729
2730 \sa addItem()
2731*/
2732void QGraphicsScene::clear()
2733{
2734 Q_D(QGraphicsScene);
2735 // Recursive descent delete
2736 for (int i = 0; i < d->indexedItems.size(); ++i) {
2737 if (QGraphicsItem *item = d->indexedItems.at(i)) {
2738 if (!item->parentItem())
2739 delete item;
2740 }
2741 }
2742 QList<QGraphicsItem *> unindexedParents;
2743 for (int i = 0; i < d->unindexedItems.size(); ++i) {
2744 QGraphicsItem *item = d->unindexedItems.at(i);
2745 if (!item->parentItem())
2746 unindexedParents << item;
2747 }
2748 d->unindexedItems.clear();
2749 qDeleteAll(unindexedParents);
2750
2751 d->indexedItems.clear();
2752 d->freeItemIndexes.clear();
2753 d->lastItemCount = 0;
2754 d->bspTree.clear();
2755 d->largestUntransformableItem = QRectF();
2756}
2757
2758/*!
2759 Groups all items in \a items into a new QGraphicsItemGroup, and returns a
2760 pointer to the group. The group is created with the common ancestor of \a
2761 items as its parent, and with position (0, 0). The items are all
2762 reparented to the group, and their positions and transformations are
2763 mapped to the group. If \a items is empty, this function will return an
2764 empty top-level QGraphicsItemGroup.
2765
2766 QGraphicsScene has ownership of the group item; you do not need to delete
2767 it. To dismantle (ungroup) a group, call destroyItemGroup().
2768
2769 \sa destroyItemGroup(), QGraphicsItemGroup::addToGroup()
2770*/
2771QGraphicsItemGroup *QGraphicsScene::createItemGroup(const QList<QGraphicsItem *> &items)
2772{
2773 // Build a list of the first item's ancestors
2774 QList<QGraphicsItem *> ancestors;
2775 int n = 0;
2776 if (!items.isEmpty()) {
2777 QGraphicsItem *parent = items.at(n++);
2778 while ((parent = parent->parentItem()))
2779 ancestors.append(parent);
2780 }
2781
2782 // Find the common ancestor for all items
2783 QGraphicsItem *commonAncestor = 0;
2784 if (!ancestors.isEmpty()) {
2785 while (n < items.size()) {
2786 int commonIndex = -1;
2787 QGraphicsItem *parent = items.at(n++);
2788 do {
2789 int index = ancestors.indexOf(parent, qMax(0, commonIndex));
2790 if (index != -1) {
2791 commonIndex = index;
2792 break;
2793 }
2794 } while ((parent = parent->parentItem()));
2795
2796 if (commonIndex == -1) {
2797 commonAncestor = 0;
2798 break;
2799 }
2800
2801 commonAncestor = ancestors.at(commonIndex);
2802 }
2803 }
2804
2805 // Create a new group at that level
2806 QGraphicsItemGroup *group = new QGraphicsItemGroup(commonAncestor);
2807 if (!commonAncestor)
2808 addItem(group);
2809 foreach (QGraphicsItem *item, items)
2810 group->addToGroup(item);
2811 return group;
2812}
2813
2814/*!
2815 Reparents all items in \a group to \a group's parent item, then removes \a
2816 group from the scene, and finally deletes it. The items' positions and
2817 transformations are mapped from the group to the group's parent.
2818
2819 \sa createItemGroup(), QGraphicsItemGroup::removeFromGroup()
2820*/
2821void QGraphicsScene::destroyItemGroup(QGraphicsItemGroup *group)
2822{
2823 foreach (QGraphicsItem *item, group->children())
2824 group->removeFromGroup(item);
2825 removeItem(group);
2826 delete group;
2827}
2828
2829/*!
2830 Adds or moves the item \a item and all its childen to the scene.
2831
2832 If the item is visible (i.e., QGraphicsItem::isVisible() returns
2833 true), QGraphicsScene will emit changed() once control goes back
2834 to the event loop.
2835
2836 If the item is already in a different scene, it will first be removed from
2837 its old scene, and then added to this scene as a top-level.
2838
2839 QGraphicsScene will send ItemSceneChange notifications to \a item while
2840 it is added to the scene. If item does not currently belong to a scene, only one
2841 notification is sent. If it does belong to scene already (i.e., it is
2842 moved to this scene), QGraphicsScene will send an addition notification as
2843 the item is removed from its previous scene.
2844
2845 \sa removeItem(), addEllipse(), addLine(), addPath(), addPixmap(),
2846 addRect(), addText(), addWidget()
2847*/
2848void QGraphicsScene::addItem(QGraphicsItem *item)
2849{
2850 Q_D(QGraphicsScene);
2851 if (!item) {
2852 qWarning("QGraphicsScene::addItem: cannot add null item");
2853 return;
2854 }
2855 if (item->scene() == this) {
2856 qWarning("QGraphicsScene::addItem: item has already been added to this scene");
2857 return;
2858 }
2859
2860 // Remove this item from its existing scene
2861 if (QGraphicsScene *oldScene = item->scene())
2862 oldScene->removeItem(item);
2863
2864 // Notify the item that its scene is changing, and allow the item to
2865 // react.
2866 const QVariant newSceneVariant(item->itemChange(QGraphicsItem::ItemSceneChange,
2867 qVariantFromValue<QGraphicsScene *>(this)));
2868 QGraphicsScene *targetScene = qVariantValue<QGraphicsScene *>(newSceneVariant);
2869 if (targetScene != this) {
2870 if (targetScene && item->scene() != targetScene)
2871 targetScene->addItem(item);
2872 return;
2873 }
2874
2875 // Prevent reusing a recently deleted pointer: purge all removed items
2876 // from our lists.
2877 d->purgeRemovedItems();
2878
2879 // Invalidate any sort caching; arrival of a new item means we need to
2880 // resort.
2881 d->invalidateSortCache();
2882
2883 // Detach this item from its parent if the parent's scene is different
2884 // from this scene.
2885 if (QGraphicsItem *itemParent = item->parentItem()) {
2886 if (itemParent->scene() != this)
2887 item->setParentItem(0);
2888 }
2889
2890 // Add the item to this scene
2891 item->d_func()->scene = targetScene;
2892
2893 // Indexing requires sceneBoundingRect(), but because \a item might
2894 // not be completely constructed at this point, we need to store it in
2895 // a temporary list and schedule an indexing for later.
2896 d->unindexedItems << item;
2897 item->d_func()->index = -1;
2898 d->startIndexTimer();
2899
2900 // Update the scene's sort cache settings.
2901 item->d_ptr->globalStackingOrder = -1;
2902 d->invalidateSortCache();
2903
2904 // Add to list of items that require an update. We cannot assume that the
2905 // item is fully constructed, so calling item->update() can lead to a pure
2906 // virtual function call to boundingRect().
2907 if (!d->updateAll) {
2908 if (d->pendingUpdateItems.isEmpty())
2909 QMetaObject::invokeMethod(this, "_q_updateLater", Qt::QueuedConnection);
2910 d->pendingUpdateItems << item;
2911 }
2912
2913 // Disable selectionChanged() for individual items
2914 ++d->selectionChanging;
2915 int oldSelectedItemSize = d->selectedItems.size();
2916
2917 // Update selection lists
2918 if (item->isSelected())
2919 d->selectedItems << item;
2920 if (item->isWidget() && item->isVisible() && static_cast<QGraphicsWidget *>(item)->windowType() == Qt::Popup)
2921 d->addPopup(static_cast<QGraphicsWidget *>(item));
2922
2923 // Update creation order focus chain. Make sure to leave the widget's
2924 // internal tab order intact.
2925 if (item->isWidget()) {
2926 QGraphicsWidget *widget = static_cast<QGraphicsWidget *>(item);
2927 if (!d->tabFocusFirst) {
2928 // No first tab focus widget - make this the first tab focus
2929 // widget.
2930 d->tabFocusFirst = widget;
2931 } else if (!widget->parentWidget()) {
2932 // Adding a widget that is not part of a tab focus chain.
2933 QGraphicsWidget *last = d->tabFocusFirst->d_func()->focusPrev;
2934 QGraphicsWidget *lastNew = widget->d_func()->focusPrev;
2935 last->d_func()->focusNext = widget;
2936 widget->d_func()->focusPrev = last;
2937 d->tabFocusFirst->d_func()->focusPrev = lastNew;
2938 lastNew->d_func()->focusNext = d->tabFocusFirst;
2939 }
2940 }
2941
2942 // Add all children recursively
2943 foreach (QGraphicsItem *child, item->children())
2944 addItem(child);
2945
2946 // Resolve font and palette.
2947 item->d_ptr->resolveFont(d->font.resolve());
2948 item->d_ptr->resolvePalette(d->palette.resolve());
2949
2950 if (!item->d_ptr->explicitlyHidden) {
2951 if (d->unpolishedItems.isEmpty())
2952 QMetaObject::invokeMethod(this, "_q_polishItems", Qt::QueuedConnection);
2953 d->unpolishedItems << item;
2954 }
2955
2956 // Reenable selectionChanged() for individual items
2957 --d->selectionChanging;
2958 if (!d->selectionChanging && d->selectedItems.size() != oldSelectedItemSize)
2959 emit selectionChanged();
2960
2961 // Deliver post-change notification
2962 item->itemChange(QGraphicsItem::ItemSceneHasChanged, newSceneVariant);
2963}
2964
2965/*!
2966 Creates and adds an ellipse item to the scene, and returns the item
2967 pointer. The geometry of the ellipse is defined by \a rect, and its pen
2968 and brush are initialized to \a pen and \a brush.
2969
2970 Note that the item's geometry is provided in item coordinates, and its
2971 position is initialized to (0, 0).
2972
2973 If the item is visible (i.e., QGraphicsItem::isVisible() returns true),
2974 QGraphicsScene will emit changed() once control goes back to the event
2975 loop.
2976
2977 \sa addLine(), addPath(), addPixmap(), addRect(), addText(), addItem(),
2978 addWidget()
2979*/
2980QGraphicsEllipseItem *QGraphicsScene::addEllipse(const QRectF &rect, const QPen &pen, const QBrush &brush)
2981{
2982 QGraphicsEllipseItem *item = new QGraphicsEllipseItem(rect);
2983 item->setPen(pen);
2984 item->setBrush(brush);
2985 addItem(item);
2986 return item;
2987}
2988
2989/*!
2990 \fn QGraphicsEllipseItem *QGraphicsScene::addEllipse(qreal x, qreal y, qreal w, qreal h, const QPen &pen, const QBrush &brush)
2991 \since 4.3
2992
2993 This convenience function is equivalent to calling addEllipse(QRectF(\a x,
2994 \a y, \a w, \a h), \a pen, \a brush).
2995*/
2996
2997/*!
2998 Creates and adds a line item to the scene, and returns the item
2999 pointer. The geometry of the line is defined by \a line, and its pen
3000 is initialized to \a pen.
3001
3002 Note that the item's geometry is provided in item coordinates, and its
3003 position is initialized to (0, 0).
3004
3005 If the item is visible (i.e., QGraphicsItem::isVisible() returns true),
3006 QGraphicsScene will emit changed() once control goes back to the event
3007 loop.
3008
3009 \sa addEllipse(), addPath(), addPixmap(), addRect(), addText(), addItem(),
3010 addWidget()
3011*/
3012QGraphicsLineItem *QGraphicsScene::addLine(const QLineF &line, const QPen &pen)
3013{
3014 QGraphicsLineItem *item = new QGraphicsLineItem(line);
3015 item->setPen(pen);
3016 addItem(item);
3017 return item;
3018}
3019
3020/*!
3021 \fn QGraphicsLineItem *QGraphicsScene::addLine(qreal x1, qreal y1, qreal x2, qreal y2, const QPen &pen)
3022 \since 4.3
3023
3024 This convenience function is equivalent to calling addLine(QLineF(\a x1,
3025 \a y1, \a x2, \a y2), \a pen).
3026*/
3027
3028/*!
3029 Creates and adds a path item to the scene, and returns the item
3030 pointer. The geometry of the path is defined by \a path, and its pen and
3031 brush are initialized to \a pen and \a brush.
3032
3033 Note that the item's geometry is provided in item coordinates, and its
3034 position is initialized to (0, 0).
3035
3036 If the item is visible (i.e., QGraphicsItem::isVisible() returns true),
3037 QGraphicsScene will emit changed() once control goes back to the event
3038 loop.
3039
3040 \sa addEllipse(), addLine(), addPixmap(), addRect(), addText(), addItem(),
3041 addWidget()
3042*/
3043QGraphicsPathItem *QGraphicsScene::addPath(const QPainterPath &path, const QPen &pen, const QBrush &brush)
3044{
3045 QGraphicsPathItem *item = new QGraphicsPathItem(path);
3046 item->setPen(pen);
3047 item->setBrush(brush);
3048 addItem(item);
3049 return item;
3050}
3051
3052/*!
3053 Creates and adds a pixmap item to the scene, and returns the item
3054 pointer. The pixmap is defined by \a pixmap.
3055
3056 Note that the item's geometry is provided in item coordinates, and its
3057 position is initialized to (0, 0).
3058
3059 If the item is visible (i.e., QGraphicsItem::isVisible() returns true),
3060 QGraphicsScene will emit changed() once control goes back to the event
3061 loop.
3062
3063 \sa addEllipse(), addLine(), addPath(), addRect(), addText(), addItem(),
3064 addWidget()
3065*/
3066QGraphicsPixmapItem *QGraphicsScene::addPixmap(const QPixmap &pixmap)
3067{
3068 QGraphicsPixmapItem *item = new QGraphicsPixmapItem(pixmap);
3069 addItem(item);
3070 return item;
3071}
3072
3073/*!
3074 Creates and adds a polygon item to the scene, and returns the item
3075 pointer. The polygon is defined by \a polygon, and its pen and
3076 brush are initialized to \a pen and \a brush.
3077
3078 Note that the item's geometry is provided in item coordinates, and its
3079 position is initialized to (0, 0).
3080
3081 If the item is visible (i.e., QGraphicsItem::isVisible() returns true),
3082 QGraphicsScene will emit changed() once control goes back to the event
3083 loop.
3084
3085 \sa addEllipse(), addLine(), addPath(), addRect(), addText(), addItem(),
3086 addWidget()
3087*/
3088QGraphicsPolygonItem *QGraphicsScene::addPolygon(const QPolygonF &polygon,
3089 const QPen &pen, const QBrush &brush)
3090{
3091 QGraphicsPolygonItem *item = new QGraphicsPolygonItem(polygon);
3092 item->setPen(pen);
3093 item->setBrush(brush);
3094 addItem(item);
3095 return item;
3096}
3097
3098/*!
3099 Creates and adds a rectangle item to the scene, and returns the item
3100 pointer. The geometry of the rectangle is defined by \a rect, and its pen
3101 and brush are initialized to \a pen and \a brush.
3102
3103 Note that the item's geometry is provided in item coordinates, and its
3104 position is initialized to (0, 0). For example, if a QRect(50, 50, 100,
3105 100) is added, its top-left corner will be at (50, 50) relative to the
3106 origin in the items coordinate system.
3107
3108 If the item is visible (i.e., QGraphicsItem::isVisible() returns true),
3109 QGraphicsScene will emit changed() once control goes back to the event
3110 loop.
3111
3112 \sa addEllipse(), addLine(), addPixmap(), addPixmap(), addText(),
3113 addItem(), addWidget()
3114*/
3115QGraphicsRectItem *QGraphicsScene::addRect(const QRectF &rect, const QPen &pen, const QBrush &brush)
3116{
3117 QGraphicsRectItem *item = new QGraphicsRectItem(rect);
3118 item->setPen(pen);
3119 item->setBrush(brush);
3120 addItem(item);
3121 return item;
3122}
3123
3124/*!
3125 \fn QGraphicsRectItem *QGraphicsScene::addRect(qreal x, qreal y, qreal w, qreal h, const QPen &pen, const QBrush &brush)
3126 \since 4.3
3127
3128 This convenience function is equivalent to calling addRect(QRectF(\a x,
3129 \a y, \a w, \a h), \a pen, \a brush).
3130*/
3131
3132/*!
3133 Creates and adds a text item to the scene, and returns the item
3134 pointer. The text string is initialized to \a text, and its font
3135 is initialized to \a font.
3136
3137 The item's position is initialized to (0, 0).
3138
3139 If the item is visible (i.e., QGraphicsItem::isVisible() returns true),
3140 QGraphicsScene will emit changed() once control goes back to the event
3141 loop.
3142
3143 \sa addEllipse(), addLine(), addPixmap(), addPixmap(), addRect(),
3144 addItem(), addWidget()
3145*/
3146QGraphicsTextItem *QGraphicsScene::addText(const QString &text, const QFont &font)
3147{
3148 QGraphicsTextItem *item = new QGraphicsTextItem(text);
3149 item->setFont(font);
3150 addItem(item);
3151 return item;
3152}
3153
3154/*!
3155 Creates and adds a QGraphicsSimpleTextItem to the scene, and returns the
3156 item pointer. The text string is initialized to \a text, and its font is
3157 initialized to \a font.
3158
3159 The item's position is initialized to (0, 0).
3160
3161 If the item is visible (i.e., QGraphicsItem::isVisible() returns true),
3162 QGraphicsScene will emit changed() once control goes back to the event
3163 loop.
3164
3165 \sa addEllipse(), addLine(), addPixmap(), addPixmap(), addRect(),
3166 addItem(), addWidget()
3167*/
3168QGraphicsSimpleTextItem *QGraphicsScene::addSimpleText(const QString &text, const QFont &font)
3169{
3170 QGraphicsSimpleTextItem *item = new QGraphicsSimpleTextItem(text);
3171 item->setFont(font);
3172 addItem(item);
3173 return item;
3174}
3175
3176/*!
3177 Creates a new QGraphicsProxyWidget for \a widget, adds it to the scene,
3178 and returns a pointer to the proxy. \a wFlags set the default window flags
3179 for the embedding proxy widget.
3180
3181 The item's position is initialized to (0, 0).
3182
3183 If the item is visible (i.e., QGraphicsItem::isVisible() returns true),
3184 QGraphicsScene will emit changed() once control goes back to the event
3185 loop.
3186
3187 Note that widgets with the Qt::WA_PaintOnScreen widget attribute
3188 set and widgets that wrap an external application or controller
3189 are not supported. Examples are QGLWidget and QAxWidget.
3190
3191 \sa addEllipse(), addLine(), addPixmap(), addPixmap(), addRect(),
3192 addText(), addSimpleText(), addItem()
3193*/
3194QGraphicsProxyWidget *QGraphicsScene::addWidget(QWidget *widget, Qt::WindowFlags wFlags)
3195{
3196 QGraphicsProxyWidget *proxy = new QGraphicsProxyWidget(0, wFlags);
3197 proxy->setWidget(widget);
3198 addItem(proxy);
3199 return proxy;
3200}
3201
3202/*!
3203 Removes the item \a item and all its children from the scene. The
3204 ownership of \a item is passed on to the caller (i.e.,
3205 QGraphicsScene will no longer delete \a item when destroyed).
3206
3207 \sa addItem()
3208*/
3209void QGraphicsScene::removeItem(QGraphicsItem *item)
3210{
3211 // ### Refactoring: This function shares much functionality with _q_removeItemLater()
3212 Q_D(QGraphicsScene);
3213 if (!item) {
3214 qWarning("QGraphicsScene::removeItem: cannot remove 0-item");
3215 return;
3216 }
3217 if (item->scene() != this) {
3218 qWarning("QGraphicsScene::removeItem: item %p's scene (%p)"
3219 " is different from this scene (%p)",
3220 item, item->scene(), this);
3221 return;
3222 }
3223
3224 // Notify the item that it's scene is changing to 0, allowing the item to
3225 // react.
3226 const QVariant newSceneVariant(item->itemChange(QGraphicsItem::ItemSceneChange,
3227 qVariantFromValue<QGraphicsScene *>(0)));
3228 QGraphicsScene *targetScene = qVariantValue<QGraphicsScene *>(newSceneVariant);
3229 if (targetScene != 0 && targetScene != this) {
3230 targetScene->addItem(item);
3231 return;
3232 }
3233
3234 // If the item has focus, remove it (and any focusWidget reference).
3235 item->clearFocus();
3236
3237 // Clear its background
3238 item->update();
3239
3240 // Note: This will access item's sceneBoundingRect(), which (as this is
3241 // C++) is why we cannot call removeItem() from QGraphicsItem's
3242 // destructor.
3243 d->removeFromIndex(item);
3244
3245 if (item == d->tabFocusFirst) {
3246 QGraphicsWidget *widget = static_cast<QGraphicsWidget *>(item);
3247 widget->d_func()->fixFocusChainBeforeReparenting(0, 0);
3248 }
3249 // Set the item's scene ptr to 0.
3250 item->d_func()->scene = 0;
3251
3252 // Detach the item from its parent.
3253 if (QGraphicsItem *parentItem = item->parentItem()) {
3254 if (parentItem->scene()) {
3255 Q_ASSERT_X(parentItem->scene() == this, "QGraphicsScene::removeItem",
3256 "Parent item's scene is different from this item's scene");
3257 item->setParentItem(0);
3258 }
3259 }
3260
3261 // Remove from our item lists.
3262 int index = item->d_func()->index;
3263 if (index != -1) {
3264 d->freeItemIndexes << index;
3265 d->indexedItems[index] = 0;
3266 } else {
3267 d->unindexedItems.removeAll(item);
3268 }
3269
3270 // Remove from scene transform cache
3271 int transformIndex = item->d_func()->sceneTransformIndex;
3272 if (transformIndex != -1) {
3273 d->validTransforms.setBit(transformIndex, 0);
3274 d->freeSceneTransformSlots.append(transformIndex);
3275 item->d_func()->sceneTransformIndex = -1;
3276 }
3277
3278 if (item == d->focusItem)
3279 d->focusItem = 0;
3280 if (item == d->lastFocusItem)
3281 d->lastFocusItem = 0;
3282 if (item == d->activeWindow) {
3283 // ### deactivate...
3284 d->activeWindow = 0;
3285 }
3286
3287 // Disable selectionChanged() for individual items
3288 ++d->selectionChanging;
3289 int oldSelectedItemsSize = d->selectedItems.size();
3290
3291 // Update selected & hovered item bookkeeping
3292 d->selectedItems.remove(item);
3293 d->hoverItems.removeAll(item);
3294 d->pendingUpdateItems.removeAll(item);
3295 d->cachedItemsUnderMouse.removeAll(item);
3296 d->unpolishedItems.removeAll(item);
3297 d->dirtyItems.removeAll(item);
3298
3299 //We remove all references of item from the sceneEventFilter arrays
3300 QMultiMap<QGraphicsItem*, QGraphicsItem*>::iterator iterator = d->sceneEventFilters.begin();
3301 while (iterator != d->sceneEventFilters.end()) {
3302 if (iterator.value() == item || iterator.key() == item)
3303 iterator = d->sceneEventFilters.erase(iterator);
3304 else
3305 ++iterator;
3306 }
3307
3308
3309 //Ensure dirty flag have the correct default value so the next time it will be added it will receive updates
3310 item->d_func()->dirty = 0;
3311 item->d_func()->dirtyChildren = 0;
3312
3313 // Remove all children recursively
3314 foreach (QGraphicsItem *child, item->children())
3315 removeItem(child);
3316
3317 // Reset the mouse grabber and focus item data.
3318 if (d->mouseGrabberItems.contains(item))
3319 d->ungrabMouse(item);
3320
3321 // Reset the keyboard grabber
3322 if (d->keyboardGrabberItems.contains(item))
3323 item->ungrabKeyboard();
3324
3325 // Reset the last mouse grabber item
3326 if (item == d->lastMouseGrabberItem)
3327 d->lastMouseGrabberItem = 0;
3328
3329 // Reenable selectionChanged() for individual items
3330 --d->selectionChanging;
3331
3332 if (!d->selectionChanging && d->selectedItems.size() != oldSelectedItemsSize)
3333 emit selectionChanged();
3334
3335 // Deliver post-change notification
3336 item->itemChange(QGraphicsItem::ItemSceneHasChanged, newSceneVariant);
3337}
3338
3339/*!
3340 Returns the scene's current focus item, or 0 if no item currently has
3341 focus.
3342
3343 The focus item receives keyboard input when the scene receives a
3344 key event.
3345
3346 \sa setFocusItem(), QGraphicsItem::hasFocus()
3347*/
3348QGraphicsItem *QGraphicsScene::focusItem() const
3349{
3350 Q_D(const QGraphicsScene);
3351 return d->focusItem;
3352}
3353
3354/*!
3355 Sets the scene's focus item to \a item, with the focus reason \a
3356 focusReason, after removing focus from any previous item that may have had
3357 focus.
3358
3359 If \a item is 0, or if it either does not accept focus (i.e., it does not
3360 have the QGraphicsItem::ItemIsFocusable flag enabled), or is not visible
3361 or not enabled, this function only removes focus from any previous
3362 focusitem.
3363
3364 If item is not 0, and the scene does not currently have focus (i.e.,
3365 hasFocus() returns false), this function will call setFocus()
3366 automatically.
3367
3368 \sa focusItem(), hasFocus(), setFocus()
3369*/
3370void QGraphicsScene::setFocusItem(QGraphicsItem *item, Qt::FocusReason focusReason)
3371{
3372 Q_D(QGraphicsScene);
3373 if (item == d->focusItem)
3374 return;
3375 if (item && (!(item->flags() & QGraphicsItem::ItemIsFocusable)
3376 || !item->isVisible() || !item->isEnabled())) {
3377 item = 0;
3378 }
3379
3380 if (item) {
3381 setFocus(focusReason);
3382 if (item == d->focusItem)
3383 return;
3384 }
3385
3386 if (d->focusItem) {
3387 QFocusEvent event(QEvent::FocusOut, focusReason);
3388 d->lastFocusItem = d->focusItem;
3389 d->focusItem = 0;
3390 d->sendEvent(d->lastFocusItem, &event);
3391 }
3392
3393 if (item) {
3394 if (item->isWidget()) {
3395 // Update focus child chain.
3396 static_cast<QGraphicsWidget *>(item)->d_func()->setFocusWidget();
3397 }
3398
3399 d->focusItem = item;
3400 QFocusEvent event(QEvent::FocusIn, focusReason);
3401 d->sendEvent(item, &event);
3402 }
3403}
3404
3405/*!
3406 Returns true if the scene has focus; otherwise returns false. If the scene
3407 has focus, it will will forward key events from QKeyEvent to any item that
3408 has focus.
3409
3410 \sa setFocus(), setFocusItem()
3411*/
3412bool QGraphicsScene::hasFocus() const
3413{
3414 Q_D(const QGraphicsScene);
3415 return d->hasFocus;
3416}
3417
3418/*!
3419 Sets focus on the scene by sending a QFocusEvent to the scene, passing \a
3420 focusReason as the reason. If the scene regains focus after having
3421 previously lost it while an item had focus, the last focus item will
3422 receive focus with \a focusReason as the reason.
3423
3424 If the scene already has focus, this function does nothing.
3425
3426 \sa hasFocus(), clearFocus(), setFocusItem()
3427*/
3428void QGraphicsScene::setFocus(Qt::FocusReason focusReason)
3429{
3430 Q_D(QGraphicsScene);
3431 if (d->hasFocus)
3432 return;
3433 QFocusEvent event(QEvent::FocusIn, focusReason);
3434 QCoreApplication::sendEvent(this, &event);
3435}
3436
3437/*!
3438 Clears focus from the scene. If any item has focus when this function is
3439 called, it will lose focus, and regain focus again once the scene regains
3440 focus.
3441
3442 A scene that does not have focus ignores key events.
3443
3444 \sa hasFocus(), setFocus(), setFocusItem()
3445*/
3446void QGraphicsScene::clearFocus()
3447{
3448 Q_D(QGraphicsScene);
3449 if (d->hasFocus) {
3450 d->hasFocus = false;
3451 setFocusItem(0, Qt::OtherFocusReason);
3452 }
3453}
3454
3455/*!
3456 \property QGraphicsScene::stickyFocus
3457 \brief whether or not clicking the scene will clear focus
3458
3459 If this property is false (the default), then clicking on the scene
3460 background or on an item that does not accept focus, will clear
3461 focus. Otherwise, focus will remain unchanged.
3462
3463 The focus change happens in response to a mouse press. You can reimplement
3464 mousePressEvent() in a subclass of QGraphicsScene to toggle this property
3465 based on where the user has clicked.
3466
3467 \sa clearFocus(), setFocusItem()
3468*/
3469void QGraphicsScene::setStickyFocus(bool enabled)
3470{
3471 Q_D(QGraphicsScene);
3472 d->stickyFocus = enabled;
3473}
3474bool QGraphicsScene::stickyFocus() const
3475{
3476 Q_D(const QGraphicsScene);
3477 return d->stickyFocus;
3478}
3479
3480/*!
3481 Returns the current mouse grabber item, or 0 if no item is currently
3482 grabbing the mouse. The mouse grabber item is the item that receives all
3483 mouse events sent to the scene.
3484
3485 An item becomes a mouse grabber when it receives and accepts a
3486 mouse press event, and it stays the mouse grabber until either of
3487 the following events occur:
3488
3489 \list
3490 \o If the item receives a mouse release event when there are no other
3491 buttons pressed, it loses the mouse grab.
3492 \o If the item becomes invisible (i.e., someone calls \c {item->setVisible(false))},
3493 or if it becomes disabled (i.e., someone calls \c {item->setEnabled(false))},
3494 it loses the mouse grab.
3495 \o If the item is removed from the scene, it loses the mouse grab.
3496 \endlist
3497
3498 If the item loses its mouse grab, the scene will ignore all mouse events
3499 until a new item grabs the mouse (i.e., until a new item receives a mouse
3500 press event).
3501*/
3502QGraphicsItem *QGraphicsScene::mouseGrabberItem() const
3503{
3504 Q_D(const QGraphicsScene);
3505 return !d->mouseGrabberItems.isEmpty() ? d->mouseGrabberItems.last() : 0;
3506}
3507
3508/*!
3509 \property QGraphicsScene::backgroundBrush
3510 \brief the background brush of the scene.
3511
3512 Set this property to changes the scene's background to a different color,
3513 gradient or texture. The default background brush is Qt::NoBrush. The
3514 background is drawn before (behind) the items.
3515
3516 Example:
3517
3518 \snippet doc/src/snippets/code/src_gui_graphicsview_qgraphicsscene.cpp 3
3519
3520 QGraphicsScene::render() calls drawBackground() to draw the scene
3521 background. For more detailed control over how the background is drawn,
3522 you can reimplement drawBackground() in a subclass of QGraphicsScene.
3523*/
3524QBrush QGraphicsScene::backgroundBrush() const
3525{
3526 Q_D(const QGraphicsScene);
3527 return d->backgroundBrush;
3528}
3529void QGraphicsScene::setBackgroundBrush(const QBrush &brush)
3530{
3531 Q_D(QGraphicsScene);
3532 d->backgroundBrush = brush;
3533 foreach (QGraphicsView *view, d->views) {
3534 view->resetCachedContent();
3535 view->viewport()->update();
3536 }
3537 update();
3538}
3539
3540/*!
3541 \property QGraphicsScene::foregroundBrush
3542 \brief the foreground brush of the scene.
3543
3544 Change this property to set the scene's foreground to a different
3545 color, gradient or texture.
3546
3547 The foreground is drawn after (on top of) the items. The default
3548 foreground brush is Qt::NoBrush ( i.e. the foreground is not
3549 drawn).
3550
3551 Example:
3552
3553 \snippet doc/src/snippets/code/src_gui_graphicsview_qgraphicsscene.cpp 4
3554
3555 QGraphicsScene::render() calls drawForeground() to draw the scene
3556 foreground. For more detailed control over how the foreground is
3557 drawn, you can reimplement the drawForeground() function in a
3558 QGraphicsScene subclass.
3559*/
3560QBrush QGraphicsScene::foregroundBrush() const
3561{
3562 Q_D(const QGraphicsScene);
3563 return d->foregroundBrush;
3564}
3565void QGraphicsScene::setForegroundBrush(const QBrush &brush)
3566{
3567 Q_D(QGraphicsScene);
3568 d->foregroundBrush = brush;
3569 foreach (QGraphicsView *view, views())
3570 view->viewport()->update();
3571 update();
3572}
3573
3574/*!
3575 This method is used by input methods to query a set of properties of
3576 the scene to be able to support complex input method operations as support
3577 for surrounding text and reconversions.
3578
3579 The \a query parameter specifies which property is queried.
3580
3581 \sa QWidget::inputMethodQuery()
3582*/
3583QVariant QGraphicsScene::inputMethodQuery(Qt::InputMethodQuery query) const
3584{
3585 Q_D(const QGraphicsScene);
3586 if (!d->focusItem)
3587 return QVariant();
3588 const QTransform matrix = d->focusItem->sceneTransform();
3589 QVariant value = d->focusItem->inputMethodQuery(query);
3590 if (value.type() == QVariant::RectF)
3591 value = matrix.mapRect(value.toRectF());
3592 else if (value.type() == QVariant::PointF)
3593 value = matrix.map(value.toPointF());
3594 else if (value.type() == QVariant::Rect)
3595 value = matrix.mapRect(value.toRect());
3596 else if (value.type() == QVariant::Point)
3597 value = matrix.map(value.toPoint());
3598 return value;
3599}
3600
3601/*!
3602 \fn void QGraphicsScene::update(const QRectF &rect)
3603 Schedules a redraw of the area \a rect on the scene.
3604
3605 \sa sceneRect(), changed()
3606*/
3607void QGraphicsScene::update(const QRectF &rect)
3608{
3609 Q_D(QGraphicsScene);
3610 if (d->updateAll || (rect.isEmpty() && !rect.isNull()))
3611 return;
3612
3613 // Check if anyone's connected; if not, we can send updates directly to
3614 // the views. Otherwise or if there are no views, use old behavior.
3615 bool directUpdates = !(d->connectedSignals & d->changedSignalMask) && !d->views.isEmpty();
3616 if (rect.isNull()) {
3617 d->updateAll = true;
3618 d->updatedRects.clear();
3619 if (directUpdates) {
3620 // Update all views.
3621 for (int i = 0; i < d->views.size(); ++i)
3622 d->views.at(i)->d_func()->updateAll();
3623 }
3624 } else {
3625 if (directUpdates) {
3626 // Update all views.
3627 for (int i = 0; i < d->views.size(); ++i) {
3628 QGraphicsView *view = d->views.at(i);
3629 view->d_func()->updateRegion(QRegion(view->mapFromScene(rect).boundingRect()));
3630 }
3631 } else {
3632 d->updatedRects << rect;
3633 }
3634 }
3635
3636 if (!directUpdates && !d->calledEmitUpdated) {
3637 d->calledEmitUpdated = true;
3638 QMetaObject::invokeMethod(this, "_q_emitUpdated", Qt::QueuedConnection);
3639 }
3640}
3641
3642/*!
3643 \fn void QGraphicsScene::update(qreal x, qreal y, qreal w, qreal h)
3644 \overload
3645 \since 4.3
3646
3647 This function is equivalent to calling update(QRectF(\a x, \a y, \a w,
3648 \a h));
3649*/
3650
3651/*!
3652 Invalidates and schedules a redraw of the \a layers in \a rect on the
3653 scene. Any cached content in \a layers is unconditionally invalidated and
3654 redrawn.
3655
3656 You can use this function overload to notify QGraphicsScene of changes to
3657 the background or the foreground of the scene. This function is commonly
3658 used for scenes with tile-based backgrounds to notify changes when
3659 QGraphicsView has enabled
3660 \l{QGraphicsView::CacheBackground}{CacheBackground}.
3661
3662 Example:
3663
3664 \snippet doc/src/snippets/code/src_gui_graphicsview_qgraphicsscene.cpp 5
3665
3666 Note that QGraphicsView currently supports background caching only (see
3667 QGraphicsView::CacheBackground). This function is equivalent to calling
3668 update() if any layer but BackgroundLayer is passed.
3669
3670 \sa QGraphicsView::resetCachedContent()
3671*/
3672void QGraphicsScene::invalidate(const QRectF &rect, SceneLayers layers)
3673{
3674 foreach (QGraphicsView *view, views())
3675 view->invalidateScene(rect, layers);
3676 update(rect);
3677}
3678
3679/*!
3680 \fn void QGraphicsScene::invalidate(qreal x, qreal y, qreal w, qreal h, SceneLayers layers)
3681 \overload
3682 \since 4.3
3683
3684 This convenience function is equivalent to calling invalidate(QRectF(\a x, \a
3685 y, \a w, \a h), \a layers);
3686*/
3687
3688/*!
3689 Returns a list of all the views that display this scene.
3690
3691 \sa QGraphicsView::scene()
3692*/
3693QList <QGraphicsView *> QGraphicsScene::views() const
3694{
3695 Q_D(const QGraphicsScene);
3696 return d->views;
3697}
3698
3699/*!
3700 This slot \e advances the scene by one step, by calling
3701 QGraphicsItem::advance() for all items on the scene. This is done in two
3702 phases: in the first phase, all items are notified that the scene is about
3703 to change, and in the second phase all items are notified that they can
3704 move. In the first phase, QGraphicsItem::advance() is called passing a
3705 value of 0 as an argument, and 1 is passed in the second phase.
3706
3707 \sa QGraphicsItem::advance(), QGraphicsItemAnimation, QTimeLine
3708*/
3709void QGraphicsScene::advance()
3710{
3711 for (int i = 0; i < 2; ++i) {
3712 foreach (QGraphicsItem *item, items())
3713 item->advance(i);
3714 }
3715}
3716
3717/*!
3718 Processes the event \a event, and dispatches it to the respective
3719 event handlers.
3720
3721 In addition to calling the convenience event handlers, this
3722 function is responsible for converting mouse move events to hover
3723 events for when there is no mouse grabber item. Hover events are
3724 delivered directly to items; there is no convenience function for
3725 them.
3726
3727 Unlike QWidget, QGraphicsScene does not have the convenience functions
3728 \l{QWidget::}{enterEvent()} and \l{QWidget::}{leaveEvent()}. Use this
3729 function to obtain those events instead.
3730
3731 \sa contextMenuEvent(), keyPressEvent(), keyReleaseEvent(),
3732 mousePressEvent(), mouseMoveEvent(), mouseReleaseEvent(),
3733 mouseDoubleClickEvent(), focusInEvent(), focusOutEvent()
3734*/
3735bool QGraphicsScene::event(QEvent *event)
3736{
3737 Q_D(QGraphicsScene);
3738
3739 switch (event->type()) {
3740 case QEvent::GraphicsSceneMousePress:
3741 case QEvent::GraphicsSceneMouseMove:
3742 case QEvent::GraphicsSceneMouseRelease:
3743 case QEvent::GraphicsSceneMouseDoubleClick:
3744 case QEvent::GraphicsSceneHoverEnter:
3745 case QEvent::GraphicsSceneHoverLeave:
3746 case QEvent::GraphicsSceneHoverMove:
3747 // Reset the under-mouse list to ensure that this event gets fresh
3748 // item-under-mouse data. Be careful about this list; if people delete
3749 // items from inside event handlers, this list can quickly end up
3750 // having stale pointers in it. We need to clear it before dispatching
3751 // events that use it.
3752 d->cachedItemsUnderMouse.clear();
3753 default:
3754 break;
3755 }
3756
3757 switch (event->type()) {
3758 case QEvent::GraphicsSceneDragEnter:
3759 dragEnterEvent(static_cast<QGraphicsSceneDragDropEvent *>(event));
3760 break;
3761 case QEvent::GraphicsSceneDragMove:
3762 dragMoveEvent(static_cast<QGraphicsSceneDragDropEvent *>(event));
3763 break;
3764 case QEvent::GraphicsSceneDragLeave:
3765 dragLeaveEvent(static_cast<QGraphicsSceneDragDropEvent *>(event));
3766 break;
3767 case QEvent::GraphicsSceneDrop:
3768 dropEvent(static_cast<QGraphicsSceneDragDropEvent *>(event));
3769 break;
3770 case QEvent::GraphicsSceneContextMenu:
3771 contextMenuEvent(static_cast<QGraphicsSceneContextMenuEvent *>(event));
3772 break;
3773 case QEvent::KeyPress:
3774 if (!d->focusItem) {
3775 QKeyEvent *k = static_cast<QKeyEvent *>(event);
3776 if (k->key() == Qt::Key_Tab || k->key() == Qt::Key_Backtab) {
3777 if (!(k->modifiers() & (Qt::ControlModifier | Qt::AltModifier))) { //### Add MetaModifier?
3778 bool res = false;
3779 if (k->key() == Qt::Key_Backtab
3780 || (k->key() == Qt::Key_Tab && (k->modifiers() & Qt::ShiftModifier))) {
3781 res = focusNextPrevChild(false);
3782 } else if (k->key() == Qt::Key_Tab) {
3783 res = focusNextPrevChild(true);
3784 }
3785 if (!res)
3786 event->ignore();
3787 return true;
3788 }
3789 }
3790 }
3791 keyPressEvent(static_cast<QKeyEvent *>(event));
3792 break;
3793 case QEvent::KeyRelease:
3794 keyReleaseEvent(static_cast<QKeyEvent *>(event));
3795 break;
3796 case QEvent::ShortcutOverride: {
3797 QGraphicsItem *parent = focusItem();
3798 while (parent) {
3799 d->sendEvent(parent, event);
3800 if (event->isAccepted())
3801 return true;
3802 parent = parent->parentItem();
3803 }
3804 }
3805 return false;
3806 case QEvent::GraphicsSceneMouseMove:
3807 mouseMoveEvent(static_cast<QGraphicsSceneMouseEvent *>(event));
3808 break;
3809 case QEvent::GraphicsSceneMousePress:
3810 mousePressEvent(static_cast<QGraphicsSceneMouseEvent *>(event));
3811 break;
3812 case QEvent::GraphicsSceneMouseRelease:
3813 mouseReleaseEvent(static_cast<QGraphicsSceneMouseEvent *>(event));
3814 break;
3815 case QEvent::GraphicsSceneMouseDoubleClick:
3816 mouseDoubleClickEvent(static_cast<QGraphicsSceneMouseEvent *>(event));
3817 break;
3818 case QEvent::GraphicsSceneWheel:
3819 wheelEvent(static_cast<QGraphicsSceneWheelEvent *>(event));
3820 break;
3821 case QEvent::FocusIn:
3822 focusInEvent(static_cast<QFocusEvent *>(event));
3823 break;
3824 case QEvent::FocusOut:
3825 focusOutEvent(static_cast<QFocusEvent *>(event));
3826 break;
3827 case QEvent::GraphicsSceneHoverEnter:
3828 case QEvent::GraphicsSceneHoverLeave:
3829 case QEvent::GraphicsSceneHoverMove:
3830 d->dispatchHoverEvent(static_cast<QGraphicsSceneHoverEvent *>(event));
3831 break;
3832 case QEvent::Leave:
3833 d->leaveScene();
3834 break;
3835 case QEvent::GraphicsSceneHelp:
3836 helpEvent(static_cast<QGraphicsSceneHelpEvent *>(event));
3837 break;
3838 case QEvent::InputMethod:
3839 inputMethodEvent(static_cast<QInputMethodEvent *>(event));
3840 break;
3841 case QEvent::WindowActivate: {
3842 if (!d->activationRefCount++) {
3843 // Notify all non-window widgets.
3844 foreach (QGraphicsItem *item, items()) {
3845 if (item->isWidget() && item->isVisible() && !item->isWindow() && !item->parentWidget()) {
3846 QEvent event(QEvent::WindowActivate);
3847 QApplication::sendEvent(static_cast<QGraphicsWidget *>(item), &event);
3848 }
3849 }
3850
3851 // Restore window activation.
3852 QGraphicsItem *nextFocusItem = d->focusItem ? d->focusItem : d->lastFocusItem;
3853 if (nextFocusItem && nextFocusItem->window())
3854 setActiveWindow(static_cast<QGraphicsWidget *>(nextFocusItem));
3855 else if (d->tabFocusFirst && d->tabFocusFirst->isWindow())
3856 setActiveWindow(d->tabFocusFirst);
3857 }
3858 break;
3859 }
3860 case QEvent::WindowDeactivate: {
3861 if (!--d->activationRefCount) {
3862 // Remove window activation.
3863 setActiveWindow(0);
3864
3865 // Notify all non-window widgets.
3866 foreach (QGraphicsItem *item, items()) {
3867 if (item->isWidget() && item->isVisible() && !item->isWindow() && !item->parentWidget()) {
3868 QEvent event(QEvent::WindowDeactivate);
3869 QApplication::sendEvent(static_cast<QGraphicsWidget *>(item), &event);
3870 }
3871 }
3872 }
3873 break;
3874 }
3875 case QEvent::ApplicationFontChange: {
3876 // Resolve the existing scene font.
3877 d->resolveFont();
3878 break;
3879 }
3880 case QEvent::FontChange:
3881 // Update the entire scene when the font changes.
3882 update();
3883 break;
3884 case QEvent::ApplicationPaletteChange: {
3885 // Resolve the existing scene palette.
3886 d->resolvePalette();
3887 break;
3888 }
3889 case QEvent::PaletteChange:
3890 // Update the entire scene when the palette changes.
3891 update();
3892 break;
3893 case QEvent::StyleChange:
3894 // Reresolve all widgets' styles. Update all top-level widgets'
3895 // geometries that do not have an explicit style set.
3896 update();
3897 break;
3898 case QEvent::Timer:
3899 if (d->indexTimerId && static_cast<QTimerEvent *>(event)->timerId() == d->indexTimerId) {
3900 if (d->restartIndexTimer) {
3901 d->restartIndexTimer = false;
3902 } else {
3903 // this call will kill the timer
3904 d->_q_updateIndex();
3905 }
3906 }
3907 // Fallthrough intended - support timers in subclasses.
3908 default:
3909 return QObject::event(event);
3910 }
3911 return true;
3912}
3913
3914/*!
3915 \reimp
3916
3917 QGraphicsScene filters QApplication's events to detect palette and font
3918 changes.
3919*/
3920bool QGraphicsScene::eventFilter(QObject *watched, QEvent *event)
3921{
3922 if (watched != qApp)
3923 return false;
3924
3925 switch (event->type()) {
3926 case QEvent::ApplicationPaletteChange:
3927 qApp->postEvent(this, new QEvent(QEvent::ApplicationPaletteChange));
3928 break;
3929 case QEvent::ApplicationFontChange:
3930 qApp->postEvent(this, new QEvent(QEvent::ApplicationFontChange));
3931 break;
3932 default:
3933 break;
3934 }
3935 return false;
3936}
3937
3938/*!
3939 This event handler, for event \a contextMenuEvent, can be reimplemented in
3940 a subclass to receive context menu events. The default implementation
3941 forwards the event to the topmost item that accepts context menu events at
3942 the position of the event. If no items accept context menu events at this
3943 position, the event is ignored.
3944
3945 \sa QGraphicsItem::contextMenuEvent()
3946*/
3947void QGraphicsScene::contextMenuEvent(QGraphicsSceneContextMenuEvent *contextMenuEvent)
3948{
3949 Q_D(QGraphicsScene);
3950 // Ignore by default.
3951 contextMenuEvent->ignore();
3952
3953 // Send the event to all items at this position until one item accepts the
3954 // event.
3955 foreach (QGraphicsItem *item, d->itemsAtPosition(contextMenuEvent->screenPos(),
3956 contextMenuEvent->scenePos(),
3957 contextMenuEvent->widget())) {
3958 contextMenuEvent->setPos(item->d_ptr->genericMapFromScene(contextMenuEvent->scenePos(),
3959 contextMenuEvent->widget()));
3960 contextMenuEvent->accept();
3961 if (!d->sendEvent(item, contextMenuEvent))
3962 break;
3963
3964 if (contextMenuEvent->isAccepted())
3965 break;
3966 }
3967}
3968
3969/*!
3970 This event handler, for event \a event, can be reimplemented in a subclass
3971 to receive drag enter events for the scene.
3972
3973 The default implementation accepts the event and prepares the scene to
3974 accept drag move events.
3975
3976 \sa QGraphicsItem::dragEnterEvent(), dragMoveEvent(), dragLeaveEvent(),
3977 dropEvent()
3978*/
3979void QGraphicsScene::dragEnterEvent(QGraphicsSceneDragDropEvent *event)
3980{
3981 Q_D(QGraphicsScene);
3982 d->dragDropItem = 0;
3983 d->lastDropAction = Qt::IgnoreAction;
3984 event->accept();
3985}
3986
3987/*!
3988 This event handler, for event \a event, can be reimplemented in a subclass
3989 to receive drag move events for the scene.
3990
3991 \sa QGraphicsItem::dragMoveEvent(), dragEnterEvent(), dragLeaveEvent(),
3992 dropEvent()
3993*/
3994void QGraphicsScene::dragMoveEvent(QGraphicsSceneDragDropEvent *event)
3995{
3996 Q_D(QGraphicsScene);
3997 event->ignore();
3998
3999 if (!d->mouseGrabberItems.isEmpty()) {
4000 // Mouse grabbers that start drag events lose the mouse grab.
4001 d->clearMouseGrabber();
4002 d->mouseGrabberButtonDownPos.clear();
4003 d->mouseGrabberButtonDownScenePos.clear();
4004 d->mouseGrabberButtonDownScreenPos.clear();
4005 }
4006
4007 bool eventDelivered = false;
4008
4009 // Find the topmost enabled items under the cursor. They are all
4010 // candidates for accepting drag & drop events.
4011 foreach (QGraphicsItem *item, d->itemsAtPosition(event->screenPos(),
4012 event->scenePos(),
4013 event->widget())) {
4014 if (!item->isEnabled() || !item->acceptDrops())
4015 continue;
4016
4017 if (item != d->dragDropItem) {
4018 // Enter the new drag drop item. If it accepts the event, we send
4019 // the leave to the parent item.
4020 QGraphicsSceneDragDropEvent dragEnter(QEvent::GraphicsSceneDragEnter);
4021 d->cloneDragDropEvent(&dragEnter, event);
4022 dragEnter.setDropAction(event->proposedAction());
4023 d->sendDragDropEvent(item, &dragEnter);
4024 event->setAccepted(dragEnter.isAccepted());
4025 event->setDropAction(dragEnter.dropAction());
4026 if (!event->isAccepted()) {
4027 // Propagate to the item under
4028 continue;
4029 }
4030
4031 d->lastDropAction = event->dropAction();
4032
4033 if (d->dragDropItem) {
4034 // Leave the last drag drop item. A perfect implementation
4035 // would set the position of this event to the point where
4036 // this event and the last event intersect with the item's
4037 // shape, but that's not easy to do. :-)
4038 QGraphicsSceneDragDropEvent dragLeave(QEvent::GraphicsSceneDragLeave);
4039 d->cloneDragDropEvent(&dragLeave, event);
4040 d->sendDragDropEvent(d->dragDropItem, &dragLeave);
4041 }
4042
4043 // We've got a new drag & drop item
4044 d->dragDropItem = item;
4045 }
4046
4047 // Send the move event.
4048 event->setDropAction(d->lastDropAction);
4049 event->accept();
4050 d->sendDragDropEvent(item, event);
4051 if (event->isAccepted())
4052 d->lastDropAction = event->dropAction();
4053 eventDelivered = true;
4054 break;
4055 }
4056
4057 if (!eventDelivered) {
4058 if (d->dragDropItem) {
4059 // Leave the last drag drop item
4060 QGraphicsSceneDragDropEvent dragLeave(QEvent::GraphicsSceneDragLeave);
4061 d->cloneDragDropEvent(&dragLeave, event);
4062 d->sendDragDropEvent(d->dragDropItem, &dragLeave);
4063 d->dragDropItem = 0;
4064 }
4065 // Propagate
4066 event->setDropAction(Qt::IgnoreAction);
4067 }
4068}
4069
4070/*!
4071 This event handler, for event \a event, can be reimplemented in a subclass
4072 to receive drag leave events for the scene.
4073
4074 \sa QGraphicsItem::dragLeaveEvent(), dragEnterEvent(), dragMoveEvent(),
4075 dropEvent()
4076*/
4077void QGraphicsScene::dragLeaveEvent(QGraphicsSceneDragDropEvent *event)
4078{
4079 Q_D(QGraphicsScene);
4080 if (d->dragDropItem) {
4081 // Leave the last drag drop item
4082 d->sendDragDropEvent(d->dragDropItem, event);
4083 d->dragDropItem = 0;
4084 }
4085}
4086
4087/*!
4088 This event handler, for event \a event, can be reimplemented in a subclass
4089 to receive drop events for the scene.
4090
4091 \sa QGraphicsItem::dropEvent(), dragEnterEvent(), dragMoveEvent(),
4092 dragLeaveEvent()
4093*/
4094void QGraphicsScene::dropEvent(QGraphicsSceneDragDropEvent *event)
4095{
4096 Q_UNUSED(event);
4097 Q_D(QGraphicsScene);
4098 if (d->dragDropItem) {
4099 // Drop on the last drag drop item
4100 d->sendDragDropEvent(d->dragDropItem, event);
4101 d->dragDropItem = 0;
4102 }
4103}
4104
4105/*!
4106 This event handler, for event \a focusEvent, can be reimplemented in a
4107 subclass to receive focus in events.
4108
4109 The default implementation sets focus on the scene, and then on the last
4110 focus item.
4111
4112 \sa QGraphicsItem::focusOutEvent()
4113*/
4114void QGraphicsScene::focusInEvent(QFocusEvent *focusEvent)
4115{
4116 Q_D(QGraphicsScene);
4117
4118 d->hasFocus = true;
4119 switch (focusEvent->reason()) {
4120 case Qt::TabFocusReason:
4121 if (!focusNextPrevChild(true))
4122 focusEvent->ignore();
4123 break;
4124 case Qt::BacktabFocusReason:
4125 if (!focusNextPrevChild(false))
4126 focusEvent->ignore();
4127 break;
4128 default:
4129 if (d->lastFocusItem) {
4130 // Set focus on the last focus item
4131 setFocusItem(d->lastFocusItem, focusEvent->reason());
4132 }
4133 break;
4134 }
4135}
4136
4137/*!
4138 This event handler, for event \a focusEvent, can be reimplemented in a
4139 subclass to receive focus out events.
4140
4141 The default implementation removes focus from any focus item, then removes
4142 focus from the scene.
4143
4144 \sa QGraphicsItem::focusInEvent()
4145*/
4146void QGraphicsScene::focusOutEvent(QFocusEvent *focusEvent)
4147{
4148 Q_D(QGraphicsScene);
4149 d->hasFocus = false;
4150 setFocusItem(0, focusEvent->reason());
4151
4152 // Remove all popups when the scene loses focus.
4153 if (!d->popupWidgets.isEmpty())
4154 d->removePopup(d->popupWidgets.first());
4155}
4156
4157/*!
4158 This event handler, for event \a helpEvent, can be
4159 reimplemented in a subclass to receive help events. The events
4160 are of type QEvent::ToolTip, which are created when a tooltip is
4161 requested.
4162
4163 The default implementation shows the tooltip of the topmost
4164 item, i.e., the item with the highest z-value, at the mouse
4165 cursor position. If no item has a tooltip set, this function
4166 does nothing.
4167
4168 \sa QGraphicsItem::toolTip(), QGraphicsSceneHelpEvent
4169*/
4170void QGraphicsScene::helpEvent(QGraphicsSceneHelpEvent *helpEvent)
4171{
4172#ifdef QT_NO_TOOLTIP
4173 Q_UNUSED(helpEvent);
4174#else
4175 // Find the first item that does tooltips
4176 Q_D(QGraphicsScene);
4177 QList<QGraphicsItem *> itemsAtPos = d->itemsAtPosition(helpEvent->screenPos(),
4178 helpEvent->scenePos(),
4179 helpEvent->widget());
4180 QGraphicsItem *toolTipItem = 0;
4181 for (int i = 0; i < itemsAtPos.size(); ++i) {
4182 QGraphicsItem *tmp = itemsAtPos.at(i);
4183 if (!tmp->toolTip().isEmpty()) {
4184 toolTipItem = tmp;
4185 break;
4186 }
4187 }
4188
4189 // Show or hide the tooltip
4190 QString text;
4191 QPoint point;
4192 if (toolTipItem && !toolTipItem->toolTip().isEmpty()) {
4193 text = toolTipItem->toolTip();
4194 point = helpEvent->screenPos();
4195 }
4196 QToolTip::showText(point, text);
4197 helpEvent->setAccepted(!text.isEmpty());
4198#endif
4199}
4200
4201bool QGraphicsScenePrivate::itemAcceptsHoverEvents_helper(const QGraphicsItem *item) const
4202{
4203 return item->acceptHoverEvents()
4204 || (item->isWidget() && static_cast<const QGraphicsWidget *>(item)->d_func()->hasDecoration());
4205}
4206
4207/*!
4208 This event handler, for event \a hoverEvent, can be reimplemented in a
4209 subclass to receive hover enter events. The default implementation
4210 forwards the event to the topmost item that accepts hover events at the
4211 scene position from the event.
4212
4213 \sa QGraphicsItem::hoverEvent(), QGraphicsItem::setAcceptHoverEvents()
4214*/
4215bool QGraphicsScenePrivate::dispatchHoverEvent(QGraphicsSceneHoverEvent *hoverEvent)
4216{
4217 // Find the first item that accepts hover events, reusing earlier
4218 // calculated data is possible.
4219 if (cachedItemsUnderMouse.isEmpty()) {
4220 cachedItemsUnderMouse = itemsAtPosition(hoverEvent->screenPos(),
4221 hoverEvent->scenePos(),
4222 hoverEvent->widget());
4223 }
4224
4225 QGraphicsItem *item = 0;
4226 for (int i = 0; i < cachedItemsUnderMouse.size(); ++i) {
4227 QGraphicsItem *tmp = cachedItemsUnderMouse.at(i);
4228 if (itemAcceptsHoverEvents_helper(tmp)) {
4229 item = tmp;
4230 break;
4231 }
4232 }
4233
4234 // Find the common ancestor item for the new topmost hoverItem and the
4235 // last item in the hoverItem list.
4236 QGraphicsItem *commonAncestorItem = (item && !hoverItems.isEmpty()) ? item->commonAncestorItem(hoverItems.last()) : 0;
4237 while (commonAncestorItem && !itemAcceptsHoverEvents_helper(commonAncestorItem))
4238 commonAncestorItem = commonAncestorItem->parentItem();
4239 if (commonAncestorItem && commonAncestorItem->window() != item->window()) {
4240 // The common ancestor isn't in the same window as the two hovered
4241 // items.
4242 commonAncestorItem = 0;
4243 }
4244
4245 // Check if the common ancestor item is known.
4246 int index = commonAncestorItem ? hoverItems.indexOf(commonAncestorItem) : -1;
4247 // Send hover leaves to any existing hovered children of the common
4248 // ancestor item.
4249 for (int i = hoverItems.size() - 1; i > index; --i) {
4250 QGraphicsItem *lastItem = hoverItems.takeLast();
4251 if (itemAcceptsHoverEvents_helper(lastItem))
4252 sendHoverEvent(QEvent::GraphicsSceneHoverLeave, lastItem, hoverEvent);
4253 }
4254
4255 // Item is a child of a known item. Generate enter events for the
4256 // missing links.
4257 QList<QGraphicsItem *> parents;
4258 QGraphicsItem *parent = item;
4259 while (parent && parent != commonAncestorItem) {
4260 parents.prepend(parent);
4261 if (parent->isWindow()) {
4262 // Stop at the window - we don't deliver beyond this point.
4263 break;
4264 }
4265 parent = parent->parentItem();
4266 }
4267 for (int i = 0; i < parents.size(); ++i) {
4268 parent = parents.at(i);
4269 hoverItems << parent;
4270 if (itemAcceptsHoverEvents_helper(parent))
4271 sendHoverEvent(QEvent::GraphicsSceneHoverEnter, parent, hoverEvent);
4272 }
4273
4274 // Generate a move event for the item itself
4275 if (item && !hoverItems.isEmpty() && item == hoverItems.last()) {
4276 sendHoverEvent(QEvent::GraphicsSceneHoverMove, item, hoverEvent);
4277 return true;
4278 }
4279 return false;
4280}
4281
4282/*!
4283 \internal
4284
4285 Handles all actions necessary to clean up the scene when the mouse leaves
4286 the view.
4287*/
4288void QGraphicsScenePrivate::leaveScene()
4289{
4290 Q_Q(QGraphicsScene);
4291#ifndef QT_NO_TOOLTIP
4292 // Remove any tooltips
4293 QToolTip::showText(QPoint(), QString());
4294#endif
4295 // Send HoverLeave events to all existing hover items, topmost first.
4296 QGraphicsView *senderWidget = qobject_cast<QGraphicsView *>(q->sender());
4297 QGraphicsSceneHoverEvent hoverEvent;
4298 hoverEvent.setWidget(senderWidget);
4299
4300 if (senderWidget) {
4301 QPoint cursorPos = QCursor::pos();
4302 hoverEvent.setScenePos(senderWidget->mapToScene(senderWidget->mapFromGlobal(cursorPos)));
4303 hoverEvent.setLastScenePos(hoverEvent.scenePos());
4304 hoverEvent.setScreenPos(cursorPos);
4305 hoverEvent.setLastScreenPos(hoverEvent.screenPos());
4306 }
4307
4308 while (!hoverItems.isEmpty()) {
4309 QGraphicsItem *lastItem = hoverItems.takeLast();
4310 if (lastItem->acceptHoverEvents()
4311 || (lastItem->isWidget() && static_cast<QGraphicsWidget*>(lastItem)->d_func()->hasDecoration()))
4312 sendHoverEvent(QEvent::GraphicsSceneHoverLeave, lastItem, &hoverEvent);
4313 }
4314}
4315
4316/*!
4317 This event handler, for event \a keyEvent, can be reimplemented in a
4318 subclass to receive keypress events. The default implementation forwards
4319 the event to current focus item.
4320
4321 \sa QGraphicsItem::keyPressEvent(), focusItem()
4322*/
4323void QGraphicsScene::keyPressEvent(QKeyEvent *keyEvent)
4324{
4325 // ### Merge this function with keyReleaseEvent; they are identical
4326 // ### (except this comment).
4327 Q_D(QGraphicsScene);
4328 QGraphicsItem *item = !d->keyboardGrabberItems.isEmpty() ? d->keyboardGrabberItems.last() : 0;
4329 if (!item)
4330 item = focusItem();
4331 if (item) {
4332 QGraphicsItem *p = item;
4333 do {
4334 // Accept the event by default
4335 keyEvent->accept();
4336 // Send it; QGraphicsItem::keyPressEvent ignores it. If the event
4337 // is filtered out, stop propagating it.
4338 if (!d->sendEvent(p, keyEvent))
4339 break;
4340 } while (!keyEvent->isAccepted() && !p->isWindow() && (p = p->parentItem()));
4341 } else {
4342 keyEvent->ignore();
4343 }
4344}
4345
4346/*!
4347 This event handler, for event \a keyEvent, can be reimplemented in a
4348 subclass to receive key release events. The default implementation
4349 forwards the event to current focus item.
4350
4351 \sa QGraphicsItem::keyReleaseEvent(), focusItem()
4352*/
4353void QGraphicsScene::keyReleaseEvent(QKeyEvent *keyEvent)
4354{
4355 // ### Merge this function with keyPressEvent; they are identical (except
4356 // ### this comment).
4357 Q_D(QGraphicsScene);
4358 QGraphicsItem *item = !d->keyboardGrabberItems.isEmpty() ? d->keyboardGrabberItems.last() : 0;
4359 if (!item)
4360 item = focusItem();
4361 if (item) {
4362 QGraphicsItem *p = item;
4363 do {
4364 // Accept the event by default
4365 keyEvent->accept();
4366 // Send it; QGraphicsItem::keyPressEvent ignores it. If the event
4367 // is filtered out, stop propagating it.
4368 if (!d->sendEvent(p, keyEvent))
4369 break;
4370 } while (!keyEvent->isAccepted() && !p->isWindow() && (p = p->parentItem()));
4371 } else {
4372 keyEvent->ignore();
4373 }
4374}
4375
4376/*!
4377 This event handler, for event \a mouseEvent, can be reimplemented
4378 in a subclass to receive mouse press events for the scene.
4379
4380 The default implementation depends on the state of the scene. If
4381 there is a mouse grabber item, then the event is sent to the mouse
4382 grabber. Otherwise, it is forwarded to the topmost item that
4383 accepts mouse events at the scene position from the event, and
4384 that item promptly becomes the mouse grabber item.
4385
4386 If there is no item at the given position on the scene, the
4387 selection area is reset, any focus item loses its input focus, and
4388 the event is then ignored.
4389
4390 \sa QGraphicsItem::mousePressEvent(),
4391 QGraphicsItem::setAcceptedMouseButtons()
4392*/
4393void QGraphicsScene::mousePressEvent(QGraphicsSceneMouseEvent *mouseEvent)
4394{
4395 Q_D(QGraphicsScene);
4396 d->mousePressEventHandler(mouseEvent);
4397}
4398
4399/*!
4400 This event handler, for event \a mouseEvent, can be reimplemented
4401 in a subclass to receive mouse move events for the scene.
4402
4403 The default implementation depends on the mouse grabber state. If there is
4404 a mouse grabber item, the event is sent to the mouse grabber. If there
4405 are any items that accept hover events at the current position, the event
4406 is translated into a hover event and accepted; otherwise it's ignored.
4407
4408 \sa QGraphicsItem::mousePressEvent(), QGraphicsItem::mouseReleaseEvent(),
4409 QGraphicsItem::mouseDoubleClickEvent(), QGraphicsItem::setAcceptedMouseButtons()
4410*/
4411void QGraphicsScene::mouseMoveEvent(QGraphicsSceneMouseEvent *mouseEvent)
4412{
4413 Q_D(QGraphicsScene);
4414 if (d->mouseGrabberItems.isEmpty()) {
4415 if (mouseEvent->buttons())
4416 return;
4417 QGraphicsSceneHoverEvent hover;
4418 _q_hoverFromMouseEvent(&hover, mouseEvent);
4419 mouseEvent->setAccepted(d->dispatchHoverEvent(&hover));
4420 return;
4421 }
4422
4423 // Forward the event to the mouse grabber
4424 d->sendMouseEvent(mouseEvent);
4425 mouseEvent->accept();
4426}
4427
4428/*!
4429 This event handler, for event \a mouseEvent, can be reimplemented
4430 in a subclass to receive mouse release events for the scene.
4431
4432 The default implementation depends on the mouse grabber state. If
4433 there is no mouse grabber, the event is ignored. Otherwise, if
4434 there is a mouse grabber item, the event is sent to the mouse
4435 grabber. If this mouse release represents the last pressed button
4436 on the mouse, the mouse grabber item then loses the mouse grab.
4437
4438 \sa QGraphicsItem::mousePressEvent(), QGraphicsItem::mouseMoveEvent(),
4439 QGraphicsItem::mouseDoubleClickEvent(), QGraphicsItem::setAcceptedMouseButtons()
4440*/
4441void QGraphicsScene::mouseReleaseEvent(QGraphicsSceneMouseEvent *mouseEvent)
4442{
4443 Q_D(QGraphicsScene);
4444 if (d->mouseGrabberItems.isEmpty()) {
4445 mouseEvent->ignore();
4446 return;
4447 }
4448
4449 // Forward the event to the mouse grabber
4450 d->sendMouseEvent(mouseEvent);
4451 mouseEvent->accept();
4452
4453 // Reset the mouse grabber when the last mouse button has been released.
4454 if (!mouseEvent->buttons()) {
4455 if (!d->mouseGrabberItems.isEmpty()) {
4456 d->lastMouseGrabberItem = d->mouseGrabberItems.last();
4457 if (d->lastMouseGrabberItemHasImplicitMouseGrab)
4458 d->mouseGrabberItems.last()->ungrabMouse();
4459 } else {
4460 d->lastMouseGrabberItem = 0;
4461 }
4462
4463 // Generate a hoverevent
4464 QGraphicsSceneHoverEvent hoverEvent;
4465 _q_hoverFromMouseEvent(&hoverEvent, mouseEvent);
4466 d->dispatchHoverEvent(&hoverEvent);
4467 }
4468}
4469
4470/*!
4471 This event handler, for event \a mouseEvent, can be reimplemented
4472 in a subclass to receive mouse doubleclick events for the scene.
4473
4474 If someone doubleclicks on the scene, the scene will first receive
4475 a mouse press event, followed by a release event (i.e., a click),
4476 then a doubleclick event, and finally a release event. If the
4477 doubleclick event is delivered to a different item than the one
4478 that received the first press and release, it will be delivered as
4479 a press event. However, tripleclick events are not delivered as
4480 doubleclick events in this case.
4481
4482 The default implementation is similar to mousePressEvent().
4483
4484 \sa QGraphicsItem::mousePressEvent(), QGraphicsItem::mouseMoveEvent(),
4485 QGraphicsItem::mouseReleaseEvent(), QGraphicsItem::setAcceptedMouseButtons()
4486*/
4487void QGraphicsScene::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *mouseEvent)
4488{
4489 Q_D(QGraphicsScene);
4490 d->mousePressEventHandler(mouseEvent);
4491}
4492
4493/*!
4494 This event handler, for event \a wheelEvent, can be reimplemented in a
4495 subclass to receive mouse wheel events for the scene.
4496
4497 By default, the event is delivered to the topmost visible item under the
4498 cursor. If ignored, the event propagates to the item beneath, and again
4499 until the event is accepted, or it reaches the scene. If no items accept
4500 the event, it is ignored.
4501
4502 \sa QGraphicsItem::wheelEvent()
4503*/
4504void QGraphicsScene::wheelEvent(QGraphicsSceneWheelEvent *wheelEvent)
4505{
4506 Q_D(QGraphicsScene);
4507 QList<QGraphicsItem *> wheelCandidates = d->itemsAtPosition(wheelEvent->screenPos(),
4508 wheelEvent->scenePos(),
4509 wheelEvent->widget());
4510
4511 bool hasSetFocus = false;
4512 foreach (QGraphicsItem *item, wheelCandidates) {
4513 if (!hasSetFocus && item->isEnabled() && (item->flags() & QGraphicsItem::ItemIsFocusable)) {
4514 if (item->isWidget() && static_cast<QGraphicsWidget *>(item)->focusPolicy() == Qt::WheelFocus) {
4515 hasSetFocus = true;
4516 if (item != focusItem())
4517 setFocusItem(item, Qt::MouseFocusReason);
4518 }
4519 }
4520
4521 wheelEvent->setPos(item->d_ptr->genericMapFromScene(wheelEvent->scenePos(),
4522 wheelEvent->widget()));
4523 wheelEvent->accept();
4524 bool isWindow = item->isWindow();
4525 d->sendEvent(item, wheelEvent);
4526 if (isWindow || wheelEvent->isAccepted())
4527 break;
4528 }
4529}
4530
4531/*!
4532 This event handler, for event \a event, can be reimplemented in a
4533 subclass to receive input method events for the scene.
4534
4535 The default implementation forwards the event to the focusItem().
4536 If no item currently has focus, this function does nothing.
4537
4538 \sa QGraphicsItem::inputMethodEvent()
4539*/
4540void QGraphicsScene::inputMethodEvent(QInputMethodEvent *event)
4541{
4542 Q_D(QGraphicsScene);
4543 if (!d->focusItem)
4544 return;
4545 d->sendEvent(d->focusItem, event);
4546}
4547
4548/*!
4549 Draws the background of the scene using \a painter, before any items and
4550 the foreground are drawn. Reimplement this function to provide a custom
4551 background for the scene.
4552
4553 All painting is done in \e scene coordinates. The \a rect
4554 parameter is the exposed rectangle.
4555
4556 If all you want is to define a color, texture, or gradient for the
4557 background, you can call setBackgroundBrush() instead.
4558
4559 \sa drawForeground(), drawItems()
4560*/
4561void QGraphicsScene::drawBackground(QPainter *painter, const QRectF &rect)
4562{
4563 Q_D(QGraphicsScene);
4564
4565 if (d->backgroundBrush.style() != Qt::NoBrush) {
4566 if (d->painterStateProtection)
4567 painter->save();
4568 painter->setBrushOrigin(0, 0);
4569 painter->fillRect(rect, backgroundBrush());
4570 if (d->painterStateProtection)
4571 painter->restore();
4572 }
4573}
4574
4575/*!
4576 Draws the foreground of the scene using \a painter, after the background
4577 and all items have been drawn. Reimplement this function to provide a
4578 custom foreground for the scene.
4579
4580 All painting is done in \e scene coordinates. The \a rect
4581 parameter is the exposed rectangle.
4582
4583 If all you want is to define a color, texture or gradient for the
4584 foreground, you can call setForegroundBrush() instead.
4585
4586 \sa drawBackground(), drawItems()
4587*/
4588void QGraphicsScene::drawForeground(QPainter *painter, const QRectF &rect)
4589{
4590 Q_D(QGraphicsScene);
4591
4592 if (d->foregroundBrush.style() != Qt::NoBrush) {
4593 if (d->painterStateProtection)
4594 painter->save();
4595 painter->setBrushOrigin(0, 0);
4596 painter->fillRect(rect, foregroundBrush());
4597 if (d->painterStateProtection)
4598 painter->restore();
4599 }
4600}
4601
4602static void _q_paintItem(QGraphicsItem *item, QPainter *painter,
4603 const QStyleOptionGraphicsItem *option, QWidget *widget,
4604 bool useWindowOpacity, bool painterStateProtection)
4605{
4606 if (!item->isWidget()) {
4607 item->paint(painter, option, widget);
4608 return;
4609 }
4610 QGraphicsWidget *widgetItem = static_cast<QGraphicsWidget *>(item);
4611 QGraphicsProxyWidget *proxy = qobject_cast<QGraphicsProxyWidget *>(widgetItem);
4612 const qreal windowOpacity = (proxy && proxy->widget() && useWindowOpacity)
4613 ? proxy->widget()->windowOpacity() : 1.0;
4614 const qreal oldPainterOpacity = painter->opacity();
4615
4616 if (qFuzzyCompare(windowOpacity + 1, qreal(1.0)))
4617 return;
4618 // Set new painter opacity.
4619 if (windowOpacity < 1.0)
4620 painter->setOpacity(oldPainterOpacity * windowOpacity);
4621
4622 // set layoutdirection on the painter
4623 Qt::LayoutDirection oldLayoutDirection = painter->layoutDirection();
4624 painter->setLayoutDirection(widgetItem->layoutDirection());
4625
4626 if (widgetItem->isWindow() && widgetItem->windowType() != Qt::Popup && widgetItem->windowType() != Qt::ToolTip
4627 && !(widgetItem->windowFlags() & Qt::FramelessWindowHint)) {
4628 if (painterStateProtection)
4629 painter->save();
4630 widgetItem->paintWindowFrame(painter, option, widget);
4631 if (painterStateProtection)
4632 painter->restore();
4633 }
4634
4635 widgetItem->paint(painter, option, widget);
4636
4637 // Restore layoutdirection on the painter.
4638 painter->setLayoutDirection(oldLayoutDirection);
4639 // Restore painter opacity.
4640 if (windowOpacity < 1.0)
4641 painter->setOpacity(oldPainterOpacity);
4642}
4643
4644static void _q_paintIntoCache(QPixmap *pix, QGraphicsItem *item, const QRegion &pixmapExposed,
4645 const QTransform &itemToPixmap, QPainter::RenderHints renderHints,
4646 const QStyleOptionGraphicsItem *option, bool painterStateProtection)
4647{
4648 QPixmap subPix;
4649 QPainter pixmapPainter;
4650 QRect br = pixmapExposed.boundingRect();
4651
4652 // Don't use subpixmap if we get a full update.
4653 if (pixmapExposed.isEmpty() || (pixmapExposed.numRects() == 1 && br.contains(pix->rect()))) {
4654 pix->fill(Qt::transparent);
4655 pixmapPainter.begin(pix);
4656 } else {
4657 subPix = QPixmap(br.size());
4658 subPix.fill(Qt::transparent);
4659 pixmapPainter.begin(&subPix);
4660 pixmapPainter.translate(-br.topLeft());
4661 if (!pixmapExposed.isEmpty()) {
4662 // Applied to subPix; paint is adjusted to the coordinate space is
4663 // correct.
4664 pixmapPainter.setClipRegion(pixmapExposed);
4665 }
4666 }
4667
4668 pixmapPainter.setRenderHints(pixmapPainter.renderHints(), false);
4669 pixmapPainter.setRenderHints(renderHints, true);
4670 pixmapPainter.setWorldTransform(itemToPixmap, true);
4671
4672 // Render.
4673 _q_paintItem(item, &pixmapPainter, option, 0, false, painterStateProtection);
4674 pixmapPainter.end();
4675
4676 if (!subPix.isNull()) {
4677 // Blit the subpixmap into the main pixmap.
4678 pixmapPainter.begin(pix);
4679 pixmapPainter.setCompositionMode(QPainter::CompositionMode_Source);
4680 pixmapPainter.setClipRegion(pixmapExposed);
4681 pixmapPainter.drawPixmap(br.topLeft(), subPix);
4682 pixmapPainter.end();
4683 }
4684}
4685
4686/*!
4687 \internal
4688
4689 Draws items directly, or using cache.
4690*/
4691void QGraphicsScenePrivate::drawItemHelper(QGraphicsItem *item, QPainter *painter,
4692 const QStyleOptionGraphicsItem *option, QWidget *widget,
4693 bool painterStateProtection)
4694{
4695 QGraphicsItemPrivate *itemd = item->d_ptr;
4696 QGraphicsItem::CacheMode cacheMode = QGraphicsItem::CacheMode(itemd->cacheMode);
4697
4698 // Render directly, using no cache.
4699 if (cacheMode == QGraphicsItem::NoCache
4700#ifdef Q_WS_X11
4701 || !X11->use_xrender
4702#endif
4703 ) {
4704 _q_paintItem(static_cast<QGraphicsWidget *>(item), painter, option, widget, true, painterStateProtection);
4705 return;
4706 }
4707
4708 const qreal oldPainterOpacity = painter->opacity();
4709 qreal newPainterOpacity = oldPainterOpacity;
4710 QGraphicsProxyWidget *proxy = item->isWidget() ? qobject_cast<QGraphicsProxyWidget *>(static_cast<QGraphicsWidget *>(item)) : 0;
4711 if (proxy && proxy->widget()) {
4712 const qreal windowOpacity = proxy->widget()->windowOpacity();
4713 if (windowOpacity < 1.0)
4714 newPainterOpacity *= windowOpacity;
4715 }
4716
4717 // Item's (local) bounding rect
4718 QRectF brect = item->boundingRect();
4719 QRectF adjustedBrect(brect);
4720 _q_adjustRect(&adjustedBrect);
4721 if (adjustedBrect.isEmpty())
4722 return;
4723
4724 // Fetch the off-screen transparent buffer and exposed area info.
4725 QString pixmapKey;
4726 QPixmap pix;
4727 QGraphicsItemCache *itemCache = itemd->extraItemCache();
4728 if (cacheMode == QGraphicsItem::ItemCoordinateCache) {
4729 if (itemCache->boundingRect != brect.toRect()) {
4730 itemCache->boundingRect = brect.toRect();
4731 itemCache->allExposed = true;
4732 itemCache->exposed.clear();
4733 }
4734 pixmapKey = itemCache->key;
4735 } else {
4736 if ((pixmapKey = itemCache->deviceData.value(widget).key).isEmpty()) {
4737 pixmapKey.sprintf("qgv-%p-%p", item, widget);
4738 QGraphicsItemCache::DeviceData data;
4739 data.key = pixmapKey;
4740 itemCache->deviceData.insert(widget, data);
4741 }
4742 }
4743
4744 // Find pixmap in cache.
4745 if (!itemCache->allExposed)
4746 QPixmapCache::find(pixmapKey, pix);
4747
4748 // Render using item coordinate cache mode.
4749 if (cacheMode == QGraphicsItem::ItemCoordinateCache) {
4750 QSize pixmapSize;
4751 bool fixedCacheSize = false;
4752 QRectF brectAligned = brect.toAlignedRect();
4753 if ((fixedCacheSize = itemCache->fixedSize.isValid())) {
4754 pixmapSize = itemCache->fixedSize;
4755 } else {
4756 pixmapSize = brectAligned.size().toSize();
4757 }
4758
4759 // Create or recreate the pixmap.
4760 int adjust = itemCache->fixedSize.isValid() ? 0 : 2;
4761 QSize adjustSize(adjust*2, adjust*2);
4762 QRectF br = brectAligned.adjusted(-adjust, -adjust, adjust, adjust);
4763 if (pix.isNull() || (!fixedCacheSize && (pixmapSize + adjustSize) != pix.size())) {
4764 pix = QPixmap(pixmapSize + adjustSize);
4765 itemCache->exposed.clear();
4766 itemCache->allExposed = true;
4767 }
4768
4769 // Redraw any newly exposed areas.
4770 if (itemCache->allExposed || !itemCache->exposed.isEmpty()) {
4771 // Fit the item's bounding rect into the pixmap's coordinates.
4772 QTransform itemToPixmap;
4773 if (fixedCacheSize) {
4774 const QPointF scale(pixmapSize.width() / brect.width(), pixmapSize.height() / brect.height());
4775 itemToPixmap.scale(scale.x(), scale.y());
4776 }
4777 itemToPixmap.translate(-br.x(), -br.y());
4778
4779 // Generate the item's exposedRect and map its list of expose
4780 // rects to device coordinates.
4781 QStyleOptionGraphicsItem cacheOption = *option;
4782 QRegion pixmapExposed;
4783 QRectF exposedRect;
4784 if (!itemCache->allExposed) {
4785 for (int i = 0; i < itemCache->exposed.size(); ++i) {
4786 QRectF r = itemCache->exposed.at(i);
4787 exposedRect |= r;
4788 pixmapExposed += itemToPixmap.mapRect(r).toAlignedRect();
4789 }
4790 } else {
4791 exposedRect = brect;
4792 }
4793 cacheOption.exposedRect = exposedRect;
4794
4795 // Render.
4796 _q_paintIntoCache(&pix, item, pixmapExposed, itemToPixmap, painter->renderHints(),
4797 &cacheOption, painterStateProtection);
4798
4799 // Reinsert this pixmap into the cache.
4800 QPixmapCache::insert(pixmapKey, pix);
4801
4802 // Reset expose data.
4803 itemCache->allExposed = false;
4804 itemCache->exposed.clear();
4805 }
4806
4807 // Redraw the exposed area using the transformed painter. Depending on
4808 // the hardware, this may be a server-side operation, or an expensive
4809 // qpixmap-image-transform-pixmap roundtrip.
4810 if (newPainterOpacity != oldPainterOpacity) {
4811 painter->setOpacity(newPainterOpacity);
4812 painter->drawPixmap(br, pix, QRectF(QPointF(), pix.size()));
4813 painter->setOpacity(oldPainterOpacity);
4814 } else {
4815 painter->drawPixmap(br, pix, QRectF(QPointF(), pix.size()));
4816 }
4817 return;
4818 }
4819
4820 // Render using device coordinate cache mode.
4821 if (cacheMode == QGraphicsItem::DeviceCoordinateCache) {
4822 // Find the item's bounds in device coordinates.
4823 QRectF deviceBounds = painter->worldTransform().mapRect(brect);
4824 QRect deviceRect = deviceBounds.toRect().adjusted(-1, -1, 1, 1);
4825 if (deviceRect.isEmpty())
4826 return;
4827 QRect viewRect = widget ? widget->rect() : QRect();
4828 if (widget && !viewRect.intersects(deviceRect))
4829 return;
4830
4831 // Resort to direct rendering if the device rect exceeds the
4832 // (optional) maximum bounds. (QGraphicsSvgItem uses this).
4833 QSize maximumCacheSize =
4834 itemd->extra(QGraphicsItemPrivate::ExtraMaxDeviceCoordCacheSize).toSize();
4835 if (!maximumCacheSize.isEmpty()
4836 && (deviceRect.width() > maximumCacheSize.width()
4837 || deviceRect.height() > maximumCacheSize.height())) {
4838 _q_paintItem(static_cast<QGraphicsWidget *>(item), painter, option, widget,
4839 oldPainterOpacity != newPainterOpacity, painterStateProtection);
4840 return;
4841 }
4842
4843 // Create or reuse offscreen pixmap, possibly scroll/blit from the old one.
4844 bool pixModified = false;
4845 QGraphicsItemCache::DeviceData *deviceData = &itemCache->deviceData[widget];
4846 bool invertable = true;
4847 QTransform diff = deviceData->lastTransform.inverted(&invertable);
4848 if (invertable)
4849 diff *= painter->worldTransform();
4850 deviceData->lastTransform = painter->worldTransform();
4851 if (!invertable || diff.type() > QTransform::TxTranslate) {
4852 pixModified = true;
4853 itemCache->allExposed = true;
4854 itemCache->exposed.clear();
4855 pix = QPixmap();
4856 }
4857
4858 // ### This is a pretty bad way to determine when to start partial
4859 // exposure for DeviceCoordinateCache but it's the least intrusive
4860 // approach for now.
4861#if 0
4862 // Only if the device rect isn't fully contained.
4863 bool allowPartialCacheExposure = !viewRect.contains(deviceRect);
4864#else
4865 // Only if deviceRect is 20% taller or wider than the desktop.
4866 QRect desktopRect = qApp->desktop()->availableGeometry(widget);
4867 bool allowPartialCacheExposure = (desktopRect.width() * 1.2 < deviceRect.width()
4868 || desktopRect.height() * 1.2 < deviceRect.height());
4869#endif
4870 QRegion scrollExposure;
4871 if (deviceData->cacheIndent != QPoint() || allowPartialCacheExposure) {
4872 // Part of pixmap is drawn. Either device contains viewrect (big
4873 // item covers whole screen) or parts of device are outside the
4874 // viewport. In either case the device rect must be the intersect
4875 // between the two.
4876 int dx = deviceRect.left() < viewRect.left() ? viewRect.left() - deviceRect.left() : 0;
4877 int dy = deviceRect.top() < viewRect.top() ? viewRect.top() - deviceRect.top() : 0;
4878 QPoint newCacheIndent(dx, dy);
4879 deviceRect &= viewRect;
4880
4881 if (pix.isNull()) {
4882 deviceData->cacheIndent = QPoint();
4883 itemCache->allExposed = true;
4884 itemCache->exposed.clear();
4885 pixModified = true;
4886 }
4887
4888 // Copy / "scroll" the old pixmap onto the new ole and calculate
4889 // scrolled exposure.
4890 if (newCacheIndent != deviceData->cacheIndent || deviceRect.size() != pix.size()) {
4891 QPoint diff = newCacheIndent - deviceData->cacheIndent;
4892 QPixmap newPix(deviceRect.size());
4893 // ### Investigate removing this fill (test with Plasma and
4894 // graphicssystem raster).
4895 newPix.fill(Qt::transparent);
4896 if (!pix.isNull()) {
4897 QPainter newPixPainter(&newPix);
4898 newPixPainter.drawPixmap(-diff, pix);
4899 newPixPainter.end();
4900 }
4901 QRegion exposed;
4902 exposed += newPix.rect();
4903 if (!pix.isNull())
4904 exposed -= QRect(-diff, pix.size());
4905 scrollExposure = exposed;
4906
4907 pix = newPix;
4908 pixModified = true;
4909 }
4910 deviceData->cacheIndent = newCacheIndent;
4911 } else {
4912 // Full pixmap is drawn.
4913 deviceData->cacheIndent = QPoint();
4914
4915 // Auto-adjust the pixmap size.
4916 if (deviceRect.size() != pix.size()) {
4917 // exposed needs to cover the whole pixmap
4918 pix = QPixmap(deviceRect.size());
4919 pixModified = true;
4920 itemCache->allExposed = true;
4921 itemCache->exposed.clear();
4922 }
4923 }
4924
4925 // Check for newly invalidated areas.
4926 if (itemCache->allExposed || !itemCache->exposed.isEmpty() || !scrollExposure.isEmpty()) {
4927 // Construct an item-to-pixmap transform.
4928 QPointF p = deviceRect.topLeft();
4929 QTransform itemToPixmap = painter->worldTransform();
4930 if (!p.isNull())
4931 itemToPixmap *= QTransform::fromTranslate(-p.x(), -p.y());
4932
4933 // Map the item's logical expose to pixmap coordinates.
4934 QRegion pixmapExposed = scrollExposure;
4935 if (!itemCache->allExposed) {
4936 const QVector<QRectF> &exposed = itemCache->exposed;
4937 for (int i = 0; i < exposed.size(); ++i)
4938 pixmapExposed += itemToPixmap.mapRect(exposed.at(i)).toRect().adjusted(-1, -1, 1, 1);
4939 }
4940
4941 // Calculate the style option's exposedRect.
4942 QRectF br;
4943 if (itemCache->allExposed) {
4944 br = item->boundingRect();
4945 } else {
4946 const QVector<QRectF> &exposed = itemCache->exposed;
4947 for (int i = 0; i < exposed.size(); ++i)
4948 br |= exposed.at(i);
4949 QTransform pixmapToItem = itemToPixmap.inverted();
4950 foreach (QRect r, scrollExposure.rects())
4951 br |= pixmapToItem.mapRect(r);
4952 }
4953 QStyleOptionGraphicsItem cacheOption = *option;
4954 cacheOption.exposedRect = br.adjusted(-1, -1, 1, 1);
4955
4956 // Render the exposed areas.
4957 _q_paintIntoCache(&pix, item, pixmapExposed, itemToPixmap, painter->renderHints(),
4958 &cacheOption, painterStateProtection);
4959
4960 // Reset expose data.
4961 pixModified = true;
4962 itemCache->allExposed = false;
4963 itemCache->exposed.clear();
4964 }
4965
4966 if (pixModified) {
4967 // Reinsert this pixmap into the cache
4968 QPixmapCache::insert(pixmapKey, pix);
4969 }
4970
4971 // Redraw the exposed area using an untransformed painter. This
4972 // effectively becomes a bitblit that does not transform the cache.
4973 QTransform restoreTransform = painter->worldTransform();
4974 painter->setWorldTransform(QTransform());
4975 if (newPainterOpacity != oldPainterOpacity) {
4976 painter->setOpacity(newPainterOpacity);
4977 painter->drawPixmap(deviceRect.topLeft(), pix);
4978 painter->setOpacity(oldPainterOpacity);
4979 } else {
4980 painter->drawPixmap(deviceRect.topLeft(), pix);
4981 }
4982 painter->setWorldTransform(restoreTransform);
4983 return;
4984 }
4985}
4986
4987/*!
4988 Paints the given \a items using the provided \a painter, after the
4989 background has been drawn, and before the foreground has been
4990 drawn. All painting is done in \e scene coordinates. Before
4991 drawing each item, the painter must be transformed using
4992 QGraphicsItem::sceneMatrix().
4993
4994 The \a options parameter is the list of style option objects for
4995 each item in \a items. The \a numItems parameter is the number of
4996 items in \a items and options in \a options. The \a widget
4997 parameter is optional; if specified, it should point to the widget
4998 that is being painted on.
4999
5000 The default implementation prepares the painter matrix, and calls
5001 QGraphicsItem::paint() on all items. Reimplement this function to
5002 provide custom painting of all items for the scene; gaining
5003 complete control over how each item is drawn. In some cases this
5004 can increase drawing performance significantly.
5005
5006 Example:
5007
5008 \snippet doc/src/snippets/graphicssceneadditemsnippet.cpp 0
5009
5010 \sa drawBackground(), drawForeground()
5011*/
5012void QGraphicsScene::drawItems(QPainter *painter,
5013 int numItems,
5014 QGraphicsItem *items[],
5015 const QStyleOptionGraphicsItem options[], QWidget *widget)
5016{
5017 Q_D(QGraphicsScene);
5018
5019 // Detect if painter state protection is disabled.
5020 QTransform viewTransform = painter->worldTransform();
5021 QVarLengthArray<QGraphicsItem *, 16> childClippers;
5022
5023 for (int i = 0; i < numItems; ++i) {
5024 QGraphicsItem *item = items[i];
5025 if (!(item->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren)) {
5026 if (!childClippers.isEmpty()) {
5027 // Item is not clipped to any ancestor: pop all current clippers.
5028 for (int i = 0; i < childClippers.size(); ++i)
5029 painter->restore();
5030 childClippers.clear();
5031 }
5032 } else {
5033 // Item is clipped to an ancestor, which may or may not be in our
5034 // child clipper list. Let's start by finding the item's closest
5035 // clipping ancestor.
5036 QGraphicsItem *clipParent = item->parentItem();
5037 while (clipParent && !(clipParent->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape))
5038 clipParent = clipParent->parentItem();
5039
5040 // Pop any in-between clippers. If the clipper is unknown, pop
5041 // them all. ### QVarLengthArray::lastIndexOf().
5042 int index = -1;
5043 for (int n = childClippers.size() - 1; n >= 0; --n) {
5044 if (childClippers[n] == clipParent) {
5045 index = n;
5046 break;
5047 }
5048 }
5049 if (index != -1) {
5050 int toPop = childClippers.size() - index - 1;
5051 if (toPop > 0) {
5052 for (int i = 0; i < toPop; ++i)
5053 painter->restore();
5054 childClippers.resize(index + 1);
5055 }
5056 }
5057
5058 // Sanity check
5059 if (!childClippers.isEmpty())
5060 Q_ASSERT(childClippers[childClippers.size() - 1] == clipParent);
5061
5062 // If the clipper list is empty at this point, but we're still
5063 // clipped to an ancestor, then we need to build the clip chain
5064 // ourselves. There is only one case that can produce this issue:
5065 // This item is stacked behind an ancestor:
5066 // ItemStacksBehindParent.
5067 if (childClippers.isEmpty()) {
5068 Q_ASSERT(clipParent != 0);
5069 // Build a stack of clippers.
5070 QVarLengthArray<QGraphicsItem *, 16> clippers;
5071 QGraphicsItem *p = clipParent;
5072 do {
5073 if (p->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape)
5074 clippers.append(p);
5075 } while ((p = p->parentItem()) && (p->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren));
5076
5077 // ### This code path can also use the itemTransform
5078 // optimization, but it's hit very rarely.
5079 for (int i = clippers.size() - 1; i >= 0; --i) {
5080 QGraphicsItem *clipper = clippers[i];
5081 if (clipper->d_ptr->itemIsUntransformable()) {
5082 painter->setWorldTransform(clipper->deviceTransform(viewTransform), false);
5083 } else {
5084 painter->setWorldTransform(clipper->sceneTransform() * viewTransform, false);
5085 }
5086
5087 childClippers.append(clipper);
5088 painter->save();
5089 painter->setClipPath(clipper->shape(), Qt::IntersectClip);
5090 }
5091 Q_ASSERT(childClippers[childClippers.size() - 1] == clipParent);
5092 }
5093 }
5094
5095 // Set up the painter transform
5096 if (item->d_ptr->itemIsUntransformable()) {
5097 painter->setWorldTransform(item->deviceTransform(viewTransform), false);
5098 } else {
5099 painter->setWorldTransform(item->sceneTransform() * viewTransform, false);
5100 }
5101
5102 // Save painter
5103 bool saveState = (d->painterStateProtection || (item->flags() & QGraphicsItem::ItemClipsToShape));
5104 if (saveState)
5105 painter->save();
5106
5107 // Set local clip
5108 if (item->flags() & QGraphicsItem::ItemClipsToShape)
5109 painter->setClipPath(item->shape(), Qt::IntersectClip);
5110
5111 // Setup opacity
5112 painter->setOpacity(item->effectiveOpacity());
5113
5114 // Draw the item
5115 d->drawItemHelper(item, painter, &options[i], widget, d->painterStateProtection);
5116
5117 if (saveState)
5118 painter->restore();
5119
5120 if (item->flags() & QGraphicsItem::ItemClipsChildrenToShape) {
5121 // Clip descendents to this item's shape, and keep the painter
5122 // saved.
5123 childClippers.append(item);
5124 painter->save();
5125 painter->setClipPath(item->shape(), Qt::IntersectClip);
5126 }
5127 }
5128
5129 for (int i = 0; i < childClippers.size(); ++i)
5130 painter->restore();
5131
5132 painter->setWorldTransform(viewTransform);
5133}
5134
5135/*!
5136 \since 4.4
5137
5138 Finds a new widget to give the keyboard focus to, as appropriate for Tab
5139 and Shift+Tab, and returns true if it can find a new widget, or false if
5140 it cannot. If \a next is true, this function searches forward; if \a next
5141 is false, it searches backward.
5142
5143 You can reimplement this function in a subclass of QGraphicsScene to
5144 provide fine-grained control over how tab focus passes inside your
5145 scene. The default implementation is based on the tab focus chain defined
5146 by QGraphicsWidget::setTabOrder().
5147*/
5148bool QGraphicsScene::focusNextPrevChild(bool next)
5149{
5150 Q_D(QGraphicsScene);
5151
5152 QGraphicsItem *item = focusItem();
5153 if (item && !item->isWidget()) {
5154 // Tab out of the scene.
5155 return false;
5156 }
5157 if (!item) {
5158 if (d->lastFocusItem && !d->lastFocusItem->isWidget()) {
5159 // Restore focus to the last focusable non-widget item that had
5160 // focus.
5161 setFocusItem(d->lastFocusItem, next ? Qt::TabFocusReason : Qt::BacktabFocusReason);
5162 return true;
5163 }
5164 }
5165 if (!d->tabFocusFirst) {
5166 // No widgets...
5167 return false;
5168 }
5169
5170 // The item must be a widget.
5171 QGraphicsWidget *widget = 0;
5172 if (!item) {
5173 widget = next ? d->tabFocusFirst : d->tabFocusFirst->d_func()->focusPrev;
5174 } else {
5175 QGraphicsWidget *test = static_cast<QGraphicsWidget *>(item);
5176 widget = next ? test->d_func()->focusNext : test->d_func()->focusPrev;
5177 if ((next && widget == d->tabFocusFirst) || (!next && widget == d->tabFocusFirst->d_func()->focusPrev))
5178 return false;
5179 }
5180 QGraphicsWidget *widgetThatHadFocus = widget;
5181
5182 // Run around the focus chain until we find a widget that can take tab focus.
5183 do {
5184 if (widget->flags() & QGraphicsItem::ItemIsFocusable
5185 && widget->isEnabled() && widget->isVisibleTo(0)
5186 && (widget->focusPolicy() & Qt::TabFocus)
5187 && (!item || !item->isWindow() || item->isAncestorOf(widget))
5188 ) {
5189 setFocusItem(widget, next ? Qt::TabFocusReason : Qt::BacktabFocusReason);
5190 return true;
5191 }
5192 widget = next ? widget->d_func()->focusNext : widget->d_func()->focusPrev;
5193 if ((next && widget == d->tabFocusFirst) || (!next && widget == d->tabFocusFirst->d_func()->focusPrev))
5194 return false;
5195 } while (widget != widgetThatHadFocus);
5196
5197 return false;
5198}
5199
5200/*!
5201 \fn QGraphicsScene::changed(const QList<QRectF> &region)
5202
5203 This signal is emitted by QGraphicsScene when control reaches the
5204 event loop, if the scene content changes. The \a region parameter
5205 contains a list of scene rectangles that indicate the area that
5206 has been changed.
5207
5208 \sa QGraphicsView::updateScene()
5209*/
5210
5211/*!
5212 \fn QGraphicsScene::sceneRectChanged(const QRectF &rect)
5213
5214 This signal is emitted by QGraphicsScene whenever the scene rect changes.
5215 The \a rect parameter is the new scene rectangle.
5216
5217 \sa QGraphicsView::updateSceneRect()
5218*/
5219
5220/*!
5221 \fn QGraphicsScene::selectionChanged()
5222 \since 4.3
5223
5224 This signal is emitted by QGraphicsScene whenever the selection
5225 changes. You can call selectedItems() to get the new list of selected
5226 items.
5227
5228 The selection changes whenever an item is selected or unselected, a
5229 selection area is set, cleared or otherwise changed, if a preselected item
5230 is added to the scene, or if a selected item is removed from the scene.
5231
5232 QGraphicsScene emits this signal only once for group selection operations.
5233 For example, if you set a selection area, select or unselect a
5234 QGraphicsItemGroup, or if you add or remove from the scene a parent item
5235 that contains several selected items, selectionChanged() is emitted only
5236 once after the operation has completed (instead of once for each item).
5237
5238 \sa setSelectionArea(), selectedItems(), QGraphicsItem::setSelected()
5239*/
5240
5241/*!
5242 \internal
5243
5244 This private function is called by QGraphicsItem, which is a friend of
5245 QGraphicsScene. It is used by QGraphicsScene to record the rectangles that
5246 need updating. It also launches a single-shot timer to ensure that
5247 updated() will be emitted later.
5248
5249 The \a item parameter is the item that changed, and \a rect is the
5250 area of the item that changed given in item coordinates.
5251*/
5252void QGraphicsScene::itemUpdated(QGraphicsItem *item, const QRectF &rect)
5253{
5254 Q_D(QGraphicsScene);
5255 // Deliver the actual update.
5256 if (!d->updateAll) {
5257 if (d->views.isEmpty() || ((d->connectedSignals & d->changedSignalMask) && !item->d_ptr->itemIsUntransformable()
5258 && qFuzzyCompare(item->boundingRegionGranularity(), qreal(0.0)))) {
5259 // This block of code is kept for compatibility. Since 4.5, by default
5260 // QGraphicsView does not connect the signal and we use the below
5261 // method of delivering updates.
5262 update(item->sceneBoundingRect());
5263 } else {
5264 // ### Remove _q_adjustedRects().
5265 QRectF boundingRect(adjustedItemBoundingRect(item));
5266 if (!rect.isNull()) {
5267 QRectF adjustedRect(rect);
5268 _q_adjustRect(&adjustedRect);
5269 boundingRect &= adjustedRect;
5270 }
5271
5272 // Update each view directly.
5273 for (int i = 0; i < d->views.size(); ++i)
5274 d->views.at(i)->d_func()->itemUpdated(item, boundingRect);
5275 }
5276 }
5277 if (item->d_ptr->dirty) {
5278 d->dirtyItems << item;
5279 d->resetDirtyItemsLater();
5280 }
5281
5282 if (!item->isVisible())
5283 return; // Hiding an item won't effect the largestUntransformableItem/sceneRect.
5284
5285 // Update d->largestUntransformableItem by mapping this item's bounding
5286 // rect back to the topmost untransformable item's untransformed
5287 // coordinate system (which sort of equals the 1:1 coordinate system of an
5288 // untransformed view).
5289 if (item->d_ptr->itemIsUntransformable()) {
5290 QGraphicsItem *parent = item;
5291 while (parent && (parent->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorIgnoresTransformations))
5292 parent = parent->parentItem();
5293 d->largestUntransformableItem |= item->mapToItem(parent, item->boundingRect()).boundingRect();
5294 }
5295
5296 // Only track the automatically growing scene rect if the scene has no
5297 // defined scene rect.
5298 if (!d->hasSceneRect) {
5299 QRectF oldGrowingItemsBoundingRect = d->growingItemsBoundingRect;
5300 QRectF adjustedItemSceneBoundingRect(item->sceneBoundingRect());
5301 _q_adjustRect(&adjustedItemSceneBoundingRect);
5302 d->growingItemsBoundingRect |= adjustedItemSceneBoundingRect;
5303 if (d->growingItemsBoundingRect != oldGrowingItemsBoundingRect)
5304 emit sceneRectChanged(d->growingItemsBoundingRect);
5305 }
5306}
5307
5308/*!
5309 \since 4.4
5310
5311 Returns the scene's style, or the same as QApplication::style() if the
5312 scene has not been explicitly assigned a style.
5313
5314 \sa setStyle()
5315*/
5316QStyle *QGraphicsScene::style() const
5317{
5318 Q_D(const QGraphicsScene);
5319 // ### This function, and the use of styles in general, is non-reentrant.
5320 return d->style ? d->style : qApp->style();
5321}
5322
5323/*!
5324 \since 4.4
5325
5326 Sets or replaces the style of the scene to \a style, and reparents the
5327 style to this scene. Any previously assigned style is deleted. The scene's
5328 style defaults to QApplication::style(), and serves as the default for all
5329 QGraphicsWidget items in the scene.
5330
5331 Changing the style, either directly by calling this function, or
5332 indirectly by calling QApplication::setStyle(), will automatically update
5333 the style for all widgets in the scene that do not have a style explicitly
5334 assigned to them.
5335
5336 If \a style is 0, QGraphicsScene will revert to QApplication::style().
5337
5338 \sa style()
5339*/
5340void QGraphicsScene::setStyle(QStyle *style)
5341{
5342 Q_D(QGraphicsScene);
5343 // ### This function, and the use of styles in general, is non-reentrant.
5344 if (style == d->style)
5345 return;
5346
5347 // Delete the old style,
5348 delete d->style;
5349 if ((d->style = style))
5350 d->style->setParent(this);
5351
5352 // Notify the scene.
5353 QEvent event(QEvent::StyleChange);
5354 QApplication::sendEvent(this, &event);
5355
5356 // Notify all widgets that don't have a style explicitly set.
5357 foreach (QGraphicsItem *item, items()) {
5358 if (item->isWidget()) {
5359 QGraphicsWidget *widget = static_cast<QGraphicsWidget *>(item);
5360 if (!widget->testAttribute(Qt::WA_SetStyle))
5361 QApplication::sendEvent(widget, &event);
5362 }
5363 }
5364}
5365
5366/*!
5367 \property QGraphicsScene::font
5368 \since 4.4
5369 \brief the scene's default font
5370
5371 This property provides the scene's font. The scene font defaults to,
5372 and resolves all its entries from, QApplication::font.
5373
5374 If the scene's font changes, either directly through setFont() or
5375 indirectly when the application font changes, QGraphicsScene first
5376 sends itself a \l{QEvent::FontChange}{FontChange} event, and it then
5377 sends \l{QEvent::FontChange}{FontChange} events to all top-level
5378 widget items in the scene. These items respond by resolving their own
5379 fonts to the scene, and they then notify their children, who again
5380 notify their children, and so on, until all widget items have updated
5381 their fonts.
5382
5383 Changing the scene font, (directly or indirectly through
5384 QApplication::setFont(),) automatically schedules a redraw the entire
5385 scene.
5386
5387 \sa QWidget::font, QApplication::setFont(), palette, style()
5388*/
5389QFont QGraphicsScene::font() const
5390{
5391 Q_D(const QGraphicsScene);
5392 return d->font;
5393}
5394void QGraphicsScene::setFont(const QFont &font)
5395{
5396 Q_D(QGraphicsScene);
5397 QFont naturalFont = qApp->font();
5398 naturalFont.resolve(0);
5399 QFont resolvedFont = font.resolve(naturalFont);
5400 d->setFont_helper(resolvedFont);
5401}
5402
5403/*!
5404 \property QGraphicsScene::palette
5405 \since 4.4
5406 \brief the scene's default palette
5407
5408 This property provides the scene's palette. The scene palette defaults to,
5409 and resolves all its entries from, QApplication::palette.
5410
5411 If the scene's palette changes, either directly through setPalette() or
5412 indirectly when the application palette changes, QGraphicsScene first
5413 sends itself a \l{QEvent::PaletteChange}{PaletteChange} event, and it then
5414 sends \l{QEvent::PaletteChange}{PaletteChange} events to all top-level
5415 widget items in the scene. These items respond by resolving their own
5416 palettes to the scene, and they then notify their children, who again
5417 notify their children, and so on, until all widget items have updated
5418 their palettes.
5419
5420 Changing the scene palette, (directly or indirectly through
5421 QApplication::setPalette(),) automatically schedules a redraw the entire
5422 scene.
5423
5424 \sa QWidget::palette, QApplication::setPalette(), font, style()
5425*/
5426QPalette QGraphicsScene::palette() const
5427{
5428 Q_D(const QGraphicsScene);
5429 return d->palette;
5430}
5431void QGraphicsScene::setPalette(const QPalette &palette)
5432{
5433 Q_D(QGraphicsScene);
5434 QPalette naturalPalette = qApp->palette();
5435 naturalPalette.resolve(0);
5436 QPalette resolvedPalette = palette.resolve(naturalPalette);
5437 d->setPalette_helper(resolvedPalette);
5438}
5439
5440/*!
5441 \since 4.4
5442
5443 Returns the current active window, or 0 if there is no window is currently
5444 active.
5445
5446 \sa QGraphicsScene::setActiveWindow()
5447*/
5448QGraphicsWidget *QGraphicsScene::activeWindow() const
5449{
5450 Q_D(const QGraphicsScene);
5451 return d->activeWindow;
5452}
5453
5454/*!
5455 \since 4.4
5456 Activates \a widget, which must be a widget in this scene. You can also
5457 pass 0 for \a widget, in which case QGraphicsScene will deactivate any
5458 currently active window.
5459
5460 \sa activeWindow(), QGraphicsWidget::isActiveWindow()
5461*/
5462void QGraphicsScene::setActiveWindow(QGraphicsWidget *widget)
5463{
5464 Q_D(QGraphicsScene);
5465 if (widget && widget->scene() != this) {
5466 qWarning("QGraphicsScene::setActiveWindow: widget %p must be part of this scene",
5467 widget);
5468 return;
5469 }
5470
5471 // Activate the widget's window.
5472 QGraphicsWidget *window = widget ? widget->window() : 0;
5473 if (window == d->activeWindow)
5474 return;
5475
5476 // Deactivate the last active window.
5477 if (d->activeWindow) {
5478 if (QGraphicsWidget *fw = d->activeWindow->focusWidget()) {
5479 // Remove focus from the current focus item.
5480 if (fw == focusItem())
5481 setFocusItem(0, Qt::ActiveWindowFocusReason);
5482 }
5483
5484 QEvent event(QEvent::WindowDeactivate);
5485 QApplication::sendEvent(d->activeWindow, &event);
5486 }
5487
5488 // Update activate state.
5489 d->activeWindow = window;
5490 QEvent event(QEvent::ActivationChange);
5491 QApplication::sendEvent(this, &event);
5492
5493 // Activate
5494 if (window) {
5495 QEvent event(QEvent::WindowActivate);
5496 QApplication::sendEvent(window, &event);
5497
5498 QList<QGraphicsItem *> siblingWindows;
5499 QGraphicsItem *parent = window->parentItem();
5500 // Raise ### inefficient for toplevels
5501 foreach (QGraphicsItem *sibling, parent ? parent->children() : items()) {
5502 if (sibling != window && sibling->isWidget()
5503 && static_cast<QGraphicsWidget *>(sibling)->isWindow()) {
5504 siblingWindows << sibling;
5505 }
5506 }
5507
5508 // Find the highest z value.
5509 qreal z = window->zValue();
5510 for (int i = 0; i < siblingWindows.size(); ++i)
5511 z = qMax(z, siblingWindows.at(i)->zValue());
5512
5513 // This will probably never overflow.
5514 const qreal litt = qreal(0.001);
5515 window->setZValue(z + litt);
5516
5517 if (QGraphicsWidget *focusChild = window->focusWidget())
5518 focusChild->setFocus(Qt::ActiveWindowFocusReason);
5519 }
5520}
5521
5522QT_END_NAMESPACE
5523
5524#include "moc_qgraphicsscene.cpp"
5525
5526#endif // QT_NO_GRAPHICSVIEW
Note: See TracBrowser for help on using the repository browser.