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