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

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

trunk: Merged in qt 4.6.2 sources.

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