Ignore:
Timestamp:
Feb 11, 2010, 11:19:06 PM (15 years ago)
Author:
Dmitry A. Kuminov
Message:

trunk: Merged in qt 4.6.1 sources.

Location:
trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk

  • trunk/src/gui/graphicsview/qgraphicsscene.cpp

    r2 r561  
    22**
    33** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
    4 ** Contact: Qt Software Information (qt-info@nokia.com)
     4** All rights reserved.
     5** Contact: Nokia Corporation (qt-info@nokia.com)
    56**
    67** This file is part of the QtGui module of the Qt Toolkit.
     
    2122** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
    2223**
    23 ** In addition, as a special exception, Nokia gives you certain
    24 ** additional rights. These rights are described in the Nokia Qt LGPL
    25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
    26 ** package.
     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.
    2727**
    2828** GNU General Public License Usage
     
    3434** met: http://www.gnu.org/copyleft/gpl.html.
    3535**
    36 ** If you are unsure which license is appropriate for your use, please
    37 ** contact the sales department at qt-sales@nokia.com.
     36** If you have questions regarding the use of this file, please contact
     37** Nokia at qt-info@nokia.com.
    3838** $QT_END_LICENSE$
    3939**
    4040****************************************************************************/
    41 
    42 static const int QGRAPHICSSCENE_INDEXTIMER_TIMEOUT = 2000;
    4341
    4442/*!
     
    4745    number of 2D graphical items.
    4846    \since 4.2
    49     \ingroup multimedia
    5047    \ingroup graphicsview-api
    51     \mainclass
     48
    5249
    5350    The class serves as a container for QGraphicsItems. It is used together
     
    220217#include "qgraphicswidget.h"
    221218#include "qgraphicswidget_p.h"
     219#include "qgraphicssceneindex_p.h"
     220#include "qgraphicsscenebsptreeindex_p.h"
     221#include "qgraphicsscenelinearindex_p.h"
    222222
    223223#include <QtCore/qdebug.h>
     
    243243#include <QtGui/qtooltip.h>
    244244#include <QtGui/qtransform.h>
     245#include <QtGui/qinputcontext.h>
     246#include <QtGui/qgraphicseffect.h>
    245247#include <private/qapplication_p.h>
    246248#include <private/qobject_p.h>
     
    248250#include <private/qt_x11_p.h>
    249251#endif
     252#include <private/qgraphicseffect_p.h>
     253#include <private/qgesturemanager_p.h>
     254
     255// #define GESTURE_DEBUG
     256#ifndef GESTURE_DEBUG
     257# define DEBUG if (0) qDebug
     258#else
     259# define DEBUG qDebug
     260#endif
    250261
    251262QT_BEGIN_NAMESPACE
    252263
    253 static inline bool QRectF_intersects(const QRectF &s, const QRectF &r)
    254 {
    255     qreal xp = s.left();
    256     qreal yp = s.top();
    257     qreal w = s.width();
    258     qreal h = s.height();
    259     qreal l1 = xp;
    260     qreal r1 = xp;
    261     if (w < 0)
    262         l1 += w;
    263     else
    264         r1 += w;
    265 
    266     qreal l2 = r.left();
    267     qreal r2 = r.left();
    268     if (w < 0)
    269         l2 += r.width();
    270     else
    271         r2 += r.width();
    272 
    273     if (l1 >= r2 || l2 >= r1)
    274         return false;
    275 
    276     qreal t1 = yp;
    277     qreal b1 = yp;
    278     if (h < 0)
    279         t1 += h;
    280     else
    281         b1 += h;
    282 
    283     qreal t2 = r.top();
    284     qreal b2 = r.top();
    285     if (r.height() < 0)
    286         t2 += r.height();
    287     else
    288         b2 += r.height();
    289 
    290     return !(t1 >= b2 || t2 >= b1);
    291 }
    292 
    293 // QRectF::intersects() returns false always if either the source or target
    294 // rectangle's width or height are 0. This works around that problem.
    295 static inline void _q_adjustRect(QRectF *rect)
    296 {
    297     Q_ASSERT(rect);
    298     if (!rect->width())
    299         rect->adjust(-0.00001, 0, 0.00001, 0);
    300     if (!rect->height())
    301         rect->adjust(0, -0.00001, 0, 0.00001);
    302 }
    303 
    304 static inline QRectF adjustedItemBoundingRect(const QGraphicsItem *item)
    305 {
    306     Q_ASSERT(item);
    307     QRectF boundingRect(item->boundingRect());
    308     _q_adjustRect(&boundingRect);
    309     return boundingRect;
    310 }
     264bool qt_sendSpontaneousEvent(QObject *receiver, QEvent *event);
    311265
    312266static void _q_hoverFromMouseEvent(QGraphicsSceneHoverEvent *hover, const QGraphicsSceneMouseEvent *mouseEvent)
     
    323277}
    324278
     279int QGraphicsScenePrivate::changedSignalIndex;
     280
    325281/*!
    326282    \internal
    327283*/
    328284QGraphicsScenePrivate::QGraphicsScenePrivate()
    329     : changedSignalMask(0),
    330       indexMethod(QGraphicsScene::BspTreeIndex),
    331       bspTreeDepth(0),
     285    : indexMethod(QGraphicsScene::BspTreeIndex),
     286      index(0),
    332287      lastItemCount(0),
    333288      hasSceneRect(false),
     289      dirtyGrowingItemsBoundingRect(true),
    334290      updateAll(false),
    335291      calledEmitUpdated(false),
     292      processDirtyItemsEmitted(false),
    336293      selectionChanging(0),
    337       dirtyItemResetPending(false),
    338       regenerateIndex(true),
    339       purgePending(false),
    340       indexTimerId(0),
    341       restartIndexTimer(false),
     294      needSortTopLevelItems(true),
     295      unpolishedItemsModified(true),
     296      holesInTopLevelSiblingIndex(false),
     297      topLevelSequentialOrdering(true),
     298      scenePosDescendantsUpdatePending(false),
    342299      stickyFocus(false),
    343300      hasFocus(false),
     
    345302      lastFocusItem(0),
    346303      tabFocusFirst(0),
    347       activeWindow(0),
     304      activePanel(0),
     305      lastActivePanel(0),
    348306      activationRefCount(0),
     307      childExplicitActivation(0),
    349308      lastMouseGrabberItem(0),
    350309      lastMouseGrabberItemHasImplicitMouseGrab(false),
     
    352311      enterWidget(0),
    353312      lastDropAction(Qt::IgnoreAction),
     313      allItemsIgnoreHoverEvents(true),
     314      allItemsUseDefaultCursor(true),
    354315      painterStateProtection(true),
    355316      sortCacheEnabled(false),
    356       updatingSortCache(false),
    357       style(0)
     317      style(0),
     318      allItemsIgnoreTouchEvents(true)
    358319{
    359320}
     
    366327    Q_Q(QGraphicsScene);
    367328
     329    index = new QGraphicsSceneBspTreeIndex(q);
     330
    368331    // Keep this index so we can check for connected slots later on.
    369     changedSignalMask = (1 << q->metaObject()->indexOfSignal("changed(QList<QRectF>)"));
     332    if (!changedSignalIndex) {
     333        changedSignalIndex = signalIndex("changed(QList<QRectF>)");
     334    }
    370335    qApp->d_func()->scene_list.append(q);
    371336    q->update();
     
    375340    \internal
    376341*/
    377 QList<QGraphicsItem *> QGraphicsScenePrivate::estimateItemsInRect(const QRectF &rect) const
    378 {
    379     const_cast<QGraphicsScenePrivate *>(this)->purgeRemovedItems();
    380     const_cast<QGraphicsScenePrivate *>(this)->_q_updateSortCache();
    381 
    382     if (indexMethod == QGraphicsScene::BspTreeIndex) {
    383         // ### Only do this once in a while.
    384         QGraphicsScenePrivate *that = const_cast<QGraphicsScenePrivate *>(this);
    385 
    386         // Get items from BSP tree
    387         QList<QGraphicsItem *> items = that->bspTree.items(rect);
    388 
    389         // Fill in with any unindexed items
    390         for (int i = 0; i < unindexedItems.size(); ++i) {
    391             if (QGraphicsItem *item = unindexedItems.at(i)) {
    392                 if (!item->d_ptr->itemDiscovered && item->d_ptr->visible && !(item->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren)) {
    393                     QRectF boundingRect = item->sceneBoundingRect();
    394                     if (QRectF_intersects(boundingRect, rect)) {
    395                         item->d_ptr->itemDiscovered = 1;
    396                         items << item;
    397                     }
    398                 }
    399             }
    400         }
    401 
    402         // Reset the discovered state of all discovered items
    403         for (int i = 0; i < items.size(); ++i)
    404             items.at(i)->d_func()->itemDiscovered = 0;
    405         return items;
    406     }
    407 
    408     QList<QGraphicsItem *> itemsInRect;
    409     for (int i = 0; i < unindexedItems.size(); ++i) {
    410         if (QGraphicsItem *item = unindexedItems.at(i)) {
    411             if (item->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren)
    412                 continue;
    413             if (item->d_ptr->visible && item->effectiveOpacity() > qreal(0.0))
    414                 itemsInRect << item;
    415         }
    416     }
    417     for (int i = 0; i < indexedItems.size(); ++i) {
    418         if (QGraphicsItem *item = indexedItems.at(i)) {
    419             if (item->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren)
    420                 continue;
    421             if (item->d_ptr->visible && item->effectiveOpacity() > qreal(0.0))
    422                 itemsInRect << item;
    423         }
    424     }
    425 
    426     return itemsInRect;
    427 }
    428 
    429 /*!
    430     \internal
    431 */
    432 void QGraphicsScenePrivate::addToIndex(QGraphicsItem *item)
    433 {
    434     if (indexMethod == QGraphicsScene::BspTreeIndex) {
    435         if (item->d_func()->index != -1) {
    436             bspTree.insertItem(item, item->sceneBoundingRect());
    437             foreach (QGraphicsItem *child, item->children())
    438                 child->addToIndex();
    439         } else {
    440             // The BSP tree is regenerated if the number of items grows to a
    441             // certain threshold, or if the bounding rect of the graph doubles in
    442             // size.
    443             startIndexTimer();
    444         }
    445     }
    446 }
    447 
    448 /*!
    449     \internal
    450 */
    451 void QGraphicsScenePrivate::removeFromIndex(QGraphicsItem *item)
    452 {
    453     if (indexMethod == QGraphicsScene::BspTreeIndex) {
    454         int index = item->d_func()->index;
    455         if (index != -1) {
    456             bspTree.removeItem(item, item->sceneBoundingRect());
    457             freeItemIndexes << index;
    458             indexedItems[index] = 0;
    459             item->d_func()->index = -1;
    460             unindexedItems << item;
    461 
    462             foreach (QGraphicsItem *child, item->children())
    463                 child->removeFromIndex();
    464         }
    465 
    466         startIndexTimer();
    467     }
    468 }
    469 
    470 /*!
    471     \internal
    472 */
    473 void QGraphicsScenePrivate::resetIndex()
    474 {
    475     purgeRemovedItems();
    476     if (indexMethod == QGraphicsScene::BspTreeIndex) {
    477         for (int i = 0; i < indexedItems.size(); ++i) {
    478             if (QGraphicsItem *item = indexedItems.at(i)) {
    479                 item->d_ptr->index = -1;
    480                 unindexedItems << item;
    481             }
    482         }
    483         indexedItems.clear();
    484         freeItemIndexes.clear();
    485         regenerateIndex = true;
    486         startIndexTimer();
    487     }
    488 }
    489 
    490 static inline int intmaxlog(int n)
    491 {
    492     return  (n > 0 ? qMax(qCeil(qLn(qreal(n)) / qLn(qreal(2))), 5) : 0);
    493 }
    494 
    495 /*!
    496     \internal
    497 */
    498 void QGraphicsScenePrivate::_q_updateIndex()
    499 {
    500     if (!indexTimerId)
    501         return;
    502 
    503     Q_Q(QGraphicsScene);
    504     q->killTimer(indexTimerId);
    505     indexTimerId = 0;
    506 
    507     purgeRemovedItems();
    508 
    509     // Add unindexedItems to indexedItems
    510     QRectF unindexedItemsBoundingRect;
    511     for (int i = 0; i < unindexedItems.size(); ++i) {
    512         if (QGraphicsItem *item = unindexedItems.at(i)) {
    513             unindexedItemsBoundingRect |= item->sceneBoundingRect();
    514             if (!freeItemIndexes.isEmpty()) {
    515                 int freeIndex = freeItemIndexes.takeFirst();
    516                 item->d_func()->index = freeIndex;
    517                 indexedItems[freeIndex] = item;
    518             } else {
    519                 item->d_func()->index = indexedItems.size();
    520                 indexedItems << item;
    521             }
    522         }
    523     }
    524 
    525     // Update growing scene rect.
    526     QRectF oldGrowingItemsBoundingRect = growingItemsBoundingRect;
    527     growingItemsBoundingRect |= unindexedItemsBoundingRect;
    528 
    529     // Determine whether we should regenerate the BSP tree.
    530     if (indexMethod == QGraphicsScene::BspTreeIndex) {
    531         int depth = bspTreeDepth;
    532         if (depth == 0) {
    533             int oldDepth = intmaxlog(lastItemCount);
    534             depth = intmaxlog(indexedItems.size());
    535             static const int slack = 100;
    536             if (bspTree.leafCount() == 0 || (oldDepth != depth && qAbs(lastItemCount - indexedItems.size()) > slack)) {
    537                 // ### Crude algorithm.
    538                 regenerateIndex = true;
    539             }
    540         }
    541 
    542         // Regenerate the tree.
    543         if (regenerateIndex) {
    544             regenerateIndex = false;
    545             bspTree.initialize(q->sceneRect(), depth);
    546             unindexedItems = indexedItems;
    547             lastItemCount = indexedItems.size();
    548             q->update();
    549 
    550             // Take this opportunity to reset our largest-item counter for
    551             // untransformable items. When the items are inserted into the BSP
    552             // tree, we'll get an accurate calculation.
    553             largestUntransformableItem = QRectF();
    554         }
    555     }
    556 
    557     // Insert all unindexed items into the tree.
    558     for (int i = 0; i < unindexedItems.size(); ++i) {
    559         if (QGraphicsItem *item = unindexedItems.at(i)) {
    560             QRectF rect = item->sceneBoundingRect();
    561             if (item->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren)
    562                 continue;
    563             if (indexMethod == QGraphicsScene::BspTreeIndex)
    564                 bspTree.insertItem(item, rect);
    565 
    566             // If the item ignores view transformations, update our
    567             // largest-item-counter to ensure that the view can accurately
    568             // discover untransformable items when drawing.
    569             if (item->d_ptr->itemIsUntransformable()) {
    570                 QGraphicsItem *topmostUntransformable = item;
    571                 while (topmostUntransformable && (topmostUntransformable->d_ptr->ancestorFlags
    572                                                   & QGraphicsItemPrivate::AncestorIgnoresTransformations)) {
    573                     topmostUntransformable = topmostUntransformable->parentItem();
    574                 }
    575                 // ### Verify that this is the correct largest untransformable rectangle.
    576                 largestUntransformableItem |= item->mapToItem(topmostUntransformable, item->boundingRect()).boundingRect();
    577             }
    578         }
    579     }
    580     unindexedItems.clear();
    581 
    582     // Notify scene rect changes.
    583     if (!hasSceneRect && growingItemsBoundingRect != oldGrowingItemsBoundingRect)
    584         emit q->sceneRectChanged(growingItemsBoundingRect);
    585 }
    586 
    587 /*!
    588     \internal
    589 */
     342QGraphicsScenePrivate *QGraphicsScenePrivate::get(QGraphicsScene *q)
     343{
     344    return q->d_func();
     345}
     346
    590347void QGraphicsScenePrivate::_q_emitUpdated()
    591348{
    592349    Q_Q(QGraphicsScene);
    593350    calledEmitUpdated = false;
     351
     352    if (dirtyGrowingItemsBoundingRect) {
     353        if (!hasSceneRect) {
     354            const QRectF oldGrowingItemsBoundingRect = growingItemsBoundingRect;
     355            growingItemsBoundingRect |= q->itemsBoundingRect();
     356            if (oldGrowingItemsBoundingRect != growingItemsBoundingRect)
     357                emit q->sceneRectChanged(growingItemsBoundingRect);
     358        }
     359        dirtyGrowingItemsBoundingRect = false;
     360    }
    594361
    595362    // Ensure all views are connected if anything is connected. This disables
     
    597364    // needs to happen in order to keep compatibility with the behavior from
    598365    // Qt 4.4 and backward.
    599     if (!views.isEmpty() && (connectedSignals & changedSignalMask)) {
     366    if (isSignalConnected(changedSignalIndex)) {
    600367        for (int i = 0; i < views.size(); ++i) {
    601368            QGraphicsView *view = views.at(i);
     
    606373            }
    607374        }
    608     }
    609 
    610     // Ensure all dirty items's current positions are recorded in the list of
    611     // updated rects.
    612     for (int i = 0; i < dirtyItems.size(); ++i)
    613         updatedRects += dirtyItems.at(i)->sceneBoundingRect();
     375    } else {
     376        updateAll = false;
     377        for (int i = 0; i < views.size(); ++i)
     378            views.at(i)->d_func()->processPendingUpdates();
     379        // It's important that we update all views before we dispatch, hence two for-loops.
     380        for (int i = 0; i < views.size(); ++i)
     381            views.at(i)->d_func()->dispatchPendingUpdateRequests();
     382        return;
     383    }
    614384
    615385    // Notify the changes to anybody interested.
     
    624394    \internal
    625395
    626     Updates all items in the pending update list. At this point, the list is
    627     unlikely to contain partially constructed items.
    628 */
    629 void QGraphicsScenePrivate::_q_updateLater()
    630 {
    631     foreach (QGraphicsItem *item, pendingUpdateItems)
    632         item->update();
    633     pendingUpdateItems.clear();
     396    ### This function is almost identical to QGraphicsItemPrivate::addChild().
     397*/
     398void QGraphicsScenePrivate::registerTopLevelItem(QGraphicsItem *item)
     399{
     400    item->d_ptr->ensureSequentialSiblingIndex();
     401    needSortTopLevelItems = true; // ### maybe false
     402    item->d_ptr->siblingIndex = topLevelItems.size();
     403    topLevelItems.append(item);
    634404}
    635405
    636406/*!
    637407    \internal
     408
     409    ### This function is almost identical to QGraphicsItemPrivate::removeChild().
     410*/
     411void QGraphicsScenePrivate::unregisterTopLevelItem(QGraphicsItem *item)
     412{
     413    if (!holesInTopLevelSiblingIndex)
     414        holesInTopLevelSiblingIndex = item->d_ptr->siblingIndex != topLevelItems.size() - 1;
     415    if (topLevelSequentialOrdering && !holesInTopLevelSiblingIndex)
     416        topLevelItems.removeAt(item->d_ptr->siblingIndex);
     417    else
     418        topLevelItems.removeOne(item);
     419    // NB! Do not use topLevelItems.removeAt(item->d_ptr->siblingIndex) because
     420    // the item is not guaranteed to be at the index after the list is sorted
     421    // (see ensureSortedTopLevelItems()).
     422    item->d_ptr->siblingIndex = -1;
     423    if (topLevelSequentialOrdering)
     424        topLevelSequentialOrdering = !holesInTopLevelSiblingIndex;
     425}
     426
     427/*!
     428    \internal
    638429*/
    639430void QGraphicsScenePrivate::_q_polishItems()
    640431{
     432    QSet<QGraphicsItem *>::Iterator it = unpolishedItems.begin();
    641433    const QVariant booleanTrueVariant(true);
    642     foreach (QGraphicsItem *item, unpolishedItems) {
     434    while (!unpolishedItems.isEmpty()) {
     435        QGraphicsItem *item = *it;
     436        it = unpolishedItems.erase(it);
     437        unpolishedItemsModified = false;
    643438        if (!item->d_ptr->explicitlyHidden) {
    644439            item->itemChange(QGraphicsItem::ItemVisibleChange, booleanTrueVariant);
     
    649444            QApplication::sendEvent((QGraphicsWidget *)item, &event);
    650445        }
    651     }
    652     unpolishedItems.clear();
     446        if (unpolishedItemsModified)
     447            it = unpolishedItems.begin();
     448    }
     449}
     450
     451void QGraphicsScenePrivate::_q_processDirtyItems()
     452{
     453    processDirtyItemsEmitted = false;
     454
     455    if (updateAll) {
     456        Q_ASSERT(calledEmitUpdated);
     457        // No need for further processing (except resetting the dirty states).
     458        // The growingItemsBoundingRect is updated in _q_emitUpdated.
     459        for (int i = 0; i < topLevelItems.size(); ++i)
     460            resetDirtyItem(topLevelItems.at(i), /*recursive=*/true);
     461        return;
     462    }
     463
     464    const bool wasPendingSceneUpdate = calledEmitUpdated;
     465    const QRectF oldGrowingItemsBoundingRect = growingItemsBoundingRect;
     466
     467    // Process items recursively.
     468    for (int i = 0; i < topLevelItems.size(); ++i)
     469        processDirtyItemsRecursive(topLevelItems.at(i));
     470
     471    dirtyGrowingItemsBoundingRect = false;
     472    if (!hasSceneRect && oldGrowingItemsBoundingRect != growingItemsBoundingRect)
     473        emit q_func()->sceneRectChanged(growingItemsBoundingRect);
     474
     475    if (wasPendingSceneUpdate)
     476        return;
     477
     478    for (int i = 0; i < views.size(); ++i)
     479        views.at(i)->d_func()->processPendingUpdates();
     480
     481    if (calledEmitUpdated) {
     482        // We did a compatibility QGraphicsScene::update in processDirtyItemsRecursive
     483        // and we cannot wait for the control to reach the eventloop before the
     484        // changed signal is emitted, so we emit it now.
     485        _q_emitUpdated();
     486    }
     487
     488    // Immediately dispatch all pending update requests on the views.
     489    for (int i = 0; i < views.size(); ++i)
     490        views.at(i)->d_func()->dispatchPendingUpdateRequests();
    653491}
    654492
     
    656494    \internal
    657495*/
    658 void QGraphicsScenePrivate::_q_resetDirtyItems()
    659 {
    660     for (int i = 0; i < dirtyItems.size(); ++i) {
    661         QGraphicsItem *item = dirtyItems.at(i);
    662         item->d_ptr->dirty = 0;
    663         item->d_ptr->dirtyChildren = 0;
    664     }
    665     dirtyItems.clear();
    666     dirtyItemResetPending = false;
     496void QGraphicsScenePrivate::setScenePosItemEnabled(QGraphicsItem *item, bool enabled)
     497{
     498    QGraphicsItem *p = item->d_ptr->parent;
     499    while (p) {
     500        p->d_ptr->scenePosDescendants = enabled;
     501        p = p->d_ptr->parent;
     502    }
     503    if (!enabled && !scenePosDescendantsUpdatePending) {
     504        scenePosDescendantsUpdatePending = true;
     505        QMetaObject::invokeMethod(q_func(), "_q_updateScenePosDescendants", Qt::QueuedConnection);
     506    }
    667507}
    668508
     
    670510    \internal
    671511*/
    672 void QGraphicsScenePrivate::resetDirtyItemsLater()
    673 {
    674     Q_Q(QGraphicsScene);
    675     if (dirtyItemResetPending)
    676         return;
    677     // dirtyItems.reserve(indexedItems.size() + unindexedItems.size());
    678     dirtyItemResetPending = true;
    679     QMetaObject::invokeMethod(q, "_q_resetDirtyItems", Qt::QueuedConnection);
     512void QGraphicsScenePrivate::registerScenePosItem(QGraphicsItem *item)
     513{
     514    scenePosItems.insert(item);
     515    setScenePosItemEnabled(item, true);
    680516}
    681517
    682518/*!
    683519    \internal
     520*/
     521void QGraphicsScenePrivate::unregisterScenePosItem(QGraphicsItem *item)
     522{
     523    scenePosItems.remove(item);
     524    setScenePosItemEnabled(item, false);
     525}
     526
     527/*!
     528    \internal
     529*/
     530void QGraphicsScenePrivate::_q_updateScenePosDescendants()
     531{
     532    foreach (QGraphicsItem *item, scenePosItems) {
     533        QGraphicsItem *p = item->d_ptr->parent;
     534        while (p) {
     535            p->d_ptr->scenePosDescendants = 1;
     536            p = p->d_ptr->parent;
     537        }
     538    }
     539    scenePosDescendantsUpdatePending = false;
     540}
     541
     542/*!
     543    \internal
    684544
    685545    Schedules an item for removal. This function leaves some stale indexes
    686     around in the BSP tree; these will be cleaned up the next time someone
    687     triggers purgeRemovedItems().
    688 
    689     Note: This function is called from QGraphicsItem's destructor. \a item is
     546    around in the BSP tree if called from the item's destructor; these will
     547    be cleaned up the next time someone triggers purgeRemovedItems().
     548
     549    Note: This function might get called from QGraphicsItem's destructor. \a item is
    690550    being destroyed, so we cannot call any pure virtual functions on it (such
    691551    as boundingRect()). Also, it is unnecessary to update the item's own state
    692552    in any way.
    693 
    694     ### Refactoring: This function shares much functionality with removeItem()
    695 */
    696 void QGraphicsScenePrivate::_q_removeItemLater(QGraphicsItem *item)
     553*/
     554void QGraphicsScenePrivate::removeItemHelper(QGraphicsItem *item)
    697555{
    698556    Q_Q(QGraphicsScene);
    699557
    700     // Clear focus on the item to remove any reference in the focusWidget
    701     // chain.
     558    // Clear focus on the item to remove any reference in the focusWidget chain.
    702559    item->clearFocus();
    703560
    704     int index = item->d_func()->index;
    705     if (index != -1) {
    706         // Important: The index is useless until purgeRemovedItems() is
    707         // called.
    708         indexedItems[index] = (QGraphicsItem *)0;
    709         if (!purgePending) {
    710             purgePending = true;
    711             q->update();
    712         }
    713         removedItems << item;
     561    markDirty(item, QRectF(), /*invalidateChildren=*/false, /*force=*/false,
     562              /*ignoreOpacity=*/false, /*removingItemFromScene=*/true);
     563
     564    if (item->d_ptr->inDestructor) {
     565        // The item is actually in its destructor, we call the special method in the index.
     566        index->deleteItem(item);
    714567    } else {
    715         // Recently added items are purged immediately. unindexedItems() never
    716         // contains stale items.
    717         unindexedItems.removeAll(item);
    718         q->update();
     568        // Can potentially call item->boundingRect() (virtual function), that's why
     569        // we only can call this function if the item is not in its destructor.
     570        index->removeItem(item);
     571    }
     572
     573    item->d_ptr->clearSubFocus();
     574
     575    if (item->flags() & QGraphicsItem::ItemSendsScenePositionChanges)
     576        unregisterScenePosItem(item);
     577
     578    QGraphicsScene *oldScene = item->d_func()->scene;
     579    item->d_func()->scene = 0;
     580
     581    //We need to remove all children first because they might use their parent
     582    //attributes (e.g. sceneTransform).
     583    if (!item->d_ptr->inDestructor) {
     584        // Remove all children recursively
     585        for (int i = 0; i < item->d_ptr->children.size(); ++i)
     586            q->removeItem(item->d_ptr->children.at(i));
     587    }
     588
     589    if (!item->d_ptr->inDestructor && item == tabFocusFirst) {
     590        QGraphicsWidget *widget = static_cast<QGraphicsWidget *>(item);
     591        widget->d_func()->fixFocusChainBeforeReparenting(0, oldScene, 0);
     592    }
     593
     594    // Unregister focus proxy.
     595    item->d_ptr->resetFocusProxy();
     596
     597    // Remove from parent, or unregister from toplevels.
     598    if (QGraphicsItem *parentItem = item->parentItem()) {
     599        if (parentItem->scene()) {
     600            Q_ASSERT_X(parentItem->scene() == q, "QGraphicsScene::removeItem",
     601                       "Parent item's scene is different from this item's scene");
     602            item->d_ptr->setParentItemHelper(0);
     603        }
     604    } else {
     605        unregisterTopLevelItem(item);
    719606    }
    720607
     
    724611    if (item == lastFocusItem)
    725612        lastFocusItem = 0;
    726     if (item == activeWindow) {
     613    if (item == activePanel) {
    727614        // ### deactivate...
    728         activeWindow = 0;
     615        activePanel = 0;
     616    }
     617    if (item == lastActivePanel)
     618        lastActivePanel = 0;
     619
     620    // Cancel active touches
     621    {
     622        QMap<int, QGraphicsItem *>::iterator it = itemForTouchPointId.begin();
     623        while (it != itemForTouchPointId.end()) {
     624            if (it.value() == item) {
     625                sceneCurrentTouchPoints.remove(it.key());
     626                it = itemForTouchPointId.erase(it);
     627            } else {
     628                ++it;
     629            }
     630        }
    729631    }
    730632
     
    736638    selectedItems.remove(item);
    737639    hoverItems.removeAll(item);
    738     pendingUpdateItems.removeAll(item);
    739640    cachedItemsUnderMouse.removeAll(item);
    740     unpolishedItems.removeAll(item);
    741     dirtyItems.removeAll(item);
     641    unpolishedItems.remove(item);
     642    unpolishedItemsModified = true;
     643    resetDirtyItem(item);
    742644
    743645    //We remove all references of item from the sceneEventFilter arrays
     
    750652    }
    751653
    752     // Remove from scene transform cache
    753     int transformIndex = item->d_func()->sceneTransformIndex;
    754     if (transformIndex != -1) {
    755         validTransforms.setBit(transformIndex, 0);
    756         freeSceneTransformSlots.append(transformIndex);
    757     }
    758 
    759     // Remove all children recursively.
    760     foreach (QGraphicsItem *child, item->children())
    761         _q_removeItemLater(child);
    762 
    763     // Reset the mouse grabber
     654    if (item->isPanel() && item->isVisible() && item->panelModality() != QGraphicsItem::NonModal)
     655        leaveModal(item);
     656
     657    // Reset the mouse grabber and focus item data.
    764658    if (mouseGrabberItems.contains(item))
    765         ungrabMouse(item, /* item is dying */ true);
     659        ungrabMouse(item, /* item is dying */ item->d_ptr->inDestructor);
    766660
    767661    // Reset the keyboard grabber
    768662    if (keyboardGrabberItems.contains(item))
    769         ungrabKeyboard(item, /* item is dying */ true);
     663        ungrabKeyboard(item, /* item is dying */ item->d_ptr->inDestructor);
    770664
    771665    // Reset the last mouse grabber item
     
    781675/*!
    782676    \internal
    783 
    784     Removes stale pointers from all data structures.
    785 */
    786 void QGraphicsScenePrivate::purgeRemovedItems()
     677*/
     678void QGraphicsScenePrivate::setActivePanelHelper(QGraphicsItem *item, bool duringActivationEvent)
    787679{
    788680    Q_Q(QGraphicsScene);
    789 
    790     if (!purgePending && removedItems.isEmpty())
     681    if (item && item->scene() != q) {
     682        qWarning("QGraphicsScene::setActivePanel: item %p must be part of this scene",
     683                 item);
    791684        return;
    792 
    793     // Remove stale items from the BSP tree.
    794     if (indexMethod != QGraphicsScene::NoIndex)
    795         bspTree.removeItems(removedItems);
    796 
    797     // Purge this list.
    798     removedItems.clear();
    799     freeItemIndexes.clear();
    800     for (int i = 0; i < indexedItems.size(); ++i) {
    801         if (!indexedItems.at(i))
    802             freeItemIndexes << i;
    803     }
    804     purgePending = false;
    805 
    806     // No locality info for the items; update the whole scene.
    807     q->update();
     685    }
     686
     687    // Ensure the scene has focus when we change panel activation.
     688    q->setFocus(Qt::ActiveWindowFocusReason);
     689
     690    // Find the item's panel.
     691    QGraphicsItem *panel = item ? item->panel() : 0;
     692    lastActivePanel = panel ? activePanel : 0;
     693    if (panel == activePanel || (!q->isActive() && !duringActivationEvent))
     694        return;
     695
     696    // Deactivate the last active panel.
     697    if (activePanel) {
     698        if (QGraphicsItem *fi = activePanel->focusItem()) {
     699            // Remove focus from the current focus item.
     700            if (fi == q->focusItem())
     701                q->setFocusItem(0, Qt::ActiveWindowFocusReason);
     702        }
     703
     704        QEvent event(QEvent::WindowDeactivate);
     705        q->sendEvent(activePanel, &event);
     706    } else if (panel && !duringActivationEvent) {
     707        // Deactivate the scene if changing activation to a panel.
     708        QEvent event(QEvent::WindowDeactivate);
     709        foreach (QGraphicsItem *item, q->items()) {
     710            if (item->isVisible() && !item->isPanel() && !item->parentItem())
     711                q->sendEvent(item, &event);
     712        }
     713    }
     714
     715    // Update activate state.
     716    activePanel = panel;
     717    QEvent event(QEvent::ActivationChange);
     718    QApplication::sendEvent(q, &event);
     719
     720    // Activate
     721    if (panel) {
     722        QEvent event(QEvent::WindowActivate);
     723        q->sendEvent(panel, &event);
     724
     725        // Set focus on the panel's focus item.
     726        if (QGraphicsItem *focusItem = panel->focusItem())
     727            focusItem->setFocus(Qt::ActiveWindowFocusReason);
     728    } else if (q->isActive()) {
     729        // Activate the scene
     730        QEvent event(QEvent::WindowActivate);
     731        foreach (QGraphicsItem *item, q->items()) {
     732            if (item->isVisible() && !item->isPanel() && !item->parentItem())
     733                q->sendEvent(item, &event);
     734        }
     735    }
    808736}
    809737
    810738/*!
    811739    \internal
    812 
    813     Starts or restarts the timer used for reindexing unindexed items.
    814 */
    815 void QGraphicsScenePrivate::startIndexTimer()
     740*/
     741void QGraphicsScenePrivate::setFocusItemHelper(QGraphicsItem *item,
     742                                               Qt::FocusReason focusReason)
    816743{
    817744    Q_Q(QGraphicsScene);
    818     if (indexTimerId) {
    819         restartIndexTimer = true;
    820     } else {
    821         indexTimerId = q->startTimer(QGRAPHICSSCENE_INDEXTIMER_TIMEOUT);
    822     }
     745    if (item == focusItem)
     746        return;
     747
     748    // Clear focus if asked to set focus on something that can't
     749    // accept input focus.
     750    if (item && (!(item->flags() & QGraphicsItem::ItemIsFocusable)
     751                 || !item->isVisible() || !item->isEnabled())) {
     752        item = 0;
     753    }
     754
     755    // Set focus on the scene if an item requests focus.
     756    if (item) {
     757        q->setFocus(focusReason);
     758        if (item == focusItem)
     759            return;
     760    }
     761
     762    if (focusItem) {
     763        QFocusEvent event(QEvent::FocusOut, focusReason);
     764        lastFocusItem = focusItem;
     765        focusItem = 0;
     766        sendEvent(lastFocusItem, &event);
     767
     768#ifndef QT_NO_IM
     769        if (lastFocusItem
     770            && (lastFocusItem->flags() & QGraphicsItem::ItemAcceptsInputMethod)) {
     771            // Reset any visible preedit text
     772            QInputMethodEvent imEvent;
     773            sendEvent(lastFocusItem, &imEvent);
     774
     775            // Close any external input method panel. This happens
     776            // automatically by removing WA_InputMethodEnabled on
     777            // the views, but if we are changing focus, we have to
     778            // do it ourselves.
     779            if (item) {
     780                for (int i = 0; i < views.size(); ++i)
     781                    views.at(i)->inputContext()->reset();
     782            }
     783        }
     784#endif //QT_NO_IM
     785    }
     786
     787    if (item) {
     788        focusItem = item;
     789        QFocusEvent event(QEvent::FocusIn, focusReason);
     790        sendEvent(item, &event);
     791    }
     792
     793    updateInputMethodSensitivityInViews();
    823794}
    824795
     
    864835            QFocusEvent event(QEvent::FocusIn, Qt::PopupFocusReason);
    865836            sendEvent(focusItem, &event);
    866         } else {
    867             ungrabKeyboard((QGraphicsItem *)widget, itemIsDying);
     837        } else if (keyboardGrabberItems.contains(static_cast<QGraphicsItem *>(widget))) {
     838            ungrabKeyboard(static_cast<QGraphicsItem *>(widget), itemIsDying);
    868839        }
    869840        if (!itemIsDying && widget->isVisible()) {
     
    881852    // Append to list of mouse grabber items, and send a mouse grab event.
    882853    if (mouseGrabberItems.contains(item)) {
    883         if (mouseGrabberItems.last() == item)
    884             qWarning("QGraphicsItem::grabMouse: already a mouse grabber");
    885         else
     854        if (mouseGrabberItems.last() == item) {
     855            Q_ASSERT(!implicit);
     856            if (!lastMouseGrabberItemHasImplicitMouseGrab) {
     857                qWarning("QGraphicsItem::grabMouse: already a mouse grabber");
     858            } else {
     859                // Upgrade to an explicit mouse grab
     860                lastMouseGrabberItemHasImplicitMouseGrab = false;
     861            }
     862        } else {
    886863            qWarning("QGraphicsItem::grabMouse: already blocked by mouse grabber: %p",
    887864                     mouseGrabberItems.last());
     865        }
    888866        return;
    889867    }
     
    10371015}
    10381016
     1017void QGraphicsScenePrivate::enableMouseTrackingOnViews()
     1018{
     1019    foreach (QGraphicsView *view, views)
     1020        view->viewport()->setMouseTracking(true);
     1021}
     1022
    10391023/*!
    10401024    Returns all items for the screen position in \a event.
     
    10461030    Q_Q(const QGraphicsScene);
    10471031    QGraphicsView *view = widget ? qobject_cast<QGraphicsView *>(widget->parentWidget()) : 0;
    1048     QList<QGraphicsItem *> items;
    1049     if (view)
    1050         items = view->items(view->viewport()->mapFromGlobal(screenPos));
    1051     else
    1052         items = q->items(scenePos);
    1053     return items;
    1054 }
    1055 
    1056 /*!
    1057     \internal
    1058 
    1059     Checks if item collides with the path and mode, but also checks that if it
    1060     doesn't collide, maybe its frame rect will.
    1061 */
    1062 bool QGraphicsScenePrivate::itemCollidesWithPath(QGraphicsItem *item,
    1063                                                  const QPainterPath &path,
    1064                                                  Qt::ItemSelectionMode mode)
    1065 {
    1066     if (item->collidesWithPath(path, mode))
    1067         return true;
    1068     if (item->isWidget()) {
    1069         // Check if this is a window, and if its frame rect collides.
    1070         QGraphicsWidget *widget = static_cast<QGraphicsWidget *>(item);
    1071         if (widget->isWindow()) {
    1072             QRectF frameRect = widget->windowFrameRect();
    1073             QPainterPath framePath;
    1074             framePath.addRect(frameRect);
    1075             bool intersects = path.intersects(frameRect);
    1076             if (mode == Qt::IntersectsItemShape || mode == Qt::IntersectsItemBoundingRect)
    1077                 return intersects || path.contains(frameRect.topLeft())
    1078                     || framePath.contains(path.elementAt(0));
    1079             return !intersects && path.contains(frameRect.topLeft());
    1080         }
    1081     }
    1082     return false;
     1032    if (!view)
     1033        return q->items(scenePos, Qt::IntersectsItemShape, Qt::DescendingOrder, QTransform());
     1034
     1035    const QRectF pointRect(QPointF(widget->mapFromGlobal(screenPos)), QSizeF(1, 1));
     1036    if (!view->isTransformed())
     1037        return q->items(pointRect, Qt::IntersectsItemShape, Qt::DescendingOrder);
     1038
     1039    const QTransform viewTransform = view->viewportTransform();
     1040    if (viewTransform.type() <= QTransform::TxScale) {
     1041        return q->items(viewTransform.inverted().mapRect(pointRect), Qt::IntersectsItemShape,
     1042                        Qt::DescendingOrder, viewTransform);
     1043    }
     1044    return q->items(viewTransform.inverted().map(pointRect), Qt::IntersectsItemShape,
     1045                    Qt::DescendingOrder, viewTransform);
    10831046}
    10841047
     
    10921055            mouseGrabberButtonDownPos.insert(Qt::MouseButton(i),
    10931056                                             mouseGrabberItems.last()->d_ptr->genericMapFromScene(event->scenePos(),
    1094                                                                                           event->widget()));
     1057                                                                                                  event->widget()));
    10951058            mouseGrabberButtonDownScenePos.insert(Qt::MouseButton(i), event->scenePos());
    10961059            mouseGrabberButtonDownScreenPos.insert(Qt::MouseButton(i), event->screenPos());
     
    11261089
    11271090/*!
     1091  \internal
     1092*/
     1093bool QGraphicsScenePrivate::filterDescendantEvent(QGraphicsItem *item, QEvent *event)
     1094{
     1095    if (item && (item->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorFiltersChildEvents)) {
     1096        QGraphicsItem *parent = item->parentItem();
     1097        while (parent) {
     1098            if (parent->d_ptr->filtersDescendantEvents && parent->sceneEventFilter(item, event))
     1099                return true;
     1100            if (!(parent->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorFiltersChildEvents))
     1101                return false;
     1102            parent = parent->parentItem();
     1103        }
     1104    }
     1105    return false;
     1106}
     1107
     1108/*!
    11281109    \internal
    11291110*/
     
    11551136bool QGraphicsScenePrivate::sendEvent(QGraphicsItem *item, QEvent *event)
    11561137{
     1138    if (QGraphicsObject *object = item->toGraphicsObject()) {
     1139        QGestureManager *gestureManager = QApplicationPrivate::instance()->gestureManager;
     1140        if (gestureManager) {
     1141            if (gestureManager->filterEvent(object, event))
     1142                return true;
     1143        }
     1144    }
     1145
    11571146    if (filterEvent(item, event))
    11581147        return false;
    1159     return (item && item->isEnabled()) ? item->sceneEvent(event) : false;
     1148    if (filterDescendantEvent(item, event))
     1149        return false;
     1150    if (!item || !item->isEnabled())
     1151        return false;
     1152    if (QGraphicsObject *o = item->toGraphicsObject()) {
     1153        bool spont = event->spontaneous();
     1154        if (spont ? qt_sendSpontaneousEvent(o, event) : QApplication::sendEvent(o, event))
     1155            return true;
     1156        event->spont = spont;
     1157    }
     1158    return item->sceneEvent(event);
    11601159}
    11611160
     
    12201219
    12211220    QGraphicsItem *item = mouseGrabberItems.last();
     1221    if (item->isBlockedByModalPanel())
     1222        return;
     1223
    12221224    for (int i = 0x1; i <= 0x10; i <<= 1) {
    12231225        Qt::MouseButton button = Qt::MouseButton(i);
     
    12431245    // Deliver to any existing mouse grabber.
    12441246    if (!mouseGrabberItems.isEmpty()) {
     1247        if (mouseGrabberItems.last()->isBlockedByModalPanel())
     1248            return;
    12451249        // The event is ignored by default, but we disregard the event's
    12461250        // accepted state after delivery; the mouse is grabbed, after all.
     
    12581262
    12591263    // Update window activation.
    1260     QGraphicsWidget *newActiveWindow = windowForItem(cachedItemsUnderMouse.value(0));
    1261     if (newActiveWindow != activeWindow)
     1264    QGraphicsItem *topItem = cachedItemsUnderMouse.value(0);
     1265    QGraphicsWidget *newActiveWindow = topItem ? topItem->window() : 0;
     1266    if (newActiveWindow && newActiveWindow->isBlockedByModalPanel(&topItem)) {
     1267        // pass activation to the blocking modal window
     1268        newActiveWindow = topItem ? topItem->window() : 0;
     1269    }
     1270
     1271    if (newActiveWindow != q->activeWindow())
    12621272        q->setActiveWindow(newActiveWindow);
    12631273
     
    12651275    bool setFocus = false;
    12661276    foreach (QGraphicsItem *item, cachedItemsUnderMouse) {
    1267         if (item->isEnabled() && (item->flags() & QGraphicsItem::ItemIsFocusable)) {
     1277        if (item->isBlockedByModalPanel()) {
     1278            // Make sure we don't clear focus.
     1279            setFocus = true;
     1280            break;
     1281        }
     1282        if (item->isEnabled() && ((item->flags() & QGraphicsItem::ItemIsFocusable) && item->d_ptr->mouseSetsFocus)) {
    12681283            if (!item->isWidget() || ((QGraphicsWidget *)item)->focusPolicy() & Qt::ClickFocus) {
    12691284                setFocus = true;
     
    12731288            }
    12741289        }
     1290        if (item->isPanel())
     1291            break;
     1292    }
     1293
     1294    // Check for scene modality.
     1295    bool sceneModality = false;
     1296    for (int i = 0; i < modalPanels.size(); ++i) {
     1297        if (modalPanels.at(i)->panelModality() == QGraphicsItem::SceneModal) {
     1298            sceneModality = true;
     1299            break;
     1300        }
    12751301    }
    12761302
    12771303    // If nobody could take focus, clear it.
    1278     if (!stickyFocus && !setFocus)
     1304    if (!stickyFocus && !setFocus && !sceneModality)
    12791305        q->setFocusItem(0, Qt::MouseFocusReason);
     1306
     1307    // Any item will do.
     1308    if (sceneModality && cachedItemsUnderMouse.isEmpty())
     1309        cachedItemsUnderMouse << modalPanels.first();
    12801310
    12811311    // Find a mouse grabber by sending mouse press events to all mouse grabber
     
    12891319        }
    12901320
     1321        // Check if this item is blocked by a modal panel and deliver the mouse event to the
     1322        // blocking panel instead of this item if blocked.
     1323        (void) item->isBlockedByModalPanel(&item);
     1324
    12911325        grabMouse(item, /* implicit = */ true);
    12921326        mouseEvent->accept();
     
    12941328        // check if the item we are sending to are disabled (before we send the event)
    12951329        bool disabled = !item->isEnabled();
    1296         bool isWindow = item->isWindow();
    1297         if (mouseEvent->type() == QEvent::GraphicsSceneMouseDoubleClick && item != lastMouseGrabberItem) {
     1330        bool isPanel = item->isPanel();
     1331        if (mouseEvent->type() == QEvent::GraphicsSceneMouseDoubleClick
     1332            && item != lastMouseGrabberItem && lastMouseGrabberItem) {
    12981333            // If this item is different from the item that received the last
    12991334            // mouse event, and mouseEvent is a doubleclick event, then the
     
    13011336            // Triple-clicking will not generate a doubleclick, though.
    13021337            QGraphicsSceneMouseEvent mousePress(QEvent::GraphicsSceneMousePress);
     1338            mousePress.spont = mouseEvent->spont;
    13031339            mousePress.accept();
    13041340            mousePress.setButton(mouseEvent->button());
     
    13331369        ungrabMouse(item, /* itemIsDying = */ dontSendUngrabEvents);
    13341370
    1335         // Don't propagate through windows.
    1336         if (isWindow)
     1371        // Don't propagate through panels.
     1372        if (isPanel)
    13371373            break;
    13381374    }
     
    13561392}
    13571393
    1358 QGraphicsWidget *QGraphicsScenePrivate::windowForItem(const QGraphicsItem *item) const
    1359 {
    1360     if (!item)
    1361         return 0;
    1362     do {
    1363         if (item->isWidget())
    1364             return static_cast<const QGraphicsWidget *>(item)->window();
    1365         item = item->parentItem();
    1366     } while (item);
    1367     return 0;
    1368 }
    1369 
    1370 
    1371 QList<QGraphicsItem *> QGraphicsScenePrivate::items_helper(const QPointF &pos) const
    1372 {
    1373     QList<QGraphicsItem *> items;
    1374 
    1375     // The index returns a rough estimate of what items are inside the rect.
    1376     // Refine it by iterating through all returned items.
    1377     QRectF adjustedRect = QRectF(pos, QSize(1,1));
    1378     foreach (QGraphicsItem *item, estimateItemsInRect(adjustedRect)) {
    1379         // Find the item's scene transform in a clever way.
    1380         QTransform x = item->sceneTransform();
    1381         bool keep = false;
    1382 
    1383         // ### _q_adjustedRect is only needed because QRectF::intersects,
    1384         // QRectF::contains and QTransform::map() and friends don't work with
    1385         // flat rectangles.
    1386         const QRectF br(adjustedItemBoundingRect(item));
    1387             // Rect intersects/contains item's shape
    1388         if (QRectF_intersects(adjustedRect, x.mapRect(br))) {
    1389             bool ok;
    1390             QTransform xinv = x.inverted(&ok);
    1391             if (ok) {
    1392                 if (item->contains(xinv.map(pos))) {
    1393                     items << item;
    1394                     keep = true;
    1395                 }
    1396             }
    1397         }
    1398 
    1399         if (keep && (item->flags() & QGraphicsItem::ItemClipsChildrenToShape)) {
    1400             // Recurse into children that clip children.
    1401             bool ok;
    1402             QTransform xinv = x.inverted(&ok);
    1403             if (ok)
    1404                 childItems_helper(&items, item, xinv.map(pos));
    1405         }
    1406     }
    1407 
    1408     sortItems(&items, Qt::AscendingOrder, sortCacheEnabled);
    1409     return items;
    1410 }
    1411 
    1412 QList<QGraphicsItem *> QGraphicsScenePrivate::items_helper(const QRectF &rect,
    1413                                                            Qt::ItemSelectionMode mode,
    1414                                                            Qt::SortOrder order) const
    1415 {
    1416     QList<QGraphicsItem *> items;
    1417 
    1418     QPainterPath path;
    1419 
    1420     // The index returns a rough estimate of what items are inside the rect.
    1421     // Refine it by iterating through all returned items.
    1422     QRectF adjustedRect(rect);
    1423     _q_adjustRect(&adjustedRect);
    1424     foreach (QGraphicsItem *item, estimateItemsInRect(adjustedRect)) {
    1425         // Find the item's scene transform in a clever way.
    1426         QTransform x = item->sceneTransform();
    1427         bool keep = false;
    1428 
    1429         // ### _q_adjustedRect is only needed because QRectF::intersects,
    1430         // QRectF::contains and QTransform::map() and friends don't work with
    1431         // flat rectangles.
    1432         const QRectF br(adjustedItemBoundingRect(item));
    1433         if (mode >= Qt::ContainsItemBoundingRect) {
    1434             // Rect intersects/contains item's bounding rect
    1435             QRectF mbr = x.mapRect(br);
    1436             if ((mode == Qt::IntersectsItemBoundingRect && QRectF_intersects(rect, mbr))
    1437                 || (mode == Qt::ContainsItemBoundingRect && rect != mbr && rect.contains(mbr))) {
    1438                 items << item;
    1439                 keep = true;
    1440             }
    1441         } else {
    1442             // Rect intersects/contains item's shape
    1443             if (QRectF_intersects(adjustedRect, x.mapRect(br))) {
    1444                 bool ok;
    1445                 QTransform xinv = x.inverted(&ok);
    1446                 if (ok) {
    1447                     if (path.isEmpty())
    1448                         path.addRect(rect);
    1449                     if (itemCollidesWithPath(item, xinv.map(path), mode)) {
    1450                         items << item;
    1451                         keep = true;
    1452                     }
    1453                 }
    1454             }
    1455         }
    1456 
    1457         if (keep && (item->flags() & QGraphicsItem::ItemClipsChildrenToShape)) {
    1458             // Recurse into children that clip children.
    1459             bool ok;
    1460             QTransform xinv = x.inverted(&ok);
    1461             if (ok) {
    1462                 if (x.type() <= QTransform::TxScale) {
    1463                     // Rect
    1464                     childItems_helper(&items, item, xinv.mapRect(rect), mode);
    1465                 } else {
    1466                     // Polygon
    1467                     childItems_helper(&items, item, xinv.map(rect), mode);
    1468                 }
    1469             }
    1470         }
    1471     }
    1472 
    1473     if (order != Qt::SortOrder(-1))
    1474         sortItems(&items, order, sortCacheEnabled);
    1475     return items;
    1476 }
    1477 
    1478 QList<QGraphicsItem *> QGraphicsScenePrivate::items_helper(const QPolygonF &polygon,
    1479                                                            Qt::ItemSelectionMode mode,
    1480                                                            Qt::SortOrder order) const
    1481 {
    1482     QList<QGraphicsItem *> items;
    1483 
    1484     QRectF polyRect(polygon.boundingRect());
    1485      _q_adjustRect(&polyRect);
    1486     QPainterPath path;
    1487 
    1488     // The index returns a rough estimate of what items are inside the rect.
    1489     // Refine it by iterating through all returned items.
    1490     foreach (QGraphicsItem *item, estimateItemsInRect(polyRect)) {
    1491         // Find the item's scene transform in a clever way.
    1492         QTransform x = item->sceneTransform();
    1493         bool keep = false;
    1494 
    1495         // ### _q_adjustedRect is only needed because QRectF::intersects,
    1496         // QRectF::contains and QTransform::map() and friends don't work with
    1497         // flat rectangles.
    1498         const QRectF br(adjustedItemBoundingRect(item));
    1499         if (mode >= Qt::ContainsItemBoundingRect) {
    1500             // Polygon contains/intersects item's bounding rect
    1501             if (path == QPainterPath())
    1502                 path.addPolygon(polygon);
    1503             if ((mode == Qt::IntersectsItemBoundingRect && path.intersects(x.mapRect(br)))
    1504                 || (mode == Qt::ContainsItemBoundingRect && path.contains(x.mapRect(br)))) {
    1505                 items << item;
    1506                 keep = true;
    1507             }
    1508         } else {
    1509             // Polygon contains/intersects item's shape
    1510             if (QRectF_intersects(polyRect, x.mapRect(br))) {
    1511                 bool ok;
    1512                 QTransform xinv = x.inverted(&ok);
    1513                 if (ok) {
    1514                     if (path == QPainterPath())
    1515                         path.addPolygon(polygon);
    1516                     if (itemCollidesWithPath(item, xinv.map(path), mode)) {
    1517                         items << item;
    1518                         keep = true;
    1519                     }
    1520                 }
    1521             }
    1522         }
    1523 
    1524         if (keep && (item->flags() & QGraphicsItem::ItemClipsChildrenToShape)) {
    1525             // Recurse into children that clip children.
    1526             bool ok;
    1527             QTransform xinv = x.inverted(&ok);
    1528             if (ok)
    1529                 childItems_helper(&items, item, xinv.map(polygon), mode);
    1530         }
    1531     }
    1532 
    1533     if (order != Qt::SortOrder(-1))
    1534         sortItems(&items, order, sortCacheEnabled);
    1535     return items;
    1536 }
    1537 
    1538 QList<QGraphicsItem *> QGraphicsScenePrivate::items_helper(const QPainterPath &path,
    1539                                                            Qt::ItemSelectionMode mode,
    1540                                                            Qt::SortOrder order) const
    1541 {
    1542     QList<QGraphicsItem *> items;
    1543     QRectF pathRect(path.controlPointRect());
    1544     _q_adjustRect(&pathRect);
    1545 
    1546     // The index returns a rough estimate of what items are inside the rect.
    1547     // Refine it by iterating through all returned items.
    1548     foreach (QGraphicsItem *item, estimateItemsInRect(pathRect)) {
    1549         // Find the item's scene transform in a clever way.
    1550         QTransform x = item->sceneTransform();
    1551         bool keep = false;
    1552 
    1553         // ### _q_adjustedRect is only needed because QRectF::intersects,
    1554         // QRectF::contains and QTransform::map() and friends don't work with
    1555         // flat rectangles.
    1556         const QRectF br(adjustedItemBoundingRect(item));
    1557         if (mode >= Qt::ContainsItemBoundingRect) {
    1558             // Path contains/intersects item's bounding rect
    1559             if ((mode == Qt::IntersectsItemBoundingRect && path.intersects(x.mapRect(br)))
    1560                 || (mode == Qt::ContainsItemBoundingRect && path.contains(x.mapRect(br)))) {
    1561                 items << item;
    1562                 keep = true;
    1563             }
    1564         } else {
    1565             // Path contains/intersects item's shape
    1566             if (QRectF_intersects(pathRect, x.mapRect(br))) {
    1567                 bool ok;
    1568                 QTransform xinv = x.inverted(&ok);
    1569                 if (ok) {
    1570                     if (itemCollidesWithPath(item, xinv.map(path), mode)) {
    1571                         items << item;
    1572                         keep = true;
    1573                     }
    1574                 }
    1575             }
    1576         }
    1577 
    1578         if (keep && (item->flags() & QGraphicsItem::ItemClipsChildrenToShape)) {
    1579             bool ok;
    1580             QTransform xinv = x.inverted(&ok);
    1581             if (ok)
    1582                 childItems_helper(&items, item, xinv.map(path), mode);
    1583         }
    1584     }
    1585 
    1586     if (order != Qt::SortOrder(-1))
    1587         sortItems(&items, order, sortCacheEnabled);
    1588     return items;
    1589 }
    1590 
    1591 void QGraphicsScenePrivate::childItems_helper(QList<QGraphicsItem *> *items,
    1592                                               const QGraphicsItem *parent,
    1593                                               const QPointF &pos) const
    1594 {
    1595     bool parentClip = (parent->flags() & QGraphicsItem::ItemClipsChildrenToShape);
    1596     if (parentClip && parent->d_ptr->isClippedAway())
    1597         return;
    1598     // ### is this needed?
    1599     if (parentClip && !parent->boundingRect().contains(pos))
    1600         return;
    1601 
    1602     QList<QGraphicsItem *> &children = parent->d_ptr->children;
    1603     for (int i = 0; i < children.size(); ++i) {
    1604         QGraphicsItem *item = children.at(i);
    1605         if (item->d_ptr->hasTransform && !item->transform().isInvertible())
    1606             continue;
    1607 
    1608         // Skip invisible items and all their children.
    1609         if (item->d_ptr->isInvisible())
    1610             continue;
    1611 
    1612         bool keep = false;
    1613         if (!item->d_ptr->isClippedAway()) {
    1614             if (item->contains(item->mapFromParent(pos))) {
    1615                 items->append(item);
    1616                 keep = true;
    1617             }
    1618         }
    1619 
    1620         if ((keep || !(item->flags() & QGraphicsItem::ItemClipsChildrenToShape)) && !item->d_ptr->children.isEmpty())
    1621             // Recurse into children.
    1622             childItems_helper(items, item, item->mapFromParent(pos));
    1623     }
    1624 }
    1625 
    1626 
    1627 void QGraphicsScenePrivate::childItems_helper(QList<QGraphicsItem *> *items,
    1628                                               const QGraphicsItem *parent,
    1629                                               const QRectF &rect,
    1630                                               Qt::ItemSelectionMode mode) const
    1631 {
    1632     bool parentClip = (parent->flags() & QGraphicsItem::ItemClipsChildrenToShape);
    1633     if (parentClip && parent->d_ptr->isClippedAway())
    1634         return;
    1635     QRectF adjustedRect(rect);
    1636     _q_adjustRect(&adjustedRect);
    1637     QRectF r = !parentClip ? adjustedRect : adjustedRect.intersected(adjustedItemBoundingRect(parent));
    1638     if (r.isEmpty())
    1639         return;
    1640 
    1641     QPainterPath path;
    1642     QList<QGraphicsItem *> &children = parent->d_ptr->children;
    1643     for (int i = 0; i < children.size(); ++i) {
    1644         QGraphicsItem *item = children.at(i);
    1645         if (item->d_ptr->hasTransform && !item->transform().isInvertible())
    1646             continue;
    1647 
    1648         // Skip invisible items and all their children.
    1649         if (item->d_ptr->isInvisible())
    1650             continue;
    1651 
    1652         bool keep = false;
    1653         if (!item->d_ptr->isClippedAway()) {
    1654             // ### _q_adjustedRect is only needed because QRectF::intersects,
    1655             // QRectF::contains and QTransform::map() and friends don't work with
    1656             // flat rectangles.
    1657             const QRectF br(adjustedItemBoundingRect(item));
    1658             QRectF mbr = item->mapRectToParent(br);
    1659             if (mode >= Qt::ContainsItemBoundingRect) {
    1660                 // Rect intersects/contains item's bounding rect
    1661                 if ((mode == Qt::IntersectsItemBoundingRect && QRectF_intersects(rect, mbr))
    1662                     || (mode == Qt::ContainsItemBoundingRect && rect != mbr && rect.contains(br))) {
    1663                     items->append(item);
    1664                     keep = true;
    1665                 }
    1666             } else {
    1667                 // Rect intersects/contains item's shape
    1668                 if (QRectF_intersects(rect, mbr)) {
    1669                     if (path == QPainterPath())
    1670                         path.addRect(rect);
    1671                     if (itemCollidesWithPath(item, item->mapFromParent(path), mode)) {
    1672                         items->append(item);
    1673                         keep = true;
    1674                     }
    1675                 }
    1676             }
    1677         }
    1678 
    1679         if ((keep || !(item->flags() & QGraphicsItem::ItemClipsChildrenToShape)) && !item->d_ptr->children.isEmpty()) {
    1680             // Recurse into children.
    1681             if (!item->d_ptr->hasTransform || item->transform().type() <= QTransform::TxScale) {
    1682                 // Rect
    1683                 childItems_helper(items, item, item->mapRectFromParent(rect), mode);
    1684             } else {
    1685                 // Polygon
    1686                 childItems_helper(items, item, item->mapFromParent(rect), mode);
    1687             }
    1688         }
    1689     }
    1690 }
    1691 
    1692 
    1693 void QGraphicsScenePrivate::childItems_helper(QList<QGraphicsItem *> *items,
    1694                                               const QGraphicsItem *parent,
    1695                                               const QPolygonF &polygon,
    1696                                               Qt::ItemSelectionMode mode) const
    1697 {
    1698     bool parentClip = (parent->flags() & QGraphicsItem::ItemClipsChildrenToShape);
    1699     if (parentClip && parent->d_ptr->isClippedAway())
    1700         return;
    1701     QRectF polyRect(polygon.boundingRect());
    1702     _q_adjustRect(&polyRect);
    1703     QRectF r = !parentClip ? polyRect : polyRect.intersected(adjustedItemBoundingRect(parent));
    1704     if (r.isEmpty())
    1705         return;
    1706 
    1707     QPainterPath path;
    1708     QList<QGraphicsItem *> &children = parent->d_ptr->children;
    1709     for (int i = 0; i < children.size(); ++i) {
    1710         QGraphicsItem *item = children.at(i);
    1711         if (item->d_ptr->hasTransform && !item->transform().isInvertible())
    1712             continue;
    1713 
    1714         // Skip invisible items.
    1715         if (item->d_ptr->isInvisible())
    1716             continue;
    1717 
    1718         bool keep = false;
    1719         if (!item->d_ptr->isClippedAway()) {
    1720             // ### _q_adjustedRect is only needed because QRectF::intersects,
    1721             // QRectF::contains and QTransform::map() and friends don't work with
    1722             // flat rectangles.
    1723             const QRectF br(adjustedItemBoundingRect(item));
    1724             if (mode >= Qt::ContainsItemBoundingRect) {
    1725                 // Polygon contains/intersects item's bounding rect
    1726                 if (path == QPainterPath())
    1727                     path.addPolygon(polygon);
    1728                 if ((mode == Qt::IntersectsItemBoundingRect && path.intersects(item->mapRectToParent(br)))
    1729                     || (mode == Qt::ContainsItemBoundingRect && path.contains(item->mapRectToParent(br)))) {
    1730                     items->append(item);
    1731                     keep = true;
    1732                 }
    1733             } else {
    1734                 // Polygon contains/intersects item's shape
    1735                 if (QRectF_intersects(polyRect, item->mapRectToParent(br))) {
    1736                     if (path == QPainterPath())
    1737                         path.addPolygon(polygon);
    1738                     if (itemCollidesWithPath(item, item->mapFromParent(path), mode)) {
    1739                         items->append(item);
    1740                         keep = true;
    1741                     }
    1742                 }
    1743             }
    1744         }
    1745 
    1746         if ((keep || !(item->flags() & QGraphicsItem::ItemClipsChildrenToShape)) && !item->d_ptr->children.isEmpty()) {
    1747             // Recurse into children that clip children.
    1748             childItems_helper(items, item, item->mapFromParent(polygon), mode);
    1749         }
    1750     }
    1751 }
    1752 
    1753 void QGraphicsScenePrivate::childItems_helper(QList<QGraphicsItem *> *items,
    1754                                               const QGraphicsItem *parent,
    1755                                               const QPainterPath &path,
    1756                                               Qt::ItemSelectionMode mode) const
    1757 {
    1758     bool parentClip = (parent->flags() & QGraphicsItem::ItemClipsChildrenToShape);
    1759     if (parentClip && parent->d_ptr->isClippedAway())
    1760         return;
    1761     QRectF pathRect(path.boundingRect());
    1762     _q_adjustRect(&pathRect);
    1763     QRectF r = !parentClip ? pathRect : pathRect.intersected(adjustedItemBoundingRect(parent));
    1764     if (r.isEmpty())
    1765         return;
    1766 
    1767     QList<QGraphicsItem *> &children = parent->d_ptr->children;
    1768     for (int i = 0; i < children.size(); ++i) {
    1769         QGraphicsItem *item = children.at(i);
    1770         if (item->d_ptr->hasTransform && !item->transform().isInvertible())
    1771             continue;
    1772 
    1773         // Skip invisible items.
    1774         if (item->d_ptr->isInvisible())
    1775             continue;
    1776 
    1777         bool keep = false;
    1778         if (!item->d_ptr->isClippedAway()) {
    1779             // ### _q_adjustedRect is only needed because QRectF::intersects,
    1780             // QRectF::contains and QTransform::map() and friends don't work with
    1781             // flat rectangles.
    1782             const QRectF br(adjustedItemBoundingRect(item));
    1783             if (mode >= Qt::ContainsItemBoundingRect) {
    1784                 // Polygon contains/intersects item's bounding rect
    1785                 if ((mode == Qt::IntersectsItemBoundingRect && path.intersects(item->mapRectToParent(br)))
    1786                     || (mode == Qt::ContainsItemBoundingRect && path.contains(item->mapRectToParent(br)))) {
    1787                     items->append(item);
    1788                     keep = true;
    1789                 }
    1790             } else {
    1791                 // Path contains/intersects item's shape
    1792                 if (QRectF_intersects(pathRect, item->mapRectToParent(br))) {
    1793                     if (itemCollidesWithPath(item, item->mapFromParent(path), mode)) {
    1794                         items->append(item);
    1795                         keep = true;
    1796                     }
    1797                 }
    1798             }
    1799         }
    1800 
    1801         if ((keep || !(item->flags() & QGraphicsItem::ItemClipsChildrenToShape)) && !item->d_ptr->children.isEmpty()) {
    1802             // Recurse into children that clip children.
    1803             childItems_helper(items, item, item->mapFromParent(path), mode);
    1804         }
    1805     }
    1806 }
    1807 
    1808 void QGraphicsScenePrivate::invalidateSortCache()
    1809 {
    1810     Q_Q(QGraphicsScene);
    1811     if (!sortCacheEnabled || updatingSortCache)
    1812         return;
    1813 
    1814     updatingSortCache = true;
    1815     QMetaObject::invokeMethod(q, "_q_updateSortCache", Qt::QueuedConnection);
    1816 }
    1817 
    18181394/*!
    18191395    \internal
    18201396
    1821     Should not be exported, but we can't change that now.
    1822     ### Qt 5: Remove symbol / make static
    1823 */
    1824 inline bool qt_closestLeaf(const QGraphicsItem *item1, const QGraphicsItem *item2)
    1825 {
    1826     // Return true if sibling item1 is on top of item2.
    1827     const QGraphicsItemPrivate *d1 = item1->d_ptr;
    1828     const QGraphicsItemPrivate *d2 = item2->d_ptr;
    1829     bool f1 = d1->flags & QGraphicsItem::ItemStacksBehindParent;
    1830     bool f2 = d2->flags & QGraphicsItem::ItemStacksBehindParent;
    1831     if (f1 != f2) return f2;
    1832     qreal z1 = d1->z;
    1833     qreal z2 = d2->z;
    1834     return z1 != z2 ? z1 > z2 : item1 > item2;
    1835 }
    1836 
    1837 /*!
    1838     \internal
    1839 
    1840     Should not be exported, but we can't change that now.
    1841 */
    1842 inline bool qt_closestItemFirst(const QGraphicsItem *item1, const QGraphicsItem *item2)
    1843 {
    1844     return QGraphicsScenePrivate::closestItemFirst_withoutCache(item1, item2);
    1845 }
    1846 
    1847 /*!
    1848     Returns true if \a item1 is on top of \a item2.
    1849 
    1850     \internal
    1851 */
    1852 bool QGraphicsScenePrivate::closestItemFirst_withoutCache(const QGraphicsItem *item1, const QGraphicsItem *item2)
    1853 {
    1854     // Siblings? Just check their z-values.
    1855     const QGraphicsItemPrivate *d1 = item1->d_ptr;
    1856     const QGraphicsItemPrivate *d2 = item2->d_ptr;
    1857     if (d1->parent == d2->parent)
    1858         return qt_closestLeaf(item1, item2);
    1859 
    1860     // Find common ancestor, and each item's ancestor closest to the common
    1861     // ancestor.
    1862     int item1Depth = d1->depth;
    1863     int item2Depth = d2->depth;
    1864     const QGraphicsItem *p = item1;
    1865     const QGraphicsItem *t1 = item1;
    1866     while (item1Depth > item2Depth && (p = p->d_ptr->parent)) {
    1867         if (p == item2) {
    1868             // item2 is one of item1's ancestors; item1 is on top
    1869             return !(t1->d_ptr->flags & QGraphicsItem::ItemStacksBehindParent);
    1870         }
    1871         t1 = p;
    1872         --item1Depth;
    1873     }
    1874     p = item2;
    1875     const QGraphicsItem *t2 = item2;
    1876     while (item2Depth > item1Depth && (p = p->d_ptr->parent)) {
    1877         if (p == item1) {
    1878             // item1 is one of item2's ancestors; item1 is not on top
    1879             return (t2->d_ptr->flags & QGraphicsItem::ItemStacksBehindParent);
    1880         }
    1881         t2 = p;
    1882         --item2Depth;
    1883     }
    1884 
    1885     // item1Ancestor is now at the same level as item2Ancestor, but not the same.
    1886     const QGraphicsItem *a1 = t1;
    1887     const QGraphicsItem *a2 = t2;
    1888     while (a1) {
    1889         const QGraphicsItem *p1 = a1;
    1890         const QGraphicsItem *p2 = a2;
    1891         a1 = a1->parentItem();
    1892         a2 = a2->parentItem();
    1893         if (a1 && a1 == a2)
    1894             return qt_closestLeaf(p1, p2);
    1895     }
    1896 
    1897     // No common ancestor? Then just compare the items' toplevels directly.
    1898     return qt_closestLeaf(t1->topLevelItem(), t2->topLevelItem());
    1899 }
    1900 
    1901 /*!
    1902     Returns true if \a item2 is on top of \a item1.
    1903 
    1904     \internal
    1905 */
    1906 bool QGraphicsScenePrivate::closestItemLast_withoutCache(const QGraphicsItem *item1, const QGraphicsItem *item2)
    1907 {
    1908     return closestItemFirst_withoutCache(item2, item1);
    1909 }
    1910 
    1911 void QGraphicsScenePrivate::climbTree(QGraphicsItem *item, int *stackingOrder)
    1912 {
    1913     if (!item->d_ptr->children.isEmpty()) {
    1914         QList<QGraphicsItem *> childList = item->d_ptr->children;
    1915         qSort(childList.begin(), childList.end(), qt_closestLeaf);
    1916         for (int i = 0; i < childList.size(); ++i) {
    1917             QGraphicsItem *item = childList.at(i);
    1918             if (!(item->flags() & QGraphicsItem::ItemStacksBehindParent))
    1919                 climbTree(childList.at(i), stackingOrder);
    1920         }
    1921         item->d_ptr->globalStackingOrder = (*stackingOrder)++;
    1922         for (int i = 0; i < childList.size(); ++i) {
    1923             QGraphicsItem *item = childList.at(i);
    1924             if (item->flags() & QGraphicsItem::ItemStacksBehindParent)
    1925                 climbTree(childList.at(i), stackingOrder);
    1926         }
    1927     } else {
    1928         item->d_ptr->globalStackingOrder = (*stackingOrder)++;
    1929     }
    1930 }
    1931 
    1932 void QGraphicsScenePrivate::_q_updateSortCache()
    1933 {
    1934     _q_updateIndex();
    1935 
    1936     if (!sortCacheEnabled || !updatingSortCache)
    1937         return;
    1938 
    1939     updatingSortCache = false;
    1940     int stackingOrder = 0;
    1941 
    1942     QList<QGraphicsItem *> topLevels;
    1943 
    1944     for (int i = 0; i < indexedItems.size(); ++i) {
    1945         QGraphicsItem *item = indexedItems.at(i);
    1946         if (item && item->parentItem() == 0)
    1947             topLevels << item;
    1948     }
    1949     for (int i = 0; i < unindexedItems.size(); ++i) {
    1950         QGraphicsItem *item = unindexedItems.at(i);
    1951         if (item->parentItem() == 0)
    1952             topLevels << item;
    1953     }
    1954 
    1955     qSort(topLevels.begin(), topLevels.end(), qt_closestLeaf);
    1956     for (int i = 0; i < topLevels.size(); ++i)
    1957         climbTree(topLevels.at(i), &stackingOrder);
    1958 }
    1959 
    1960 void QGraphicsScenePrivate::sortItems(QList<QGraphicsItem *> *itemList, Qt::SortOrder order,
    1961                                       bool sortCacheEnabled)
    1962 {
    1963     if (sortCacheEnabled) {
    1964         if (order == Qt::AscendingOrder) {
    1965             qSort(itemList->begin(), itemList->end(), closestItemFirst_withCache);
    1966         } else if (order == Qt::DescendingOrder) {
    1967             qSort(itemList->begin(), itemList->end(), closestItemLast_withCache);
    1968         }
    1969     } else {
    1970         if (order == Qt::AscendingOrder) {
    1971             qSort(itemList->begin(), itemList->end(), closestItemFirst_withoutCache);
    1972         } else if (order == Qt::DescendingOrder) {
    1973             qSort(itemList->begin(), itemList->end(), closestItemLast_withoutCache);
    1974         }
     1397    Ensures that the list of toplevels is sorted by insertion order, and that
     1398    the siblingIndexes are packed (no gaps), and start at 0.
     1399
     1400    ### This function is almost identical to
     1401    QGraphicsItemPrivate::ensureSequentialSiblingIndex().
     1402*/
     1403void QGraphicsScenePrivate::ensureSequentialTopLevelSiblingIndexes()
     1404{
     1405    if (!topLevelSequentialOrdering) {
     1406        qSort(topLevelItems.begin(), topLevelItems.end(), QGraphicsItemPrivate::insertionOrder);
     1407        topLevelSequentialOrdering = true;
     1408        needSortTopLevelItems = 1;
     1409    }
     1410    if (holesInTopLevelSiblingIndex) {
     1411        holesInTopLevelSiblingIndex = 0;
     1412        for (int i = 0; i < topLevelItems.size(); ++i)
     1413            topLevelItems[i]->d_ptr->siblingIndex = i;
    19751414    }
    19761415}
     
    19971436void QGraphicsScenePrivate::resolveFont()
    19981437{
    1999     QFont naturalFont = qApp->font();
     1438    QFont naturalFont = QApplication::font();
    20001439    naturalFont.resolve(0);
    20011440    QFont resolvedFont = font.resolve(naturalFont);
     
    20531492void QGraphicsScenePrivate::resolvePalette()
    20541493{
    2055     QPalette naturalPalette = qApp->palette();
     1494    QPalette naturalPalette = QApplication::palette();
    20561495    naturalPalette.resolve(0);
    20571496    QPalette resolvedPalette = palette.resolve(naturalPalette);
     
    21081547    : QObject(*new QGraphicsScenePrivate, parent)
    21091548{
     1549    d_func()->init();
    21101550    setSceneRect(sceneRect);
    2111     d_func()->init();
    21121551}
    21131552
     
    21231562    : QObject(*new QGraphicsScenePrivate, parent)
    21241563{
     1564    d_func()->init();
    21251565    setSceneRect(x, y, width, height);
    2126     d_func()->init();
    2127 }
    2128 
    2129 /*!
    2130     Destroys the QGraphicsScene object.
     1566}
     1567
     1568/*!
     1569  Removes and deletes all items from the scene object
     1570  before destroying the scene object. The scene object
     1571  is removed from the application's global scene list,
     1572  and it is removed from all associated views.
    21311573*/
    21321574QGraphicsScene::~QGraphicsScene()
    21331575{
    21341576    Q_D(QGraphicsScene);
     1577
    21351578    // Remove this scene from qApp's global scene list.
    21361579    qApp->d_func()->scene_list.removeAll(this);
     
    21611604{
    21621605    Q_D(const QGraphicsScene);
    2163     const_cast<QGraphicsScenePrivate *>(d)->_q_updateIndex();
    2164     return d->hasSceneRect ? d->sceneRect : d->growingItemsBoundingRect;
     1606    if (d->hasSceneRect)
     1607        return d->sceneRect;
     1608
     1609    if (d->dirtyGrowingItemsBoundingRect) {
     1610        // Lazily update the growing items bounding rect
     1611        QGraphicsScenePrivate *thatd = const_cast<QGraphicsScenePrivate *>(d);
     1612        QRectF oldGrowingBoundingRect = thatd->growingItemsBoundingRect;
     1613        thatd->growingItemsBoundingRect |= itemsBoundingRect();
     1614        thatd->dirtyGrowingItemsBoundingRect = false;
     1615        if (oldGrowingBoundingRect != thatd->growingItemsBoundingRect)
     1616            emit const_cast<QGraphicsScene *>(this)->sceneRectChanged(thatd->growingItemsBoundingRect);
     1617    }
     1618    return d->growingItemsBoundingRect;
    21651619}
    21661620void QGraphicsScene::setSceneRect(const QRectF &rect)
     
    21701624        d->hasSceneRect = !rect.isNull();
    21711625        d->sceneRect = rect;
    2172         d->resetIndex();
    2173         emit sceneRectChanged(rect);
     1626        emit sceneRectChanged(d->hasSceneRect ? rect : d->growingItemsBoundingRect);
    21741627    }
    21751628}
     
    22121665                            Qt::AspectRatioMode aspectRatioMode)
    22131666{
    2214     Q_D(QGraphicsScene);
     1667    // ### Switch to using the recursive rendering algorithm instead.
    22151668
    22161669    // Default source rect = scene rect
     
    22701723    // Generate the style options
    22711724    QStyleOptionGraphicsItem *styleOptionArray = new QStyleOptionGraphicsItem[numItems];
    2272     for (int i = 0; i < numItems; ++i) {
    2273         QGraphicsItem *item = itemArray[i];
    2274 
    2275         QStyleOptionGraphicsItem option;
    2276         option.state = QStyle::State_None;
    2277         option.rect = item->boundingRect().toRect();
    2278         if (item->isSelected())
    2279             option.state |= QStyle::State_Selected;
    2280         if (item->isEnabled())
    2281             option.state |= QStyle::State_Enabled;
    2282         if (item->hasFocus())
    2283             option.state |= QStyle::State_HasFocus;
    2284         if (d->hoverItems.contains(item))
    2285             option.state |= QStyle::State_MouseOver;
    2286         if (item == mouseGrabberItem())
    2287             option.state |= QStyle::State_Sunken;
    2288 
    2289         // Calculate a simple level-of-detail metric.
    2290         // ### almost identical code in QGraphicsView::paintEvent()
    2291         //     and QGraphicsView::render() - consider refactoring
    2292         QTransform itemToDeviceTransform;
    2293         if (item->d_ptr->itemIsUntransformable()) {
    2294             itemToDeviceTransform = item->deviceTransform(painterTransform);
    2295         } else {
    2296             itemToDeviceTransform = item->sceneTransform() * painterTransform;
    2297         }
    2298 
    2299         option.levelOfDetail = qSqrt(itemToDeviceTransform.map(v1).length() * itemToDeviceTransform.map(v2).length());
    2300         option.matrix = itemToDeviceTransform.toAffine(); //### discards perspective
    2301 
    2302         option.exposedRect = item->boundingRect();
    2303         option.exposedRect &= itemToDeviceTransform.inverted().mapRect(targetRect);
    2304 
    2305         styleOptionArray[i] = option;
    2306     }
     1725    for (int i = 0; i < numItems; ++i)
     1726        itemArray[i]->d_ptr->initStyleOption(&styleOptionArray[i], painterTransform, targetRect.toRect());
    23071727
    23081728    // Render the scene.
     
    23411761{
    23421762    Q_D(QGraphicsScene);
    2343     d->resetIndex();
     1763    if (d->indexMethod == method)
     1764        return;
     1765
    23441766    d->indexMethod = method;
     1767
     1768    QList<QGraphicsItem *> oldItems = d->index->items(Qt::DescendingOrder);
     1769    delete d->index;
     1770    if (method == BspTreeIndex)
     1771        d->index = new QGraphicsSceneBspTreeIndex(this);
     1772    else
     1773        d->index = new QGraphicsSceneLinearIndex(this);
     1774    for (int i = oldItems.size() - 1; i >= 0; --i)
     1775        d->index->addItem(oldItems.at(i));
    23451776}
    23461777
     
    23801811{
    23811812    Q_D(const QGraphicsScene);
    2382     return d->bspTreeDepth;
     1813    QGraphicsSceneBspTreeIndex *bspTree = qobject_cast<QGraphicsSceneBspTreeIndex *>(d->index);
     1814    return bspTree ? bspTree->bspTreeDepth() : 0;
    23831815}
    23841816void QGraphicsScene::setBspTreeDepth(int depth)
    23851817{
    23861818    Q_D(QGraphicsScene);
    2387     if (d->bspTreeDepth == depth)
    2388         return;
    2389 
    23901819    if (depth < 0) {
    23911820        qWarning("QGraphicsScene::setBspTreeDepth: invalid depth %d ignored; must be >= 0", depth);
     
    23931822    }
    23941823
    2395     d->bspTreeDepth = depth;
    2396     d->resetIndex();
     1824    QGraphicsSceneBspTreeIndex *bspTree = qobject_cast<QGraphicsSceneBspTreeIndex *>(d->index);
     1825    if (!bspTree) {
     1826        qWarning("QGraphicsScene::setBspTreeDepth: can not apply if indexing method is not BSP");
     1827        return;
     1828    }
     1829    bspTree->setBspTreeDepth(depth);
    23971830}
    23981831
     
    24011834    \brief whether sort caching is enabled
    24021835    \since 4.5
    2403 
    2404     When enabled, this property adds a cache that speeds up sorting and
    2405     transformations for scenes with deep hierarchies (i.e., items with many
    2406     levels of descendents), at the cost of using more memory (approx. 100 more
    2407     bytes of memory per item).
    2408 
    2409     Items that are not part of a deep hierarchy suffer no penalty from this
    2410     cache.
     1836    \obsolete
     1837
     1838    Since Qt 4.6, this property has no effect.
    24111839*/
    24121840bool QGraphicsScene::isSortCacheEnabled() const
     
    24181846{
    24191847    Q_D(QGraphicsScene);
    2420     if (enabled == d->sortCacheEnabled)
     1848    if (d->sortCacheEnabled == enabled)
    24211849        return;
    2422     if ((d->sortCacheEnabled = enabled))
    2423         d->invalidateSortCache();
     1850    d->sortCacheEnabled = enabled;
    24241851}
    24251852
     
    24331860QRectF QGraphicsScene::itemsBoundingRect() const
    24341861{
     1862    // Does not take untransformable items into account.
    24351863    QRectF boundingRect;
    24361864    foreach (QGraphicsItem *item, items())
     
    24401868
    24411869/*!
    2442     Returns a list of all items on the scene, in no particular order.
    2443 
    2444     \sa addItem(), removeItem()
     1870    Returns a list of all items in the scene in descending stacking order.
     1871
     1872    \sa addItem(), removeItem(), {QGraphicsItem#Sorting}{Sorting}
    24451873*/
    24461874QList<QGraphicsItem *> QGraphicsScene::items() const
    24471875{
    24481876    Q_D(const QGraphicsScene);
    2449     const_cast<QGraphicsScenePrivate *>(d)->purgeRemovedItems();
    2450 
    2451     // If freeItemIndexes is empty, we know there are no holes in indexedItems and
    2452     // unindexedItems.
    2453     if (d->freeItemIndexes.isEmpty()) {
    2454         if (d->unindexedItems.isEmpty())
    2455             return d->indexedItems;
    2456         return d->indexedItems + d->unindexedItems;
    2457     }
    2458 
    2459     // Rebuild the list of items to avoid holes. ### We could also just
    2460     // compress the item lists at this point.
    2461     QList<QGraphicsItem *> itemList;
    2462     foreach (QGraphicsItem *item, d->indexedItems + d->unindexedItems) {
    2463         if (item)
    2464             itemList << item;
    2465     }
    2466     return itemList;
    2467 }
    2468 
    2469 /*!
     1877    return d->index->items(Qt::DescendingOrder);
     1878}
     1879
     1880/*!
     1881    Returns an ordered list of all items on the scene. \a order decides the
     1882    stacking order.
     1883
     1884    \sa addItem(), removeItem(), {QGraphicsItem#Sorting}{Sorting}
     1885*/
     1886QList<QGraphicsItem *> QGraphicsScene::items(Qt::SortOrder order) const
     1887{
     1888    Q_D(const QGraphicsScene);
     1889    return d->index->items(order);
     1890}
     1891
     1892/*!
     1893    \obsolete
     1894
    24701895    Returns all visible items at position \a pos in the scene. The items are
    2471     listed in descending Z order (i.e., the first item in the list is the
     1896    listed in descending stacking order (i.e., the first item in the list is the
    24721897    top-most item, and the last item is the bottom-most item).
    24731898
    2474     \sa itemAt()
     1899    This function is deprecated and returns incorrect results if the scene
     1900    contains items that ignore transformations. Use the overload that takes
     1901    a QTransform instead.
     1902
     1903    \sa itemAt(), {QGraphicsItem#Sorting}{Sorting}
    24751904*/
    24761905QList<QGraphicsItem *> QGraphicsScene::items(const QPointF &pos) const
    24771906{
    24781907    Q_D(const QGraphicsScene);
    2479     return d->items_helper(pos);
    2480 }
    2481 
    2482 
    2483 /*!
    2484     \fn QList<QGraphicsItem *> QGraphicsScene::items(const QRectF &rectangle, Qt::ItemSelectionMode mode) const
    2485 
     1908    return d->index->items(pos, Qt::IntersectsItemShape, Qt::DescendingOrder);
     1909}
     1910
     1911/*!
    24861912    \overload
     1913    \obsolete
    24871914
    24881915    Returns all visible items that, depending on \a mode, are either inside or
     
    24921919    exact shape intersects with or is contained by \a rectangle are returned.
    24931920
    2494     \sa itemAt()
    2495 */
    2496 QList<QGraphicsItem *> QGraphicsScene::items(const QRectF &rect, Qt::ItemSelectionMode mode) const
     1921    This function is deprecated and returns incorrect results if the scene
     1922    contains items that ignore transformations. Use the overload that takes
     1923    a QTransform instead.
     1924
     1925    \sa itemAt(), {QGraphicsItem#Sorting}{Sorting}
     1926*/
     1927QList<QGraphicsItem *> QGraphicsScene::items(const QRectF &rectangle, Qt::ItemSelectionMode mode) const
    24971928{
    24981929    Q_D(const QGraphicsScene);
    2499     return d->items_helper(rect, mode, Qt::AscendingOrder);
     1930    return d->index->items(rectangle, mode, Qt::DescendingOrder);
    25001931}
    25011932
    25021933/*!
    25031934    \fn QList<QGraphicsItem *> QGraphicsScene::items(qreal x, qreal y, qreal w, qreal h, Qt::ItemSelectionMode mode) const
     1935    \obsolete
    25041936    \since 4.3
    25051937
    25061938    This convenience function is equivalent to calling items(QRectF(\a x, \a y, \a w, \a h), \a mode).
    2507 */
    2508 
    2509 /*!
     1939   
     1940    This function is deprecated and returns incorrect results if the scene
     1941    contains items that ignore transformations. Use the overload that takes
     1942    a QTransform instead.
     1943*/
     1944
     1945/*!
     1946    \fn QList<QGraphicsItem *> QGraphicsScene::items(qreal x, qreal y, qreal w, qreal h, Qt::ItemSelectionMode mode, Qt::SortOrder order, const QTransform &deviceTransform) const
    25101947    \overload
     1948    \since 4.6
     1949
     1950    \brief Returns all visible items that, depending on \a mode, are
     1951    either inside or intersect with the rectangle defined by \a x, \a y,
     1952    \a w and \a h, in a list sorted using \a order.
     1953
     1954    \a deviceTransform is the transformation that applies to the view, and needs to
     1955    be provided if the scene contains items that ignore transformations.
     1956*/
     1957
     1958/*!
     1959    \fn QList<QGraphicsItem *> QGraphicsScene::items(const QPolygonF &polygon, Qt::ItemSelectionMode mode) const
     1960    \overload
     1961    \obsolete
    25111962
    25121963    Returns all visible items that, depending on \a mode, are either inside or
     
    25161967    exact shape intersects with or is contained by \a polygon are returned.
    25171968
    2518     \sa itemAt()
     1969    This function is deprecated and returns incorrect results if the scene
     1970    contains items that ignore transformations. Use the overload that takes
     1971    a QTransform instead.
     1972
     1973    \sa itemAt(), {QGraphicsItem#Sorting}{Sorting}
    25191974*/
    25201975QList<QGraphicsItem *> QGraphicsScene::items(const QPolygonF &polygon, Qt::ItemSelectionMode mode) const
    25211976{
    25221977    Q_D(const QGraphicsScene);
    2523     return d->items_helper(polygon, mode, Qt::AscendingOrder);
    2524 }
    2525 
    2526 /*!
     1978    return d->index->items(polygon, mode, Qt::DescendingOrder);
     1979}
     1980
     1981/*!
     1982    \fn QList<QGraphicsItem *> QGraphicsScene::items(const QPainterPath &path, Qt::ItemSelectionMode mode) const
    25271983    \overload
     1984    \obsolete
    25281985
    25291986    Returns all visible items that, depending on \a path, are either inside or
     
    25331990    exact shape intersects with or is contained by \a path are returned.
    25341991
    2535     \sa itemAt()
     1992    This function is deprecated and returns incorrect results if the scene
     1993    contains items that ignore transformations. Use the overload that takes
     1994    a QTransform instead.
     1995
     1996    \sa itemAt(), {QGraphicsItem#Sorting}{Sorting}
    25361997*/
    25371998QList<QGraphicsItem *> QGraphicsScene::items(const QPainterPath &path, Qt::ItemSelectionMode mode) const
    25381999{
    25392000    Q_D(const QGraphicsScene);
    2540     return d->items_helper(path, mode, Qt::AscendingOrder);
     2001    return d->index->items(path, mode, Qt::DescendingOrder);
     2002}
     2003
     2004/*!
     2005    \fn QList<QGraphicsItem *> QGraphicsScene::items(const QPointF &pos, Qt::ItemSelectionMode mode, Qt::SortOrder order, const QTransform &deviceTransform) const
     2006    \since 4.6
     2007
     2008    \brief Returns all visible items that, depending on \a mode, are at
     2009    the specified \a pos in a list sorted using \a order.
     2010
     2011    The default value for \a mode is Qt::IntersectsItemShape; all items whose
     2012    exact shape intersects with \a pos are returned.
     2013
     2014    \a deviceTransform is the transformation that applies to the view, and needs to
     2015    be provided if the scene contains items that ignore transformations.
     2016
     2017    \sa itemAt(), {QGraphicsItem#Sorting}{Sorting}
     2018*/
     2019QList<QGraphicsItem *> QGraphicsScene::items(const QPointF &pos, Qt::ItemSelectionMode mode,
     2020                                             Qt::SortOrder order, const QTransform &deviceTransform) const
     2021{
     2022    Q_D(const QGraphicsScene);
     2023    return d->index->items(pos, mode, order, deviceTransform);
     2024}
     2025
     2026/*!
     2027    \fn QList<QGraphicsItem *> QGraphicsScene::items(const QRectF &rect, Qt::ItemSelectionMode mode, Qt::SortOrder order, const QTransform &deviceTransform) const
     2028    \overload
     2029    \since 4.6
     2030
     2031    \brief Returns all visible items that, depending on \a mode, are
     2032    either inside or intersect with the specified \a rect and return a
     2033    list sorted using \a order.
     2034
     2035    The default value for \a mode is Qt::IntersectsItemShape; all items whose
     2036    exact shape intersects with or is contained by \a rect are returned.
     2037
     2038    \a deviceTransform is the transformation that applies to the view, and needs to
     2039    be provided if the scene contains items that ignore transformations.
     2040
     2041    \sa itemAt(), {QGraphicsItem#Sorting}{Sorting}
     2042*/
     2043QList<QGraphicsItem *> QGraphicsScene::items(const QRectF &rect, Qt::ItemSelectionMode mode,
     2044                                             Qt::SortOrder order, const QTransform &deviceTransform) const
     2045{
     2046    Q_D(const QGraphicsScene);
     2047    return d->index->items(rect, mode, order, deviceTransform);
     2048}
     2049
     2050/*!
     2051    \fn QList<QGraphicsItem *> QGraphicsScene::items(const QPolygonF &polygon, Qt::ItemSelectionMode mode, Qt::SortOrder order, const QTransform &deviceTransform) const
     2052    \overload
     2053    \since 4.6
     2054
     2055    \brief Returns all visible items that, depending on \a mode, are
     2056    either inside or intersect with the specified \a polygon and return
     2057    a list sorted using \a order.
     2058
     2059    The default value for \a mode is Qt::IntersectsItemShape; all items whose
     2060    exact shape intersects with or is contained by \a polygon are returned.
     2061
     2062    \a deviceTransform is the transformation that applies to the view, and needs to
     2063    be provided if the scene contains items that ignore transformations.
     2064
     2065    \sa itemAt(), {QGraphicsItem#Sorting}{Sorting}
     2066*/
     2067QList<QGraphicsItem *> QGraphicsScene::items(const QPolygonF &polygon, Qt::ItemSelectionMode mode,
     2068                                             Qt::SortOrder order, const QTransform &deviceTransform) const
     2069{
     2070    Q_D(const QGraphicsScene);
     2071    return d->index->items(polygon, mode, order, deviceTransform);
     2072}
     2073
     2074/*!
     2075    \fn QList<QGraphicsItem *> QGraphicsScene::items(const QPainterPath &path, Qt::ItemSelectionMode mode, Qt::SortOrder order, const QTransform &deviceTransform) const
     2076    \overload
     2077    \since 4.6
     2078
     2079    \brief Returns all visible items that, depending on \a mode, are
     2080    either inside or intersect with the specified \a path and return a
     2081    list sorted using \a order.
     2082
     2083    The default value for \a mode is Qt::IntersectsItemShape; all items whose
     2084    exact shape intersects with or is contained by \a path are returned.
     2085
     2086    \a deviceTransform is the transformation that applies to the view, and needs to
     2087    be provided if the scene contains items that ignore transformations.
     2088
     2089    \sa itemAt(), {QGraphicsItem#Sorting}{Sorting}
     2090*/
     2091QList<QGraphicsItem *> QGraphicsScene::items(const QPainterPath &path, Qt::ItemSelectionMode mode,
     2092                                             Qt::SortOrder order, const QTransform &deviceTransform) const
     2093{
     2094    Q_D(const QGraphicsScene);
     2095    return d->index->items(path, mode, order, deviceTransform);
    25412096}
    25422097
     
    25472102    intersects \a item or is contained inside \a item's shape are returned.
    25482103
    2549     The items are returned in descending Z order (i.e., the first item in the
    2550     list is the top-most item, and the last item is the bottom-most item).
    2551 
    2552     \sa items(), itemAt(), QGraphicsItem::collidesWithItem()
     2104    The items are returned in descending stacking order (i.e., the first item
     2105    in the list is the uppermost item, and the last item is the lowermost
     2106    item).
     2107
     2108    \sa items(), itemAt(), QGraphicsItem::collidesWithItem(), {QGraphicsItem#Sorting}{Sorting}
    25532109*/
    25542110QList<QGraphicsItem *> QGraphicsScene::collidingItems(const QGraphicsItem *item,
     
    25612117    }
    25622118
     2119    // Does not support ItemIgnoresTransformations.
    25632120    QList<QGraphicsItem *> tmp;
    2564     foreach (QGraphicsItem *itemInVicinity, d->estimateItemsInRect(item->sceneBoundingRect())) {
     2121    foreach (QGraphicsItem *itemInVicinity, d->index->estimateItems(item->sceneBoundingRect(), Qt::DescendingOrder)) {
    25652122        if (item != itemInVicinity && item->collidesWithItem(itemInVicinity, mode))
    25662123            tmp << itemInVicinity;
    25672124    }
    2568     d->sortItems(&tmp, Qt::AscendingOrder, d->sortCacheEnabled);
    25692125    return tmp;
    25702126}
    25712127
    25722128/*!
    2573     \fn QGraphicsItem *QGraphicsScene::itemAt(const QPointF &position) const
     2129    \overload
     2130    \obsolete
    25742131
    25752132    Returns the topmost visible item at the specified \a position, or 0 if
    25762133    there are no items at this position.
    25772134
    2578     \note The topmost item is the one with the highest Z-value.
    2579 
    2580     \sa items(), collidingItems(), QGraphicsItem::setZValue()
    2581 */
    2582 QGraphicsItem *QGraphicsScene::itemAt(const QPointF &pos) const
    2583 {
    2584     QList<QGraphicsItem *> itemsAtPoint = items(pos);
     2135    This function is deprecated and returns incorrect results if the scene
     2136    contains items that ignore transformations. Use the overload that takes
     2137    a QTransform instead.
     2138
     2139    \sa items(), collidingItems(), {QGraphicsItem#Sorting}{Sorting}
     2140*/
     2141QGraphicsItem *QGraphicsScene::itemAt(const QPointF &position) const
     2142{
     2143    QList<QGraphicsItem *> itemsAtPoint = items(position);
    25852144    return itemsAtPoint.isEmpty() ? 0 : itemsAtPoint.first();
    25862145}
     2146
     2147/*!
     2148    \since 4.6
     2149
     2150    Returns the topmost visible item at the specified \a position, or 0
     2151    if there are no items at this position.
     2152
     2153    \a deviceTransform is the transformation that applies to the view, and needs to
     2154    be provided if the scene contains items that ignore transformations.
     2155
     2156    \sa items(), collidingItems(), {QGraphicsItem#Sorting}{Sorting}
     2157*/
     2158QGraphicsItem *QGraphicsScene::itemAt(const QPointF &position, const QTransform &deviceTransform) const
     2159{
     2160    QList<QGraphicsItem *> itemsAtPoint = items(position, Qt::IntersectsItemShape,
     2161                                                Qt::DescendingOrder, deviceTransform);
     2162    return itemsAtPoint.isEmpty() ? 0 : itemsAtPoint.first();
     2163}
     2164
     2165/*!
     2166    \fn QGraphicsScene::itemAt(qreal x, qreal y, const QTransform &deviceTransform) const
     2167    \overload
     2168    \since 4.6
     2169
     2170    Returns the topmost item at the position specified by (\a x, \a
     2171    y), or 0 if there are no items at this position.
     2172
     2173    \a deviceTransform is the transformation that applies to the view, and needs to
     2174    be provided if the scene contains items that ignore transformations.
     2175
     2176    This convenience function is equivalent to calling \c
     2177    {itemAt(QPointF(x, y), deviceTransform)}.
     2178*/
    25872179
    25882180/*!
    25892181    \fn QGraphicsScene::itemAt(qreal x, qreal y) const
    25902182    \overload
     2183    \obsolete
    25912184
    25922185    Returns the topmost item at the position specified by (\a x, \a
     
    25962189    {itemAt(QPointF(x, y))}.
    25972190
    2598     \note The topmost item is the one with the highest Z-value.
     2191    This function is deprecated and returns incorrect results if the scene
     2192    contains items that ignore transformations. Use the overload that takes
     2193    a QTransform instead.
    25992194*/
    26002195
     
    26362231
    26372232/*!
     2233    \since 4.6
     2234
    26382235    Sets the selection area to \a path. All items within this area are
    26392236    immediately selected, and all items outside are unselected. You can get
    26402237    the list of all selected items by calling selectedItems().
    26412238
     2239    \a deviceTransform is the transformation that applies to the view, and needs to
     2240    be provided if the scene contains items that ignore transformations.
     2241
    26422242    For an item to be selected, it must be marked as \e selectable
    26432243    (QGraphicsItem::ItemIsSelectable).
     
    26452245    \sa clearSelection(), selectionArea()
    26462246*/
     2247void QGraphicsScene::setSelectionArea(const QPainterPath &path, const QTransform &deviceTransform)
     2248{
     2249    setSelectionArea(path, Qt::IntersectsItemShape, deviceTransform);
     2250}
     2251
     2252/*!
     2253    \obsolete
     2254    \overload
     2255
     2256    Sets the selection area to \a path.
     2257
     2258    This function is deprecated and leads to incorrect results if the scene
     2259    contains items that ignore transformations. Use the overload that takes
     2260    a QTransform instead.
     2261*/
    26472262void QGraphicsScene::setSelectionArea(const QPainterPath &path)
    26482263{
    2649     setSelectionArea(path, Qt::IntersectsItemShape);
    2650 }
    2651 
    2652 /*!
     2264    setSelectionArea(path, Qt::IntersectsItemShape, QTransform());
     2265}
     2266
     2267/*!
     2268    \obsolete
    26532269    \overload
    26542270    \since 4.3
     
    26602276*/
    26612277void QGraphicsScene::setSelectionArea(const QPainterPath &path, Qt::ItemSelectionMode mode)
     2278{
     2279    setSelectionArea(path, mode, QTransform());
     2280}
     2281
     2282/*!
     2283    \overload
     2284    \since 4.6
     2285
     2286    Sets the selection area to \a path using \a mode to determine if items are
     2287    included in the selection area.
     2288
     2289    \a deviceTransform is the transformation that applies to the view, and needs to
     2290    be provided if the scene contains items that ignore transformations.
     2291
     2292    \sa clearSelection(), selectionArea()
     2293*/
     2294void QGraphicsScene::setSelectionArea(const QPainterPath &path, Qt::ItemSelectionMode mode,
     2295                                      const QTransform &deviceTransform)
    26622296{
    26632297    Q_D(QGraphicsScene);
     
    26762310
    26772311    // Set all items in path to selected.
    2678     foreach (QGraphicsItem *item, items(path, mode)) {
     2312    foreach (QGraphicsItem *item, items(path, mode, Qt::DescendingOrder, deviceTransform)) {
    26792313        if (item->flags() & QGraphicsItem::ItemIsSelectable) {
    26802314            if (!item->isSelected())
     
    27332367{
    27342368    Q_D(QGraphicsScene);
    2735     // Recursive descent delete
    2736     for (int i = 0; i < d->indexedItems.size(); ++i) {
    2737         if (QGraphicsItem *item = d->indexedItems.at(i)) {
    2738             if (!item->parentItem())
    2739                 delete item;
    2740         }
    2741     }
    2742     QList<QGraphicsItem *> unindexedParents;
    2743     for (int i = 0; i < d->unindexedItems.size(); ++i) {
    2744         QGraphicsItem *item = d->unindexedItems.at(i);
    2745         if (!item->parentItem())
    2746             unindexedParents << item;
    2747     }
    2748     d->unindexedItems.clear();
    2749     qDeleteAll(unindexedParents);
    2750 
    2751     d->indexedItems.clear();
    2752     d->freeItemIndexes.clear();
     2369    // NB! We have to clear the index before deleting items; otherwise the
     2370    // index might try to access dangling item pointers.
     2371    d->index->clear();
     2372    // NB! QGraphicsScenePrivate::unregisterTopLevelItem() removes items
     2373    while (!d->topLevelItems.isEmpty())
     2374        delete d->topLevelItems.first();
     2375    Q_ASSERT(d->topLevelItems.isEmpty());
    27532376    d->lastItemCount = 0;
    2754     d->bspTree.clear();
    2755     d->largestUntransformableItem = QRectF();
     2377    d->allItemsIgnoreHoverEvents = true;
     2378    d->allItemsUseDefaultCursor = true;
     2379    d->allItemsIgnoreTouchEvents = true;
    27562380}
    27572381
     
    28282452
    28292453/*!
    2830     Adds or moves the item \a item and all its childen to the scene.
     2454    Adds or moves the \a item and all its childen to this scene.
     2455    This scene takes ownership of the \a item.
    28312456
    28322457    If the item is visible (i.e., QGraphicsItem::isVisible() returns
     
    28342459    to the event loop.
    28352460
    2836     If the item is already in a different scene, it will first be removed from
    2837     its old scene, and then added to this scene as a top-level.
    2838 
    2839     QGraphicsScene will send ItemSceneChange notifications to \a item while
    2840     it is added to the scene. If item does not currently belong to a scene, only one
    2841     notification is sent. If it does belong to scene already (i.e., it is
    2842     moved to this scene), QGraphicsScene will send an addition notification as
    2843     the item is removed from its previous scene.
     2461    If the item is already in a different scene, it will first be
     2462    removed from its old scene, and then added to this scene as a
     2463    top-level.
     2464
     2465    QGraphicsScene will send ItemSceneChange notifications to \a item
     2466    while it is added to the scene. If item does not currently belong
     2467    to a scene, only one notification is sent. If it does belong to
     2468    scene already (i.e., it is moved to this scene), QGraphicsScene
     2469    will send an addition notification as the item is removed from its
     2470    previous scene.
     2471
     2472    If the item is a panel, the scene is active, and there is no
     2473    active panel in the scene, then the item will be activated.
    28442474
    28452475    \sa removeItem(), addEllipse(), addLine(), addPath(), addPixmap(),
    2846     addRect(), addText(), addWidget()
     2476    addRect(), addText(), addWidget(), {QGraphicsItem#Sorting}{Sorting}
    28472477*/
    28482478void QGraphicsScene::addItem(QGraphicsItem *item)
     
    28572487        return;
    28582488    }
    2859 
    28602489    // Remove this item from its existing scene
    28612490    if (QGraphicsScene *oldScene = item->scene())
     
    28732502    }
    28742503
    2875     // Prevent reusing a recently deleted pointer: purge all removed items
    2876     // from our lists.
    2877     d->purgeRemovedItems();
    2878 
    2879     // Invalidate any sort caching; arrival of a new item means we need to
    2880     // resort.
    2881     d->invalidateSortCache();
    2882 
    28832504    // Detach this item from its parent if the parent's scene is different
    28842505    // from this scene.
     
    28912512    item->d_func()->scene = targetScene;
    28922513
    2893     // Indexing requires sceneBoundingRect(), but because \a item might
    2894     // not be completely constructed at this point, we need to store it in
    2895     // a temporary list and schedule an indexing for later.
    2896     d->unindexedItems << item;
    2897     item->d_func()->index = -1;
    2898     d->startIndexTimer();
    2899 
    2900     // Update the scene's sort cache settings.
    2901     item->d_ptr->globalStackingOrder = -1;
    2902     d->invalidateSortCache();
     2514    // Add the item in the index
     2515    d->index->addItem(item);
     2516
     2517    // Add to list of toplevels if this item is a toplevel.
     2518    if (!item->d_ptr->parent)
     2519        d->registerTopLevelItem(item);
    29032520
    29042521    // Add to list of items that require an update. We cannot assume that the
    29052522    // item is fully constructed, so calling item->update() can lead to a pure
    29062523    // virtual function call to boundingRect().
    2907     if (!d->updateAll) {
    2908         if (d->pendingUpdateItems.isEmpty())
    2909             QMetaObject::invokeMethod(this, "_q_updateLater", Qt::QueuedConnection);
    2910         d->pendingUpdateItems << item;
    2911     }
     2524    d->markDirty(item);
     2525    d->dirtyGrowingItemsBoundingRect = true;
    29122526
    29132527    // Disable selectionChanged() for individual items
    29142528    ++d->selectionChanging;
    29152529    int oldSelectedItemSize = d->selectedItems.size();
     2530
     2531    // Enable mouse tracking if the item accepts hover events or has a cursor set.
     2532    if (d->allItemsIgnoreHoverEvents && d->itemAcceptsHoverEvents_helper(item)) {
     2533        d->allItemsIgnoreHoverEvents = false;
     2534        d->enableMouseTrackingOnViews();
     2535    }
     2536#ifndef QT_NO_CURSOR
     2537    if (d->allItemsUseDefaultCursor && item->hasCursor()) {
     2538        d->allItemsUseDefaultCursor = false;
     2539        if (d->allItemsIgnoreHoverEvents) // already enabled otherwise
     2540            d->enableMouseTrackingOnViews();
     2541    }
     2542#endif //QT_NO_CURSOR
     2543
     2544    // Enable touch events if the item accepts touch events.
     2545    if (d->allItemsIgnoreTouchEvents && item->acceptTouchEvents()) {
     2546        d->allItemsIgnoreTouchEvents = false;
     2547        d->enableTouchEventsOnViews();
     2548    }
    29162549
    29172550    // Update selection lists
     
    29202553    if (item->isWidget() && item->isVisible() && static_cast<QGraphicsWidget *>(item)->windowType() == Qt::Popup)
    29212554        d->addPopup(static_cast<QGraphicsWidget *>(item));
     2555    if (item->isPanel() && item->isVisible() && item->panelModality() != QGraphicsItem::NonModal)
     2556        d->enterModal(item);
    29222557
    29232558    // Update creation order focus chain. Make sure to leave the widget's
     
    29482583    item->d_ptr->resolvePalette(d->palette.resolve());
    29492584
    2950     if (!item->d_ptr->explicitlyHidden) {
    2951        if (d->unpolishedItems.isEmpty())
    2952            QMetaObject::invokeMethod(this, "_q_polishItems", Qt::QueuedConnection);
    2953        d->unpolishedItems << item;
    2954     }
     2585    if (d->unpolishedItems.isEmpty())
     2586        QMetaObject::invokeMethod(this, "_q_polishItems", Qt::QueuedConnection);
     2587    d->unpolishedItems.insert(item);
     2588    d->unpolishedItemsModified = true;
    29552589
    29562590    // Reenable selectionChanged() for individual items
     
    29612595    // Deliver post-change notification
    29622596    item->itemChange(QGraphicsItem::ItemSceneHasChanged, newSceneVariant);
     2597
     2598    // Update explicit activation
     2599    bool autoActivate = true;
     2600    if (!d->childExplicitActivation && item->d_ptr->explicitActivate)
     2601        d->childExplicitActivation = item->d_ptr->wantsActive ? 1 : 2;
     2602    if (d->childExplicitActivation && item->isPanel()) {
     2603        if (d->childExplicitActivation == 1)
     2604            setActivePanel(item);
     2605        else
     2606            autoActivate = false;
     2607        d->childExplicitActivation = 0;
     2608    } else if (!item->d_ptr->parent) {
     2609        d->childExplicitActivation = 0;
     2610    }
     2611
     2612    // Auto-activate this item's panel if nothing else has been activated
     2613    if (autoActivate) {
     2614        if (!d->lastActivePanel && !d->activePanel && item->isPanel()) {
     2615            if (isActive())
     2616                setActivePanel(item);
     2617            else
     2618                d->lastActivePanel = item;
     2619        }
     2620    }
     2621
     2622    if (item->flags() & QGraphicsItem::ItemSendsScenePositionChanges)
     2623        d->registerScenePosItem(item);
     2624
     2625    // Ensure that newly added items that have subfocus set, gain
     2626    // focus automatically if there isn't a focus item already.
     2627    if (!d->focusItem && item != d->lastFocusItem && item->focusItem() == item)
     2628        item->focusItem()->setFocus();
     2629
     2630    d->updateInputMethodSensitivityInViews();
    29632631}
    29642632
     
    32322900    }
    32332901
    3234     // If the item has focus, remove it (and any focusWidget reference).
    3235     item->clearFocus();
    3236 
    3237     // Clear its background
    3238     item->update();
    3239 
    3240     // Note: This will access item's sceneBoundingRect(), which (as this is
    3241     // C++) is why we cannot call removeItem() from QGraphicsItem's
    3242     // destructor.
    3243     d->removeFromIndex(item);
    3244 
    3245     if (item == d->tabFocusFirst) {
    3246         QGraphicsWidget *widget = static_cast<QGraphicsWidget *>(item);
    3247         widget->d_func()->fixFocusChainBeforeReparenting(0, 0);
    3248     }
    3249     // Set the item's scene ptr to 0.
    3250     item->d_func()->scene = 0;
    3251 
    3252     // Detach the item from its parent.
    3253     if (QGraphicsItem *parentItem = item->parentItem()) {
    3254         if (parentItem->scene()) {
    3255             Q_ASSERT_X(parentItem->scene() == this, "QGraphicsScene::removeItem",
    3256                        "Parent item's scene is different from this item's scene");
    3257             item->setParentItem(0);
    3258         }
    3259     }
    3260 
    3261     // Remove from our item lists.
    3262     int index = item->d_func()->index;
    3263     if (index != -1) {
    3264         d->freeItemIndexes << index;
    3265         d->indexedItems[index] = 0;
    3266     } else {
    3267         d->unindexedItems.removeAll(item);
    3268     }
    3269 
    3270     // Remove from scene transform cache
    3271     int transformIndex = item->d_func()->sceneTransformIndex;
    3272     if (transformIndex != -1) {
    3273         d->validTransforms.setBit(transformIndex, 0);
    3274         d->freeSceneTransformSlots.append(transformIndex);
    3275         item->d_func()->sceneTransformIndex = -1;
    3276     }
    3277 
    3278     if (item == d->focusItem)
    3279         d->focusItem = 0;
    3280     if (item == d->lastFocusItem)
    3281         d->lastFocusItem = 0;
    3282     if (item == d->activeWindow) {
    3283         // ### deactivate...
    3284         d->activeWindow = 0;
    3285     }
    3286 
    3287     // Disable selectionChanged() for individual items
    3288     ++d->selectionChanging;
    3289     int oldSelectedItemsSize = d->selectedItems.size();
    3290 
    3291     // Update selected & hovered item bookkeeping
    3292     d->selectedItems.remove(item);
    3293     d->hoverItems.removeAll(item);
    3294     d->pendingUpdateItems.removeAll(item);
    3295     d->cachedItemsUnderMouse.removeAll(item);
    3296     d->unpolishedItems.removeAll(item);
    3297     d->dirtyItems.removeAll(item);
    3298 
    3299     //We remove all references of item from the sceneEventFilter arrays
    3300     QMultiMap<QGraphicsItem*, QGraphicsItem*>::iterator iterator = d->sceneEventFilters.begin();
    3301     while (iterator != d->sceneEventFilters.end()) {
    3302         if (iterator.value() == item || iterator.key() == item)
    3303             iterator = d->sceneEventFilters.erase(iterator);
    3304         else
    3305             ++iterator;
    3306     }
    3307 
    3308 
    3309     //Ensure dirty flag have the correct default value so the next time it will be added it will receive updates
    3310     item->d_func()->dirty = 0;
    3311     item->d_func()->dirtyChildren = 0;
    3312 
    3313     // Remove all children recursively
    3314     foreach (QGraphicsItem *child, item->children())
    3315         removeItem(child);
    3316 
    3317     // Reset the mouse grabber and focus item data.
    3318     if (d->mouseGrabberItems.contains(item))
    3319         d->ungrabMouse(item);
    3320 
    3321     // Reset the keyboard grabber
    3322     if (d->keyboardGrabberItems.contains(item))
    3323         item->ungrabKeyboard();
    3324 
    3325     // Reset the last mouse grabber item
    3326     if (item == d->lastMouseGrabberItem)
    3327         d->lastMouseGrabberItem = 0;
    3328 
    3329     // Reenable selectionChanged() for individual items
    3330     --d->selectionChanging;
    3331 
    3332     if (!d->selectionChanging && d->selectedItems.size() != oldSelectedItemsSize)
    3333         emit selectionChanged();
     2902    d->removeItemHelper(item);
    33342903
    33352904    // Deliver post-change notification
    33362905    item->itemChange(QGraphicsItem::ItemSceneHasChanged, newSceneVariant);
    3337 }
    3338 
    3339 /*!
    3340     Returns the scene's current focus item, or 0 if no item currently has
    3341     focus.
     2906
     2907    d->updateInputMethodSensitivityInViews();
     2908}
     2909
     2910/*!
     2911    When the scene is active, this functions returns the scene's current focus
     2912    item, or 0 if no item currently has focus. When the scene is inactive, this
     2913    functions returns the item that will gain input focus when the scene becomes
     2914    active.
    33422915
    33432916    The focus item receives keyboard input when the scene receives a
    33442917    key event.
    33452918
    3346     \sa setFocusItem(), QGraphicsItem::hasFocus()
     2919    \sa setFocusItem(), QGraphicsItem::hasFocus(), isActive()
    33472920*/
    33482921QGraphicsItem *QGraphicsScene::focusItem() const
    33492922{
    33502923    Q_D(const QGraphicsScene);
    3351     return d->focusItem;
     2924    return isActive() ? d->focusItem : d->lastFocusItem;
    33522925}
    33532926
     
    33712944{
    33722945    Q_D(QGraphicsScene);
    3373     if (item == d->focusItem)
    3374         return;
    3375     if (item && (!(item->flags() & QGraphicsItem::ItemIsFocusable)
    3376                  || !item->isVisible() || !item->isEnabled())) {
    3377         item = 0;
    3378     }
    3379 
    3380     if (item) {
    3381         setFocus(focusReason);
    3382         if (item == d->focusItem)
    3383             return;
    3384     }
    3385 
    3386     if (d->focusItem) {
    3387         QFocusEvent event(QEvent::FocusOut, focusReason);
    3388         d->lastFocusItem = d->focusItem;
    3389         d->focusItem = 0;
    3390         d->sendEvent(d->lastFocusItem, &event);
    3391     }
    3392 
    3393     if (item) {
    3394         if (item->isWidget()) {
    3395             // Update focus child chain.
    3396             static_cast<QGraphicsWidget *>(item)->d_func()->setFocusWidget();
    3397         }
    3398 
    3399         d->focusItem = item;
    3400         QFocusEvent event(QEvent::FocusIn, focusReason);
    3401         d->sendEvent(item, &event);
    3402     }
     2946    if (item)
     2947        item->setFocus(focusReason);
     2948    else
     2949        d->setFocusItemHelper(item, focusReason);
    34032950}
    34042951
     
    34292976{
    34302977    Q_D(QGraphicsScene);
    3431     if (d->hasFocus)
     2978    if (d->hasFocus || !isActive())
    34322979        return;
    34332980    QFocusEvent event(QEvent::FocusIn, focusReason);
     
    34553002/*!
    34563003    \property QGraphicsScene::stickyFocus
    3457     \brief whether or not clicking the scene will clear focus
    3458 
    3459     If this property is false (the default), then clicking on the scene
    3460     background or on an item that does not accept focus, will clear
    3461     focus. Otherwise, focus will remain unchanged.
    3462 
    3463     The focus change happens in response to a mouse press. You can reimplement
     3004    \brief whether clicking into the scene background will clear focus
     3005
     3006    \since 4.6
     3007
     3008    In a QGraphicsScene with stickyFocus set to true, focus will remain
     3009    unchanged when the user clicks into the scene background or on an item
     3010    that does not accept focus. Otherwise, focus will be cleared.
     3011
     3012    By default, this property is false.
     3013
     3014    Focus changes in response to a mouse press. You can reimplement
    34643015    mousePressEvent() in a subclass of QGraphicsScene to toggle this property
    34653016    based on where the user has clicked.
     
    35843135{
    35853136    Q_D(const QGraphicsScene);
    3586     if (!d->focusItem)
     3137    if (!d->focusItem || !(d->focusItem->flags() & QGraphicsItem::ItemAcceptsInputMethod))
    35873138        return QVariant();
    35883139    const QTransform matrix = d->focusItem->sceneTransform();
     
    36133164    // Check if anyone's connected; if not, we can send updates directly to
    36143165    // the views. Otherwise or if there are no views, use old behavior.
    3615     bool directUpdates = !(d->connectedSignals & d->changedSignalMask) && !d->views.isEmpty();
     3166    bool directUpdates = !(d->isSignalConnected(d->changedSignalIndex)) && !d->views.isEmpty();
    36163167    if (rect.isNull()) {
    36173168        d->updateAll = true;
     
    36203171            // Update all views.
    36213172            for (int i = 0; i < d->views.size(); ++i)
    3622                 d->views.at(i)->d_func()->updateAll();
     3173                d->views.at(i)->d_func()->fullUpdatePending = true;
    36233174        }
    36243175    } else {
     
    36343185    }
    36353186
    3636     if (!directUpdates && !d->calledEmitUpdated) {
     3187    if (!d->calledEmitUpdated) {
    36373188        d->calledEmitUpdated = true;
    36383189        QMetaObject::invokeMethod(this, "_q_emitUpdated", Qt::QueuedConnection);
     
    37453296    case QEvent::GraphicsSceneHoverLeave:
    37463297    case QEvent::GraphicsSceneHoverMove:
     3298    case QEvent::TouchBegin:
     3299    case QEvent::TouchUpdate:
     3300    case QEvent::TouchEnd:
    37473301        // Reset the under-mouse list to ensure that this event gets fresh
    37483302        // item-under-mouse data. Be careful about this list; if people delete
     
    37503304        // having stale pointers in it. We need to clear it before dispatching
    37513305        // events that use it.
     3306        // ### this should only be cleared if we received a new mouse move event,
     3307        // which relies on us fixing the replay mechanism in QGraphicsView.
    37523308        d->cachedItemsUnderMouse.clear();
    37533309    default:
     
    38053361        return false;
    38063362    case QEvent::GraphicsSceneMouseMove:
    3807         mouseMoveEvent(static_cast<QGraphicsSceneMouseEvent *>(event));
     3363    {
     3364        QGraphicsSceneMouseEvent *mouseEvent = static_cast<QGraphicsSceneMouseEvent *>(event);
     3365        d->lastSceneMousePos = mouseEvent->scenePos();
     3366        mouseMoveEvent(mouseEvent);
    38083367        break;
     3368    }
    38093369    case QEvent::GraphicsSceneMousePress:
    38103370        mousePressEvent(static_cast<QGraphicsSceneMouseEvent *>(event));
     
    38283388    case QEvent::GraphicsSceneHoverLeave:
    38293389    case QEvent::GraphicsSceneHoverMove:
    3830         d->dispatchHoverEvent(static_cast<QGraphicsSceneHoverEvent *>(event));
     3390    {
     3391        QGraphicsSceneHoverEvent *hoverEvent = static_cast<QGraphicsSceneHoverEvent *>(event);
     3392        d->lastSceneMousePos = hoverEvent->scenePos();
     3393        d->dispatchHoverEvent(hoverEvent);
    38313394        break;
     3395    }
    38323396    case QEvent::Leave:
    38333397        d->leaveScene();
     
    38393403        inputMethodEvent(static_cast<QInputMethodEvent *>(event));
    38403404        break;
    3841     case QEvent::WindowActivate: {
     3405    case QEvent::WindowActivate:
    38423406        if (!d->activationRefCount++) {
    3843             // Notify all non-window widgets.
    3844             foreach (QGraphicsItem *item, items()) {
    3845                 if (item->isWidget() && item->isVisible() && !item->isWindow() && !item->parentWidget()) {
    3846                     QEvent event(QEvent::WindowActivate);
    3847                     QApplication::sendEvent(static_cast<QGraphicsWidget *>(item), &event);
     3407            if (d->lastActivePanel) {
     3408                // Activate the last panel.
     3409                d->setActivePanelHelper(d->lastActivePanel, true);
     3410            } else if (d->tabFocusFirst && d->tabFocusFirst->isPanel()) {
     3411                // Activate the panel of the first item in the tab focus
     3412                // chain.
     3413                d->setActivePanelHelper(d->tabFocusFirst, true);
     3414            } else {
     3415                // Activate all toplevel items.
     3416                QEvent event(QEvent::WindowActivate);
     3417                foreach (QGraphicsItem *item, items()) {
     3418                    if (item->isVisible() && !item->isPanel() && !item->parentItem())
     3419                        sendEvent(item, &event);
    38483420                }
    38493421            }
    3850 
    3851             // Restore window activation.
    3852             QGraphicsItem *nextFocusItem = d->focusItem ? d->focusItem : d->lastFocusItem;
    3853             if (nextFocusItem && nextFocusItem->window())
    3854                 setActiveWindow(static_cast<QGraphicsWidget *>(nextFocusItem));
    3855             else if (d->tabFocusFirst && d->tabFocusFirst->isWindow())
    3856                 setActiveWindow(d->tabFocusFirst);
    38573422        }
    38583423        break;
    3859     }
    3860     case QEvent::WindowDeactivate: {
     3424    case QEvent::WindowDeactivate:
    38613425        if (!--d->activationRefCount) {
    3862             // Remove window activation.
    3863             setActiveWindow(0);
    3864 
    3865             // Notify all non-window widgets.
    3866             foreach (QGraphicsItem *item, items()) {
    3867                 if (item->isWidget() && item->isVisible() && !item->isWindow() && !item->parentWidget()) {
    3868                     QEvent event(QEvent::WindowDeactivate);
    3869                     QApplication::sendEvent(static_cast<QGraphicsWidget *>(item), &event);
     3426            if (d->activePanel) {
     3427                // Deactivate the active panel (but keep it so we can
     3428                // reactivate it later).
     3429                QGraphicsItem *lastActivePanel = d->activePanel;
     3430                d->setActivePanelHelper(0, true);
     3431                d->lastActivePanel = lastActivePanel;
     3432            } else {
     3433                // Activate all toplevel items.
     3434                QEvent event(QEvent::WindowDeactivate);
     3435                foreach (QGraphicsItem *item, items()) {
     3436                    if (item->isVisible() && !item->isPanel() && !item->parentItem())
     3437                        sendEvent(item, &event);
    38703438                }
    38713439            }
    38723440        }
    38733441        break;
    3874     }
    38753442    case QEvent::ApplicationFontChange: {
    38763443        // Resolve the existing scene font.
     
    38963463        update();
    38973464        break;
    3898     case QEvent::Timer:
    3899         if (d->indexTimerId && static_cast<QTimerEvent *>(event)->timerId() == d->indexTimerId) {
    3900             if (d->restartIndexTimer) {
    3901                 d->restartIndexTimer = false;
    3902             } else {
    3903                 // this call will kill the timer
    3904                 d->_q_updateIndex();
    3905             }
    3906         }
    3907         // Fallthrough intended - support timers in subclasses.
     3465    case QEvent::TouchBegin:
     3466    case QEvent::TouchUpdate:
     3467    case QEvent::TouchEnd:
     3468        d->touchEventHandler(static_cast<QTouchEvent *>(event));
     3469        break;
     3470    case QEvent::Gesture:
     3471    case QEvent::GestureOverride:
     3472        d->gestureEventHandler(static_cast<QGestureEvent *>(event));
     3473        break;
    39083474    default:
    39093475        return QObject::event(event);
     
    39253491    switch (event->type()) {
    39263492    case QEvent::ApplicationPaletteChange:
    3927         qApp->postEvent(this, new QEvent(QEvent::ApplicationPaletteChange));
     3493        QApplication::postEvent(this, new QEvent(QEvent::ApplicationPaletteChange));
    39283494        break;
    39293495    case QEvent::ApplicationFontChange:
    3930         qApp->postEvent(this, new QEvent(QEvent::ApplicationFontChange));
     3496        QApplication::postEvent(this, new QEvent(QEvent::ApplicationFontChange));
    39313497        break;
    39323498    default:
     
    41943760        point = helpEvent->screenPos();
    41953761    }
    4196     QToolTip::showText(point, text);
     3762    QToolTip::showText(point, text, helpEvent->widget());
    41973763    helpEvent->setAccepted(!text.isEmpty());
    41983764#endif
     
    42013767bool QGraphicsScenePrivate::itemAcceptsHoverEvents_helper(const QGraphicsItem *item) const
    42023768{
    4203     return item->acceptHoverEvents()
    4204         || (item->isWidget() && static_cast<const QGraphicsWidget *>(item)->d_func()->hasDecoration());
     3769    return (!item->isBlockedByModalPanel() &&
     3770            (item->acceptHoverEvents()
     3771             || (item->isWidget()
     3772                 && static_cast<const QGraphicsWidget *>(item)->d_func()->hasDecoration())));
    42053773}
    42063774
     
    42153783bool QGraphicsScenePrivate::dispatchHoverEvent(QGraphicsSceneHoverEvent *hoverEvent)
    42163784{
     3785    if (allItemsIgnoreHoverEvents)
     3786        return false;
     3787
    42173788    // Find the first item that accepts hover events, reusing earlier
    42183789    // calculated data is possible.
     
    42373808    while (commonAncestorItem && !itemAcceptsHoverEvents_helper(commonAncestorItem))
    42383809        commonAncestorItem = commonAncestorItem->parentItem();
    4239     if (commonAncestorItem && commonAncestorItem->window() != item->window()) {
    4240         // The common ancestor isn't in the same window as the two hovered
     3810    if (commonAncestorItem && commonAncestorItem->panel() != item->panel()) {
     3811        // The common ancestor isn't in the same panel as the two hovered
    42413812        // items.
    42423813        commonAncestorItem = 0;
     
    42593830    while (parent && parent != commonAncestorItem) {
    42603831        parents.prepend(parent);
    4261         if (parent->isWindow()) {
    4262             // Stop at the window - we don't deliver beyond this point.
     3832        if (parent->isPanel()) {
     3833            // Stop at the panel - we don't deliver beyond this point.
    42633834            break;
    42643835        }
     
    42733844
    42743845    // Generate a move event for the item itself
    4275     if (item && !hoverItems.isEmpty() && item == hoverItems.last()) {
     3846    if (item
     3847        && !hoverItems.isEmpty()
     3848        && item == hoverItems.last()) {
    42763849        sendHoverEvent(QEvent::GraphicsSceneHoverMove, item, hoverEvent);
    42773850        return true;
     
    42903863    Q_Q(QGraphicsScene);
    42913864#ifndef QT_NO_TOOLTIP
    4292     // Remove any tooltips
    4293     QToolTip::showText(QPoint(), QString());
     3865    QToolTip::hideText();
    42943866#endif
    42953867    // Send HoverLeave events to all existing hover items, topmost first.
     
    43083880    while (!hoverItems.isEmpty()) {
    43093881        QGraphicsItem *lastItem = hoverItems.takeLast();
    4310         if (lastItem->acceptHoverEvents()
    4311             || (lastItem->isWidget() && static_cast<QGraphicsWidget*>(lastItem)->d_func()->hasDecoration()))
     3882        if (itemAcceptsHoverEvents_helper(lastItem))
    43123883            sendHoverEvent(QEvent::GraphicsSceneHoverLeave, lastItem, &hoverEvent);
    43133884    }
     
    43363907            // Send it; QGraphicsItem::keyPressEvent ignores it.  If the event
    43373908            // is filtered out, stop propagating it.
     3909            if (p->isBlockedByModalPanel())
     3910                break;
    43383911            if (!d->sendEvent(p, keyEvent))
    43393912                break;
    4340         } while (!keyEvent->isAccepted() && !p->isWindow() && (p = p->parentItem()));
     3913        } while (!keyEvent->isAccepted() && !p->isPanel() && (p = p->parentItem()));
    43413914    } else {
    43423915        keyEvent->ignore();
     
    43663939            // Send it; QGraphicsItem::keyPressEvent ignores it.  If the event
    43673940            // is filtered out, stop propagating it.
     3941            if (p->isBlockedByModalPanel())
     3942                break;
    43683943            if (!d->sendEvent(p, keyEvent))
    43693944                break;
    4370         } while (!keyEvent->isAccepted() && !p->isWindow() && (p = p->parentItem()));
     3945        } while (!keyEvent->isAccepted() && !p->isPanel() && (p = p->parentItem()));
    43713946    } else {
    43723947        keyEvent->ignore();
     
    43943969{
    43953970    Q_D(QGraphicsScene);
     3971    if (d->mouseGrabberItems.isEmpty()) {
     3972        // Dispatch hover events
     3973        QGraphicsSceneHoverEvent hover;
     3974        _q_hoverFromMouseEvent(&hover, mouseEvent);
     3975        d->dispatchHoverEvent(&hover);
     3976    }
     3977
    43963978    d->mousePressEventHandler(mouseEvent);
    43973979}
     
    45114093    bool hasSetFocus = false;
    45124094    foreach (QGraphicsItem *item, wheelCandidates) {
    4513         if (!hasSetFocus && item->isEnabled() && (item->flags() & QGraphicsItem::ItemIsFocusable)) {
     4095        if (!hasSetFocus && item->isEnabled()
     4096            && ((item->flags() & QGraphicsItem::ItemIsFocusable) && item->d_ptr->mouseSetsFocus)) {
    45144097            if (item->isWidget() && static_cast<QGraphicsWidget *>(item)->focusPolicy() == Qt::WheelFocus) {
    45154098                hasSetFocus = true;
     
    45224105                                                            wheelEvent->widget()));
    45234106        wheelEvent->accept();
    4524         bool isWindow = item->isWindow();
     4107        bool isPanel = item->isPanel();
    45254108        d->sendEvent(item, wheelEvent);
    4526         if (isWindow || wheelEvent->isAccepted())
     4109        if (isPanel || wheelEvent->isAccepted())
    45274110            break;
    45284111    }
     
    45344117
    45354118    The default implementation forwards the event to the focusItem().
    4536     If no item currently has focus, this function does nothing.
     4119    If no item currently has focus or the current focus item does not
     4120    accept input methods, this function does nothing.
    45374121
    45384122    \sa QGraphicsItem::inputMethodEvent()
     
    45414125{
    45424126    Q_D(QGraphicsScene);
    4543     if (!d->focusItem)
    4544         return;
    4545     d->sendEvent(d->focusItem, event);
     4127    if (d->focusItem && (d->focusItem->flags() & QGraphicsItem::ItemAcceptsInputMethod))
     4128        d->sendEvent(d->focusItem, event);
    45464129}
    45474130
     
    46144197    const qreal oldPainterOpacity = painter->opacity();
    46154198
    4616     if (qFuzzyCompare(windowOpacity + 1, qreal(1.0)))
     4199    if (qFuzzyIsNull(windowOpacity))
    46174200        return;
    46184201    // Set new painter opacity.
     
    46514234
    46524235    // Don't use subpixmap if we get a full update.
    4653     if (pixmapExposed.isEmpty() || (pixmapExposed.numRects() == 1 && br.contains(pix->rect()))) {
     4236    if (pixmapExposed.isEmpty() || (pixmapExposed.rectCount() == 1 && br.contains(pix->rect()))) {
    46544237        pix->fill(Qt::transparent);
    46554238        pixmapPainter.begin(pix);
     
    46774260        // Blit the subpixmap into the main pixmap.
    46784261        pixmapPainter.begin(pix);
    4679         pixmapPainter.setCompositionMode(QPainter::CompositionMode_Source);
    46804262        pixmapPainter.setClipRegion(pixmapExposed);
    46814263        pixmapPainter.drawPixmap(br.topLeft(), subPix);
     
    46934275                                           bool painterStateProtection)
    46944276{
    4695     QGraphicsItemPrivate *itemd = item->d_ptr;
     4277    QGraphicsItemPrivate *itemd = item->d_ptr.data();
    46964278    QGraphicsItem::CacheMode cacheMode = QGraphicsItem::CacheMode(itemd->cacheMode);
    46974279
     
    47234305
    47244306    // Fetch the off-screen transparent buffer and exposed area info.
    4725     QString pixmapKey;
     4307    QPixmapCache::Key pixmapKey;
    47264308    QPixmap pix;
     4309    bool pixmapFound;
    47274310    QGraphicsItemCache *itemCache = itemd->extraItemCache();
    47284311    if (cacheMode == QGraphicsItem::ItemCoordinateCache) {
     
    47344317        pixmapKey = itemCache->key;
    47354318    } else {
    4736         if ((pixmapKey = itemCache->deviceData.value(widget).key).isEmpty()) {
    4737             pixmapKey.sprintf("qgv-%p-%p", item, widget);
    4738             QGraphicsItemCache::DeviceData data;
    4739             data.key = pixmapKey;
    4740             itemCache->deviceData.insert(widget, data);
    4741         }
     4319        pixmapKey = itemCache->deviceData.value(widget).key;
    47424320    }
    47434321
    47444322    // Find pixmap in cache.
    4745     if (!itemCache->allExposed)
    4746         QPixmapCache::find(pixmapKey, pix);
     4323    pixmapFound = QPixmapCache::find(pixmapKey, &pix);
    47474324
    47484325    // Render using item coordinate cache mode.
     
    47694346        // Redraw any newly exposed areas.
    47704347        if (itemCache->allExposed || !itemCache->exposed.isEmpty()) {
     4348
     4349            //We know that we will modify the pixmap, removing it from the cache
     4350            //will detach the one we have and avoid a deep copy
     4351            if (pixmapFound)
     4352                QPixmapCache::remove(pixmapKey);
     4353
    47714354            // Fit the item's bounding rect into the pixmap's coordinates.
    47724355            QTransform itemToPixmap;
     
    47794362            // Generate the item's exposedRect and map its list of expose
    47804363            // rects to device coordinates.
    4781             QStyleOptionGraphicsItem cacheOption = *option;
     4364            styleOptionTmp = *option;
    47824365            QRegion pixmapExposed;
    47834366            QRectF exposedRect;
     
    47914374                exposedRect = brect;
    47924375            }
    4793             cacheOption.exposedRect = exposedRect;
     4376            styleOptionTmp.exposedRect = exposedRect;
    47944377
    47954378            // Render.
    47964379            _q_paintIntoCache(&pix, item, pixmapExposed, itemToPixmap, painter->renderHints(),
    4797                               &cacheOption, painterStateProtection);
    4798 
    4799             // Reinsert this pixmap into the cache.
    4800             QPixmapCache::insert(pixmapKey, pix);
     4380                              &styleOptionTmp, painterStateProtection);
     4381
     4382            // insert this pixmap into the cache.
     4383            itemCache->key = QPixmapCache::insert(pix);
    48014384
    48024385            // Reset expose data.
     
    48644447#else
    48654448        // Only if deviceRect is 20% taller or wider than the desktop.
    4866         QRect desktopRect = qApp->desktop()->availableGeometry(widget);
    4867         bool allowPartialCacheExposure = (desktopRect.width() * 1.2 < deviceRect.width()
    4868                                           || desktopRect.height() * 1.2 < deviceRect.height());
     4449        bool allowPartialCacheExposure = false;
     4450        if (widget) {
     4451            QRect desktopRect = QApplication::desktop()->availableGeometry(widget);
     4452            allowPartialCacheExposure = (desktopRect.width() * 1.2 < deviceRect.width()
     4453                                         || desktopRect.height() * 1.2 < deviceRect.height());
     4454        }
    48694455#endif
    48704456        QRegion scrollExposure;
     
    49254511        // Check for newly invalidated areas.
    49264512        if (itemCache->allExposed || !itemCache->exposed.isEmpty() || !scrollExposure.isEmpty()) {
     4513            //We know that we will modify the pixmap, removing it from the cache
     4514            //will detach the one we have and avoid a deep copy
     4515            if (pixmapFound)
     4516                QPixmapCache::remove(pixmapKey);
     4517
    49274518            // Construct an item-to-pixmap transform.
    49284519            QPointF p = deviceRect.topLeft();
     
    49514542                    br |= pixmapToItem.mapRect(r);
    49524543            }
    4953             QStyleOptionGraphicsItem cacheOption = *option;
    4954             cacheOption.exposedRect = br.adjusted(-1, -1, 1, 1);
     4544            styleOptionTmp = *option;
     4545            styleOptionTmp.exposedRect = br.adjusted(-1, -1, 1, 1);
    49554546
    49564547            // Render the exposed areas.
    49574548            _q_paintIntoCache(&pix, item, pixmapExposed, itemToPixmap, painter->renderHints(),
    4958                               &cacheOption, painterStateProtection);
     4549                              &styleOptionTmp, painterStateProtection);
    49594550
    49604551            // Reset expose data.
     
    49654556
    49664557        if (pixModified) {
    4967             // Reinsert this pixmap into the cache
    4968             QPixmapCache::insert(pixmapKey, pix);
     4558            // Insert this pixmap into the cache.
     4559            deviceData->key = QPixmapCache::insert(pix);
    49694560        }
    49704561
     
    49854576}
    49864577
     4578void QGraphicsScenePrivate::drawItems(QPainter *painter, const QTransform *const viewTransform,
     4579                                      QRegion *exposedRegion, QWidget *widget)
     4580{
     4581    // Make sure we don't have unpolished items before we draw.
     4582    if (!unpolishedItems.isEmpty())
     4583        _q_polishItems();
     4584
     4585    QRectF exposedSceneRect;
     4586    if (exposedRegion && indexMethod != QGraphicsScene::NoIndex) {
     4587        exposedSceneRect = exposedRegion->boundingRect().adjusted(-1, -1, 1, 1);
     4588        if (viewTransform)
     4589            exposedSceneRect = viewTransform->inverted().mapRect(exposedSceneRect);
     4590    }
     4591    const QList<QGraphicsItem *> tli = index->estimateTopLevelItems(exposedSceneRect, Qt::AscendingOrder);
     4592    for (int i = 0; i < tli.size(); ++i)
     4593        drawSubtreeRecursive(tli.at(i), painter, viewTransform, exposedRegion, widget);
     4594}
     4595
     4596void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter *painter,
     4597                                                 const QTransform *const viewTransform,
     4598                                                 QRegion *exposedRegion, QWidget *widget,
     4599                                                 qreal parentOpacity, const QTransform *const effectTransform)
     4600{
     4601    Q_ASSERT(item);
     4602
     4603    if (!item->d_ptr->visible)
     4604        return;
     4605
     4606    const bool itemHasContents = !(item->d_ptr->flags & QGraphicsItem::ItemHasNoContents);
     4607    const bool itemHasChildren = !item->d_ptr->children.isEmpty();
     4608    if (!itemHasContents && !itemHasChildren)
     4609        return; // Item has neither contents nor children!(?)
     4610
     4611    const qreal opacity = item->d_ptr->combineOpacityFromParent(parentOpacity);
     4612    const bool itemIsFullyTransparent = (opacity < 0.0001);
     4613    if (itemIsFullyTransparent && (!itemHasChildren || item->d_ptr->childrenCombineOpacity()))
     4614        return;
     4615
     4616    QTransform transform(Qt::Uninitialized);
     4617    QTransform *transformPtr = 0;
     4618    bool translateOnlyTransform = false;
     4619#define ENSURE_TRANSFORM_PTR \
     4620    if (!transformPtr) { \
     4621        Q_ASSERT(!itemIsUntransformable); \
     4622        if (viewTransform) { \
     4623            transform = item->d_ptr->sceneTransform; \
     4624            transform *= *viewTransform; \
     4625            transformPtr = &transform; \
     4626        } else { \
     4627            transformPtr = &item->d_ptr->sceneTransform; \
     4628            translateOnlyTransform = item->d_ptr->sceneTransformTranslateOnly; \
     4629        } \
     4630    }
     4631
     4632    // Update the item's scene transform if the item is transformable;
     4633    // otherwise calculate the full transform,
     4634    bool wasDirtyParentSceneTransform = false;
     4635    const bool itemIsUntransformable = item->d_ptr->itemIsUntransformable();
     4636    if (itemIsUntransformable) {
     4637        transform = item->deviceTransform(viewTransform ? *viewTransform : QTransform());
     4638        transformPtr = &transform;
     4639    } else if (item->d_ptr->dirtySceneTransform) {
     4640        item->d_ptr->updateSceneTransformFromParent();
     4641        Q_ASSERT(!item->d_ptr->dirtySceneTransform);
     4642        wasDirtyParentSceneTransform = true;
     4643    }
     4644
     4645    const bool itemClipsChildrenToShape = (item->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape);
     4646    bool drawItem = itemHasContents && !itemIsFullyTransparent;
     4647    if (drawItem) {
     4648        const QRectF brect = adjustedItemEffectiveBoundingRect(item);
     4649        ENSURE_TRANSFORM_PTR
     4650        QRect viewBoundingRect = translateOnlyTransform ? brect.translated(transformPtr->dx(), transformPtr->dy()).toRect()
     4651                                                        : transformPtr->mapRect(brect).toRect();
     4652        if (widget)
     4653            item->d_ptr->paintedViewBoundingRects.insert(widget, viewBoundingRect);
     4654        viewBoundingRect.adjust(-1, -1, 1, 1);
     4655        drawItem = exposedRegion ? exposedRegion->intersects(viewBoundingRect) : !viewBoundingRect.isEmpty();
     4656        if (!drawItem) {
     4657            if (!itemHasChildren)
     4658                return;
     4659            if (itemClipsChildrenToShape) {
     4660                if (wasDirtyParentSceneTransform)
     4661                    item->d_ptr->invalidateChildrenSceneTransform();
     4662                return;
     4663            }
     4664        }
     4665    } // else we know for sure this item has children we must process.
     4666
     4667    if (itemHasChildren && itemClipsChildrenToShape)
     4668        ENSURE_TRANSFORM_PTR;
     4669
     4670#ifndef QT_NO_GRAPHICSEFFECT
     4671    if (item->d_ptr->graphicsEffect && item->d_ptr->graphicsEffect->isEnabled()) {
     4672        ENSURE_TRANSFORM_PTR;
     4673        QGraphicsItemPaintInfo info(viewTransform, transformPtr, effectTransform, exposedRegion, widget, &styleOptionTmp,
     4674                                    painter, opacity, wasDirtyParentSceneTransform, drawItem);
     4675        QGraphicsEffectSource *source = item->d_ptr->graphicsEffect->d_func()->source;
     4676        QGraphicsItemEffectSourcePrivate *sourced = static_cast<QGraphicsItemEffectSourcePrivate *>
     4677                                                    (source->d_func());
     4678        sourced->info = &info;
     4679        const QTransform restoreTransform = painter->worldTransform();
     4680        if (effectTransform)
     4681            painter->setWorldTransform(*transformPtr * *effectTransform);
     4682        else
     4683            painter->setWorldTransform(*transformPtr);
     4684        painter->setOpacity(opacity);
     4685
     4686        if (sourced->currentCachedSystem() != Qt::LogicalCoordinates
     4687            && sourced->lastEffectTransform != painter->worldTransform())
     4688        {
     4689            sourced->lastEffectTransform = painter->worldTransform();
     4690            sourced->invalidateCache(QGraphicsEffectSourcePrivate::TransformChanged);
     4691        }
     4692
     4693        item->d_ptr->graphicsEffect->draw(painter);
     4694        painter->setWorldTransform(restoreTransform);
     4695        sourced->info = 0;
     4696    } else
     4697#endif //QT_NO_GRAPHICSEFFECT
     4698    {
     4699        draw(item, painter, viewTransform, transformPtr, exposedRegion, widget, opacity,
     4700             effectTransform, wasDirtyParentSceneTransform, drawItem);
     4701    }
     4702}
     4703
     4704void QGraphicsScenePrivate::draw(QGraphicsItem *item, QPainter *painter, const QTransform *const viewTransform,
     4705                                 const QTransform *const transformPtr, QRegion *exposedRegion, QWidget *widget,
     4706                                 qreal opacity, const QTransform *effectTransform,
     4707                                 bool wasDirtyParentSceneTransform, bool drawItem)
     4708{
     4709    const bool itemIsFullyTransparent = (opacity < 0.0001);
     4710    const bool itemClipsChildrenToShape = (item->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape);
     4711    const bool itemHasChildren = !item->d_ptr->children.isEmpty();
     4712
     4713    int i = 0;
     4714    if (itemHasChildren) {
     4715        item->d_ptr->ensureSortedChildren();
     4716
     4717        if (itemClipsChildrenToShape) {
     4718            painter->save();
     4719            Q_ASSERT(transformPtr);
     4720            if (effectTransform)
     4721                painter->setWorldTransform(*transformPtr * *effectTransform);
     4722            else
     4723                painter->setWorldTransform(*transformPtr);
     4724            painter->setClipPath(item->shape(), Qt::IntersectClip);
     4725        }
     4726
     4727        // Draw children behind
     4728        for (i = 0; i < item->d_ptr->children.size(); ++i) {
     4729            QGraphicsItem *child = item->d_ptr->children.at(i);
     4730            if (wasDirtyParentSceneTransform)
     4731                child->d_ptr->dirtySceneTransform = 1;
     4732            if (!(child->d_ptr->flags & QGraphicsItem::ItemStacksBehindParent))
     4733                break;
     4734            if (itemIsFullyTransparent && !(child->d_ptr->flags & QGraphicsItem::ItemIgnoresParentOpacity))
     4735                continue;
     4736            drawSubtreeRecursive(child, painter, viewTransform, exposedRegion, widget, opacity, effectTransform);
     4737        }
     4738    }
     4739
     4740    // Draw item
     4741    if (drawItem) {
     4742        Q_ASSERT(!itemIsFullyTransparent);
     4743        Q_ASSERT(!(item->d_ptr->flags & QGraphicsItem::ItemHasNoContents));
     4744        Q_ASSERT(transformPtr);
     4745        item->d_ptr->initStyleOption(&styleOptionTmp, *transformPtr, exposedRegion
     4746                                     ? *exposedRegion : QRegion(), exposedRegion == 0);
     4747
     4748        const bool itemClipsToShape = item->d_ptr->flags & QGraphicsItem::ItemClipsToShape;
     4749        const bool savePainter = itemClipsToShape || painterStateProtection;
     4750        if (savePainter)
     4751            painter->save();
     4752
     4753        if (!itemHasChildren || !itemClipsChildrenToShape) {
     4754            if (effectTransform)
     4755                painter->setWorldTransform(*transformPtr * *effectTransform);
     4756            else
     4757                painter->setWorldTransform(*transformPtr);
     4758        }
     4759
     4760        if (itemClipsToShape)
     4761            painter->setClipPath(item->shape(), Qt::IntersectClip);
     4762        painter->setOpacity(opacity);
     4763
     4764        if (!item->d_ptr->cacheMode && !item->d_ptr->isWidget)
     4765            item->paint(painter, &styleOptionTmp, widget);
     4766        else
     4767            drawItemHelper(item, painter, &styleOptionTmp, widget, painterStateProtection);
     4768
     4769        if (savePainter)
     4770            painter->restore();
     4771    }
     4772
     4773    // Draw children in front
     4774    if (itemHasChildren) {
     4775        for (; i < item->d_ptr->children.size(); ++i) {
     4776            QGraphicsItem *child = item->d_ptr->children.at(i);
     4777            if (wasDirtyParentSceneTransform)
     4778                child->d_ptr->dirtySceneTransform = 1;
     4779            if (itemIsFullyTransparent && !(child->d_ptr->flags & QGraphicsItem::ItemIgnoresParentOpacity))
     4780                continue;
     4781            drawSubtreeRecursive(child, painter, viewTransform, exposedRegion, widget, opacity, effectTransform);
     4782        }
     4783    }
     4784
     4785    // Restore child clip
     4786    if (itemHasChildren && itemClipsChildrenToShape)
     4787        painter->restore();
     4788}
     4789
     4790void QGraphicsScenePrivate::markDirty(QGraphicsItem *item, const QRectF &rect, bool invalidateChildren,
     4791                                      bool force, bool ignoreOpacity, bool removingItemFromScene)
     4792{
     4793    Q_ASSERT(item);
     4794    if (updateAll)
     4795        return;
     4796
     4797    if (item->d_ptr->discardUpdateRequest(/*ignoreVisibleBit=*/force,
     4798                                          /*ignoreDirtyBit=*/removingItemFromScene || invalidateChildren,
     4799                                          /*ignoreOpacity=*/ignoreOpacity)) {
     4800        if (item->d_ptr->dirty) {
     4801            // The item is already marked as dirty and will be processed later. However,
     4802            // we have to make sure ignoreVisible and ignoreOpacity are set properly;
     4803            // otherwise things like: item->update(); item->hide() (force is now true)
     4804            // won't work as expected.
     4805            if (force)
     4806                item->d_ptr->ignoreVisible = 1;
     4807            if (ignoreOpacity)
     4808                item->d_ptr->ignoreOpacity = 1;
     4809        }
     4810        return;
     4811    }
     4812
     4813    const bool fullItemUpdate = rect.isNull();
     4814    if (!fullItemUpdate && rect.isEmpty())
     4815        return;
     4816
     4817    if (!processDirtyItemsEmitted) {
     4818        QMetaObject::invokeMethod(q_ptr, "_q_processDirtyItems", Qt::QueuedConnection);
     4819        processDirtyItemsEmitted = true;
     4820    }
     4821
     4822    if (removingItemFromScene) {
     4823        // Note that this function can be called from the item's destructor, so
     4824        // do NOT call any virtual functions on it within this block.
     4825        if (isSignalConnected(changedSignalIndex) || views.isEmpty()) {
     4826            // This block of code is kept for compatibility. Since 4.5, by default
     4827            // QGraphicsView does not connect the signal and we use the below
     4828            // method of delivering updates.
     4829            q_func()->update();
     4830            return;
     4831        }
     4832
     4833        for (int i = 0; i < views.size(); ++i) {
     4834            QGraphicsViewPrivate *viewPrivate = views.at(i)->d_func();
     4835            QRect rect = item->d_ptr->paintedViewBoundingRects.value(viewPrivate->viewport);
     4836            rect.translate(viewPrivate->dirtyScrollOffset);
     4837            viewPrivate->updateRect(rect);
     4838        }
     4839        return;
     4840    }
     4841
     4842    bool hasNoContents = item->d_ptr->flags & QGraphicsItem::ItemHasNoContents
     4843                         && !item->d_ptr->graphicsEffect;
     4844    if (!hasNoContents) {
     4845        item->d_ptr->dirty = 1;
     4846        if (fullItemUpdate)
     4847            item->d_ptr->fullUpdatePending = 1;
     4848        else if (!item->d_ptr->fullUpdatePending)
     4849            item->d_ptr->needsRepaint |= rect;
     4850    }
     4851
     4852    if (invalidateChildren) {
     4853        item->d_ptr->allChildrenDirty = 1;
     4854        item->d_ptr->dirtyChildren = 1;
     4855    }
     4856
     4857    if (force)
     4858        item->d_ptr->ignoreVisible = 1;
     4859    if (ignoreOpacity)
     4860        item->d_ptr->ignoreOpacity = 1;
     4861
     4862    QGraphicsItem *p = item->d_ptr->parent;
     4863    while (p) {
     4864        p->d_ptr->dirtyChildren = 1;
     4865#ifndef QT_NO_GRAPHICSEFFECT
     4866        if (p->d_ptr->graphicsEffect && p->d_ptr->graphicsEffect->isEnabled()) {
     4867            p->d_ptr->dirty = 1;
     4868            p->d_ptr->fullUpdatePending = 1;
     4869        }
     4870#endif //QT_NO_GRAPHICSEFFECT
     4871        p = p->d_ptr->parent;
     4872    }
     4873}
     4874
     4875static inline bool updateHelper(QGraphicsViewPrivate *view, QGraphicsItemPrivate *item,
     4876                                const QRectF &rect, bool itemIsUntransformable)
     4877{
     4878    Q_ASSERT(view);
     4879    Q_ASSERT(item);
     4880
     4881    QGraphicsItem *itemq = static_cast<QGraphicsItem *>(item->q_ptr);
     4882    QGraphicsView *viewq = static_cast<QGraphicsView *>(view->q_ptr);
     4883
     4884    if (itemIsUntransformable) {
     4885        const QTransform xform = itemq->deviceTransform(viewq->viewportTransform());
     4886        if (!item->hasBoundingRegionGranularity)
     4887            return view->updateRect(xform.mapRect(rect).toRect());
     4888        return view->updateRegion(xform.map(QRegion(rect.toRect())));
     4889    }
     4890
     4891    if (item->sceneTransformTranslateOnly && view->identityMatrix) {
     4892        const qreal dx = item->sceneTransform.dx();
     4893        const qreal dy = item->sceneTransform.dy();
     4894        if (!item->hasBoundingRegionGranularity) {
     4895            QRectF r(rect);
     4896            r.translate(dx - view->horizontalScroll(), dy - view->verticalScroll());
     4897            return view->updateRect(r.toRect());
     4898        }
     4899        QRegion r(rect.toRect());
     4900        r.translate(qRound(dx) - view->horizontalScroll(), qRound(dy) - view->verticalScroll());
     4901        return view->updateRegion(r);
     4902    }
     4903
     4904    if (!viewq->isTransformed()) {
     4905        if (!item->hasBoundingRegionGranularity)
     4906            return view->updateRect(item->sceneTransform.mapRect(rect).toRect());
     4907        return view->updateRegion(item->sceneTransform.map(QRegion(rect.toRect())));
     4908    }
     4909
     4910    QTransform xform = item->sceneTransform;
     4911    xform *= viewq->viewportTransform();
     4912    if (!item->hasBoundingRegionGranularity)
     4913        return view->updateRect(xform.mapRect(rect).toRect());
     4914    return view->updateRegion(xform.map(QRegion(rect.toRect())));
     4915}
     4916
     4917void QGraphicsScenePrivate::processDirtyItemsRecursive(QGraphicsItem *item, bool dirtyAncestorContainsChildren,
     4918                                                       qreal parentOpacity)
     4919{
     4920    Q_Q(QGraphicsScene);
     4921    Q_ASSERT(item);
     4922    Q_ASSERT(!updateAll);
     4923
     4924    if (!item->d_ptr->dirty && !item->d_ptr->dirtyChildren) {
     4925        resetDirtyItem(item);
     4926        return;
     4927    }
     4928
     4929    const bool itemIsHidden = !item->d_ptr->ignoreVisible && !item->d_ptr->visible;
     4930    if (itemIsHidden) {
     4931        resetDirtyItem(item, /*recursive=*/true);
     4932        return;
     4933    }
     4934
     4935    bool itemHasContents = !(item->d_ptr->flags & QGraphicsItem::ItemHasNoContents);
     4936    const bool itemHasChildren = !item->d_ptr->children.isEmpty();
     4937    if (!itemHasContents) {
     4938        if (!itemHasChildren) {
     4939            resetDirtyItem(item);
     4940            return; // Item has neither contents nor children!(?)
     4941        }
     4942        if (item->d_ptr->graphicsEffect)
     4943            itemHasContents = true;
     4944    }
     4945
     4946    const qreal opacity = item->d_ptr->combineOpacityFromParent(parentOpacity);
     4947    const bool itemIsFullyTransparent = !item->d_ptr->ignoreOpacity && opacity < 0.0001;
     4948    if (itemIsFullyTransparent && (!itemHasChildren || item->d_ptr->childrenCombineOpacity())) {
     4949        resetDirtyItem(item, /*recursive=*/itemHasChildren);
     4950        return;
     4951    }
     4952
     4953    bool wasDirtyParentSceneTransform = item->d_ptr->dirtySceneTransform;
     4954    const bool itemIsUntransformable = item->d_ptr->itemIsUntransformable();
     4955    if (wasDirtyParentSceneTransform && !itemIsUntransformable) {
     4956        item->d_ptr->updateSceneTransformFromParent();
     4957        Q_ASSERT(!item->d_ptr->dirtySceneTransform);
     4958    }
     4959
     4960    const bool wasDirtyParentViewBoundingRects = item->d_ptr->paintedViewBoundingRectsNeedRepaint;
     4961    if (itemIsFullyTransparent || !itemHasContents || dirtyAncestorContainsChildren) {
     4962        // Make sure we don't process invisible items or items with no content.
     4963        item->d_ptr->dirty = 0;
     4964        item->d_ptr->fullUpdatePending = 0;
     4965        // Might have a dirty view bounding rect otherwise.
     4966        if (itemIsFullyTransparent || !itemHasContents)
     4967            item->d_ptr->paintedViewBoundingRectsNeedRepaint = 0;
     4968    }
     4969
     4970    if (!hasSceneRect && item->d_ptr->geometryChanged && item->d_ptr->visible) {
     4971        // Update growingItemsBoundingRect.
     4972        if (item->d_ptr->sceneTransformTranslateOnly) {
     4973            growingItemsBoundingRect |= item->boundingRect().translated(item->d_ptr->sceneTransform.dx(),
     4974                                                                        item->d_ptr->sceneTransform.dy());
     4975        } else {
     4976            growingItemsBoundingRect |= item->d_ptr->sceneTransform.mapRect(item->boundingRect());
     4977        }
     4978    }
     4979
     4980    // Process item.
     4981    if (item->d_ptr->dirty || item->d_ptr->paintedViewBoundingRectsNeedRepaint) {
     4982        const bool useCompatUpdate = views.isEmpty() || isSignalConnected(changedSignalIndex);
     4983        const QRectF itemBoundingRect = adjustedItemEffectiveBoundingRect(item);
     4984
     4985        if (useCompatUpdate && !itemIsUntransformable && qFuzzyIsNull(item->boundingRegionGranularity())) {
     4986            // This block of code is kept for compatibility. Since 4.5, by default
     4987            // QGraphicsView does not connect the signal and we use the below
     4988            // method of delivering updates.
     4989            if (item->d_ptr->sceneTransformTranslateOnly) {
     4990                q->update(itemBoundingRect.translated(item->d_ptr->sceneTransform.dx(),
     4991                                                      item->d_ptr->sceneTransform.dy()));
     4992            } else {
     4993                q->update(item->d_ptr->sceneTransform.mapRect(itemBoundingRect));
     4994            }
     4995        } else {
     4996            QRectF dirtyRect;
     4997            bool uninitializedDirtyRect = true;
     4998
     4999            for (int j = 0; j < views.size(); ++j) {
     5000                QGraphicsView *view = views.at(j);
     5001                QGraphicsViewPrivate *viewPrivate = view->d_func();
     5002                QRect &paintedViewBoundingRect = item->d_ptr->paintedViewBoundingRects[viewPrivate->viewport];
     5003                if (viewPrivate->fullUpdatePending
     5004                    || viewPrivate->viewportUpdateMode == QGraphicsView::NoViewportUpdate) {
     5005                    // Okay, if we have a full update pending or no viewport update, this item's
     5006                    // paintedViewBoundingRect  will be updated correctly in the next paintEvent if
     5007                    // it is inside the viewport, but for now we can pretend that it is outside.
     5008                    paintedViewBoundingRect = QRect(-1, -1, -1, -1);
     5009                    continue;
     5010                }
     5011
     5012                if (item->d_ptr->paintedViewBoundingRectsNeedRepaint) {
     5013                    paintedViewBoundingRect.translate(viewPrivate->dirtyScrollOffset);
     5014                    if (!viewPrivate->updateRect(paintedViewBoundingRect))
     5015                        paintedViewBoundingRect = QRect(-1, -1, -1, -1); // Outside viewport.
     5016                }
     5017
     5018                if (!item->d_ptr->dirty)
     5019                    continue;
     5020
     5021                if (!item->d_ptr->paintedViewBoundingRectsNeedRepaint
     5022                    && paintedViewBoundingRect.x() == -1 && paintedViewBoundingRect.y() == -1
     5023                    && paintedViewBoundingRect.width() == -1 && paintedViewBoundingRect.height() == -1) {
     5024                    continue; // Outside viewport.
     5025                }
     5026
     5027                if (uninitializedDirtyRect) {
     5028                    dirtyRect = itemBoundingRect;
     5029                    if (!item->d_ptr->fullUpdatePending) {
     5030                        _q_adjustRect(&item->d_ptr->needsRepaint);
     5031                        dirtyRect &= item->d_ptr->needsRepaint;
     5032                    }
     5033                    uninitializedDirtyRect = false;
     5034                }
     5035
     5036                if (dirtyRect.isEmpty())
     5037                    continue; // Discard updates outside the bounding rect.
     5038
     5039                if (!updateHelper(viewPrivate, item->d_ptr.data(), dirtyRect, itemIsUntransformable)
     5040                    && item->d_ptr->paintedViewBoundingRectsNeedRepaint) {
     5041                    paintedViewBoundingRect = QRect(-1, -1, -1, -1); // Outside viewport.
     5042                }
     5043            }
     5044        }
     5045    }
     5046
     5047    // Process children.
     5048    if (itemHasChildren && item->d_ptr->dirtyChildren) {
     5049        if (!dirtyAncestorContainsChildren) {
     5050            dirtyAncestorContainsChildren = item->d_ptr->fullUpdatePending
     5051                                            && (item->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape);
     5052        }
     5053        const bool allChildrenDirty = item->d_ptr->allChildrenDirty;
     5054        const bool parentIgnoresVisible = item->d_ptr->ignoreVisible;
     5055        const bool parentIgnoresOpacity = item->d_ptr->ignoreOpacity;
     5056        for (int i = 0; i < item->d_ptr->children.size(); ++i) {
     5057            QGraphicsItem *child = item->d_ptr->children.at(i);
     5058            if (wasDirtyParentSceneTransform)
     5059                child->d_ptr->dirtySceneTransform = 1;
     5060            if (wasDirtyParentViewBoundingRects)
     5061                child->d_ptr->paintedViewBoundingRectsNeedRepaint = 1;
     5062            if (parentIgnoresVisible)
     5063                child->d_ptr->ignoreVisible = 1;
     5064            if (parentIgnoresOpacity)
     5065                child->d_ptr->ignoreOpacity = 1;
     5066            if (allChildrenDirty) {
     5067                child->d_ptr->dirty = 1;
     5068                child->d_ptr->fullUpdatePending = 1;
     5069                child->d_ptr->dirtyChildren = 1;
     5070                child->d_ptr->allChildrenDirty = 1;
     5071            }
     5072            processDirtyItemsRecursive(child, dirtyAncestorContainsChildren, opacity);
     5073        }
     5074    } else if (wasDirtyParentSceneTransform) {
     5075        item->d_ptr->invalidateChildrenSceneTransform();
     5076    }
     5077
     5078    resetDirtyItem(item);
     5079}
     5080
    49875081/*!
    49885082    Paints the given \a items using the provided \a painter, after the
     
    49905084    drawn.  All painting is done in \e scene coordinates. Before
    49915085    drawing each item, the painter must be transformed using
    4992     QGraphicsItem::sceneMatrix().
     5086    QGraphicsItem::sceneTransform().
    49935087
    49945088    The \a options parameter is the list of style option objects for
     
    50085102    \snippet doc/src/snippets/graphicssceneadditemsnippet.cpp 0
    50095103
     5104    \obsolete Since Qt 4.6, this function is not called anymore unless
     5105    the QGraphicsView::IndirectPainting flag is given as an Optimization
     5106    flag.
     5107
    50105108    \sa drawBackground(), drawForeground()
    50115109*/
     
    50165114{
    50175115    Q_D(QGraphicsScene);
    5018 
    5019     // Detect if painter state protection is disabled.
     5116    // Make sure we don't have unpolished items before we draw.
     5117    if (!d->unpolishedItems.isEmpty())
     5118        d->_q_polishItems();
     5119
    50205120    QTransform viewTransform = painter->worldTransform();
    5021     QVarLengthArray<QGraphicsItem *, 16> childClippers;
    5022 
     5121    Q_UNUSED(options);
     5122
     5123    // Determine view, expose and flags.
     5124    QGraphicsView *view = widget ? qobject_cast<QGraphicsView *>(widget->parentWidget()) : 0;
     5125    QRegion *expose = 0;
     5126    if (view)
     5127        expose = &view->d_func()->exposedRegion;
     5128
     5129    // Find all toplevels, they are already sorted.
     5130    QList<QGraphicsItem *> topLevelItems;
    50235131    for (int i = 0; i < numItems; ++i) {
    5024         QGraphicsItem *item = items[i];
    5025         if (!(item->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren)) {
    5026             if (!childClippers.isEmpty()) {
    5027                 // Item is not clipped to any ancestor: pop all current clippers.
    5028                 for (int i = 0; i < childClippers.size(); ++i)
    5029                     painter->restore();
    5030                 childClippers.clear();
    5031             }
    5032         } else {
    5033             // Item is clipped to an ancestor, which may or may not be in our
    5034             // child clipper list. Let's start by finding the item's closest
    5035             // clipping ancestor.
    5036             QGraphicsItem *clipParent = item->parentItem();
    5037             while (clipParent && !(clipParent->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape))
    5038                 clipParent = clipParent->parentItem();
    5039 
    5040             // Pop any in-between clippers. If the clipper is unknown, pop
    5041             // them all.  ### QVarLengthArray::lastIndexOf().
    5042             int index = -1;
    5043             for (int n = childClippers.size() - 1; n >= 0; --n) {
    5044                 if (childClippers[n] == clipParent) {
    5045                     index = n;
    5046                     break;
    5047                 }
    5048             }
    5049             if (index != -1) {
    5050                 int toPop = childClippers.size() - index - 1;
    5051                 if (toPop > 0) {
    5052                     for (int i = 0; i < toPop; ++i)
    5053                         painter->restore();
    5054                     childClippers.resize(index + 1);
    5055                 }
    5056             }
    5057 
    5058             // Sanity check
    5059             if (!childClippers.isEmpty())
    5060                 Q_ASSERT(childClippers[childClippers.size() - 1] == clipParent);
    5061 
    5062             // If the clipper list is empty at this point, but we're still
    5063             // clipped to an ancestor, then we need to build the clip chain
    5064             // ourselves. There is only one case that can produce this issue:
    5065             // This item is stacked behind an ancestor:
    5066             // ItemStacksBehindParent.
    5067             if (childClippers.isEmpty()) {
    5068                 Q_ASSERT(clipParent != 0);
    5069                 // Build a stack of clippers.
    5070                 QVarLengthArray<QGraphicsItem *, 16> clippers;
    5071                 QGraphicsItem *p = clipParent;
    5072                 do {
    5073                     if (p->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape)
    5074                         clippers.append(p);
    5075                 } while ((p = p->parentItem()) && (p->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren));
    5076 
    5077                 // ### This code path can also use the itemTransform
    5078                 // optimization, but it's hit very rarely.
    5079                 for (int i = clippers.size() - 1; i >= 0; --i) {
    5080                     QGraphicsItem *clipper = clippers[i];
    5081                     if (clipper->d_ptr->itemIsUntransformable()) {
    5082                         painter->setWorldTransform(clipper->deviceTransform(viewTransform), false);
    5083                     } else {
    5084                         painter->setWorldTransform(clipper->sceneTransform() * viewTransform, false);
    5085                     }
    5086 
    5087                     childClippers.append(clipper);
    5088                     painter->save();
    5089                     painter->setClipPath(clipper->shape(), Qt::IntersectClip);
    5090                 }
    5091                 Q_ASSERT(childClippers[childClippers.size() - 1] == clipParent);
    5092             }
    5093         }
    5094 
    5095         // Set up the painter transform
    5096         if (item->d_ptr->itemIsUntransformable()) {
    5097             painter->setWorldTransform(item->deviceTransform(viewTransform), false);
    5098         } else {
    5099             painter->setWorldTransform(item->sceneTransform() * viewTransform, false);
    5100         }
    5101        
    5102         // Save painter
    5103         bool saveState = (d->painterStateProtection || (item->flags() & QGraphicsItem::ItemClipsToShape));
    5104         if (saveState)
    5105             painter->save();
    5106 
    5107         // Set local clip
    5108         if (item->flags() & QGraphicsItem::ItemClipsToShape)
    5109             painter->setClipPath(item->shape(), Qt::IntersectClip);
    5110 
    5111         // Setup opacity
    5112         painter->setOpacity(item->effectiveOpacity());
    5113 
    5114         // Draw the item
    5115         d->drawItemHelper(item, painter, &options[i], widget, d->painterStateProtection);
    5116 
    5117         if (saveState)
    5118             painter->restore();
    5119 
    5120         if (item->flags() & QGraphicsItem::ItemClipsChildrenToShape) {
    5121             // Clip descendents to this item's shape, and keep the painter
    5122             // saved.
    5123             childClippers.append(item);
    5124             painter->save();
    5125             painter->setClipPath(item->shape(), Qt::IntersectClip);
    5126         }
    5127     }
    5128 
    5129     for (int i = 0; i < childClippers.size(); ++i)
    5130         painter->restore();
     5132        QGraphicsItem *item = items[i]->topLevelItem();
     5133        if (!item->d_ptr->itemDiscovered) {
     5134            topLevelItems << item;
     5135            item->d_ptr->itemDiscovered = 1;
     5136            d->drawSubtreeRecursive(item, painter, &viewTransform, expose, widget);
     5137        }
     5138    }
     5139
     5140    // Reset discovery bits.
     5141    for (int i = 0; i < topLevelItems.size(); ++i)
     5142        topLevelItems.at(i)->d_ptr->itemDiscovered = 0;
    51315143
    51325144    painter->setWorldTransform(viewTransform);
     
    51855197            && widget->isEnabled() && widget->isVisibleTo(0)
    51865198            && (widget->focusPolicy() & Qt::TabFocus)
    5187             && (!item || !item->isWindow() || item->isAncestorOf(widget))
     5199            && (!item || !item->isPanel() || item->isAncestorOf(widget))
    51885200            ) {
    51895201            setFocusItem(widget, next ? Qt::TabFocusReason : Qt::BacktabFocusReason);
     
    52405252
    52415253/*!
    5242     \internal
    5243 
    5244     This private function is called by QGraphicsItem, which is a friend of
    5245     QGraphicsScene. It is used by QGraphicsScene to record the rectangles that
    5246     need updating. It also launches a single-shot timer to ensure that
    5247     updated() will be emitted later.
    5248 
    5249     The \a item parameter is the item that changed, and \a rect is the
    5250     area of the item that changed given in item coordinates.
    5251 */
    5252 void QGraphicsScene::itemUpdated(QGraphicsItem *item, const QRectF &rect)
    5253 {
    5254     Q_D(QGraphicsScene);
    5255     // Deliver the actual update.
    5256     if (!d->updateAll) {
    5257         if (d->views.isEmpty() || ((d->connectedSignals & d->changedSignalMask) && !item->d_ptr->itemIsUntransformable()
    5258                                    && qFuzzyCompare(item->boundingRegionGranularity(), qreal(0.0)))) {
    5259             // This block of code is kept for compatibility. Since 4.5, by default
    5260             // QGraphicsView does not connect the signal and we use the below
    5261             // method of delivering updates.
    5262             update(item->sceneBoundingRect());
    5263         } else {
    5264             // ### Remove _q_adjustedRects().
    5265             QRectF boundingRect(adjustedItemBoundingRect(item));
    5266             if (!rect.isNull()) {
    5267                 QRectF adjustedRect(rect);
    5268                 _q_adjustRect(&adjustedRect);
    5269                 boundingRect &= adjustedRect;
    5270             }
    5271 
    5272             // Update each view directly.
    5273             for (int i = 0; i < d->views.size(); ++i)
    5274                 d->views.at(i)->d_func()->itemUpdated(item, boundingRect);
    5275         }
    5276     }
    5277     if (item->d_ptr->dirty) {
    5278         d->dirtyItems << item;
    5279         d->resetDirtyItemsLater();
    5280     }
    5281 
    5282     if (!item->isVisible())
    5283         return; // Hiding an item won't effect the largestUntransformableItem/sceneRect.
    5284 
    5285     // Update d->largestUntransformableItem by mapping this item's bounding
    5286     // rect back to the topmost untransformable item's untransformed
    5287     // coordinate system (which sort of equals the 1:1 coordinate system of an
    5288     // untransformed view).
    5289     if (item->d_ptr->itemIsUntransformable()) {
    5290         QGraphicsItem *parent = item;
    5291         while (parent && (parent->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorIgnoresTransformations))
    5292             parent = parent->parentItem();
    5293         d->largestUntransformableItem |= item->mapToItem(parent, item->boundingRect()).boundingRect();
    5294     }
    5295 
    5296     // Only track the automatically growing scene rect if the scene has no
    5297     // defined scene rect.
    5298     if (!d->hasSceneRect) {
    5299         QRectF oldGrowingItemsBoundingRect = d->growingItemsBoundingRect;
    5300         QRectF adjustedItemSceneBoundingRect(item->sceneBoundingRect());
    5301         _q_adjustRect(&adjustedItemSceneBoundingRect);
    5302         d->growingItemsBoundingRect |= adjustedItemSceneBoundingRect;
    5303         if (d->growingItemsBoundingRect != oldGrowingItemsBoundingRect)
    5304             emit sceneRectChanged(d->growingItemsBoundingRect);
    5305     }
    5306 }
    5307 
    5308 /*!
    53095254    \since 4.4
    53105255
     
    53185263    Q_D(const QGraphicsScene);
    53195264    // ### This function, and the use of styles in general, is non-reentrant.
    5320     return d->style ? d->style : qApp->style();
     5265    return d->style ? d->style : QApplication::style();
    53215266}
    53225267
     
    53955340{
    53965341    Q_D(QGraphicsScene);
    5397     QFont naturalFont = qApp->font();
     5342    QFont naturalFont = QApplication::font();
    53985343    naturalFont.resolve(0);
    53995344    QFont resolvedFont = font.resolve(naturalFont);
     
    54325377{
    54335378    Q_D(QGraphicsScene);
    5434     QPalette naturalPalette = qApp->palette();
     5379    QPalette naturalPalette = QApplication::palette();
    54355380    naturalPalette.resolve(0);
    54365381    QPalette resolvedPalette = palette.resolve(naturalPalette);
     
    54395384
    54405385/*!
     5386    \since 4.6
     5387
     5388    Returns true if the scene is active (e.g., it's viewed by
     5389    at least one QGraphicsView that is active); otherwise returns false.
     5390
     5391    \sa QGraphicsItem::isActive(), QWidget::isActiveWindow()
     5392*/
     5393bool QGraphicsScene::isActive() const
     5394{
     5395    Q_D(const QGraphicsScene);
     5396    return d->activationRefCount > 0;
     5397}
     5398
     5399/*!
     5400    \since 4.6
     5401    Returns the current active panel, or 0 if no panel is currently active.
     5402
     5403    \sa QGraphicsScene::setActivePanel()
     5404*/
     5405QGraphicsItem *QGraphicsScene::activePanel() const
     5406{
     5407    Q_D(const QGraphicsScene);
     5408    return d->activePanel;
     5409}
     5410
     5411/*!
     5412    \since 4.6
     5413    Activates \a item, which must be an item in this scene. You
     5414    can also pass 0 for \a item, in which case QGraphicsScene will
     5415    deactivate any currently active panel.
     5416
     5417    If the scene is currently inactive, \a item remains inactive until the
     5418    scene becomes active (or, ir \a item is 0, no item will be activated).
     5419
     5420    \sa activePanel(), isActive(), QGraphicsItem::isActive()
     5421*/
     5422void QGraphicsScene::setActivePanel(QGraphicsItem *item)
     5423{
     5424    Q_D(QGraphicsScene);
     5425    d->setActivePanelHelper(item, false);
     5426}
     5427
     5428/*!
    54415429    \since 4.4
    54425430
    5443     Returns the current active window, or 0 if there is no window is currently
     5431    Returns the current active window, or 0 if no window is currently
    54445432    active.
    54455433
     
    54495437{
    54505438    Q_D(const QGraphicsScene);
    5451     return d->activeWindow;
     5439    if (d->activePanel && d->activePanel->isWindow())
     5440        return static_cast<QGraphicsWidget *>(d->activePanel);
     5441    return 0;
    54525442}
    54535443
     
    54625452void QGraphicsScene::setActiveWindow(QGraphicsWidget *widget)
    54635453{
    5464     Q_D(QGraphicsScene);
    54655454    if (widget && widget->scene() != this) {
    54665455        qWarning("QGraphicsScene::setActiveWindow: widget %p must be part of this scene",
     
    54695458    }
    54705459
    5471     // Activate the widget's window.
    5472     QGraphicsWidget *window = widget ? widget->window() : 0;
    5473     if (window == d->activeWindow)
    5474         return;
    5475 
    5476     // Deactivate the last active window.
    5477     if (d->activeWindow) {
    5478         if (QGraphicsWidget *fw = d->activeWindow->focusWidget()) {
    5479             // Remove focus from the current focus item.
    5480             if (fw == focusItem())
    5481                 setFocusItem(0, Qt::ActiveWindowFocusReason);
    5482         }
    5483 
    5484         QEvent event(QEvent::WindowDeactivate);
    5485         QApplication::sendEvent(d->activeWindow, &event);
    5486     }
    5487 
    5488     // Update activate state.
    5489     d->activeWindow = window;
    5490     QEvent event(QEvent::ActivationChange);
    5491     QApplication::sendEvent(this, &event);
    5492 
    5493     // Activate
    5494     if (window) {
    5495         QEvent event(QEvent::WindowActivate);
    5496         QApplication::sendEvent(window, &event);
    5497 
     5460    // Activate the widget's panel (all windows are panels).
     5461    QGraphicsItem *panel = widget ? widget->panel() : 0;
     5462    setActivePanel(panel);
     5463
     5464    // Raise
     5465    if (panel) {
    54985466        QList<QGraphicsItem *> siblingWindows;
    5499         QGraphicsItem *parent = window->parentItem();
     5467        QGraphicsItem *parent = panel->parentItem();
    55005468        // Raise ### inefficient for toplevels
    55015469        foreach (QGraphicsItem *sibling, parent ? parent->children() : items()) {
    5502             if (sibling != window && sibling->isWidget()
    5503                 && static_cast<QGraphicsWidget *>(sibling)->isWindow()) {
     5470            if (sibling != panel && sibling->isWindow())
    55045471                siblingWindows << sibling;
    5505             }
    55065472        }
    55075473
    55085474        // Find the highest z value.
    5509         qreal z = window->zValue();
     5475        qreal z = panel->zValue();
    55105476        for (int i = 0; i < siblingWindows.size(); ++i)
    55115477            z = qMax(z, siblingWindows.at(i)->zValue());
     
    55135479        // This will probably never overflow.
    55145480        const qreal litt = qreal(0.001);
    5515         window->setZValue(z + litt);
    5516 
    5517         if (QGraphicsWidget *focusChild = window->focusWidget())
    5518             focusChild->setFocus(Qt::ActiveWindowFocusReason);
     5481        panel->setZValue(z + litt);
     5482    }
     5483}
     5484
     5485/*!
     5486    \since 4.6
     5487
     5488    Sends event \a event to item \a item through possible event filters.
     5489
     5490    The event is sent only if the item is enabled.
     5491
     5492    Returns \c false if the event was filtered or if the item is disabled.
     5493    Otherwise returns the value that was returned from the event handler.
     5494
     5495    \sa QGraphicsItem::sceneEvent(), QGraphicsItem::sceneEventFilter()
     5496*/
     5497bool QGraphicsScene::sendEvent(QGraphicsItem *item, QEvent *event)
     5498{
     5499    Q_D(QGraphicsScene);
     5500    if (!item) {
     5501        qWarning("QGraphicsScene::sendEvent: cannot send event to a null item");
     5502        return false;
     5503    }
     5504    if (item->scene() != this) {
     5505        qWarning("QGraphicsScene::sendEvent: item %p's scene (%p)"
     5506                 " is different from this scene (%p)",
     5507                 item, item->scene(), this);
     5508        return false;
     5509    }
     5510    return d->sendEvent(item, event);
     5511}
     5512
     5513void QGraphicsScenePrivate::addView(QGraphicsView *view)
     5514{
     5515    views << view;
     5516}
     5517
     5518void QGraphicsScenePrivate::removeView(QGraphicsView *view)
     5519{
     5520    views.removeAll(view);
     5521}
     5522
     5523void QGraphicsScenePrivate::updateTouchPointsForItem(QGraphicsItem *item, QTouchEvent *touchEvent)
     5524{
     5525    QList<QTouchEvent::TouchPoint> touchPoints = touchEvent->touchPoints();
     5526    for (int i = 0; i < touchPoints.count(); ++i) {
     5527        QTouchEvent::TouchPoint &touchPoint = touchPoints[i];
     5528        touchPoint.setRect(item->mapFromScene(touchPoint.sceneRect()).boundingRect());
     5529        touchPoint.setStartPos(item->d_ptr->genericMapFromScene(touchPoint.startScenePos(), touchEvent->widget()));
     5530        touchPoint.setLastPos(item->d_ptr->genericMapFromScene(touchPoint.lastScenePos(), touchEvent->widget()));
     5531    }
     5532    touchEvent->setTouchPoints(touchPoints);
     5533}
     5534
     5535int QGraphicsScenePrivate::findClosestTouchPointId(const QPointF &scenePos)
     5536{
     5537    int closestTouchPointId = -1;
     5538    qreal closestDistance = qreal(0.);
     5539    foreach (const QTouchEvent::TouchPoint &touchPoint, sceneCurrentTouchPoints) {
     5540        qreal distance = QLineF(scenePos, touchPoint.scenePos()).length();
     5541        if (closestTouchPointId == -1|| distance < closestDistance) {
     5542            closestTouchPointId = touchPoint.id();
     5543            closestDistance = distance;
     5544        }
     5545    }
     5546    return closestTouchPointId;
     5547}
     5548
     5549void QGraphicsScenePrivate::touchEventHandler(QTouchEvent *sceneTouchEvent)
     5550{
     5551    typedef QPair<Qt::TouchPointStates, QList<QTouchEvent::TouchPoint> > StatesAndTouchPoints;
     5552    QHash<QGraphicsItem *, StatesAndTouchPoints> itemsNeedingEvents;
     5553
     5554    for (int i = 0; i < sceneTouchEvent->touchPoints().count(); ++i) {
     5555        const QTouchEvent::TouchPoint &touchPoint = sceneTouchEvent->touchPoints().at(i);
     5556
     5557        // update state
     5558        QGraphicsItem *item = 0;
     5559        if (touchPoint.state() == Qt::TouchPointPressed) {
     5560            if (sceneTouchEvent->deviceType() == QTouchEvent::TouchPad) {
     5561                // on touch-pad devices, send all touch points to the same item
     5562                item = itemForTouchPointId.isEmpty()
     5563                       ? 0
     5564                       : itemForTouchPointId.constBegin().value();
     5565            }
     5566
     5567            if (!item) {
     5568                // determine which item this touch point will go to
     5569                cachedItemsUnderMouse = itemsAtPosition(touchPoint.screenPos().toPoint(),
     5570                                                        touchPoint.scenePos(),
     5571                                                        sceneTouchEvent->widget());
     5572                item = cachedItemsUnderMouse.isEmpty() ? 0 : cachedItemsUnderMouse.first();
     5573            }
     5574
     5575            if (sceneTouchEvent->deviceType() == QTouchEvent::TouchScreen) {
     5576                // on touch-screens, combine this touch point with the closest one we find if it
     5577                // is a a direct descendent or ancestor (
     5578                int closestTouchPointId = findClosestTouchPointId(touchPoint.scenePos());
     5579                QGraphicsItem *closestItem = itemForTouchPointId.value(closestTouchPointId);
     5580                if (!item
     5581                    || (closestItem
     5582                        && (item->isAncestorOf(closestItem)
     5583                            || closestItem->isAncestorOf(item)))) {
     5584                    item = closestItem;
     5585                }
     5586            }
     5587            if (!item)
     5588                continue;
     5589
     5590            itemForTouchPointId.insert(touchPoint.id(), item);
     5591            sceneCurrentTouchPoints.insert(touchPoint.id(), touchPoint);
     5592        } else if (touchPoint.state() == Qt::TouchPointReleased) {
     5593            item = itemForTouchPointId.take(touchPoint.id());
     5594            if (!item)
     5595                continue;
     5596
     5597            sceneCurrentTouchPoints.remove(touchPoint.id());
     5598        } else {
     5599            item = itemForTouchPointId.value(touchPoint.id());
     5600            if (!item)
     5601                continue;
     5602            Q_ASSERT(sceneCurrentTouchPoints.contains(touchPoint.id()));
     5603            sceneCurrentTouchPoints[touchPoint.id()] = touchPoint;
     5604        }
     5605
     5606        StatesAndTouchPoints &statesAndTouchPoints = itemsNeedingEvents[item];
     5607        statesAndTouchPoints.first |= touchPoint.state();
     5608        statesAndTouchPoints.second.append(touchPoint);
     5609    }
     5610
     5611    if (itemsNeedingEvents.isEmpty()) {
     5612        sceneTouchEvent->accept();
     5613        return;
     5614    }
     5615
     5616    bool ignoreSceneTouchEvent = true;
     5617    QHash<QGraphicsItem *, StatesAndTouchPoints>::ConstIterator it = itemsNeedingEvents.constBegin();
     5618    const QHash<QGraphicsItem *, StatesAndTouchPoints>::ConstIterator end = itemsNeedingEvents.constEnd();
     5619    for (; it != end; ++it) {
     5620        QGraphicsItem *item = it.key();
     5621
     5622        (void) item->isBlockedByModalPanel(&item);
     5623
     5624        // determine event type from the state mask
     5625        QEvent::Type eventType;
     5626        switch (it.value().first) {
     5627        case Qt::TouchPointPressed:
     5628            // all touch points have pressed state
     5629            eventType = QEvent::TouchBegin;
     5630            break;
     5631        case Qt::TouchPointReleased:
     5632            // all touch points have released state
     5633            eventType = QEvent::TouchEnd;
     5634            break;
     5635        case Qt::TouchPointStationary:
     5636            // don't send the event if nothing changed
     5637            continue;
     5638        default:
     5639            // all other combinations
     5640            eventType = QEvent::TouchUpdate;
     5641            break;
     5642        }
     5643
     5644        QTouchEvent touchEvent(eventType);
     5645        touchEvent.setWidget(sceneTouchEvent->widget());
     5646        touchEvent.setDeviceType(sceneTouchEvent->deviceType());
     5647        touchEvent.setModifiers(sceneTouchEvent->modifiers());
     5648        touchEvent.setTouchPointStates(it.value().first);
     5649        touchEvent.setTouchPoints(it.value().second);
     5650
     5651        switch (touchEvent.type()) {
     5652        case QEvent::TouchBegin:
     5653        {
     5654            // if the TouchBegin handler recurses, we assume that means the event
     5655            // has been implicitly accepted and continue to send touch events
     5656            item->d_ptr->acceptedTouchBeginEvent = true;
     5657            bool res = sendTouchBeginEvent(item, &touchEvent)
     5658                       && touchEvent.isAccepted();
     5659            if (!res)
     5660                ignoreSceneTouchEvent = false;
     5661            break;
     5662        }
     5663        default:
     5664            if (item->d_ptr->acceptedTouchBeginEvent) {
     5665                updateTouchPointsForItem(item, &touchEvent);
     5666                (void) sendEvent(item, &touchEvent);
     5667                ignoreSceneTouchEvent = false;
     5668            }
     5669            break;
     5670        }
     5671    }
     5672    sceneTouchEvent->setAccepted(ignoreSceneTouchEvent);
     5673}
     5674
     5675bool QGraphicsScenePrivate::sendTouchBeginEvent(QGraphicsItem *origin, QTouchEvent *touchEvent)
     5676{
     5677    Q_Q(QGraphicsScene);
     5678
     5679    if (cachedItemsUnderMouse.isEmpty() || cachedItemsUnderMouse.first() != origin) {
     5680        const QTouchEvent::TouchPoint &firstTouchPoint = touchEvent->touchPoints().first();
     5681        cachedItemsUnderMouse = itemsAtPosition(firstTouchPoint.screenPos().toPoint(),
     5682                                                firstTouchPoint.scenePos(),
     5683                                                touchEvent->widget());
     5684    }
     5685    Q_ASSERT(cachedItemsUnderMouse.first() == origin);
     5686
     5687    // Set focus on the topmost enabled item that can take focus.
     5688    bool setFocus = false;
     5689    foreach (QGraphicsItem *item, cachedItemsUnderMouse) {
     5690        if (item->isEnabled() && ((item->flags() & QGraphicsItem::ItemIsFocusable) && item->d_ptr->mouseSetsFocus)) {
     5691            if (!item->isWidget() || ((QGraphicsWidget *)item)->focusPolicy() & Qt::ClickFocus) {
     5692                setFocus = true;
     5693                if (item != q->focusItem())
     5694                    q->setFocusItem(item, Qt::MouseFocusReason);
     5695                break;
     5696            }
     5697        }
     5698        if (item->isPanel())
     5699            break;
     5700    }
     5701
     5702    // If nobody could take focus, clear it.
     5703    if (!stickyFocus && !setFocus)
     5704        q->setFocusItem(0, Qt::MouseFocusReason);
     5705
     5706    bool res = false;
     5707    bool eventAccepted = touchEvent->isAccepted();
     5708    foreach (QGraphicsItem *item, cachedItemsUnderMouse) {
     5709        // first, try to deliver the touch event
     5710        updateTouchPointsForItem(item, touchEvent);
     5711        bool acceptTouchEvents = item->acceptTouchEvents();
     5712        touchEvent->setAccepted(acceptTouchEvents);
     5713        res = acceptTouchEvents && sendEvent(item, touchEvent);
     5714        eventAccepted = touchEvent->isAccepted();
     5715        if (itemForTouchPointId.value(touchEvent->touchPoints().first().id()) == 0) {
     5716            // item was deleted
     5717            item = 0;
     5718        } else {
     5719            item->d_ptr->acceptedTouchBeginEvent = (res && eventAccepted);
     5720        }
     5721        touchEvent->spont = false;
     5722        if (res && eventAccepted) {
     5723            // the first item to accept the TouchBegin gets an implicit grab.
     5724            for (int i = 0; i < touchEvent->touchPoints().count(); ++i) {
     5725                const QTouchEvent::TouchPoint &touchPoint = touchEvent->touchPoints().at(i);
     5726                itemForTouchPointId[touchPoint.id()] = item; // can be zero
     5727            }
     5728            break;
     5729        }
     5730        if (item && item->isPanel())
     5731            break;
     5732    }
     5733
     5734    touchEvent->setAccepted(eventAccepted);
     5735    return res;
     5736}
     5737
     5738void QGraphicsScenePrivate::enableTouchEventsOnViews()
     5739{
     5740    foreach (QGraphicsView *view, views)
     5741        view->viewport()->setAttribute(Qt::WA_AcceptTouchEvents, true);
     5742}
     5743
     5744void QGraphicsScenePrivate::updateInputMethodSensitivityInViews()
     5745{
     5746    for (int i = 0; i < views.size(); ++i)
     5747        views.at(i)->d_func()->updateInputMethodSensitivity();
     5748}
     5749
     5750void QGraphicsScenePrivate::enterModal(QGraphicsItem *panel, QGraphicsItem::PanelModality previousModality)
     5751{
     5752    Q_Q(QGraphicsScene);
     5753    Q_ASSERT(panel && panel->isPanel());
     5754
     5755    QGraphicsItem::PanelModality panelModality = panel->d_ptr->panelModality;
     5756    if (previousModality != QGraphicsItem::NonModal) {
     5757        // the panel is changing from one modality type to another... temporarily set it back so
     5758        // that blockedPanels is populated correctly
     5759        panel->d_ptr->panelModality = previousModality;
     5760    }
     5761
     5762    QSet<QGraphicsItem *> blockedPanels;
     5763    QList<QGraphicsItem *> items = q->items(); // ### store panels separately
     5764    for (int i = 0; i < items.count(); ++i) {
     5765        QGraphicsItem *item = items.at(i);
     5766        if (item->isPanel() && item->isBlockedByModalPanel())
     5767            blockedPanels.insert(item);
     5768    }
     5769    // blockedPanels contains all currently blocked panels
     5770
     5771    if (previousModality != QGraphicsItem::NonModal) {
     5772        // reset the modality to the proper value, since we changed it above
     5773        panel->d_ptr->panelModality = panelModality;
     5774        // remove this panel so that it will be reinserted at the front of the stack
     5775        modalPanels.removeAll(panel);
     5776    }
     5777
     5778    modalPanels.prepend(panel);
     5779
     5780    if (!hoverItems.isEmpty()) {
     5781        // send GraphicsSceneHoverLeave events to newly blocked hoverItems
     5782        QGraphicsSceneHoverEvent hoverEvent;
     5783        hoverEvent.setScenePos(lastSceneMousePos);
     5784        dispatchHoverEvent(&hoverEvent);
     5785    }
     5786
     5787    if (!mouseGrabberItems.isEmpty() && lastMouseGrabberItemHasImplicitMouseGrab) {
     5788        QGraphicsItem *item = mouseGrabberItems.last();
     5789        if (item->isBlockedByModalPanel())
     5790            ungrabMouse(item, /*itemIsDying =*/ false);
     5791    }
     5792
     5793    QEvent windowBlockedEvent(QEvent::WindowBlocked);
     5794    QEvent windowUnblockedEvent(QEvent::WindowUnblocked);
     5795    for (int i = 0; i < items.count(); ++i) {
     5796        QGraphicsItem *item = items.at(i);
     5797        if (item->isPanel()) {
     5798            if (!blockedPanels.contains(item) && item->isBlockedByModalPanel()) {
     5799                // send QEvent::WindowBlocked to newly blocked panels
     5800                sendEvent(item, &windowBlockedEvent);
     5801            } else if (blockedPanels.contains(item) && !item->isBlockedByModalPanel()) {
     5802                // send QEvent::WindowUnblocked to unblocked panels when downgrading
     5803                // a panel from SceneModal to PanelModal
     5804                sendEvent(item, &windowUnblockedEvent);
     5805            }
     5806        }
     5807    }
     5808}
     5809
     5810void QGraphicsScenePrivate::leaveModal(QGraphicsItem *panel)
     5811{
     5812    Q_Q(QGraphicsScene);
     5813    Q_ASSERT(panel && panel->isPanel());
     5814
     5815    QSet<QGraphicsItem *> blockedPanels;
     5816    QList<QGraphicsItem *> items = q->items(); // ### same as above
     5817    for (int i = 0; i < items.count(); ++i) {
     5818        QGraphicsItem *item = items.at(i);
     5819        if (item->isPanel() && item->isBlockedByModalPanel())
     5820            blockedPanels.insert(item);
     5821    }
     5822
     5823    modalPanels.removeAll(panel);
     5824
     5825    QEvent e(QEvent::WindowUnblocked);
     5826    for (int i = 0; i < items.count(); ++i) {
     5827        QGraphicsItem *item = items.at(i);
     5828        if (item->isPanel() && blockedPanels.contains(item) && !item->isBlockedByModalPanel())
     5829            sendEvent(item, &e);
     5830    }
     5831
     5832    // send GraphicsSceneHoverEnter events to newly unblocked items
     5833    QGraphicsSceneHoverEvent hoverEvent;
     5834    hoverEvent.setScenePos(lastSceneMousePos);
     5835    dispatchHoverEvent(&hoverEvent);
     5836}
     5837
     5838void QGraphicsScenePrivate::getGestureTargets(const QSet<QGesture *> &gestures,
     5839                                              QWidget *viewport,
     5840                                              QMap<Qt::GestureType, QGesture *> *conflictedGestures,
     5841                                              QList<QList<QGraphicsObject *> > *conflictedItems,
     5842                                              QHash<QGesture *, QGraphicsObject *> *normalGestures)
     5843{
     5844    foreach (QGesture *gesture, gestures) {
     5845        Qt::GestureType gestureType = gesture->gestureType();
     5846        if (gesture->hasHotSpot()) {
     5847            QPoint screenPos = gesture->hotSpot().toPoint();
     5848            QList<QGraphicsItem *> items = itemsAtPosition(screenPos, QPointF(), viewport);
     5849            QList<QGraphicsObject *> result;
     5850            for (int j = 0; j < items.size(); ++j) {
     5851                QGraphicsObject *item = items.at(j)->toGraphicsObject();
     5852                if (!item)
     5853                    continue;
     5854                QGraphicsItemPrivate *d = item->QGraphicsItem::d_func();
     5855                if (d->gestureContext.contains(gestureType)) {
     5856                    result.append(item);
     5857                }
     5858            }
     5859            DEBUG() << "QGraphicsScenePrivate::getGestureTargets:"
     5860                    << gesture << result;
     5861            if (result.size() == 1) {
     5862                normalGestures->insert(gesture, result.first());
     5863            } else if (!result.isEmpty()) {
     5864                conflictedGestures->insert(gestureType, gesture);
     5865                conflictedItems->append(result);
     5866            }
     5867        }
     5868    }
     5869}
     5870
     5871void QGraphicsScenePrivate::gestureEventHandler(QGestureEvent *event)
     5872{
     5873    QWidget *viewport = event->widget();
     5874    if (!viewport)
     5875        return;
     5876    QList<QGesture *> allGestures = event->gestures();
     5877    DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:"
     5878            << "Delivering gestures:" <<  allGestures;
     5879
     5880    typedef QHash<QGraphicsObject *, QList<QGesture *> > GesturesPerItem;
     5881    GesturesPerItem gesturesPerItem;
     5882
     5883    QSet<QGesture *> startedGestures;
     5884    foreach (QGesture *gesture, allGestures) {
     5885        QGraphicsObject *target = gestureTargets.value(gesture, 0);
     5886        if (!target) {
     5887            // when we are not in started mode but don't have a target
     5888            // then the only one interested in gesture is the view/scene
     5889            if (gesture->state() == Qt::GestureStarted)
     5890                startedGestures.insert(gesture);
     5891        } else {
     5892            gesturesPerItem[target].append(gesture);
     5893        }
     5894    }
     5895
     5896    QMap<Qt::GestureType, QGesture *> conflictedGestures;
     5897    QList<QList<QGraphicsObject *> > conflictedItems;
     5898    QHash<QGesture *, QGraphicsObject *> normalGestures;
     5899    getGestureTargets(startedGestures, viewport, &conflictedGestures, &conflictedItems,
     5900                      &normalGestures);
     5901    DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:"
     5902            << "Conflicting gestures:" <<  conflictedGestures.values() << conflictedItems;
     5903    Q_ASSERT((conflictedGestures.isEmpty() && conflictedItems.isEmpty()) ||
     5904              (!conflictedGestures.isEmpty() && !conflictedItems.isEmpty()));
     5905
     5906    // gestures that were sent as override events, but no one accepted them
     5907    QHash<QGesture *, QGraphicsObject *> ignoredConflictedGestures;
     5908
     5909    // deliver conflicted gestures as override events first
     5910    while (!conflictedGestures.isEmpty() && !conflictedItems.isEmpty()) {
     5911        // get the topmost item to deliver the override event
     5912        Q_ASSERT(!conflictedItems.isEmpty());
     5913        Q_ASSERT(!conflictedItems.first().isEmpty());
     5914        QGraphicsObject *topmost = conflictedItems.first().first();
     5915        for (int i = 1; i < conflictedItems.size(); ++i) {
     5916            QGraphicsObject *item = conflictedItems.at(i).first();
     5917            if (qt_closestItemFirst(item, topmost)) {
     5918                topmost = item;
     5919            }
     5920        }
     5921        // get a list of gestures to send to the item
     5922        QList<Qt::GestureType> grabbedGestures =
     5923                topmost->QGraphicsItem::d_func()->gestureContext.keys();
     5924        QList<QGesture *> gestures;
     5925        for (int i = 0; i < grabbedGestures.size(); ++i) {
     5926            if (QGesture *g = conflictedGestures.value(grabbedGestures.at(i), 0)) {
     5927                gestures.append(g);
     5928                if (!ignoredConflictedGestures.contains(g))
     5929                    ignoredConflictedGestures.insert(g, topmost);
     5930            }
     5931        }
     5932
     5933        // send gesture override to the topmost item
     5934        QGestureEvent ev(gestures);
     5935        ev.t = QEvent::GestureOverride;
     5936        ev.setWidget(event->widget());
     5937        // mark event and individual gestures as ignored
     5938        ev.ignore();
     5939        foreach(QGesture *g, gestures)
     5940            ev.setAccepted(g, false);
     5941        DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:"
     5942                << "delivering override to"
     5943                << topmost << gestures;
     5944        sendEvent(topmost, &ev);
     5945        // mark all accepted gestures to deliver them as normal gesture events
     5946        foreach (QGesture *g, gestures) {
     5947            if (ev.isAccepted() || ev.isAccepted(g)) {
     5948                conflictedGestures.remove(g->gestureType());
     5949                gestureTargets.remove(g);
     5950                // add the gesture to the list of normal delivered gestures
     5951                normalGestures.insert(g, topmost);
     5952                DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:"
     5953                        << "override was accepted:"
     5954                        << g << topmost;
     5955                ignoredConflictedGestures.remove(g);
     5956            }
     5957        }
     5958        // remove the item that we've already delivered from the list
     5959        for (int i = 0; i < conflictedItems.size(); ) {
     5960            QList<QGraphicsObject *> &items = conflictedItems[i];
     5961            if (items.first() == topmost) {
     5962                items.removeFirst();
     5963                if (items.isEmpty()) {
     5964                    conflictedItems.removeAt(i);
     5965                    continue;
     5966                }
     5967            }
     5968            ++i;
     5969        }
     5970    }
     5971
     5972    // put back those started gestures that are not in the conflicted state
     5973    // and remember their targets
     5974    QHash<QGesture *, QGraphicsObject *>::const_iterator it = normalGestures.begin(),
     5975                                                          e = normalGestures.end();
     5976    for (; it != e; ++it) {
     5977        QGesture *g = it.key();
     5978        QGraphicsObject *receiver = it.value();
     5979        Q_ASSERT(!gestureTargets.contains(g));
     5980        gestureTargets.insert(g, receiver);
     5981        gesturesPerItem[receiver].append(g);
     5982    }
     5983    it = ignoredConflictedGestures.begin();
     5984    e = ignoredConflictedGestures.end();
     5985    for (; it != e; ++it) {
     5986        QGesture *g = it.key();
     5987        QGraphicsObject *receiver = it.value();
     5988        Q_ASSERT(!gestureTargets.contains(g));
     5989        gestureTargets.insert(g, receiver);
     5990        gesturesPerItem[receiver].append(g);
     5991    }
     5992
     5993    DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:"
     5994            << "Started gestures:" << normalGestures.keys()
     5995            << "All gestures:" << gesturesPerItem.values();
     5996
     5997    // deliver all events
     5998    QList<QGesture *> alreadyIgnoredGestures;
     5999    QHash<QGraphicsObject *, QSet<QGesture *> > itemIgnoredGestures;
     6000    QList<QGraphicsObject *> targetItems = gesturesPerItem.keys();
     6001    qSort(targetItems.begin(), targetItems.end(), qt_closestItemFirst);
     6002    for (int i = 0; i < targetItems.size(); ++i) {
     6003        QGraphicsObject *item = targetItems.at(i);
     6004        QList<QGesture *> gestures = gesturesPerItem.value(item);
     6005        // remove gestures that were already delivered once and were ignored
     6006        DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:"
     6007                << "already ignored gestures for item"
     6008                << item << ":" << itemIgnoredGestures.value(item);
     6009
     6010        if (itemIgnoredGestures.contains(item)) // don't deliver twice to the same item
     6011            continue;
     6012
     6013        QGraphicsItemPrivate *gid = item->QGraphicsItem::d_func();
     6014        foreach(QGesture *g, alreadyIgnoredGestures) {
     6015            QMap<Qt::GestureType, Qt::GestureFlags>::iterator contextit =
     6016                    gid->gestureContext.find(g->gestureType());
     6017            bool deliver = contextit != gid->gestureContext.end() &&
     6018                (g->state() == Qt::GestureStarted ||
     6019                 (contextit.value() & Qt::ReceivePartialGestures));
     6020            if (deliver)
     6021                gestures += g;
     6022        }
     6023        if (gestures.isEmpty())
     6024            continue;
     6025        DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:"
     6026                << "delivering to"
     6027                << item << gestures;
     6028        QGestureEvent ev(gestures);
     6029        ev.setWidget(event->widget());
     6030        sendEvent(item, &ev);
     6031        QSet<QGesture *> ignoredGestures;
     6032        foreach (QGesture *g, gestures) {
     6033            if (!ev.isAccepted() && !ev.isAccepted(g)) {
     6034                ignoredGestures.insert(g);
     6035            } else {
     6036                if (g->state() == Qt::GestureStarted)
     6037                    gestureTargets[g] = item;
     6038            }
     6039        }
     6040        if (!ignoredGestures.isEmpty()) {
     6041            // get a list of items under the (current) hotspot of each ignored
     6042            // gesture and start delivery again from the beginning
     6043            DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:"
     6044                    << "item has ignored the event, will propagate."
     6045                    << item << ignoredGestures;
     6046            itemIgnoredGestures[item] += ignoredGestures;
     6047            QMap<Qt::GestureType, QGesture *> conflictedGestures;
     6048            QList<QList<QGraphicsObject *> > itemsForConflictedGestures;
     6049            QHash<QGesture *, QGraphicsObject *> normalGestures;
     6050            getGestureTargets(ignoredGestures, viewport,
     6051                              &conflictedGestures, &itemsForConflictedGestures,
     6052                              &normalGestures);
     6053            QSet<QGraphicsObject *> itemsSet = targetItems.toSet();
     6054            for (int k = 0; k < itemsForConflictedGestures.size(); ++k)
     6055                itemsSet += itemsForConflictedGestures.at(k).toSet();
     6056            targetItems = itemsSet.toList();
     6057            qSort(targetItems.begin(), targetItems.end(), qt_closestItemFirst);
     6058            alreadyIgnoredGestures = conflictedGestures.values();
     6059            DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:"
     6060                    << "new targets:" << targetItems;
     6061            i = -1; // start delivery again
     6062            continue;
     6063        }
     6064    }
     6065    foreach (QGesture *g, startedGestures) {
     6066        if (g->gestureCancelPolicy() == QGesture::CancelAllInContext) {
     6067            DEBUG() << "lets try to cancel some";
     6068            // find gestures in context in Qt::GestureStarted or Qt::GestureUpdated state and cancel them
     6069            cancelGesturesForChildren(g, event->widget());
     6070        }
     6071    }
     6072
     6073    // forget about targets for gestures that have ended
     6074    foreach (QGesture *g, allGestures) {
     6075        switch (g->state()) {
     6076        case Qt::GestureFinished:
     6077        case Qt::GestureCanceled:
     6078            gestureTargets.remove(g);
     6079            break;
     6080        default:
     6081            break;
     6082        }
     6083    }
     6084}
     6085
     6086void QGraphicsScenePrivate::cancelGesturesForChildren(QGesture *original, QWidget *viewport)
     6087{
     6088    Q_ASSERT(original);
     6089    QGraphicsItem *originalItem = gestureTargets.value(original);
     6090    Q_ASSERT(originalItem);
     6091
     6092    // iterate over all active gestures and for each find the owner
     6093    // if the owner is part of our sub-hierarchy, cancel it.
     6094
     6095    QSet<QGesture *> canceledGestures;
     6096    QHash<QGesture *, QGraphicsObject *>::Iterator iter = gestureTargets.begin();
     6097    while (iter != gestureTargets.end()) {
     6098        QGraphicsObject *item = iter.value();
     6099        // note that we don't touch the gestures for our originalItem
     6100        if (item != originalItem && originalItem->isAncestorOf(item)) {
     6101            DEBUG() << "  found a gesture to cancel" << iter.key();
     6102            iter.key()->d_func()->state = Qt::GestureCanceled;
     6103            canceledGestures << iter.key();
     6104        }
     6105        ++iter;
     6106    }
     6107
     6108    // sort them per target item by cherry picking from almostCanceledGestures and delivering
     6109    QSet<QGesture *> almostCanceledGestures = canceledGestures;
     6110    QSet<QGesture *>::Iterator setIter;
     6111    while (!almostCanceledGestures.isEmpty()) {
     6112        QGraphicsObject *target = 0;
     6113        QSet<QGesture*> gestures;
     6114        setIter = almostCanceledGestures.begin();
     6115        // sort per target item
     6116        while (setIter != almostCanceledGestures.end()) {
     6117            QGraphicsObject *item = gestureTargets.value(*setIter);
     6118            if (target == 0)
     6119                target = item;
     6120            if (target == item) {
     6121                gestures << *setIter;
     6122                setIter = almostCanceledGestures.erase(setIter);
     6123            } else {
     6124                ++setIter;
     6125            }
     6126        }
     6127        Q_ASSERT(target);
     6128
     6129        QList<QGesture *> list = gestures.toList();
     6130        QGestureEvent ev(list);
     6131        sendEvent(target, &ev);
     6132
     6133        foreach (QGesture *g, list) {
     6134            if (ev.isAccepted() || ev.isAccepted(g))
     6135                gestures.remove(g);
     6136        }
     6137
     6138        foreach (QGesture *g, gestures) {
     6139            if (!g->hasHotSpot())
     6140                continue;
     6141
     6142            QPoint screenPos = g->hotSpot().toPoint();
     6143            QList<QGraphicsItem *> items = itemsAtPosition(screenPos, QPointF(), viewport);
     6144            for (int j = 0; j < items.size(); ++j) {
     6145                QGraphicsObject *item = items.at(j)->toGraphicsObject();
     6146                if (!item)
     6147                    continue;
     6148                QGraphicsItemPrivate *d = item->QGraphicsItem::d_func();
     6149                if (d->gestureContext.contains(g->gestureType())) {
     6150                    QList<QGesture *> list;
     6151                    list << g;
     6152                    QGestureEvent ev(list);
     6153                    sendEvent(item, &ev);
     6154                    if (ev.isAccepted() || ev.isAccepted(g))
     6155                        break; // successfully delivered
     6156                }
     6157            }
     6158        }
     6159    }
     6160
     6161    QGestureManager *gestureManager = QApplicationPrivate::instance()->gestureManager;
     6162    Q_ASSERT(gestureManager); // it would be very odd if we got called without a manager.
     6163    for (setIter = canceledGestures.begin(); setIter != canceledGestures.end(); ++setIter) {
     6164        gestureManager->recycle(*setIter);
     6165        gestureTargets.remove(*setIter);
    55196166    }
    55206167}
Note: See TracChangeset for help on using the changeset viewer.