text: /****************************************************************************
  **
  ** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
  ** Contact: http://www.qt-project.org/legal
  **
  ** This file is part of the QtGui module of the Qt Toolkit.
  **
  ** $QT_BEGIN_LICENSE:LGPL$
  ** Commercial License Usage
  ** Licensees holding valid commercial Qt licenses may use this file in
  ** accordance with the commercial license agreement provided with the
  ** Software or, alternatively, in accordance with the terms contained in
  ** a written agreement between you and Digia.  For licensing terms and
  ** conditions see http://qt.digia.com/licensing.  For further information
  ** use the contact form at http://qt.digia.com/contact-us.
  **
  ** GNU Lesser General Public License Usage
  ** Alternatively, this file may be used under the terms of the GNU Lesser
  ** General Public License version 2.1 as published by the Free Software
  ** Foundation and appearing in the file LICENSE.LGPL included in the
  ** packaging of this file.  Please review the following information to
  ** ensure the GNU Lesser General Public License version 2.1 requirements
  ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
  **
  ** In addition, as a special exception, Digia gives you certain additional
  ** rights.  These rights are described in the Digia Qt LGPL Exception
  ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
  **
  ** GNU General Public License Usage
  ** Alternatively, this file may be used under the terms of the GNU
  ** General Public License version 3.0 as published by the Free Software
  ** Foundation and appearing in the file LICENSE.GPL included in the
  ** packaging of this file.  Please review the following information to
  ** ensure the GNU General Public License version 3.0 requirements will be
  ** met: http://www.gnu.org/copyleft/gpl.html.
  **
  **
  ** $QT_END_LICENSE$
  **
  ****************************************************************************/
  
  /*!
      \class QGraphicsScene
      \brief The QGraphicsScene class provides a surface for managing a large
      number of 2D graphical items.
      \since 4.2
      \ingroup graphicsview-api
  
  
      The class serves as a container for QGraphicsItems. It is used together
      with QGraphicsView for visualizing graphical items, such as lines,
      rectangles, text, or even custom items, on a 2D surface. QGraphicsScene is
      part of the \l{Graphics View Framework}.
  
      QGraphicsScene also provides functionality that lets you efficiently
      determine both the location of items, and for determining what items are
      visible within an arbitrary area on the scene. With the QGraphicsView
      widget, you can either visualize the whole scene, or zoom in and view only
      parts of the scene.
  
      Example:
  
      \snippet doc/src/snippets/code/src_gui_graphicsview_qgraphicsscene.cpp 0
  
      Note that QGraphicsScene has no visual appearance of its own; it only
      manages the items. You need to create a QGraphicsView widget to visualize
      the scene.
  
      To add items to a scene, you start off by constructing a QGraphicsScene
      object. Then, you have two options: either add your existing QGraphicsItem
      objects by calling addItem(), or you can call one of the convenience
      functions addEllipse(), addLine(), addPath(), addPixmap(), addPolygon(),
      addRect(), or addText(), which all return a pointer to the newly added item.
      The dimensions of the items added with these functions are relative to the
      item's coordinate system, and the items position is initialized to (0,
      0) in the scene.
  
      You can then visualize the scene using QGraphicsView. When the scene
      changes, (e.g., when an item moves or is transformed) QGraphicsScene
      emits the changed() signal. To remove an item, call removeItem().
  
      QGraphicsScene uses an indexing algorithm to manage the location of items
      efficiently. By default, a BSP (Binary Space Partitioning) tree is used; an
      algorithm suitable for large scenes where most items remain static (i.e.,
      do not move around). You can choose to disable this index by calling
      setItemIndexMethod(). For more information about the available indexing
      algorithms, see the itemIndexMethod property.
  
      The scene's bounding rect is set by calling setSceneRect(). Items can be
      placed at any position on the scene, and the size of the scene is by
      default unlimited. The scene rect is used only for internal bookkeeping,
      maintaining the scene's item index. If the scene rect is unset,
      QGraphicsScene will use the bounding area of all items, as returned by
      itemsBoundingRect(), as the scene rect. However, itemsBoundingRect() is a
      relatively time consuming function, as it operates by collecting
      positional information for every item on the scene. Because of this, you
      should always set the scene rect when operating on large scenes.
  
      One of QGraphicsScene's greatest strengths is its ability to efficiently
      determine the location of items. Even with millions of items on the scene,
      the items() functions can determine the location of an item within few
      milliseconds. There are several overloads to items(): one that finds items
      at a certain position, one that finds items inside or intersecting with a
      polygon or a rectangle, and more. The list of returned items is sorted by
      stacking order, with the topmost item being the first item in the list.
      For convenience, there is also an itemAt() function that returns the
      topmost item at a given position.
  
      QGraphicsScene maintains selection information for the scene. To select
      items, call setSelectionArea(), and to clear the current selection, call
      clearSelection(). Call selectedItems() to get the list of all selected
      items.
  
      \section1 Event Handling and Propagation
  
      Another responsibility that QGraphicsScene has, is to propagate events
      from QGraphicsView. To send an event to a scene, you construct an event
      that inherits QEvent, and then send it using, for example,
      QApplication::sendEvent(). event() is responsible for dispatching
      the event to the individual items. Some common events are handled by
      convenience event handlers. For example, key press events are handled by
      keyPressEvent(), and mouse press events are handled by mousePressEvent().
  
      Key events are delivered to the \e {focus item}. To set the focus item,
      you can either call setFocusItem(), passing an item that accepts focus, or
      the item itself can call QGraphicsItem::setFocus().  Call focusItem() to
      get the current focus item. For compatibility with widgets, the scene also
      maintains its own focus information. By default, the scene does not have
      focus, and all key events are discarded. If setFocus() is called, or if an
      item on the scene gains focus, the scene automatically gains focus. If the
      scene has focus, hasFocus() will return true, and key events will be
      forwarded to the focus item, if any. If the scene loses focus, (i.e.,
      someone calls clearFocus()) while an item has focus, the scene will
      maintain its item focus information, and once the scene regains focus, it
      will make sure the last focus item regains focus.
  
      For mouse-over effects, QGraphicsScene dispatches \e {hover
      events}. If an item accepts hover events (see
      QGraphicsItem::acceptHoverEvents()), it will receive a \l
      {QEvent::}{GraphicsSceneHoverEnter} event when the mouse enters
      its area. As the mouse continues moving inside the item's area,
      QGraphicsScene will send it \l {QEvent::}{GraphicsSceneHoverMove}
      events. When the mouse leaves the item's area, the item will
      receive a \l {QEvent::}{GraphicsSceneHoverLeave} event.
  
      All mouse events are delivered to the current \e {mouse grabber}
      item. An item becomes the scene's mouse grabber if it accepts
      mouse events (see QGraphicsItem::acceptedMouseButtons()) and it
      receives a mouse press. It stays the mouse grabber until it
      receives a mouse release when no other mouse buttons are
      pressed. You can call mouseGrabberItem() to determine what item is
      currently grabbing the mouse.
  
      \sa QGraphicsItem, QGraphicsView
  */
  
  /*!
      \enum QGraphicsScene::SceneLayer
      \since 4.3
  
      This enum describes the rendering layers in a QGraphicsScene. When
      QGraphicsScene draws the scene contents, it renders each of these layers
      separately, in order.
  
      Each layer represents a flag that can be OR'ed together when calling
      functions such as invalidate() or QGraphicsView::invalidateScene().
  
      \value ItemLayer The item layer. QGraphicsScene renders all items are in
      this layer by calling the virtual function drawItems(). The item layer is
      drawn after the background layer, but before the foreground layer.
  
      \value BackgroundLayer The background layer. QGraphicsScene renders the
      scene's background in this layer by calling the virtual function
      drawBackground(). The background layer is drawn first of all layers.
  
      \value ForegroundLayer The foreground layer. QGraphicsScene renders the
      scene's foreground in this layer by calling the virtual function
      drawForeground().  The foreground layer is drawn last of all layers.
  
      \value AllLayers All layers; this value represents a combination of all
      three layers.
  
      \sa invalidate(), QGraphicsView::invalidateScene()
  */
  
  /*!
      \enum QGraphicsScene::ItemIndexMethod
  
      This enum describes the indexing algorithms QGraphicsScene provides for
      managing positional information about items on the scene.
  
      \value BspTreeIndex A Binary Space Partitioning tree is applied. All
      QGraphicsScene's item location algorithms are of an order close to
      logarithmic complexity, by making use of binary search. Adding, moving and
      removing items is logarithmic. This approach is best for static scenes
      (i.e., scenes where most items do not move).
  
      \value NoIndex No index is applied. Item location is of linear complexity,
      as all items on the scene are searched. Adding, moving and removing items,
      however, is done in constant time. This approach is ideal for dynamic
      scenes, where many items are added, moved or removed continuously.
  
      \sa setItemIndexMethod(), bspTreeDepth
  */
  
  #include "qgraphicsscene.h"
  
  #ifndef QT_NO_GRAPHICSVIEW
  
  #include "qgraphicsitem.h"
  #include "qgraphicsitem_p.h"
  #include "qgraphicslayout.h"
  #include "qgraphicsscene_p.h"
  #include "qgraphicssceneevent.h"
  #include "qgraphicsview.h"
  #include "qgraphicsview_p.h"
  #include "qgraphicswidget.h"
  #include "qgraphicswidget_p.h"
  #include "qgraphicssceneindex_p.h"
  #include "qgraphicsscenebsptreeindex_p.h"
  #include "qgraphicsscenelinearindex_p.h"
  
  #include <QtCore/qdebug.h>
  #include <QtCore/qlist.h>
  #include <QtCore/qmath.h>
  #include <QtCore/qrect.h>
  #include <QtCore/qset.h>
  #include <QtCore/qstack.h>
  #include <QtCore/qtimer.h>
  #include <QtCore/qvarlengtharray.h>
  #include <QtCore/QMetaMethod>
  #include <QtGui/qapplication.h>
  #include <QtGui/qdesktopwidget.h>
  #include <QtGui/qevent.h>
  #include <QtGui/qgraphicslayout.h>
  #include <QtGui/qgraphicsproxywidget.h>
  #include <QtGui/qgraphicswidget.h>
  #include <QtGui/qmatrix.h>
  #include <QtGui/qpaintengine.h>
  #include <QtGui/qpainter.h>
  #include <QtGui/qpixmapcache.h>
  #include <QtGui/qpolygon.h>
  #include <QtGui/qstyleoption.h>
  #include <QtGui/qtooltip.h>
  #include <QtGui/qtransform.h>
  #include <QtGui/qinputcontext.h>
  #include <QtGui/qgraphicseffect.h>
  #ifndef QT_NO_ACCESSIBILITY
  # include <QtGui/qaccessible.h>
  #endif
  
  #include <private/qapplication_p.h>
  #include <private/qobject_p.h>
  #ifdef Q_WS_X11
  #include <private/qt_x11_p.h>
  #endif
  #include <private/qgraphicseffect_p.h>
  #include <private/qgesturemanager_p.h>
  #include <private/qpathclipper_p.h>
  
  // #define GESTURE_DEBUG
  #ifndef GESTURE_DEBUG
  # define G_DEBUG if (0) qDebug
  #else
  # define G_DEBUG qDebug
  #endif
  
  QT_BEGIN_NAMESPACE
  
  bool qt_sendSpontaneousEvent(QObject *receiver, QEvent *event);
  
  static void _q_hoverFromMouseEvent(QGraphicsSceneHoverEvent *hover, const QGraphicsSceneMouseEvent *mouseEvent)
  {
      hover->setWidget(mouseEvent->widget());
      hover->setPos(mouseEvent->pos());
      hover->setScenePos(mouseEvent->scenePos());
      hover->setScreenPos(mouseEvent->screenPos());
      hover->setLastPos(mouseEvent->lastPos());
      hover->setLastScenePos(mouseEvent->lastScenePos());
      hover->setLastScreenPos(mouseEvent->lastScreenPos());
      hover->setModifiers(mouseEvent->modifiers());
      hover->setAccepted(mouseEvent->isAccepted());
  }
  
  /*!
      \internal
  */
  QGraphicsScenePrivate::QGraphicsScenePrivate()
      : indexMethod(QGraphicsScene::BspTreeIndex),
        index(0),
        lastItemCount(0),
        hasSceneRect(false),
        dirtyGrowingItemsBoundingRect(true),
        updateAll(false),
        calledEmitUpdated(false),
        processDirtyItemsEmitted(false),
        needSortTopLevelItems(true),
        holesInTopLevelSiblingIndex(false),
        topLevelSequentialOrdering(true),
        scenePosDescendantsUpdatePending(false),
        stickyFocus(false),
        hasFocus(false),
        lastMouseGrabberItemHasImplicitMouseGrab(false),
        allItemsIgnoreHoverEvents(true),
        allItemsUseDefaultCursor(true),
        painterStateProtection(true),
        sortCacheEnabled(false),
        allItemsIgnoreTouchEvents(true),
        selectionChanging(0),
        rectAdjust(2),
        focusItem(0),
        lastFocusItem(0),
        passiveFocusItem(0),
        tabFocusFirst(0),
        activePanel(0),
        lastActivePanel(0),
        activationRefCount(0),
        childExplicitActivation(0),
        lastMouseGrabberItem(0),
        dragDropItem(0),
        enterWidget(0),
        lastDropAction(Qt::IgnoreAction),
        style(0)
  {
  }
  
  /*!
      \internal
  */
  void QGraphicsScenePrivate::init()
  {
      Q_Q(QGraphicsScene);
  
      index = new QGraphicsSceneBspTreeIndex(q);
  
      // Keep this index so we can check for connected slots later on.
      changedSignalIndex = signalIndex("changed(QList<QRectF>)");
      processDirtyItemsIndex = q->metaObject()->indexOfSlot("_q_processDirtyItems()");
      polishItemsIndex = q->metaObject()->indexOfSlot("_q_polishItems()");
  
      qApp->d_func()->scene_list.append(q);
      q->update();
  }
  
  /*!
      \internal
  */
  QGraphicsScenePrivate *QGraphicsScenePrivate::get(QGraphicsScene *q)
  {
      return q->d_func();
  }
  
  void QGraphicsScenePrivate::_q_emitUpdated()
  {
      Q_Q(QGraphicsScene);
      calledEmitUpdated = false;
  
      if (dirtyGrowingItemsBoundingRect) {
          if (!hasSceneRect) {
              const QRectF oldGrowingItemsBoundingRect = growingItemsBoundingRect;
              growingItemsBoundingRect |= q->itemsBoundingRect();
              if (oldGrowingItemsBoundingRect != growingItemsBoundingRect)
                  emit q->sceneRectChanged(growingItemsBoundingRect);
          }
          dirtyGrowingItemsBoundingRect = false;
      }
  
      // Ensure all views are connected if anything is connected. This disables
      // the optimization that items send updates directly to the views, but it
      // needs to happen in order to keep compatibility with the behavior from
      // Qt 4.4 and backward.
      if (isSignalConnected(changedSignalIndex)) {
          for (int i = 0; i < views.size(); ++i) {
              QGraphicsView *view = views.at(i);
              if (!view->d_func()->connectedToScene) {
                  view->d_func()->connectedToScene = true;
                  q->connect(q, SIGNAL(changed(QList<QRectF>)),
                             views.at(i), SLOT(updateScene(QList<QRectF>)));
              }
          }
      } else {
          if (views.isEmpty()) {
              updateAll = false;
              return;
          }
          for (int i = 0; i < views.size(); ++i)
              views.at(i)->d_func()->processPendingUpdates();
          // It's important that we update all views before we dispatch, hence two for-loops.
          for (int i = 0; i < views.size(); ++i)
              views.at(i)->d_func()->dispatchPendingUpdateRequests();
          return;
      }
  
      // Notify the changes to anybody interested.
      QList<QRectF> oldUpdatedRects;
      oldUpdatedRects = updateAll ? (QList<QRectF>() << q->sceneRect()) : updatedRects;
      updateAll = false;
      updatedRects.clear();
      emit q->changed(oldUpdatedRects);
  }
  
  /*!
      \internal
  
      ### This function is almost identical to QGraphicsItemPrivate::addChild().
  */
  void QGraphicsScenePrivate::registerTopLevelItem(QGraphicsItem *item)
  {
      item->d_ptr->ensureSequentialSiblingIndex();
      needSortTopLevelItems = true; // ### maybe false
      item->d_ptr->siblingIndex = topLevelItems.size();
      topLevelItems.append(item);
  }
  
  /*!
      \internal
  
      ### This function is almost identical to QGraphicsItemPrivate::removeChild().
  */
  void QGraphicsScenePrivate::unregisterTopLevelItem(QGraphicsItem *item)
  {
      if (!holesInTopLevelSiblingIndex)
          holesInTopLevelSiblingIndex = item->d_ptr->siblingIndex != topLevelItems.size() - 1;
      if (topLevelSequentialOrdering && !holesInTopLevelSiblingIndex)
          topLevelItems.removeAt(item->d_ptr->siblingIndex);
      else
          topLevelItems.removeOne(item);
      // NB! Do not use topLevelItems.removeAt(item->d_ptr->siblingIndex) because
      // the item is not guaranteed to be at the index after the list is sorted
      // (see ensureSortedTopLevelItems()).
      item->d_ptr->siblingIndex = -1;
      if (topLevelSequentialOrdering)
          topLevelSequentialOrdering = !holesInTopLevelSiblingIndex;
  }
  
  /*!
      \internal
  */
  void QGraphicsScenePrivate::_q_polishItems()
  {
      if (unpolishedItems.isEmpty())
          return;
  
      const QVariant booleanTrueVariant(true);
      QGraphicsItem *item = 0;
      QGraphicsItemPrivate *itemd = 0;
      const int oldUnpolishedCount = unpolishedItems.count();
  
      for (int i = 0; i < oldUnpolishedCount; ++i) {
          item = unpolishedItems.at(i);
          if (!item)
              continue;
          itemd = item->d_ptr.data();
          itemd->pendingPolish = false;
          if (!itemd->explicitlyHidden) {
              item->itemChange(QGraphicsItem::ItemVisibleChange, booleanTrueVariant);
              item->itemChange(QGraphicsItem::ItemVisibleHasChanged, booleanTrueVariant);
          }
          if (itemd->isWidget) {
              QEvent event(QEvent::Polish);
              QApplication::sendEvent((QGraphicsWidget *)item, &event);
          }
      }
  
      if (unpolishedItems.count() == oldUnpolishedCount) {
          // No new items were added to the vector.
          unpolishedItems.clear();
      } else {
          // New items were appended; keep them and remove the old ones.
          unpolishedItems.remove(0, oldUnpolishedCount);
          unpolishedItems.squeeze();
          QMetaObject::invokeMethod(q_ptr, "_q_polishItems", Qt::QueuedConnection);
      }
  }
  
  void QGraphicsScenePrivate::_q_processDirtyItems()
  {
      processDirtyItemsEmitted = false;
  
      if (updateAll) {
          Q_ASSERT(calledEmitUpdated);
          // No need for further processing (except resetting the dirty states).
          // The growingItemsBoundingRect is updated in _q_emitUpdated.
          for (int i = 0; i < topLevelItems.size(); ++i)
              resetDirtyItem(topLevelItems.at(i), /*recursive=*/true);
          return;
      }
  
      const bool wasPendingSceneUpdate = calledEmitUpdated;
      const QRectF oldGrowingItemsBoundingRect = growingItemsBoundingRect;
  
      // Process items recursively.
      for (int i = 0; i < topLevelItems.size(); ++i)
          processDirtyItemsRecursive(topLevelItems.at(i));
  
      dirtyGrowingItemsBoundingRect = false;
      if (!hasSceneRect && oldGrowingItemsBoundingRect != growingItemsBoundingRect)
          emit q_func()->sceneRectChanged(growingItemsBoundingRect);
  
      if (wasPendingSceneUpdate)
          return;
  
      for (int i = 0; i < views.size(); ++i)
          views.at(i)->d_func()->processPendingUpdates();
  
      if (calledEmitUpdated) {
          // We did a compatibility QGraphicsScene::update in processDirtyItemsRecursive
          // and we cannot wait for the control to reach the eventloop before the
          // changed signal is emitted, so we emit it now.
          _q_emitUpdated();
      }
  
      // Immediately dispatch all pending update requests on the views.
      for (int i = 0; i < views.size(); ++i)
          views.at(i)->d_func()->dispatchPendingUpdateRequests();
  }
  
  /*!
      \internal
  */
  void QGraphicsScenePrivate::setScenePosItemEnabled(QGraphicsItem *item, bool enabled)
  {
      QGraphicsItem *p = item->d_ptr->parent;
      while (p) {
          p->d_ptr->scenePosDescendants = enabled;
          p = p->d_ptr->parent;
      }
      if (!enabled && !scenePosDescendantsUpdatePending) {
          scenePosDescendantsUpdatePending = true;
          QMetaObject::invokeMethod(q_func(), "_q_updateScenePosDescendants", Qt::QueuedConnection);
      }
  }
  
  /*!
      \internal
  */
  void QGraphicsScenePrivate::registerScenePosItem(QGraphicsItem *item)
  {
      scenePosItems.insert(item);
      setScenePosItemEnabled(item, true);
  }
  
  /*!
      \internal
  */
  void QGraphicsScenePrivate::unregisterScenePosItem(QGraphicsItem *item)
  {
      scenePosItems.remove(item);
      setScenePosItemEnabled(item, false);
  }
  
  /*!
      \internal
  */
  void QGraphicsScenePrivate::_q_updateScenePosDescendants()
  {
      foreach (QGraphicsItem *item, scenePosItems) {
          QGraphicsItem *p = item->d_ptr->parent;
          while (p) {
              p->d_ptr->scenePosDescendants = 1;
              p = p->d_ptr->parent;
          }
      }
      scenePosDescendantsUpdatePending = false;
  }
  
  /*!
      \internal
  
      Schedules an item for removal. This function leaves some stale indexes
      around in the BSP tree if called from the item's destructor; these will
      be cleaned up the next time someone triggers purgeRemovedItems().
  
      Note: This function might get called from QGraphicsItem's destructor. \a item is
      being destroyed, so we cannot call any pure virtual functions on it (such
      as boundingRect()). Also, it is unnecessary to update the item's own state
      in any way.
  */
  void QGraphicsScenePrivate::removeItemHelper(QGraphicsItem *item)
  {
      Q_Q(QGraphicsScene);
  
      // Clear focus on the item to remove any reference in the focusWidget chain.
      item->clearFocus();
  
      markDirty(item, QRectF(), /*invalidateChildren=*/false, /*force=*/false,
                /*ignoreOpacity=*/false, /*removingItemFromScene=*/true);
  
      if (item->d_ptr->inDestructor) {
          // The item is actually in its destructor, we call the special method in the index.
          index->deleteItem(item);
      } else {
          // Can potentially call item->boundingRect() (virtual function), that's why
          // we only can call this function if the item is not in its destructor.
          index->removeItem(item);
      }
  
      item->d_ptr->clearSubFocus();
  
      if (item->flags() & QGraphicsItem::ItemSendsScenePositionChanges)
          unregisterScenePosItem(item);
  
      QGraphicsScene *oldScene = item->d_func()->scene;
      item->d_func()->scene = 0;
  
      //We need to remove all children first because they might use their parent
      //attributes (e.g. sceneTransform).
      if (!item->d_ptr->inDestructor) {
          // Remove all children recursively
          for (int i = 0; i < item->d_ptr->children.size(); ++i)
              q->removeItem(item->d_ptr->children.at(i));
      }
  
      if (!item->d_ptr->inDestructor && item == tabFocusFirst) {
          QGraphicsWidget *widget = static_cast<QGraphicsWidget *>(item);
          widget->d_func()->fixFocusChainBeforeReparenting(0, oldScene, 0);
      }
  
      // Unregister focus proxy.
      item->d_ptr->resetFocusProxy();
  
      // Remove from parent, or unregister from toplevels.
      if (QGraphicsItem *parentItem = item->parentItem()) {
          if (parentItem->scene()) {
              Q_ASSERT_X(parentItem->scene() == q, "QGraphicsScene::removeItem",
                         "Parent item's scene is different from this item's scene");
              item->setParentItem(0);
          }
      } else {
          unregisterTopLevelItem(item);
      }
  
      // Reset the mouse grabber and focus item data.
      if (item == focusItem)
          focusItem = 0;
      if (item == lastFocusItem)
          lastFocusItem = 0;
      if (item == passiveFocusItem)
          passiveFocusItem = 0;
      if (item == activePanel) {
          // ### deactivate...
          activePanel = 0;
      }
      if (item == lastActivePanel)
          lastActivePanel = 0;
  
      // Cancel active touches
      {
          QMap<int, QGraphicsItem *>::iterator it = itemForTouchPointId.begin();
          while (it != itemForTouchPointId.end()) {
              if (it.value() == item) {
                  sceneCurrentTouchPoints.remove(it.key());
                  it = itemForTouchPointId.erase(it);
              } else {
                  ++it;
              }
          }
      }
  
      // Disable selectionChanged() for individual items
      ++selectionChanging;
      int oldSelectedItemsSize = selectedItems.size();
  
      // Update selected & hovered item bookkeeping
      selectedItems.remove(item);
      hoverItems.removeAll(item);
      cachedItemsUnderMouse.removeAll(item);
      if (item->d_ptr->pendingPolish) {
          const int unpolishedIndex = unpolishedItems.indexOf(item);
          if (unpolishedIndex != -1)
              unpolishedItems[unpolishedIndex] = 0;
          item->d_ptr->pendingPolish = false;
      }
      resetDirtyItem(item);
  
      //We remove all references of item from the sceneEventFilter arrays
      QMultiMap<QGraphicsItem*, QGraphicsItem*>::iterator iterator = sceneEventFilters.begin();
      while (iterator != sceneEventFilters.end()) {
          if (iterator.value() == item || iterator.key() == item)
              iterator = sceneEventFilters.erase(iterator);
          else
              ++iterator;
      }
  
      if (item->isPanel() && item->isVisible() && item->panelModality() != QGraphicsItem::NonModal)
          leaveModal(item);
  
      // Reset the mouse grabber and focus item data.
      if (mouseGrabberItems.contains(item))
          ungrabMouse(item, /* item is dying */ item->d_ptr->inDestructor);
  
      // Reset the keyboard grabber
      if (keyboardGrabberItems.contains(item))
          ungrabKeyboard(item, /* item is dying */ item->d_ptr->inDestructor);
  
      // Reset the last mouse grabber item
      if (item == lastMouseGrabberItem)
          lastMouseGrabberItem = 0;
  
      // Reset the current drop item
      if (item == dragDropItem)
          dragDropItem = 0;
  
      // Reenable selectionChanged() for individual items
      --selectionChanging;
      if (!selectionChanging && selectedItems.size() != oldSelectedItemsSize)
          emit q->selectionChanged();
  
  #ifndef QT_NO_GESTURES
      QHash<QGesture *, QGraphicsObject *>::iterator it;
      for (it = gestureTargets.begin(); it != gestureTargets.end();) {
          if (it.value() == item)
              it = gestureTargets.erase(it);
          else
              ++it;
      }
  
      QGraphicsObject *dummy = static_cast<QGraphicsObject *>(item);
      cachedTargetItems.removeOne(dummy);
      cachedItemGestures.remove(dummy);
      cachedAlreadyDeliveredGestures.remove(dummy);
  
      foreach (Qt::GestureType gesture, item->d_ptr->gestureContext.keys())
          ungrabGesture(item, gesture);
  #endif // QT_NO_GESTURES
  }
  
  /*!
      \internal
  */
  void QGraphicsScenePrivate::setActivePanelHelper(QGraphicsItem *item, bool duringActivationEvent)
  {
      Q_Q(QGraphicsScene);
      if (item && item->scene() != q) {
          qWarning("QGraphicsScene::setActivePanel: item %p must be part of this scene",
                   item);
          return;
      }
  
      // Ensure the scene has focus when we change panel activation.
      q->setFocus(Qt::ActiveWindowFocusReason);
  
      // Find the item's panel.
      QGraphicsItem *panel = item ? item->panel() : 0;
      lastActivePanel = panel ? activePanel : 0;
      if (panel == activePanel || (!q->isActive() && !duringActivationEvent))
          return;
  
      // Deactivate the last active panel.
      if (activePanel) {
          if (QGraphicsItem *fi = activePanel->focusItem()) {
              // Remove focus from the current focus item.
              if (fi == q->focusItem())
                  q->setFocusItem(0, Qt::ActiveWindowFocusReason);
          }
  
          QEvent event(QEvent::WindowDeactivate);
          q->sendEvent(activePanel, &event);
      } else if (panel && !duringActivationEvent) {
          // Deactivate the scene if changing activation to a panel.
          QEvent event(QEvent::WindowDeactivate);
          foreach (QGraphicsItem *item, q->items()) {
              if (item->isVisible() && !item->isPanel() && !item->parentItem())
                  q->sendEvent(item, &event);
          }
      }
  
      // Update activate state.
      activePanel = panel;
      QEvent event(QEvent::ActivationChange);
      QApplication::sendEvent(q, &event);
  
      // Activate
      if (panel) {
          QEvent event(QEvent::WindowActivate);
          q->sendEvent(panel, &event);
  
          // Set focus on the panel's focus item.
          if (QGraphicsItem *focusItem = panel->focusItem())
              focusItem->setFocus(Qt::ActiveWindowFocusReason);
      } else if (q->isActive()) {
          // Activate the scene
          QEvent event(QEvent::WindowActivate);
          foreach (QGraphicsItem *item, q->items()) {
              if (item->isVisible() && !item->isPanel() && !item->parentItem())
                  q->sendEvent(item, &event);
          }
      }
  }
  
  /*!
      \internal
  */
  void QGraphicsScenePrivate::setFocusItemHelper(QGraphicsItem *item,
                                                 Qt::FocusReason focusReason)
  {
      Q_Q(QGraphicsScene);
      if (item == focusItem)
          return;
  
      // Clear focus if asked to set focus on something that can't
      // accept input focus.
      if (item && (!(item->flags() & QGraphicsItem::ItemIsFocusable)
                   || !item->isVisible() || !item->isEnabled())) {
          item = 0;
      }
  
      // Set focus on the scene if an item requests focus.
      if (item) {
          q->setFocus(focusReason);
          if (item == focusItem)
              return;
      }
  
      if (focusItem) {
          lastFocusItem = focusItem;
  
  #ifndef QT_NO_IM
          if (lastFocusItem
              && (lastFocusItem->flags() & QGraphicsItem::ItemAcceptsInputMethod)) {
              // Close any external input method panel. This happens
              // automatically by removing WA_InputMethodEnabled on
              // the views, but if we are changing focus, we have to
              // do it ourselves.
              for (int i = 0; i < views.size(); ++i)
                  if (views.at(i)->inputContext())
                      views.at(i)->inputContext()->reset();
          }
  
          focusItem = 0;
          QFocusEvent event(QEvent::FocusOut, focusReason);
          sendEvent(lastFocusItem, &event);
  #endif //QT_NO_IM
      }
  
      // This handles the case that the item has been removed from the
      // scene in response to the FocusOut event.
      if (item && item->scene() != q)
          item = 0;
  
      if (item)
          focusItem = item;
      updateInputMethodSensitivityInViews();
  
  #ifndef QT_NO_ACCESSIBILITY
      if (focusItem) {
          if (QGraphicsObject *focusObj = focusItem->toGraphicsObject()) {
              QAccessible::updateAccessibility(focusObj, 0, QAccessible::Focus);
          }
      }
  #endif
      if (item) {
          QFocusEvent event(QEvent::FocusIn, focusReason);
          sendEvent(item, &event);
      }
  }
  
  /*!
      \internal
  */
  void QGraphicsScenePrivate::addPopup(QGraphicsWidget *widget)
  {
      Q_ASSERT(widget);
      Q_ASSERT(!popupWidgets.contains(widget));
      popupWidgets << widget;
      if (QGraphicsWidget *focusWidget = widget->focusWidget()) {
          focusWidget->setFocus(Qt::PopupFocusReason);
      } else {
          grabKeyboard((QGraphicsItem *)widget);
          if (focusItem && popupWidgets.size() == 1) {
              QFocusEvent event(QEvent::FocusOut, Qt::PopupFocusReason);
              sendEvent(focusItem, &event);
          }
      }
      grabMouse((QGraphicsItem *)widget);
  }
  
  /*!
      \internal
  
      Remove \a widget from the popup list. Important notes:
  
      \a widget is guaranteed to be in the list of popups, but it might not be
      the last entry; you can hide any item in the pop list before the others,
      and this must cause all later mouse grabbers to lose the grab.
  */
  void QGraphicsScenePrivate::removePopup(QGraphicsWidget *widget, bool itemIsDying)
  {
      Q_ASSERT(widget);
      int index = popupWidgets.indexOf(widget);
      Q_ASSERT(index != -1);
  
      for (int i = popupWidgets.size() - 1; i >= index; --i) {
          QGraphicsWidget *widget = popupWidgets.takeLast();
          ungrabMouse(widget, itemIsDying);
          if (focusItem && popupWidgets.isEmpty()) {
              QFocusEvent event(QEvent::FocusIn, Qt::PopupFocusReason);
              sendEvent(focusItem, &event);
          } else if (keyboardGrabberItems.contains(static_cast<QGraphicsItem *>(widget))) {
              ungrabKeyboard(static_cast<QGraphicsItem *>(widget), itemIsDying);
          }
          if (!itemIsDying && widget->isVisible()) {
              widget->QGraphicsItem::d_ptr->setVisibleHelper(false, /* explicit = */ false);
          }
      }
  }
  
  /*!
      \internal
  */
  void QGraphicsScenePrivate::grabMouse(QGraphicsItem *item, bool implicit)
  {
      // Append to list of mouse grabber items, and send a mouse grab event.
      if (mouseGrabberItems.contains(item)) {
          if (mouseGrabberItems.last() == item) {
              Q_ASSERT(!implicit);
              if (!lastMouseGrabberItemHasImplicitMouseGrab) {
                  qWarning("QGraphicsItem::grabMouse: already a mouse grabber");
              } else {
                  // Upgrade to an explicit mouse grab
                  lastMouseGrabberItemHasImplicitMouseGrab = false;
              }
          } else {
              qWarning("QGraphicsItem::grabMouse: already blocked by mouse grabber: %p",
                       mouseGrabberItems.last());
          }
          return;
      }
  
      // Send ungrab event to the last grabber.
      if (!mouseGrabberItems.isEmpty()) {
          QGraphicsItem *last = mouseGrabberItems.last();
          if (lastMouseGrabberItemHasImplicitMouseGrab) {
              // Implicit mouse grab is immediately lost.
              last->ungrabMouse();
          } else {
              // Just send ungrab event to current grabber.
              QEvent ungrabEvent(QEvent::UngrabMouse);
              sendEvent(last, &ungrabEvent);
          }
      }
  
      mouseGrabberItems << item;
      lastMouseGrabberItemHasImplicitMouseGrab = implicit;
  
      // Send grab event to current grabber.
      QEvent grabEvent(QEvent::GrabMouse);
      sendEvent(item, &grabEvent);
  }
  
  /*!
      \internal
  */
  void QGraphicsScenePrivate::ungrabMouse(QGraphicsItem *item, bool itemIsDying)
  {
      int index = mouseGrabberItems.indexOf(item);
      if (index == -1) {
          qWarning("QGraphicsItem::ungrabMouse: not a mouse grabber");
          return;
      }
  
      if (item != mouseGrabberItems.last()) {
          // Recursively ungrab the next mouse grabber until we reach this item
          // to ensure state consistency.
          ungrabMouse(mouseGrabberItems.at(index + 1), itemIsDying);
      }
      if (!popupWidgets.isEmpty() && item == popupWidgets.last()) {
          // If the item is a popup, go via removePopup to ensure state
          // consistency and that it gets hidden correctly - beware that
          // removePopup() reenters this function to continue removing the grab.
          removePopup((QGraphicsWidget *)item, itemIsDying);
          return;
      }
  
      // Send notification about mouse ungrab.
      if (!itemIsDying) {
          QEvent event(QEvent::UngrabMouse);
          sendEvent(item, &event);
      }
  
      // Remove the item from the list of grabbers. Whenever this happens, we
      // reset the implicitGrab (there can be only ever be one implicit grabber
      // in a scene, and it is always the latest grabber; if the implicit grab
      // is lost, it is not automatically regained.
      mouseGrabberItems.takeLast();
      lastMouseGrabberItemHasImplicitMouseGrab = false;
  
      // Send notification about mouse regrab. ### It's unfortunate that all the
      // items get a GrabMouse event, but this is a rare case with a simple
      // implementation and it does ensure a consistent state.
      if (!itemIsDying && !mouseGrabberItems.isEmpty()) {
          QGraphicsItem *last = mouseGrabberItems.last();
          QEvent event(QEvent::GrabMouse);
          sendEvent(last, &event);
      }
  }
  
  /*!
      \internal
  */
  void QGraphicsScenePrivate::clearMouseGrabber()
  {
      if (!mouseGrabberItems.isEmpty())
          mouseGrabberItems.first()->ungrabMouse();
      lastMouseGrabberItem = 0;
  }
  
  /*!
      \internal
  */
  void QGraphicsScenePrivate::grabKeyboard(QGraphicsItem *item)
  {
      if (keyboardGrabberItems.contains(item)) {
          if (keyboardGrabberItems.last() == item)
              qWarning("QGraphicsItem::grabKeyboard: already a keyboard grabber");
          else
              qWarning("QGraphicsItem::grabKeyboard: already blocked by keyboard grabber: %p",
                       keyboardGrabberItems.last());
          return;
      }
  
      // Send ungrab event to the last grabber.
      if (!keyboardGrabberItems.isEmpty()) {
          // Just send ungrab event to current grabber.
          QEvent ungrabEvent(QEvent::UngrabKeyboard);
          sendEvent(keyboardGrabberItems.last(), &ungrabEvent);
      }
  
      keyboardGrabberItems << item;
  
      // Send grab event to current grabber.
      QEvent grabEvent(QEvent::GrabKeyboard);
      sendEvent(item, &grabEvent);
  }
  
  /*!
      \internal
  */
  void QGraphicsScenePrivate::ungrabKeyboard(QGraphicsItem *item, bool itemIsDying)
  {
      int index = keyboardGrabberItems.lastIndexOf(item);
      if (index == -1) {
          qWarning("QGraphicsItem::ungrabKeyboard: not a keyboard grabber");
          return;
      }
      if (item != keyboardGrabberItems.last()) {
          // Recursively ungrab the topmost keyboard grabber until we reach this
          // item to ensure state consistency.
          ungrabKeyboard(keyboardGrabberItems.at(index + 1), itemIsDying);
      }
  
      // Send notification about keyboard ungrab.
      if (!itemIsDying) {
          QEvent event(QEvent::UngrabKeyboard);
          sendEvent(item, &event);
      }
  
      // Remove the item from the list of grabbers.
      keyboardGrabberItems.takeLast();
  
      // Send notification about mouse regrab.
      if (!itemIsDying && !keyboardGrabberItems.isEmpty()) {
          QGraphicsItem *last = keyboardGrabberItems.last();
          QEvent event(QEvent::GrabKeyboard);
          sendEvent(last, &event);
      }
  }
  
  /*!
      \internal
  */
  void QGraphicsScenePrivate::clearKeyboardGrabber()
  {
      if (!keyboardGrabberItems.isEmpty())
          ungrabKeyboard(keyboardGrabberItems.first());
  }
  
  void QGraphicsScenePrivate::enableMouseTrackingOnViews()
  {
      foreach (QGraphicsView *view, views)
          view->viewport()->setMouseTracking(true);
  }
  
  /*!
      Returns all items for the screen position in \a event.
  */
  QList<QGraphicsItem *> QGraphicsScenePrivate::itemsAtPosition(const QPoint &screenPos,
                                                                const QPointF &scenePos,
                                                                QWidget *widget) const
  {
      Q_Q(const QGraphicsScene);
      QGraphicsView *view = widget ? qobject_cast<QGraphicsView *>(widget->parentWidget()) : 0;
      if (!view)
          return q->items(scenePos, Qt::IntersectsItemShape, Qt::DescendingOrder, QTransform());
  
      const QRectF pointRect(QPointF(widget->mapFromGlobal(screenPos)), QSizeF(1, 1));
      if (!view->isTransformed())
          return q->items(pointRect, Qt::IntersectsItemShape, Qt::DescendingOrder);
  
      const QTransform viewTransform = view->viewportTransform();
      if (viewTransform.type() <= QTransform::TxScale) {
          return q->items(viewTransform.inverted().mapRect(pointRect), Qt::IntersectsItemShape,
                          Qt::DescendingOrder, viewTransform);
      }
      return q->items(viewTransform.inverted().map(pointRect), Qt::IntersectsItemShape,
                      Qt::DescendingOrder, viewTransform);
  }
  
  /*!
      \internal
  */
  void QGraphicsScenePrivate::storeMouseButtonsForMouseGrabber(QGraphicsSceneMouseEvent *event)
  {
      for (int i = 0x1; i <= 0x10; i <<= 1) {
          if (event->buttons() & i) {
              mouseGrabberButtonDownPos.insert(Qt::MouseButton(i),
                                               mouseGrabberItems.last()->d_ptr->genericMapFromScene(event->scenePos(),
                                                                                                    event->widget()));
              mouseGrabberButtonDownScenePos.insert(Qt::MouseButton(i), event->scenePos());
              mouseGrabberButtonDownScreenPos.insert(Qt::MouseButton(i), event->screenPos());
          }
      }
  }
  
  /*!
      \internal
  */
  void QGraphicsScenePrivate::installSceneEventFilter(QGraphicsItem *watched, QGraphicsItem *filter)
  {
      sceneEventFilters.insert(watched, filter);
  }
  
  /*!
      \internal
  */
  void QGraphicsScenePrivate::removeSceneEventFilter(QGraphicsItem *watched, QGraphicsItem *filter)
  {
      if (!sceneEventFilters.contains(watched))
          return;
  
      QMultiMap<QGraphicsItem *, QGraphicsItem *>::Iterator it = sceneEventFilters.lowerBound(watched);
      QMultiMap<QGraphicsItem *, QGraphicsItem *>::Iterator end = sceneEventFilters.upperBound(watched);
      do {
          if (it.value() == filter)
              it = sceneEventFilters.erase(it);
          else
              ++it;
      } while (it != end);
  }
  
  /*!
    \internal
  */
  bool QGraphicsScenePrivate::filterDescendantEvent(QGraphicsItem *item, QEvent *event)
  {
      if (item && (item->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorFiltersChildEvents)) {
          QGraphicsItem *parent = item->parentItem();
          while (parent) {
              if (parent->d_ptr->filtersDescendantEvents && parent->sceneEventFilter(item, event))
                  return true;
              if (!(parent->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorFiltersChildEvents))
                  return false;
              parent = parent->parentItem();
          }
      }
      return false;
  }
  
  /*!
      \internal
  */
  bool QGraphicsScenePrivate::filterEvent(QGraphicsItem *item, QEvent *event)
  {
      if (item && !sceneEventFilters.contains(item))
          return false;
  
      QMultiMap<QGraphicsItem *, QGraphicsItem *>::Iterator it = sceneEventFilters.lowerBound(item);
      QMultiMap<QGraphicsItem *, QGraphicsItem *>::Iterator end = sceneEventFilters.upperBound(item);
      while (it != end) {
          // ### The filterer and filteree might both be deleted.
          if (it.value()->sceneEventFilter(it.key(), event))
              return true;
          ++it;
      }
      return false;
  }
  
  /*!
      \internal
  
      This is the final dispatch point for any events from the scene to the
      item. It filters the event first - if the filter returns true, the event
      is considered to have been eaten by the filter, and is therefore stopped
      (the default filter returns false). Then/otherwise, if the item is
      enabled, the event is sent; otherwise it is stopped.
  */
  bool QGraphicsScenePrivate::sendEvent(QGraphicsItem *item, QEvent *event)
  {
      if (QGraphicsObject *object = item->toGraphicsObject()) {
  #ifndef QT_NO_GESTURES
          QGestureManager *gestureManager = QApplicationPrivate::instance()->gestureManager;
          if (gestureManager) {
              if (gestureManager->filterEvent(object, event))
                  return true;
          }
  #endif // QT_NO_GESTURES
      }
  
      if (filterEvent(item, event))
          return false;
      if (filterDescendantEvent(item, event))
          return false;
      if (!item || !item->isEnabled())
          return false;
      if (QGraphicsObject *o = item->toGraphicsObject()) {
          bool spont = event->spontaneous();
          if (spont ? qt_sendSpontaneousEvent(o, event) : QApplication::sendEvent(o, event))
              return true;
          event->spont = spont;
      }
      return item->sceneEvent(event);
  }
  
  /*!
      \internal
  */
  void QGraphicsScenePrivate::cloneDragDropEvent(QGraphicsSceneDragDropEvent *dest,
                                                 QGraphicsSceneDragDropEvent *source)
  {
      dest->setWidget(source->widget());
      dest->setPos(source->pos());
      dest->setScenePos(source->scenePos());
      dest->setScreenPos(source->screenPos());
      dest->setButtons(source->buttons());
      dest->setModifiers(source->modifiers());
      dest->setPossibleActions(source->possibleActions());
      dest->setProposedAction(source->proposedAction());
      dest->setDropAction(source->dropAction());
      dest->setSource(source->source());
      dest->setMimeData(source->mimeData());
  }
  
  /*!
      \internal
  */
  void QGraphicsScenePrivate::sendDragDropEvent(QGraphicsItem *item,
                                                QGraphicsSceneDragDropEvent *dragDropEvent)
  {
      dragDropEvent->setPos(item->d_ptr->genericMapFromScene(dragDropEvent->scenePos(), dragDropEvent->widget()));
      sendEvent(item, dragDropEvent);
  }
  
  /*!
      \internal
  */
  void QGraphicsScenePrivate::sendHoverEvent(QEvent::Type type, QGraphicsItem *item,
                                             QGraphicsSceneHoverEvent *hoverEvent)
  {
      QGraphicsSceneHoverEvent event(type);
      event.setWidget(hoverEvent->widget());
      event.setPos(item->d_ptr->genericMapFromScene(hoverEvent->scenePos(), hoverEvent->widget()));
      event.setScenePos(hoverEvent->scenePos());
      event.setScreenPos(hoverEvent->screenPos());
      event.setLastPos(item->d_ptr->genericMapFromScene(hoverEvent->lastScenePos(), hoverEvent->widget()));
      event.setLastScenePos(hoverEvent->lastScenePos());
      event.setLastScreenPos(hoverEvent->lastScreenPos());
      event.setModifiers(hoverEvent->modifiers());
      sendEvent(item, &event);
  }
  
  /*!
      \internal
  */
  void QGraphicsScenePrivate::sendMouseEvent(QGraphicsSceneMouseEvent *mouseEvent)
  {
      if (mouseEvent->button() == 0 && mouseEvent->buttons() == 0 && lastMouseGrabberItemHasImplicitMouseGrab) {
          // ### This is a temporary fix for until we get proper mouse
          // grab events.
          clearMouseGrabber();
          return;
      }
  
      QGraphicsItem *item = mouseGrabberItems.last();
      if (item->isBlockedByModalPanel())
          return;
  
      for (int i = 0x1; i <= 0x10; i <<= 1) {
          Qt::MouseButton button = Qt::MouseButton(i);
          mouseEvent->setButtonDownPos(button, mouseGrabberButtonDownPos.value(button, item->d_ptr->genericMapFromScene(mouseEvent->scenePos(), mouseEvent->widget())));
          mouseEvent->setButtonDownScenePos(button, mouseGrabberButtonDownScenePos.value(button, mouseEvent->scenePos()));
          mouseEvent->setButtonDownScreenPos(button, mouseGrabberButtonDownScreenPos.value(button, mouseEvent->screenPos()));
      }
      mouseEvent->setPos(item->d_ptr->genericMapFromScene(mouseEvent->scenePos(), mouseEvent->widget()));
      mouseEvent->setLastPos(item->d_ptr->genericMapFromScene(mouseEvent->lastScenePos(), mouseEvent->widget()));
      sendEvent(item, mouseEvent);
  }
  
  /*!
      \internal
  */
  void QGraphicsScenePrivate::mousePressEventHandler(QGraphicsSceneMouseEvent *mouseEvent)
  {
      Q_Q(QGraphicsScene);
  
      // Ignore by default, unless we find a mouse grabber that accepts it.
      mouseEvent->ignore();
  
      // Deliver to any existing mouse grabber.
      if (!mouseGrabberItems.isEmpty()) {
          if (mouseGrabberItems.last()->isBlockedByModalPanel())
              return;
          // The event is ignored by default, but we disregard the event's
          // accepted state after delivery; the mouse is grabbed, after all.
          sendMouseEvent(mouseEvent);
          return;
      }
  
      // Start by determining the number of items at the current position.
      // Reuse value from earlier calculations if possible.
      if (cachedItemsUnderMouse.isEmpty()) {
          cachedItemsUnderMouse = itemsAtPosition(mouseEvent->screenPos(),
                                                  mouseEvent->scenePos(),
                                                  mouseEvent->widget());
      }
  
      // Update window activation.
      QGraphicsItem *topItem = cachedItemsUnderMouse.value(0);
      QGraphicsWidget *newActiveWindow = topItem ? topItem->window() : 0;
      if (newActiveWindow && newActiveWindow->isBlockedByModalPanel(&topItem)) {
          // pass activation to the blocking modal window
          newActiveWindow = topItem ? topItem->window() : 0;
      }
  
      if (newActiveWindow != q->activeWindow())
          q->setActiveWindow(newActiveWindow);
  
      // Set focus on the topmost enabled item that can take focus.
      bool setFocus = false;
  
      foreach (QGraphicsItem *item, cachedItemsUnderMouse) {
          if (item->isBlockedByModalPanel()
              || (item->d_ptr->flags & QGraphicsItem::ItemStopsFocusHandling)) {
              // Make sure we don't clear focus.
              setFocus = true;
              break;
          }
          if (item->isEnabled() && ((item->flags() & QGraphicsItem::ItemIsFocusable))) {
              if (!item->isWidget() || ((QGraphicsWidget *)item)->focusPolicy() & Qt::ClickFocus) {
                  setFocus = true;
                  if (item != q->focusItem() && item->d_ptr->mouseSetsFocus)
                      q->setFocusItem(item, Qt::MouseFocusReason);
                  break;
              }
          }
          if (item->isPanel())
              break;
          if (item->d_ptr->flags & QGraphicsItem::ItemStopsClickFocusPropagation)
              break;
      }
  
      // Check for scene modality.
      bool sceneModality = false;
      for (int i = 0; i < modalPanels.size(); ++i) {
          if (modalPanels.at(i)->panelModality() == QGraphicsItem::SceneModal) {
              sceneModality = true;
              break;
          }
      }
  
      // If nobody could take focus, clear it.
      if (!stickyFocus && !setFocus && !sceneModality)
          q->setFocusItem(0, Qt::MouseFocusReason);
  
      // Any item will do.
      if (sceneModality && cachedItemsUnderMouse.isEmpty())
          cachedItemsUnderMouse << modalPanels.first();
  
      // Find a mouse grabber by sending mouse press events to all mouse grabber
      // candidates one at a time, until the event is accepted. It's accepted by
      // default, so the receiver has to explicitly ignore it for it to pass
      // through.
      foreach (QGraphicsItem *item, cachedItemsUnderMouse) {
          if (!(item->acceptedMouseButtons() & mouseEvent->button())) {
              // Skip items that don't accept the event's mouse button.
              continue;
          }
  
          // Check if this item is blocked by a modal panel and deliver the mouse event to the
          // blocking panel instead of this item if blocked.
          (void) item->isBlockedByModalPanel(&item);
  
          grabMouse(item, /* implicit = */ true);
          mouseEvent->accept();
  
          // check if the item we are sending to are disabled (before we send the event)
          bool disabled = !item->isEnabled();
          bool isPanel = item->isPanel();
          if (mouseEvent->type() == QEvent::GraphicsSceneMouseDoubleClick
              && item != lastMouseGrabberItem && lastMouseGrabberItem) {
              // If this item is different from the item that received the last
              // mouse event, and mouseEvent is a doubleclick event, then the
              // event is converted to a press. Known limitation:
              // Triple-clicking will not generate a doubleclick, though.
              QGraphicsSceneMouseEvent mousePress(QEvent::GraphicsSceneMousePress);
              mousePress.spont = mouseEvent->spont;
              mousePress.accept();
              mousePress.setButton(mouseEvent->button());
              mousePress.setButtons(mouseEvent->buttons());
              mousePress.setScreenPos(mouseEvent->screenPos());
              mousePress.setScenePos(mouseEvent->scenePos());
              mousePress.setModifiers(mouseEvent->modifiers());
              mousePress.setWidget(mouseEvent->widget());
              mousePress.setButtonDownPos(mouseEvent->button(),
                                          mouseEvent->buttonDownPos(mouseEvent->button()));
              mousePress.setButtonDownScenePos(mouseEvent->button(),
                                               mouseEvent->buttonDownScenePos(mouseEvent->button()));
              mousePress.setButtonDownScreenPos(mouseEvent->button(),
                                                mouseEvent->buttonDownScreenPos(mouseEvent->button()));
              sendMouseEvent(&mousePress);
              mouseEvent->setAccepted(mousePress.isAccepted());
          } else {
              sendMouseEvent(mouseEvent);
          }
  
          bool dontSendUngrabEvents = mouseGrabberItems.isEmpty() || mouseGrabberItems.last() != item;
          if (disabled) {
              ungrabMouse(item, /* itemIsDying = */ dontSendUngrabEvents);
              break;
          }
          if (mouseEvent->isAccepted()) {
              if (!mouseGrabberItems.isEmpty())
                  storeMouseButtonsForMouseGrabber(mouseEvent);
              lastMouseGrabberItem = item;
              return;
          }
          ungrabMouse(item, /* itemIsDying = */ dontSendUngrabEvents);
  
          // Don't propagate through panels.
          if (isPanel)
              break;
      }
  
      // Is the event still ignored? Then the mouse press goes to the scene.
      // Reset the mouse grabber, clear the selection, clear focus, and leave
      // the event ignored so that it can propagate through the originating
      // view.
      if (!mouseEvent->isAccepted()) {
          clearMouseGrabber();
  
          QGraphicsView *view = mouseEvent->widget() ? qobject_cast<QGraphicsView *>(mouseEvent->widget()->parentWidget()) : 0;
          bool dontClearSelection = view && view->dragMode() == QGraphicsView::ScrollHandDrag;
          if (!dontClearSelection) {
              // Clear the selection if the originating view isn't in scroll
              // hand drag mode. The view will clear the selection if no drag
              // happened.
              q->clearSelection();
          }
      }
  }
  
  /*!
      \internal
  
      Ensures that the list of toplevels is sorted by insertion order, and that
      the siblingIndexes are packed (no gaps), and start at 0.
  
      ### This function is almost identical to
      QGraphicsItemPrivate::ensureSequentialSiblingIndex().
  */
  void QGraphicsScenePrivate::ensureSequentialTopLevelSiblingIndexes()
  {
      if (!topLevelSequentialOrdering) {
          qSort(topLevelItems.begin(), topLevelItems.end(), QGraphicsItemPrivate::insertionOrder);
          topLevelSequentialOrdering = true;
          needSortTopLevelItems = 1;
      }
      if (holesInTopLevelSiblingIndex) {
          holesInTopLevelSiblingIndex = 0;
          for (int i = 0; i < topLevelItems.size(); ++i)
              topLevelItems[i]->d_ptr->siblingIndex = i;
      }
  }
  
  /*!
      \internal
  
      Set the font and propagate the changes if the font is different from the
      current font.
  */
  void QGraphicsScenePrivate::setFont_helper(const QFont &font)
  {
      if (this->font == font && this->font.resolve() == font.resolve())
          return;
      updateFont(font);
  }
  
  /*!
      \internal
  
      Resolve the scene's font against the application font, and propagate the
      changes too all items in the scene.
  */
  void QGraphicsScenePrivate::resolveFont()
  {
      QFont naturalFont = QApplication::font();
      naturalFont.resolve(0);
      QFont resolvedFont = font.resolve(naturalFont);
      updateFont(resolvedFont);
  }
  
  /*!
      \internal
  
      Update the font, and whether or not it has changed, reresolve all fonts in
      the scene.
  */
  void QGraphicsScenePrivate::updateFont(const QFont &font)
  {
      Q_Q(QGraphicsScene);
  
      // Update local font setting.
      this->font = font;
  
      // Resolve the fonts of all top-level widget items, or widget items
      // whose parent is not a widget.
      foreach (QGraphicsItem *item, q->items()) {
          if (!item->parentItem()) {
              // Resolvefont for an item is a noop operation, but
              // every item can be a widget, or can have a widget
              // childre.
              item->d_ptr->resolveFont(font.resolve());
          }
      }
  
      // Send the scene a FontChange event.
      QEvent event(QEvent::FontChange);
      QApplication::sendEvent(q, &event);
  }
  
  /*!
      \internal
  
      Set the palette and propagate the changes if the palette is different from
      the current palette.
  */
  void QGraphicsScenePrivate::setPalette_helper(const QPalette &palette)
  {
      if (this->palette == palette && this->palette.resolve() == palette.resolve())
          return;
      updatePalette(palette);
  }
  
  /*!
      \internal
  
      Resolve the scene's palette against the application palette, and propagate
      the changes too all items in the scene.
  */
  void QGraphicsScenePrivate::resolvePalette()
  {
      QPalette naturalPalette = QApplication::palette();
      naturalPalette.resolve(0);
      QPalette resolvedPalette = palette.resolve(naturalPalette);
      updatePalette(resolvedPalette);
  }
  
  /*!
      \internal
  
      Update the palette, and whether or not it has changed, reresolve all
      palettes in the scene.
  */
  void QGraphicsScenePrivate::updatePalette(const QPalette &palette)
  {
      Q_Q(QGraphicsScene);
  
      // Update local palette setting.
      this->palette = palette;
  
      // Resolve the palettes of all top-level widget items, or widget items
      // whose parent is not a widget.
      foreach (QGraphicsItem *item, q->items()) {
          if (!item->parentItem()) {
              // Resolvefont for an item is a noop operation, but
              // every item can be a widget, or can have a widget
              // childre.
              item->d_ptr->resolvePalette(palette.resolve());
          }
      }
  
      // Send the scene a PaletteChange event.
      QEvent event(QEvent::PaletteChange);
      QApplication::sendEvent(q, &event);
  }
  
  /*!
      Constructs a QGraphicsScene object. The \a parent parameter is
      passed to QObject's constructor.
  */
  QGraphicsScene::QGraphicsScene(QObject *parent)
      : QObject(*new QGraphicsScenePrivate, parent)
  {
      d_func()->init();
  }
  
  /*!
      Constructs a QGraphicsScene object, using \a sceneRect for its
      scene rectangle. The \a parent parameter is passed to QObject's
      constructor.
  
      \sa sceneRect
  */
  QGraphicsScene::QGraphicsScene(const QRectF &sceneRect, QObject *parent)
      : QObject(*new QGraphicsScenePrivate, parent)
  {
      d_func()->init();
      setSceneRect(sceneRect);
  }
  
  /*!
      Constructs a QGraphicsScene object, using the rectangle specified
      by (\a x, \a y), and the given \a width and \a height for its
      scene rectangle. The \a parent parameter is passed to QObject's
      constructor.
  
      \sa sceneRect
  */
  QGraphicsScene::QGraphicsScene(qreal x, qreal y, qreal width, qreal height, QObject *parent)
      : QObject(*new QGraphicsScenePrivate, parent)
  {
      d_func()->init();
      setSceneRect(x, y, width, height);
  }
  
  /*!
    Removes and deletes all items from the scene object
    before destroying the scene object. The scene object
    is removed from the application's global scene list,
    and it is removed from all associated views.
  */
  QGraphicsScene::~QGraphicsScene()
  {
      Q_D(QGraphicsScene);
  
      // Remove this scene from qApp's global scene list.
      if (!QApplicationPrivate::is_app_closing)
          qApp->d_func()->scene_list.removeAll(this);
  
      clear();
  
      // Remove this scene from all associated views.
      for (int j = 0; j < d->views.size(); ++j)
          d->views.at(j)->setScene(0);
  }
  
  /*!
      \property QGraphicsScene::sceneRect
      \brief the scene rectangle; the bounding rectangle of the scene
  
      The scene rectangle defines the extent of the scene. It is
      primarily used by QGraphicsView to determine the view's default
      scrollable area, and by QGraphicsScene to manage item indexing.
  
      If unset, or if set to a null QRectF, sceneRect() will return the largest
      bounding rect of all items on the scene since the scene was created (i.e.,
      a rectangle that grows when items are added to or moved in the scene, but
      never shrinks).
  
      \sa width(), height(), QGraphicsView::sceneRect
  */
  QRectF QGraphicsScene::sceneRect() const
  {
      Q_D(const QGraphicsScene);
      if (d->hasSceneRect)
          return d->sceneRect;
  
      if (d->dirtyGrowingItemsBoundingRect) {
          // Lazily update the growing items bounding rect
          QGraphicsScenePrivate *thatd = const_cast<QGraphicsScenePrivate *>(d);
          QRectF oldGrowingBoundingRect = thatd->growingItemsBoundingRect;
          thatd->growingItemsBoundingRect |= itemsBoundingRect();
          thatd->dirtyGrowingItemsBoundingRect = false;
          if (oldGrowingBoundingRect != thatd->growingItemsBoundingRect)
              emit const_cast<QGraphicsScene *>(this)->sceneRectChanged(thatd->growingItemsBoundingRect);
      }
      return d->growingItemsBoundingRect;
  }
  void QGraphicsScene::setSceneRect(const QRectF &rect)
  {
      Q_D(QGraphicsScene);
      if (rect != d->sceneRect) {
          d->hasSceneRect = !rect.isNull();
          d->sceneRect = rect;
          emit sceneRectChanged(d->hasSceneRect ? rect : d->growingItemsBoundingRect);
      }
  }
  
  /*!
       \fn qreal QGraphicsScene::width() const
  
       This convenience function is equivalent to calling sceneRect().width().
  
       \sa height()
  */
  
  /*!
       \fn qreal QGraphicsScene::height() const
  
       This convenience function is equivalent to calling \c sceneRect().height().
  
       \sa width()
  */
  
  /*!
      Renders the \a source rect from scene into \a target, using \a painter. This
      function is useful for capturing the contents of the scene onto a paint
      device, such as a QImage (e.g., to take a screenshot), or for printing
      with QPrinter. For example:
  
      \snippet doc/src/snippets/code/src_gui_graphicsview_qgraphicsscene.cpp 1
  
      If \a source is a null rect, this function will use sceneRect() to
      determine what to render. If \a target is a null rect, the dimensions of \a
      painter's paint device will be used.
  
      The source rect contents will be transformed according to \a
      aspectRatioMode to fit into the target rect. By default, the aspect ratio
      is kept, and \a source is scaled to fit in \a target.
  
      \sa QGraphicsView::render()
  */
  void QGraphicsScene::render(QPainter *painter, const QRectF &target, const QRectF &source,
                              Qt::AspectRatioMode aspectRatioMode)
  {
      // ### Switch to using the recursive rendering algorithm instead.
  
      // Default source rect = scene rect
      QRectF sourceRect = source;
      if (sourceRect.isNull())
          sourceRect = sceneRect();
  
      // Default target rect = device rect
      QRectF targetRect = target;
      if (targetRect.isNull()) {
          if (painter->device()->devType() == QInternal::Picture)
              targetRect = sourceRect;
          else
              targetRect.setRect(0, 0, painter->device()->width(), painter->device()->height());
      }
  
      // Find the ideal x / y scaling ratio to fit \a source into \a target.
      qreal xratio = targetRect.width() / sourceRect.width();
      qreal yratio = targetRect.height() / sourceRect.height();
  
      // Scale according to the aspect ratio mode.
      switch (aspectRatioMode) {
      case Qt::KeepAspectRatio:
          xratio = yratio = qMin(xratio, yratio);
          break;
      case Qt::KeepAspectRatioByExpanding:
          xratio = yratio = qMax(xratio, yratio);
          break;
      case Qt::IgnoreAspectRatio:
          break;
      }
  
      // Find all items to draw, and reverse the list (we want to draw
      // in reverse order).
      QList<QGraphicsItem *> itemList = items(sourceRect, Qt::IntersectsItemBoundingRect);
      QGraphicsItem **itemArray = new QGraphicsItem *[itemList.size()];
      int numItems = itemList.size();
      for (int i = 0; i < numItems; ++i)
          itemArray[numItems - i - 1] = itemList.at(i);
      itemList.clear();
  
      painter->save();
  
      // Transform the painter.
      painter->setClipRect(targetRect, Qt::IntersectClip);
      QTransform painterTransform;
      painterTransform *= QTransform()
                          .translate(targetRect.left(), targetRect.top())
                          .scale(xratio, yratio)
                          .translate(-sourceRect.left(), -sourceRect.top());
      painter->setWorldTransform(painterTransform, true);
  
      // Two unit vectors.
      QLineF v1(0, 0, 1, 0);
      QLineF v2(0, 0, 0, 1);
  
      // Generate the style options
      QStyleOptionGraphicsItem *styleOptionArray = new QStyleOptionGraphicsItem[numItems];
      for (int i = 0; i < numItems; ++i)
          itemArray[i]->d_ptr->initStyleOption(&styleOptionArray[i], painterTransform, targetRect.toRect());
  
      // Render the scene.
      drawBackground(painter, sourceRect);
      drawItems(painter, numItems, itemArray, styleOptionArray);
      drawForeground(painter, sourceRect);
  
      delete [] itemArray;
      delete [] styleOptionArray;
  
      painter->restore();
  }
  
  /*!
      \property QGraphicsScene::itemIndexMethod
      \brief the item indexing method.
  
      QGraphicsScene applies an indexing algorithm to the scene, to speed up
      item discovery functions like items() and itemAt(). Indexing is most
      efficient for static scenes (i.e., where items don't move around). For
      dynamic scenes, or scenes with many animated items, the index bookkeeping
      can outweight the fast lookup speeds.
  
      For the common case, the default index method BspTreeIndex works fine.  If
      your scene uses many animations and you are experiencing slowness, you can
      disable indexing by calling \c setItemIndexMethod(NoIndex).
  
      \sa bspTreeDepth
  */
  QGraphicsScene::ItemIndexMethod QGraphicsScene::itemIndexMethod() const
  {
      Q_D(const QGraphicsScene);
      return d->indexMethod;
  }
  void QGraphicsScene::setItemIndexMethod(ItemIndexMethod method)
  {
      Q_D(QGraphicsScene);
      if (d->indexMethod == method)
          return;
  
      d->indexMethod = method;
  
      QList<QGraphicsItem *> oldItems = d->index->items(Qt::DescendingOrder);
      delete d->index;
      if (method == BspTreeIndex)
          d->index = new QGraphicsSceneBspTreeIndex(this);
      else
          d->index = new QGraphicsSceneLinearIndex(this);
      for (int i = oldItems.size() - 1; i >= 0; --i)
          d->index->addItem(oldItems.at(i));
  }
  
  /*!
      \property QGraphicsScene::bspTreeDepth
      \brief the depth of QGraphicsScene's BSP index tree
      \since 4.3
  
      This property has no effect when NoIndex is used.
  
      This value determines the depth of QGraphicsScene's BSP tree. The depth
      directly affects QGraphicsScene's performance and memory usage; the latter
      growing exponentially with the depth of the tree. With an optimal tree
      depth, QGraphicsScene can instantly determine the locality of items, even
      for scenes with thousands or millions of items. This also greatly improves
      rendering performance.
  
      By default, the value is 0, in which case Qt will guess a reasonable
      default depth based on the size, location and number of items in the
      scene. If these parameters change frequently, however, you may experience
      slowdowns as QGraphicsScene retunes the depth internally. You can avoid
      potential slowdowns by fixating the tree depth through setting this
      property.
  
      The depth of the tree and the size of the scene rectangle decide the
      granularity of the scene's partitioning. The size of each scene segment is
      determined by the following algorithm:
  
      \snippet doc/src/snippets/code/src_gui_graphicsview_qgraphicsscene.cpp 2
  
      The BSP tree has an optimal size when each segment contains between 0 and
      10 items.
  
      \sa itemIndexMethod
  */
  int QGraphicsScene::bspTreeDepth() const
  {
      Q_D(const QGraphicsScene);
      QGraphicsSceneBspTreeIndex *bspTree = qobject_cast<QGraphicsSceneBspTreeIndex *>(d->index);
      return bspTree ? bspTree->bspTreeDepth() : 0;
  }
  void QGraphicsScene::setBspTreeDepth(int depth)
  {
      Q_D(QGraphicsScene);
      if (depth < 0) {
          qWarning("QGraphicsScene::setBspTreeDepth: invalid depth %d ignored; must be >= 0", depth);
          return;
      }
  
      QGraphicsSceneBspTreeIndex *bspTree = qobject_cast<QGraphicsSceneBspTreeIndex *>(d->index);
      if (!bspTree) {
          qWarning("QGraphicsScene::setBspTreeDepth: can not apply if indexing method is not BSP");
          return;
      }
      bspTree->setBspTreeDepth(depth);
  }
  
  /*!
      \property QGraphicsScene::sortCacheEnabled
      \brief whether sort caching is enabled
      \since 4.5
      \obsolete
  
      Since Qt 4.6, this property has no effect.
  */
  bool QGraphicsScene::isSortCacheEnabled() const
  {
      Q_D(const QGraphicsScene);
      return d->sortCacheEnabled;
  }
  void QGraphicsScene::setSortCacheEnabled(bool enabled)
  {
      Q_D(QGraphicsScene);
      if (d->sortCacheEnabled == enabled)
          return;
      d->sortCacheEnabled = enabled;
  }
  
  /*!
      Calculates and returns the bounding rect of all items on the scene. This
      function works by iterating over all items, and because if this, it can
      be slow for large scenes.
  
      \sa sceneRect()
  */
  QRectF QGraphicsScene::itemsBoundingRect() const
  {
      // Does not take untransformable items into account.
      QRectF boundingRect;
      foreach (QGraphicsItem *item, items())
          boundingRect |= item->sceneBoundingRect();
      return boundingRect;
  }
  
  /*!
      Returns a list of all items in the scene in descending stacking order.
  
      \sa addItem(), removeItem(), {QGraphicsItem#Sorting}{Sorting}
  */
  QList<QGraphicsItem *> QGraphicsScene::items() const
  {
      Q_D(const QGraphicsScene);
      return d->index->items(Qt::DescendingOrder);
  }
  
  /*!
      Returns an ordered list of all items on the scene. \a order decides the
      stacking order.
  
      \sa addItem(), removeItem(), {QGraphicsItem#Sorting}{Sorting}
  */
  QList<QGraphicsItem *> QGraphicsScene::items(Qt::SortOrder order) const
  {
      Q_D(const QGraphicsScene);
      return d->index->items(order);
  }
  
  /*!
      \obsolete
  
      Returns all visible items at position \a pos in the scene. The items are
      listed in descending stacking order (i.e., the first item in the list is the
      top-most item, and the last item is the bottom-most item).
  
      This function is deprecated and returns incorrect results if the scene
      contains items that ignore transformations. Use the overload that takes
      a QTransform instead.
  
      \sa itemAt(), {QGraphicsItem#Sorting}{Sorting}
  */
  QList<QGraphicsItem *> QGraphicsScene::items(const QPointF &pos) const
  {
      Q_D(const QGraphicsScene);
      return d->index->items(pos, Qt::IntersectsItemShape, Qt::DescendingOrder);
  }
  
  /*!
      \overload
      \obsolete
  
      Returns all visible items that, depending on \a mode, are either inside or
      intersect with the specified \a rectangle.
  
      The default value for \a mode is Qt::IntersectsItemShape; all items whose
      exact shape intersects with or is contained by \a rectangle are returned.
  
      This function is deprecated and returns incorrect results if the scene
      contains items that ignore transformations. Use the overload that takes
      a QTransform instead.
  
      \sa itemAt(), {QGraphicsItem#Sorting}{Sorting}
  */
  QList<QGraphicsItem *> QGraphicsScene::items(const QRectF &rectangle, Qt::ItemSelectionMode mode) const
  {
      Q_D(const QGraphicsScene);
      return d->index->items(rectangle, mode, Qt::DescendingOrder);
  }
  
  /*!
      \fn QList<QGraphicsItem *> QGraphicsScene::items(qreal x, qreal y, qreal w, qreal h, Qt::ItemSelectionMode mode) const
      \obsolete
      \since 4.3
  
      This convenience function is equivalent to calling items(QRectF(\a x, \a y, \a w, \a h), \a mode).
  
      This function is deprecated and returns incorrect results if the scene
      contains items that ignore transformations. Use the overload that takes
      a QTransform instead.
  */
  
  /*!
      \fn QList<QGraphicsItem *> QGraphicsScene::items(qreal x, qreal y, qreal w, qreal h, Qt::ItemSelectionMode mode, Qt::SortOrder order, const QTransform &deviceTransform) const
      \overload
      \since 4.6
  
      \brief Returns all visible items that, depending on \a mode, are
      either inside or intersect with the rectangle defined by \a x, \a y,
      \a w and \a h, in a list sorted using \a order.
  
      \a deviceTransform is the transformation that applies to the view, and needs to
      be provided if the scene contains items that ignore transformations.
  */
  
  /*!
      \fn QList<QGraphicsItem *> QGraphicsScene::items(const QPolygonF &polygon, Qt::ItemSelectionMode mode) const
      \overload
      \obsolete
  
      Returns all visible items that, depending on \a mode, are either inside or
      intersect with the polygon \a polygon.
  
      The default value for \a mode is Qt::IntersectsItemShape; all items whose
      exact shape intersects with or is contained by \a polygon are returned.
  
      This function is deprecated and returns incorrect results if the scene
      contains items that ignore transformations. Use the overload that takes
      a QTransform instead.
  
      \sa itemAt(), {QGraphicsItem#Sorting}{Sorting}
  */
  QList<QGraphicsItem *> QGraphicsScene::items(const QPolygonF &polygon, Qt::ItemSelectionMode mode) const
  {
      Q_D(const QGraphicsScene);
      return d->index->items(polygon, mode, Qt::DescendingOrder);
  }
  
  /*!
      \fn QList<QGraphicsItem *> QGraphicsScene::items(const QPainterPath &path, Qt::ItemSelectionMode mode) const
      \overload
      \obsolete
  
      Returns all visible items that, depending on \a path, are either inside or
      intersect with the path \a path.
  
      The default value for \a mode is Qt::IntersectsItemShape; all items whose
      exact shape intersects with or is contained by \a path are returned.
  
      This function is deprecated and returns incorrect results if the scene
      contains items that ignore transformations. Use the overload that takes
      a QTransform instead.
  
      \sa itemAt(), {QGraphicsItem#Sorting}{Sorting}
  */
  QList<QGraphicsItem *> QGraphicsScene::items(const QPainterPath &path, Qt::ItemSelectionMode mode) const
  {
      Q_D(const QGraphicsScene);
      return d->index->items(path, mode, Qt::DescendingOrder);
  }
  
  /*!
      \fn QList<QGraphicsItem *> QGraphicsScene::items(const QPointF &pos, Qt::ItemSelectionMode mode, Qt::SortOrder order, const QTransform &deviceTransform) const
      \since 4.6
  
      \brief Returns all visible items that, depending on \a mode, are at
      the specified \a pos in a list sorted using \a order.
  
      The default value for \a mode is Qt::IntersectsItemShape; all items whose
      exact shape intersects with \a pos are returned.
  
      \a deviceTransform is the transformation that applies to the view, and needs to
      be provided if the scene contains items that ignore transformations.
  
      \sa itemAt(), {QGraphicsItem#Sorting}{Sorting}
  */
  QList<QGraphicsItem *> QGraphicsScene::items(const QPointF &pos, Qt::ItemSelectionMode mode,
                                               Qt::SortOrder order, const QTransform &deviceTransform) const
  {
      Q_D(const QGraphicsScene);
      return d->index->items(pos, mode, order, deviceTransform);
  }
  
  /*!
      \fn QList<QGraphicsItem *> QGraphicsScene::items(const QRectF &rect, Qt::ItemSelectionMode mode, Qt::SortOrder order, const QTransform &deviceTransform) const
      \overload
      \since 4.6
  
      \brief Returns all visible items that, depending on \a mode, are
      either inside or intersect with the specified \a rect and return a
      list sorted using \a order.
  
      The default value for \a mode is Qt::IntersectsItemShape; all items whose
      exact shape intersects with or is contained by \a rect are returned.
  
      \a deviceTransform is the transformation that applies to the view, and needs to
      be provided if the scene contains items that ignore transformations.
  
      \sa itemAt(), {QGraphicsItem#Sorting}{Sorting}
  */
  QList<QGraphicsItem *> QGraphicsScene::items(const QRectF &rect, Qt::ItemSelectionMode mode,
                                               Qt::SortOrder order, const QTransform &deviceTransform) const
  {
      Q_D(const QGraphicsScene);
      return d->index->items(rect, mode, order, deviceTransform);
  }
  
  /*!
      \fn QList<QGraphicsItem *> QGraphicsScene::items(const QPolygonF &polygon, Qt::ItemSelectionMode mode, Qt::SortOrder order, const QTransform &deviceTransform) const
      \overload
      \since 4.6
  
      \brief Returns all visible items that, depending on \a mode, are
      either inside or intersect with the specified \a polygon and return
      a list sorted using \a order.
  
      The default value for \a mode is Qt::IntersectsItemShape; all items whose
      exact shape intersects with or is contained by \a polygon are returned.
  
      \a deviceTransform is the transformation that applies to the view, and needs to
      be provided if the scene contains items that ignore transformations.
  
      \sa itemAt(), {QGraphicsItem#Sorting}{Sorting}
  */
  QList<QGraphicsItem *> QGraphicsScene::items(const QPolygonF &polygon, Qt::ItemSelectionMode mode,
                                               Qt::SortOrder order, const QTransform &deviceTransform) const
  {
      Q_D(const QGraphicsScene);
      return d->index->items(polygon, mode, order, deviceTransform);
  }
  
  /*!
      \fn QList<QGraphicsItem *> QGraphicsScene::items(const QPainterPath &path, Qt::ItemSelectionMode mode, Qt::SortOrder order, const QTransform &deviceTransform) const
      \overload
      \since 4.6
  
      \brief Returns all visible items that, depending on \a mode, are
      either inside or intersect with the specified \a path and return a
      list sorted using \a order.
  
      The default value for \a mode is Qt::IntersectsItemShape; all items whose
      exact shape intersects with or is contained by \a path are returned.
  
      \a deviceTransform is the transformation that applies to the view, and needs to
      be provided if the scene contains items that ignore transformations.
  
      \sa itemAt(), {QGraphicsItem#Sorting}{Sorting}
  */
  QList<QGraphicsItem *> QGraphicsScene::items(const QPainterPath &path, Qt::ItemSelectionMode mode,
                                               Qt::SortOrder order, const QTransform &deviceTransform) const
  {
      Q_D(const QGraphicsScene);
      return d->index->items(path, mode, order, deviceTransform);
  }
  
  /*!
      Returns a list of all items that collide with \a item. Collisions are
      determined by calling QGraphicsItem::collidesWithItem(); the collision
      detection is determined by \a mode. By default, all items whose shape
      intersects \a item or is contained inside \a item's shape are returned.
  
      The items are returned in descending stacking order (i.e., the first item
      in the list is the uppermost item, and the last item is the lowermost
      item).
  
      \sa items(), itemAt(), QGraphicsItem::collidesWithItem(), {QGraphicsItem#Sorting}{Sorting}
  */
  QList<QGraphicsItem *> QGraphicsScene::collidingItems(const QGraphicsItem *item,
                                                        Qt::ItemSelectionMode mode) const
  {
      Q_D(const QGraphicsScene);
      if (!item) {
          qWarning("QGraphicsScene::collidingItems: cannot find collisions for null item");
          return QList<QGraphicsItem *>();
      }
  
      // Does not support ItemIgnoresTransformations.
      QList<QGraphicsItem *> tmp;
      foreach (QGraphicsItem *itemInVicinity, d->index->estimateItems(item->sceneBoundingRect(), Qt::DescendingOrder)) {
          if (item != itemInVicinity && item->collidesWithItem(itemInVicinity, mode))
              tmp << itemInVicinity;
      }
      return tmp;
  }
  
  /*!
      \overload
      \obsolete
  
      Returns the topmost visible item at the specified \a position, or 0 if
      there are no items at this position.
  
      This function is deprecated and returns incorrect results if the scene
      contains items that ignore transformations. Use the overload that takes
      a QTransform instead.
  
      \sa items(), collidingItems(), {QGraphicsItem#Sorting}{Sorting}
  */
  QGraphicsItem *QGraphicsScene::itemAt(const QPointF &position) const
  {
      QList<QGraphicsItem *> itemsAtPoint = items(position);
      return itemsAtPoint.isEmpty() ? 0 : itemsAtPoint.first();
  }
  
  /*!
      \since 4.6
  
      Returns the topmost visible item at the specified \a position, or 0
      if there are no items at this position.
  
      \a deviceTransform is the transformation that applies to the view, and needs to
      be provided if the scene contains items that ignore transformations.
  
      \sa items(), collidingItems(), {QGraphicsItem#Sorting}{Sorting}
  */
  QGraphicsItem *QGraphicsScene::itemAt(const QPointF &position, const QTransform &deviceTransform) const
  {
      QList<QGraphicsItem *> itemsAtPoint = items(position, Qt::IntersectsItemShape,
                                                  Qt::DescendingOrder, deviceTransform);
      return itemsAtPoint.isEmpty() ? 0 : itemsAtPoint.first();
  }
  
  /*!
      \fn QGraphicsScene::itemAt(qreal x, qreal y, const QTransform &deviceTransform) const
      \overload
      \since 4.6
  
      Returns the topmost item at the position specified by (\a x, \a
      y), or 0 if there are no items at this position.
  
      \a deviceTransform is the transformation that applies to the view, and needs to
      be provided if the scene contains items that ignore transformations.
  
      This convenience function is equivalent to calling \c
      {itemAt(QPointF(x, y), deviceTransform)}.
  */
  
  /*!
      \fn QGraphicsScene::itemAt(qreal x, qreal y) const
      \overload
      \obsolete
  
      Returns the topmost item at the position specified by (\a x, \a
      y), or 0 if there are no items at this position.
  
      This convenience function is equivalent to calling \c
      {itemAt(QPointF(x, y))}.
  
      This function is deprecated and returns incorrect results if the scene
      contains items that ignore transformations. Use the overload that takes
      a QTransform instead.
  */
  
  /*!
      Returns a list of all currently selected items. The items are
      returned in no particular order.
  
      \sa setSelectionArea()
  */
  QList<QGraphicsItem *> QGraphicsScene::selectedItems() const
  {
      Q_D(const QGraphicsScene);
  
      // Optimization: Lazily removes items that are not selected.
      QGraphicsScene *that = const_cast<QGraphicsScene *>(this);
      QSet<QGraphicsItem *> actuallySelectedSet;
      foreach (QGraphicsItem *item, that->d_func()->selectedItems) {
          if (item->isSelected())
              actuallySelectedSet << item;
      }
  
      that->d_func()->selectedItems = actuallySelectedSet;
  
      return d->selectedItems.values();
  }
  
  /*!
      Returns the selection area that was previously set with
      setSelectionArea(), or an empty QPainterPath if no selection area has been
      set.
  
      \sa setSelectionArea()
  */
  QPainterPath QGraphicsScene::selectionArea() const
  {
      Q_D(const QGraphicsScene);
      return d->selectionArea;
  }
  
  /*!
      \since 4.6
  
      Sets the selection area to \a path. All items within this area are
      immediately selected, and all items outside are unselected. You can get
      the list of all selected items by calling selectedItems().
  
      \a deviceTransform is the transformation that applies to the view, and needs to
      be provided if the scene contains items that ignore transformations.
  
      For an item to be selected, it must be marked as \e selectable
      (QGraphicsItem::ItemIsSelectable).
  
      \sa clearSelection(), selectionArea()
  */
  void QGraphicsScene::setSelectionArea(const QPainterPath &path, const QTransform &deviceTransform)
  {
      setSelectionArea(path, Qt::IntersectsItemShape, deviceTransform);
  }
  
  /*!
      \obsolete
      \overload
  
      Sets the selection area to \a path.
  
      This function is deprecated and leads to incorrect results if the scene
      contains items that ignore transformations. Use the overload that takes
      a QTransform instead.
  */
  void QGraphicsScene::setSelectionArea(const QPainterPath &path)
  {
      setSelectionArea(path, Qt::IntersectsItemShape, QTransform());
  }
  
  /*!
      \obsolete
      \overload
      \since 4.3
  
      Sets the selection area to \a path using \a mode to determine if items are
      included in the selection area.
  
      \sa clearSelection(), selectionArea()
  */
  void QGraphicsScene::setSelectionArea(const QPainterPath &path, Qt::ItemSelectionMode mode)
  {
      setSelectionArea(path, mode, QTransform());
  }
  
  /*!
      \overload
      \since 4.6
  
      Sets the selection area to \a path using \a mode to determine if items are
      included in the selection area.
  
      \a deviceTransform is the transformation that applies to the view, and needs to
      be provided if the scene contains items that ignore transformations.
  
      \sa clearSelection(), selectionArea()
  */
  void QGraphicsScene::setSelectionArea(const QPainterPath &path, Qt::ItemSelectionMode mode,
                                        const QTransform &deviceTransform)
  {
      Q_D(QGraphicsScene);
  
      // Note: with boolean path operations, we can improve performance here
      // quite a lot by "growing" the old path instead of replacing it. That
      // allows us to only check the intersect area for changes, instead of
      // reevaluating the whole path over again.
      d->selectionArea = path;
  
      QSet<QGraphicsItem *> unselectItems = d->selectedItems;
  
      // Disable emitting selectionChanged() for individual items.
      ++d->selectionChanging;
      bool changed = false;
  
      // Set all items in path to selected.
      foreach (QGraphicsItem *item, items(path, mode, Qt::DescendingOrder, deviceTransform)) {
          if (item->flags() & QGraphicsItem::ItemIsSelectable) {
              if (!item->isSelected())
                  changed = true;
              unselectItems.remove(item);
              item->setSelected(true);
          }
      }
  
      // Unselect all items outside path.
      foreach (QGraphicsItem *item, unselectItems) {
          item->setSelected(false);
          changed = true;
      }
  
      // Reenable emitting selectionChanged() for individual items.
      --d->selectionChanging;
  
      if (!d->selectionChanging && changed)
          emit selectionChanged();
  }
  
  /*!
     Clears the current selection.
  
     \sa setSelectionArea(), selectedItems()
  */
  void QGraphicsScene::clearSelection()
  {
      Q_D(QGraphicsScene);
  
      // Disable emitting selectionChanged
      ++d->selectionChanging;
      bool changed = !d->selectedItems.isEmpty();
  
      foreach (QGraphicsItem *item, d->selectedItems)
          item->setSelected(false);
      d->selectedItems.clear();
  
      // Reenable emitting selectionChanged() for individual items.
      --d->selectionChanging;
  
      if (!d->selectionChanging && changed)
          emit selectionChanged();
  }
  
  /*!
      \since 4.4
  
      Removes and deletes all items from the scene, but otherwise leaves the
      state of the scene unchanged.
  
      \sa addItem()
  */
  void QGraphicsScene::clear()
  {
      Q_D(QGraphicsScene);
      // NB! We have to clear the index before deleting items; otherwise the
      // index might try to access dangling item pointers.
      d->index->clear();
      // NB! QGraphicsScenePrivate::unregisterTopLevelItem() removes items
      while (!d->topLevelItems.isEmpty())
          delete d->topLevelItems.first();
      Q_ASSERT(d->topLevelItems.isEmpty());
      d->lastItemCount = 0;
      d->allItemsIgnoreHoverEvents = true;
      d->allItemsUseDefaultCursor = true;
      d->allItemsIgnoreTouchEvents = true;
  }
  
  /*!
      Groups all items in \a items into a new QGraphicsItemGroup, and returns a
      pointer to the group. The group is created with the common ancestor of \a
      items as its parent, and with position (0, 0). The items are all
      reparented to the group, and their positions and transformations are
      mapped to the group. If \a items is empty, this function will return an
      empty top-level QGraphicsItemGroup.
  
      QGraphicsScene has ownership of the group item; you do not need to delete
      it. To dismantle (ungroup) a group, call destroyItemGroup().
  
      \sa destroyItemGroup(), QGraphicsItemGroup::addToGroup()
  */
  QGraphicsItemGroup *QGraphicsScene::createItemGroup(const QList<QGraphicsItem *> &items)
  {
      // Build a list of the first item's ancestors
      QList<QGraphicsItem *> ancestors;
      int n = 0;
      if (!items.isEmpty()) {
          QGraphicsItem *parent = items.at(n++);
          while ((parent = parent->parentItem()))
              ancestors.append(parent);
      }
  
      // Find the common ancestor for all items
      QGraphicsItem *commonAncestor = 0;
      if (!ancestors.isEmpty()) {
          while (n < items.size()) {
              int commonIndex = -1;
              QGraphicsItem *parent = items.at(n++);
              do {
                  int index = ancestors.indexOf(parent, qMax(0, commonIndex));
                  if (index != -1) {
                      commonIndex = index;
                      break;
                  }
              } while ((parent = parent->parentItem()));
  
              if (commonIndex == -1) {
                  commonAncestor = 0;
                  break;
              }
  
              commonAncestor = ancestors.at(commonIndex);
          }
      }
  
      // Create a new group at that level
      QGraphicsItemGroup *group = new QGraphicsItemGroup(commonAncestor);
      if (!commonAncestor)
          addItem(group);
      foreach (QGraphicsItem *item, items)
          group->addToGroup(item);
      return group;
  }
  
  /*!
      Reparents all items in \a group to \a group's parent item, then removes \a
      group from the scene, and finally deletes it. The items' positions and
      transformations are mapped from the group to the group's parent.
  
      \sa createItemGroup(), QGraphicsItemGroup::removeFromGroup()
  */
  void QGraphicsScene::destroyItemGroup(QGraphicsItemGroup *group)
  {
      foreach (QGraphicsItem *item, group->children())
          group->removeFromGroup(item);
      removeItem(group);
      delete group;
  }
  
  /*!
      Adds or moves the \a item and all its childen to this scene.
      This scene takes ownership of the \a item.
  
      If the item is visible (i.e., QGraphicsItem::isVisible() returns
      true), QGraphicsScene will emit changed() once control goes back
      to the event loop.
  
      If the item is already in a different scene, it will first be
      removed from its old scene, and then added to this scene as a
      top-level.
  
      QGraphicsScene will send ItemSceneChange notifications to \a item
      while it is added to the scene. If item does not currently belong
      to a scene, only one notification is sent. If it does belong to
      scene already (i.e., it is moved to this scene), QGraphicsScene
      will send an addition notification as the item is removed from its
      previous scene.
  
      If the item is a panel, the scene is active, and there is no
      active panel in the scene, then the item will be activated.
  
      \sa removeItem(), addEllipse(), addLine(), addPath(), addPixmap(),
      addRect(), addText(), addWidget(), {QGraphicsItem#Sorting}{Sorting}
  */
  void QGraphicsScene::addItem(QGraphicsItem *item)
  {
      Q_D(QGraphicsScene);
      if (!item) {
          qWarning("QGraphicsScene::addItem: cannot add null item");
          return;
      }
      if (item->d_ptr->scene == this) {
          qWarning("QGraphicsScene::addItem: item has already been added to this scene");
          return;
      }
      // Remove this item from its existing scene
      if (QGraphicsScene *oldScene = item->d_ptr->scene)
          oldScene->removeItem(item);
  
      // Notify the item that its scene is changing, and allow the item to
      // react.
      const QVariant newSceneVariant(item->itemChange(QGraphicsItem::ItemSceneChange,
                                                      QVariant::fromValue<QGraphicsScene *>(this)));
      QGraphicsScene *targetScene = qvariant_cast<QGraphicsScene *>(newSceneVariant);
      if (targetScene != this) {
          if (targetScene && item->d_ptr->scene != targetScene)
              targetScene->addItem(item);
          return;
      }
  
      // QDeclarativeItems do not rely on initial itemChanged message, as the componentComplete
      // function allows far more opportunity for delayed-construction optimization.
      if (!item->d_ptr->isDeclarativeItem) {
          if (d->unpolishedItems.isEmpty()) {
              QMetaMethod method = metaObject()->method(d->polishItemsIndex);
              method.invoke(this, Qt::QueuedConnection);
          }
          d->unpolishedItems.append(item);
          item->d_ptr->pendingPolish = true;
      }
  
      // Detach this item from its parent if the parent's scene is different
      // from this scene.
      if (QGraphicsItem *itemParent = item->d_ptr->parent) {
          if (itemParent->d_ptr->scene != this)
              item->setParentItem(0);
      }
  
      // Add the item to this scene
      item->d_func()->scene = targetScene;
  
      // Add the item in the index
      d->index->addItem(item);
  
      // Add to list of toplevels if this item is a toplevel.
      if (!item->d_ptr->parent)
          d->registerTopLevelItem(item);
  
      // Add to list of items that require an update. We cannot assume that the
      // item is fully constructed, so calling item->update() can lead to a pure
      // virtual function call to boundingRect().
      d->markDirty(item);
      d->dirtyGrowingItemsBoundingRect = true;
  
      // Disable selectionChanged() for individual items
      ++d->selectionChanging;
      int oldSelectedItemSize = d->selectedItems.size();
  
      // Enable mouse tracking if the item accepts hover events or has a cursor set.
      if (d->allItemsIgnoreHoverEvents && d->itemAcceptsHoverEvents_helper(item)) {
          d->allItemsIgnoreHoverEvents = false;
          d->enableMouseTrackingOnViews();
      }
  #ifndef QT_NO_CURSOR
      if (d->allItemsUseDefaultCursor && item->d_ptr->hasCursor) {
          d->allItemsUseDefaultCursor = false;
          if (d->allItemsIgnoreHoverEvents) // already enabled otherwise
              d->enableMouseTrackingOnViews();
      }
  #endif //QT_NO_CURSOR
  
      // Enable touch events if the item accepts touch events.
      if (d->allItemsIgnoreTouchEvents && item->d_ptr->acceptTouchEvents) {
          d->allItemsIgnoreTouchEvents = false;
          d->enableTouchEventsOnViews();
      }
  
  #ifndef QT_NO_GESTURES
      foreach (Qt::GestureType gesture, item->d_ptr->gestureContext.keys())
          d->grabGesture(item, gesture);
  #endif
  
      // Update selection lists
      if (item->isSelected())
          d->selectedItems << item;
      if (item->isWidget() && item->isVisible() && static_cast<QGraphicsWidget *>(item)->windowType() == Qt::Popup)
          d->addPopup(static_cast<QGraphicsWidget *>(item));
      if (item->isPanel() && item->isVisible() && item->panelModality() != QGraphicsItem::NonModal)
          d->enterModal(item);
  
      // Update creation order focus chain. Make sure to leave the widget's
      // internal tab order intact.
      if (item->isWidget()) {
          QGraphicsWidget *widget = static_cast<QGraphicsWidget *>(item);
          if (!d->tabFocusFirst) {
              // No first tab focus widget - make this the first tab focus
              // widget.
              d->tabFocusFirst = widget;
          } else if (!widget->parentWidget()) {
              // Adding a widget that is not part of a tab focus chain.
              QGraphicsWidget *last = d->tabFocusFirst->d_func()->focusPrev;
              QGraphicsWidget *lastNew = widget->d_func()->focusPrev;
              last->d_func()->focusNext = widget;
              widget->d_func()->focusPrev = last;
              d->tabFocusFirst->d_func()->focusPrev = lastNew;
              lastNew->d_func()->focusNext = d->tabFocusFirst;
          }
      }
  
      // Add all children recursively
      item->d_ptr->ensureSortedChildren();
      for (int i = 0; i < item->d_ptr->children.size(); ++i)
          addItem(item->d_ptr->children.at(i));
  
      // Resolve font and palette.
      item->d_ptr->resolveFont(d->font.resolve());
      item->d_ptr->resolvePalette(d->palette.resolve());
  
  
      // Reenable selectionChanged() for individual items
      --d->selectionChanging;
      if (!d->selectionChanging && d->selectedItems.size() != oldSelectedItemSize)
          emit selectionChanged();
  
      // Deliver post-change notification
      item->itemChange(QGraphicsItem::ItemSceneHasChanged, newSceneVariant);
  
      // Update explicit activation
      bool autoActivate = true;
      if (!d->childExplicitActivation && item->d_ptr->explicitActivate)
          d->childExplicitActivation = item->d_ptr->wantsActive ? 1 : 2;
      if (d->childExplicitActivation && item->isPanel()) {
          if (d->childExplicitActivation == 1)
              setActivePanel(item);
          else
              autoActivate = false;
          d->childExplicitActivation = 0;
      } else if (!item->d_ptr->parent) {
          d->childExplicitActivation = 0;
      }
  
      // Auto-activate this item's panel if nothing else has been activated
      if (autoActivate) {
          if (!d->lastActivePanel && !d->activePanel && item->isPanel()) {
              if (isActive())
                  setActivePanel(item);
              else
                  d->lastActivePanel = item;
          }
      }
  
      if (item->d_ptr->flags & QGraphicsItem::ItemSendsScenePositionChanges)
          d->registerScenePosItem(item);
  
      // Ensure that newly added items that have subfocus set, gain
      // focus automatically if there isn't a focus item already.
      if (!d->focusItem && item != d->lastFocusItem && item->focusItem() == item)
          item->focusItem()->setFocus();
  
      d->updateInputMethodSensitivityInViews();
  }
  
  /*!
      Creates and adds an ellipse item to the scene, and returns the item
      pointer. The geometry of the ellipse is defined by \a rect, and its pen
      and brush are initialized to \a pen and \a brush.
  
      Note that the item's geometry is provided in item coordinates, and its
      position is initialized to (0, 0).
  
      If the item is visible (i.e., QGraphicsItem::isVisible() returns true),
      QGraphicsScene will emit changed() once control goes back to the event
      loop.
  
      \sa addLine(), addPath(), addPixmap(), addRect(), addText(), addItem(),
      addWidget()
  */
  QGraphicsEllipseItem *QGraphicsScene::addEllipse(const QRectF &rect, const QPen &pen, const QBrush &brush)
  {
      QGraphicsEllipseItem *item = new QGraphicsEllipseItem(rect);
      item->setPen(pen);
      item->setBrush(brush);
      addItem(item);
      return item;
  }
  
  /*!
      \fn QGraphicsEllipseItem *QGraphicsScene::addEllipse(qreal x, qreal y, qreal w, qreal h, const QPen &pen, const QBrush &brush)
      \since 4.3
  
      This convenience function is equivalent to calling addEllipse(QRectF(\a x,
      \a y, \a w, \a h), \a pen, \a brush).
  */
  
  /*!
      Creates and adds a line item to the scene, and returns the item
      pointer. The geometry of the line is defined by \a line, and its pen
      is initialized to \a pen.
  
      Note that the item's geometry is provided in item coordinates, and its
      position is initialized to (0, 0).
  
      If the item is visible (i.e., QGraphicsItem::isVisible() returns true),
      QGraphicsScene will emit changed() once control goes back to the event
      loop.
  
      \sa addEllipse(), addPath(), addPixmap(), addRect(), addText(), addItem(),
      addWidget()
  */
  QGraphicsLineItem *QGraphicsScene::addLine(const QLineF &line, const QPen &pen)
  {
      QGraphicsLineItem *item = new QGraphicsLineItem(line);
      item->setPen(pen);
      addItem(item);
      return item;
  }
  
  /*!
      \fn QGraphicsLineItem *QGraphicsScene::addLine(qreal x1, qreal y1, qreal x2, qreal y2, const QPen &pen)
      \since 4.3
  
      This convenience function is equivalent to calling addLine(QLineF(\a x1,
      \a y1, \a x2, \a y2), \a pen).
  */
  
  /*!
      Creates and adds a path item to the scene, and returns the item
      pointer. The geometry of the path is defined by \a path, and its pen and
      brush are initialized to \a pen and \a brush.
  
      Note that the item's geometry is provided in item coordinates, and its
      position is initialized to (0, 0).
  
      If the item is visible (i.e., QGraphicsItem::isVisible() returns true),
      QGraphicsScene will emit changed() once control goes back to the event
      loop.
  
      \sa addEllipse(), addLine(), addPixmap(), addRect(), addText(), addItem(),
      addWidget()
  */
  QGraphicsPathItem *QGraphicsScene::addPath(const QPainterPath &path, const QPen &pen, const QBrush &brush)
  {
      QGraphicsPathItem *item = new QGraphicsPathItem(path);
      item->setPen(pen);
      item->setBrush(brush);
      addItem(item);
      return item;
  }
  
  /*!
      Creates and adds a pixmap item to the scene, and returns the item
      pointer. The pixmap is defined by \a pixmap.
  
      Note that the item's geometry is provided in item coordinates, and its
      position is initialized to (0, 0).
  
      If the item is visible (i.e., QGraphicsItem::isVisible() returns true),
      QGraphicsScene will emit changed() once control goes back to the event
      loop.
  
      \sa addEllipse(), addLine(), addPath(), addRect(), addText(), addItem(),
      addWidget()
  */
  QGraphicsPixmapItem *QGraphicsScene::addPixmap(const QPixmap &pixmap)
  {
      QGraphicsPixmapItem *item = new QGraphicsPixmapItem(pixmap);
      addItem(item);
      return item;
  }
  
  /*!
      Creates and adds a polygon item to the scene, and returns the item
      pointer. The polygon is defined by \a polygon, and its pen and
      brush are initialized to \a pen and \a brush.
  
      Note that the item's geometry is provided in item coordinates, and its
      position is initialized to (0, 0).
  
      If the item is visible (i.e., QGraphicsItem::isVisible() returns true),
      QGraphicsScene will emit changed() once control goes back to the event
      loop.
  
      \sa addEllipse(), addLine(), addPath(), addRect(), addText(), addItem(),
      addWidget()
  */
  QGraphicsPolygonItem *QGraphicsScene::addPolygon(const QPolygonF &polygon,
                                                   const QPen &pen, const QBrush &brush)
  {
      QGraphicsPolygonItem *item = new QGraphicsPolygonItem(polygon);
      item->setPen(pen);
      item->setBrush(brush);
      addItem(item);
      return item;
  }
  
  /*!
      Creates and adds a rectangle item to the scene, and returns the item
      pointer. The geometry of the rectangle is defined by \a rect, and its pen
      and brush are initialized to \a pen and \a brush.
  
      Note that the item's geometry is provided in item coordinates, and its
      position is initialized to (0, 0). For example, if a QRect(50, 50, 100,
      100) is added, its top-left corner will be at (50, 50) relative to the
      origin in the items coordinate system.
  
      If the item is visible (i.e., QGraphicsItem::isVisible() returns true),
      QGraphicsScene will emit changed() once control goes back to the event
      loop.
  
      \sa addEllipse(), addLine(), addPixmap(), addPixmap(), addText(),
      addItem(), addWidget()
  */
  QGraphicsRectItem *QGraphicsScene::addRect(const QRectF &rect, const QPen &pen, const QBrush &brush)
  {
      QGraphicsRectItem *item = new QGraphicsRectItem(rect);
      item->setPen(pen);
      item->setBrush(brush);
      addItem(item);
      return item;
  }
  
  /*!
      \fn QGraphicsRectItem *QGraphicsScene::addRect(qreal x, qreal y, qreal w, qreal h, const QPen &pen, const QBrush &brush)
      \since 4.3
  
      This convenience function is equivalent to calling addRect(QRectF(\a x,
      \a y, \a w, \a h), \a pen, \a brush).
  */
  
  /*!
      Creates and adds a text item to the scene, and returns the item
      pointer. The text string is initialized to \a text, and its font
      is initialized to \a font.
  
      The item's position is initialized to (0, 0).
  
      If the item is visible (i.e., QGraphicsItem::isVisible() returns true),
      QGraphicsScene will emit changed() once control goes back to the event
      loop.
  
      \sa addEllipse(), addLine(), addPixmap(), addPixmap(), addRect(),
      addItem(), addWidget()
  */
  QGraphicsTextItem *QGraphicsScene::addText(const QString &text, const QFont &font)
  {
      QGraphicsTextItem *item = new QGraphicsTextItem(text);
      item->setFont(font);
      addItem(item);
      return item;
  }
  
  /*!
      Creates and adds a QGraphicsSimpleTextItem to the scene, and returns the
      item pointer. The text string is initialized to \a text, and its font is
      initialized to \a font.
  
      The item's position is initialized to (0, 0).
  
      If the item is visible (i.e., QGraphicsItem::isVisible() returns true),
      QGraphicsScene will emit changed() once control goes back to the event
      loop.
  
      \sa addEllipse(), addLine(), addPixmap(), addPixmap(), addRect(),
      addItem(), addWidget()
  */
  QGraphicsSimpleTextItem *QGraphicsScene::addSimpleText(const QString &text, const QFont &font)
  {
      QGraphicsSimpleTextItem *item = new QGraphicsSimpleTextItem(text);
      item->setFont(font);
      addItem(item);
      return item;
  }
  
  /*!
      Creates a new QGraphicsProxyWidget for \a widget, adds it to the scene,
      and returns a pointer to the proxy. \a wFlags set the default window flags
      for the embedding proxy widget.
  
      The item's position is initialized to (0, 0).
  
      If the item is visible (i.e., QGraphicsItem::isVisible() returns true),
      QGraphicsScene will emit changed() once control goes back to the event
      loop.
  
      Note that widgets with the Qt::WA_PaintOnScreen widget attribute
      set and widgets that wrap an external application or controller
      are not supported. Examples are QGLWidget and QAxWidget.
  
      \sa addEllipse(), addLine(), addPixmap(), addPixmap(), addRect(),
      addText(), addSimpleText(), addItem()
  */
  QGraphicsProxyWidget *QGraphicsScene::addWidget(QWidget *widget, Qt::WindowFlags wFlags)
  {
      QGraphicsProxyWidget *proxy = new QGraphicsProxyWidget(0, wFlags);
      proxy->setWidget(widget);
      addItem(proxy);
      return proxy;
  }
  
  /*!
      Removes the item \a item and all its children from the scene.  The
      ownership of \a item is passed on to the caller (i.e.,
      QGraphicsScene will no longer delete \a item when destroyed).
  
      \sa addItem()
  */
  void QGraphicsScene::removeItem(QGraphicsItem *item)
  {
      // ### Refactoring: This function shares much functionality with _q_removeItemLater()
      Q_D(QGraphicsScene);
      if (!item) {
          qWarning("QGraphicsScene::removeItem: cannot remove 0-item");
          return;
      }
      if (item->scene() != this) {
          qWarning("QGraphicsScene::removeItem: item %p's scene (%p)"
                   " is different from this scene (%p)",
                   item, item->scene(), this);
          return;
      }
  
      // Notify the item that it's scene is changing to 0, allowing the item to
      // react.
      const QVariant newSceneVariant(item->itemChange(QGraphicsItem::ItemSceneChange,
                                                      QVariant::fromValue<QGraphicsScene *>(0)));
      QGraphicsScene *targetScene = qvariant_cast<QGraphicsScene *>(newSceneVariant);
      if (targetScene != 0 && targetScene != this) {
          targetScene->addItem(item);
          return;
      }
  
      d->removeItemHelper(item);
  
      // Deliver post-change notification
      item->itemChange(QGraphicsItem::ItemSceneHasChanged, newSceneVariant);
  
      d->updateInputMethodSensitivityInViews();
  }
  
  /*!
      When the scene is active, this functions returns the scene's current focus
      item, or 0 if no item currently has focus. When the scene is inactive, this
      functions returns the item that will gain input focus when the scene becomes
      active.
  
      The focus item receives keyboard input when the scene receives a
      key event.
  
      \sa setFocusItem(), QGraphicsItem::hasFocus(), isActive()
  */
  QGraphicsItem *QGraphicsScene::focusItem() const
  {
      Q_D(const QGraphicsScene);
      return isActive() ? d->focusItem : d->passiveFocusItem;
  }
  
  /*!
      Sets the scene's focus item to \a item, with the focus reason \a
      focusReason, after removing focus from any previous item that may have had
      focus.
  
      If \a item is 0, or if it either does not accept focus (i.e., it does not
      have the QGraphicsItem::ItemIsFocusable flag enabled), or is not visible
      or not enabled, this function only removes focus from any previous
      focusitem.
  
      If item is not 0, and the scene does not currently have focus (i.e.,
      hasFocus() returns false), this function will call setFocus()
      automatically.
  
      \sa focusItem(), hasFocus(), setFocus()
  */
  void QGraphicsScene::setFocusItem(QGraphicsItem *item, Qt::FocusReason focusReason)
  {
      Q_D(QGraphicsScene);
      if (item)
          item->setFocus(focusReason);
      else
          d->setFocusItemHelper(item, focusReason);
  }
  
  /*!
      Returns true if the scene has focus; otherwise returns false. If the scene
      has focus, it will will forward key events from QKeyEvent to any item that
      has focus.
  
      \sa setFocus(), setFocusItem()
  */
  bool QGraphicsScene::hasFocus() const
  {
      Q_D(const QGraphicsScene);
      return d->hasFocus;
  }
  
  /*!
      Sets focus on the scene by sending a QFocusEvent to the scene, passing \a
      focusReason as the reason. If the scene regains focus after having
      previously lost it while an item had focus, the last focus item will
      receive focus with \a focusReason as the reason.
  
      If the scene already has focus, this function does nothing.
  
      \sa hasFocus(), clearFocus(), setFocusItem()
  */
  void QGraphicsScene::setFocus(Qt::FocusReason focusReason)
  {
      Q_D(QGraphicsScene);
      if (d->hasFocus || !isActive())
          return;
      QFocusEvent event(QEvent::FocusIn, focusReason);
      QCoreApplication::sendEvent(this, &event);
  }
  
  /*!
      Clears focus from the scene. If any item has focus when this function is
      called, it will lose focus, and regain focus again once the scene regains
      focus.
  
      A scene that does not have focus ignores key events.
  
      \sa hasFocus(), setFocus(), setFocusItem()
  */
  void QGraphicsScene::clearFocus()
  {
      Q_D(QGraphicsScene);
      if (d->hasFocus) {
          d->hasFocus = false;
          d->passiveFocusItem = d->focusItem;
          setFocusItem(0, Qt::OtherFocusReason);
      }
  }
  
  /*!
      \property QGraphicsScene::stickyFocus
      \brief whether clicking into the scene background will clear focus
  
      \since 4.6
  
      In a QGraphicsScene with stickyFocus set to true, focus will remain
      unchanged when the user clicks into the scene background or on an item
      that does not accept focus. Otherwise, focus will be cleared.
  
      By default, this property is false.
  
      Focus changes in response to a mouse press. You can reimplement
      mousePressEvent() in a subclass of QGraphicsScene to toggle this property
      based on where the user has clicked.
  
      \sa clearFocus(), setFocusItem()
  */
  void QGraphicsScene::setStickyFocus(bool enabled)
  {
      Q_D(QGraphicsScene);
      d->stickyFocus = enabled;
  }
  bool QGraphicsScene::stickyFocus() const
  {
      Q_D(const QGraphicsScene);
      return d->stickyFocus;
  }
  
  /*!
      Returns the current mouse grabber item, or 0 if no item is currently
      grabbing the mouse. The mouse grabber item is the item that receives all
      mouse events sent to the scene.
  
      An item becomes a mouse grabber when it receives and accepts a
      mouse press event, and it stays the mouse grabber until either of
      the following events occur:
  
      \list
      \o If the item receives a mouse release event when there are no other
      buttons pressed, it loses the mouse grab.
      \o If the item becomes invisible (i.e., someone calls \c {item->setVisible(false)}),
      or if it becomes disabled (i.e., someone calls \c {item->setEnabled(false)}),
      it loses the mouse grab.
      \o If the item is removed from the scene, it loses the mouse grab.
      \endlist
  
      If the item loses its mouse grab, the scene will ignore all mouse events
      until a new item grabs the mouse (i.e., until a new item receives a mouse
      press event).
  */
  QGraphicsItem *QGraphicsScene::mouseGrabberItem() const
  {
      Q_D(const QGraphicsScene);
      return !d->mouseGrabberItems.isEmpty() ? d->mouseGrabberItems.last() : 0;
  }
  
  /*!
      \property QGraphicsScene::backgroundBrush
      \brief the background brush of the scene.
  
      Set this property to changes the scene's background to a different color,
      gradient or texture. The default background brush is Qt::NoBrush. The
      background is drawn before (behind) the items.
  
      Example:
  
      \snippet doc/src/snippets/code/src_gui_graphicsview_qgraphicsscene.cpp 3
  
      QGraphicsScene::render() calls drawBackground() to draw the scene
      background. For more detailed control over how the background is drawn,
      you can reimplement drawBackground() in a subclass of QGraphicsScene.
  */
  QBrush QGraphicsScene::backgroundBrush() const
  {
      Q_D(const QGraphicsScene);
      return d->backgroundBrush;
  }
  void QGraphicsScene::setBackgroundBrush(const QBrush &brush)
  {
      Q_D(QGraphicsScene);
      d->backgroundBrush = brush;
      foreach (QGraphicsView *view, d->views) {
          view->resetCachedContent();
          view->viewport()->update();
      }
      update();
  }
  
  /*!
      \property QGraphicsScene::foregroundBrush
      \brief the foreground brush of the scene.
  
      Change this property to set the scene's foreground to a different
      color, gradient or texture.
  
      The foreground is drawn after (on top of) the items. The default
      foreground brush is Qt::NoBrush ( i.e. the foreground is not
      drawn).
  
      Example:
  
      \snippet doc/src/snippets/code/src_gui_graphicsview_qgraphicsscene.cpp 4
  
      QGraphicsScene::render() calls drawForeground() to draw the scene
      foreground. For more detailed control over how the foreground is
      drawn, you can reimplement the drawForeground() function in a
      QGraphicsScene subclass.
  */
  QBrush QGraphicsScene::foregroundBrush() const
  {
      Q_D(const QGraphicsScene);
      return d->foregroundBrush;
  }
  void QGraphicsScene::setForegroundBrush(const QBrush &brush)
  {
      Q_D(QGraphicsScene);
      d->foregroundBrush = brush;
      foreach (QGraphicsView *view, views())
          view->viewport()->update();
      update();
  }
  
  /*!
      This method is used by input methods to query a set of properties of
      the scene to be able to support complex input method operations as support
      for surrounding text and reconversions.
  
      The \a query parameter specifies which property is queried.
  
      \sa QWidget::inputMethodQuery()
  */
  QVariant QGraphicsScene::inputMethodQuery(Qt::InputMethodQuery query) const
  {
      Q_D(const QGraphicsScene);
      if (!d->focusItem || !(d->focusItem->flags() & QGraphicsItem::ItemAcceptsInputMethod))
          return QVariant();
      const QTransform matrix = d->focusItem->sceneTransform();
      QVariant value = d->focusItem->inputMethodQuery(query);
      if (value.type() == QVariant::RectF)
          value = matrix.mapRect(value.toRectF());
      else if (value.type() == QVariant::PointF)
          value = matrix.map(value.toPointF());
      else if (value.type() == QVariant::Rect)
          value = matrix.mapRect(value.toRect());
      else if (value.type() == QVariant::Point)
          value = matrix.map(value.toPoint());
      return value;
  }
  
  /*!
      \fn void QGraphicsScene::update(const QRectF &rect)
      Schedules a redraw of the area \a rect on the scene.
  
      \sa sceneRect(), changed()
  */
  void QGraphicsScene::update(const QRectF &rect)
  {
      Q_D(QGraphicsScene);
      if (d->updateAll || (rect.isEmpty() && !rect.isNull()))
          return;
  
      // Check if anyone's connected; if not, we can send updates directly to
      // the views. Otherwise or if there are no views, use old behavior.
      bool directUpdates = !(d->isSignalConnected(d->changedSignalIndex)) && !d->views.isEmpty();
      if (rect.isNull()) {
          d->updateAll = true;
          d->updatedRects.clear();
          if (directUpdates) {
              // Update all views.
              for (int i = 0; i < d->views.size(); ++i)
                  d->views.at(i)->d_func()->fullUpdatePending = true;
          }
      } else {
          if (directUpdates) {
              // Update all views.
              for (int i = 0; i < d->views.size(); ++i) {
                  QGraphicsView *view = d->views.at(i);
                  if (view->isTransformed())
                      view->d_func()->updateRectF(view->viewportTransform().mapRect(rect));
                  else
                      view->d_func()->updateRectF(rect);
              }
          } else {
              d->updatedRects << rect;
          }
      }
  
      if (!d->calledEmitUpdated) {
          d->calledEmitUpdated = true;
          QMetaObject::invokeMethod(this, "_q_emitUpdated", Qt::QueuedConnection);
      }
  }
  
  /*!
      \fn void QGraphicsScene::update(qreal x, qreal y, qreal w, qreal h)
      \overload
      \since 4.3
  
      This function is equivalent to calling update(QRectF(\a x, \a y, \a w,
      \a h));
  */
  
  /*!
      Invalidates and schedules a redraw of the \a layers in \a rect on the
      scene. Any cached content in \a layers is unconditionally invalidated and
      redrawn.
  
      You can use this function overload to notify QGraphicsScene of changes to
      the background or the foreground of the scene. This function is commonly
      used for scenes with tile-based backgrounds to notify changes when
      QGraphicsView has enabled
      \l{QGraphicsView::CacheBackground}{CacheBackground}.
  
      Example:
  
      \snippet doc/src/snippets/code/src_gui_graphicsview_qgraphicsscene.cpp 5
  
      Note that QGraphicsView currently supports background caching only (see
      QGraphicsView::CacheBackground). This function is equivalent to calling
      update() if any layer but BackgroundLayer is passed.
  
      \sa QGraphicsView::resetCachedContent()
  */
  void QGraphicsScene::invalidate(const QRectF &rect, SceneLayers layers)
  {
      foreach (QGraphicsView *view, views())
          view->invalidateScene(rect, layers);
      update(rect);
  }
  
  /*!
      \fn void QGraphicsScene::invalidate(qreal x, qreal y, qreal w, qreal h, SceneLayers layers)
      \overload
      \since 4.3
  
      This convenience function is equivalent to calling invalidate(QRectF(\a x, \a
      y, \a w, \a h), \a layers);
  */
  
  /*!
      Returns a list of all the views that display this scene.
  
      \sa QGraphicsView::scene()
  */
  QList <QGraphicsView *> QGraphicsScene::views() const
  {
      Q_D(const QGraphicsScene);
      return d->views;
  }
  
  /*!
      This slot \e advances the scene by one step, by calling
      QGraphicsItem::advance() for all items on the scene. This is done in two
      phases: in the first phase, all items are notified that the scene is about
      to change, and in the second phase all items are notified that they can
      move. In the first phase, QGraphicsItem::advance() is called passing a
      value of 0 as an argument, and 1 is passed in the second phase.
  
      \sa QGraphicsItem::advance(), QGraphicsItemAnimation, QTimeLine
  */
  void QGraphicsScene::advance()
  {
      for (int i = 0; i < 2; ++i) {
          foreach (QGraphicsItem *item, items())
              item->advance(i);
      }
  }
  
  /*!
      Processes the event \a event, and dispatches it to the respective
      event handlers.
  
      In addition to calling the convenience event handlers, this
      function is responsible for converting mouse move events to hover
      events for when there is no mouse grabber item. Hover events are
      delivered directly to items; there is no convenience function for
      them.
  
      Unlike QWidget, QGraphicsScene does not have the convenience functions
      \l{QWidget::}{enterEvent()} and \l{QWidget::}{leaveEvent()}. Use this
      function to obtain those events instead.
  
      \sa contextMenuEvent(), keyPressEvent(), keyReleaseEvent(),
      mousePressEvent(), mouseMoveEvent(), mouseReleaseEvent(),
      mouseDoubleClickEvent(), focusInEvent(), focusOutEvent()
  */
  bool QGraphicsScene::event(QEvent *event)
  {
      Q_D(QGraphicsScene);
  
      switch (event->type()) {
      case QEvent::GraphicsSceneMousePress:
      case QEvent::GraphicsSceneMouseMove:
      case QEvent::GraphicsSceneMouseRelease:
      case QEvent::GraphicsSceneMouseDoubleClick:
      case QEvent::GraphicsSceneHoverEnter:
      case QEvent::GraphicsSceneHoverLeave:
      case QEvent::GraphicsSceneHoverMove:
      case QEvent::TouchBegin:
      case QEvent::TouchUpdate:
      case QEvent::TouchEnd:
          // Reset the under-mouse list to ensure that this event gets fresh
          // item-under-mouse data. Be careful about this list; if people delete
          // items from inside event handlers, this list can quickly end up
          // having stale pointers in it. We need to clear it before dispatching
          // events that use it.
          // ### this should only be cleared if we received a new mouse move event,
          // which relies on us fixing the replay mechanism in QGraphicsView.
          d->cachedItemsUnderMouse.clear();
      default:
          break;
      }
  
      switch (event->type()) {
      case QEvent::GraphicsSceneDragEnter:
          dragEnterEvent(static_cast<QGraphicsSceneDragDropEvent *>(event));
          break;
      case QEvent::GraphicsSceneDragMove:
          dragMoveEvent(static_cast<QGraphicsSceneDragDropEvent *>(event));
          break;
      case QEvent::GraphicsSceneDragLeave:
          dragLeaveEvent(static_cast<QGraphicsSceneDragDropEvent *>(event));
          break;
      case QEvent::GraphicsSceneDrop:
          dropEvent(static_cast<QGraphicsSceneDragDropEvent *>(event));
          break;
      case QEvent::GraphicsSceneContextMenu:
          contextMenuEvent(static_cast<QGraphicsSceneContextMenuEvent *>(event));
          break;
      case QEvent::KeyPress:
          if (!d->focusItem) {
              QKeyEvent *k = static_cast<QKeyEvent *>(event);
              if (k->key() == Qt::Key_Tab || k->key() == Qt::Key_Backtab) {
                  if (!(k->modifiers() & (Qt::ControlModifier | Qt::AltModifier))) {  //### Add MetaModifier?
                      bool res = false;
                      if (k->key() == Qt::Key_Backtab
                          || (k->key() == Qt::Key_Tab && (k->modifiers() & Qt::ShiftModifier))) {
                          res = focusNextPrevChild(false);
                      } else if (k->key() == Qt::Key_Tab) {
                          res = focusNextPrevChild(true);
                      }
                      if (!res)
                          event->ignore();
                      return true;
                  }
              }
          }
          keyPressEvent(static_cast<QKeyEvent *>(event));
          break;
      case QEvent::KeyRelease:
          keyReleaseEvent(static_cast<QKeyEvent *>(event));
          break;
      case QEvent::ShortcutOverride: {
              QGraphicsItem *parent = focusItem();
              while (parent) {
                  d->sendEvent(parent, event);
                  if (event->isAccepted())
                      return true;
                  parent = parent->parentItem();
              }
          }
          return false;
      case QEvent::GraphicsSceneMouseMove:
      {
          QGraphicsSceneMouseEvent *mouseEvent = static_cast<QGraphicsSceneMouseEvent *>(event);
          d->lastSceneMousePos = mouseEvent->scenePos();
          mouseMoveEvent(mouseEvent);
          break;
      }
      case QEvent::GraphicsSceneMousePress:
          mousePressEvent(static_cast<QGraphicsSceneMouseEvent *>(event));
          break;
      case QEvent::GraphicsSceneMouseRelease:
          mouseReleaseEvent(static_cast<QGraphicsSceneMouseEvent *>(event));
          break;
      case QEvent::GraphicsSceneMouseDoubleClick:
          mouseDoubleClickEvent(static_cast<QGraphicsSceneMouseEvent *>(event));
          break;
      case QEvent::GraphicsSceneWheel:
          wheelEvent(static_cast<QGraphicsSceneWheelEvent *>(event));
          break;
      case QEvent::FocusIn:
          focusInEvent(static_cast<QFocusEvent *>(event));
          break;
      case QEvent::FocusOut:
          focusOutEvent(static_cast<QFocusEvent *>(event));
          break;
      case QEvent::GraphicsSceneHoverEnter:
      case QEvent::GraphicsSceneHoverLeave:
      case QEvent::GraphicsSceneHoverMove:
      {
          QGraphicsSceneHoverEvent *hoverEvent = static_cast<QGraphicsSceneHoverEvent *>(event);
          d->lastSceneMousePos = hoverEvent->scenePos();
          d->dispatchHoverEvent(hoverEvent);
          break;
      }
      case QEvent::Leave:
          // hackieshly unpacking the viewport pointer from the leave event.
          d->leaveScene(reinterpret_cast<QWidget *>(event->d));
          break;
      case QEvent::GraphicsSceneHelp:
          helpEvent(static_cast<QGraphicsSceneHelpEvent *>(event));
          break;
      case QEvent::InputMethod:
          inputMethodEvent(static_cast<QInputMethodEvent *>(event));
          break;
      case QEvent::WindowActivate:
          if (!d->activationRefCount++) {
              if (d->lastActivePanel) {
                  // Activate the last panel.
                  d->setActivePanelHelper(d->lastActivePanel, true);
              } else if (d->tabFocusFirst && d->tabFocusFirst->isPanel()) {
                  // Activate the panel of the first item in the tab focus
                  // chain.
                  d->setActivePanelHelper(d->tabFocusFirst, true);
              } else {
                  // Activate all toplevel items.
                  QEvent event(QEvent::WindowActivate);
                  foreach (QGraphicsItem *item, items()) {
                      if (item->isVisible() && !item->isPanel() && !item->parentItem())
                          sendEvent(item, &event);
                  }
              }
          }
          break;
      case QEvent::WindowDeactivate:
          if (d->activationRefCount > 0)
              --d->activationRefCount;
          if (!d->activationRefCount) {
              if (d->activePanel) {
                  // Deactivate the active panel (but keep it so we can
                  // reactivate it later).
                  QGraphicsItem *lastActivePanel = d->activePanel;
                  d->setActivePanelHelper(0, true);
                  d->lastActivePanel = lastActivePanel;
              } else {
                  // Activate all toplevel items.
                  QEvent event(QEvent::WindowDeactivate);
                  foreach (QGraphicsItem *item, items()) {
                      if (item->isVisible() && !item->isPanel() && !item->parentItem())
                          sendEvent(item, &event);
                  }
              }
          }
          break;
      case QEvent::ApplicationFontChange: {
          // Resolve the existing scene font.
          d->resolveFont();
          break;
      }
      case QEvent::FontChange:
          // Update the entire scene when the font changes.
          update();
          break;
      case QEvent::ApplicationPaletteChange: {
          // Resolve the existing scene palette.
          d->resolvePalette();
          break;
      }
      case QEvent::PaletteChange:
          // Update the entire scene when the palette changes.
          update();
          break;
      case QEvent::StyleChange:
          // Reresolve all widgets' styles. Update all top-level widgets'
          // geometries that do not have an explicit style set.
          update();
          break;
      case QEvent::TouchBegin:
      case QEvent::TouchUpdate:
      case QEvent::TouchEnd:
          d->touchEventHandler(static_cast<QTouchEvent *>(event));
          break;
  #ifndef QT_NO_GESTURES
      case QEvent::Gesture:
      case QEvent::GestureOverride:
          d->gestureEventHandler(static_cast<QGestureEvent *>(event));
          break;
  #endif // QT_NO_GESTURES
      default:
          return QObject::event(event);
      }
      return true;
  }
  
  /*!
      \reimp
  
      QGraphicsScene filters QApplication's events to detect palette and font
      changes.
  */
  bool QGraphicsScene::eventFilter(QObject *watched, QEvent *event)
  {
      if (watched != qApp)
          return false;
  
      switch (event->type()) {
      case QEvent::ApplicationPaletteChange:
          QApplication::postEvent(this, new QEvent(QEvent::ApplicationPaletteChange));
          break;
      case QEvent::ApplicationFontChange:
          QApplication::postEvent(this, new QEvent(QEvent::ApplicationFontChange));
          break;
      default:
          break;
      }
      return false;
  }
  
  /*!
      This event handler, for event \a contextMenuEvent, can be reimplemented in
      a subclass to receive context menu events. The default implementation
      forwards the event to the topmost item that accepts context menu events at
      the position of the event. If no items accept context menu events at this
      position, the event is ignored.
  
      \sa QGraphicsItem::contextMenuEvent()
  */
  void QGraphicsScene::contextMenuEvent(QGraphicsSceneContextMenuEvent *contextMenuEvent)
  {
      Q_D(QGraphicsScene);
      // Ignore by default.
      contextMenuEvent->ignore();
  
      // Send the event to all items at this position until one item accepts the
      // event.
      foreach (QGraphicsItem *item, d->itemsAtPosition(contextMenuEvent->screenPos(),
                                                       contextMenuEvent->scenePos(),
                                                       contextMenuEvent->widget())) {
          contextMenuEvent->setPos(item->d_ptr->genericMapFromScene(contextMenuEvent->scenePos(),
                                                                    contextMenuEvent->widget()));
          contextMenuEvent->accept();
          if (!d->sendEvent(item, contextMenuEvent))
              break;
  
          if (contextMenuEvent->isAccepted())
              break;
      }
  }
  
  /*!
      This event handler, for event \a event, can be reimplemented in a subclass
      to receive drag enter events for the scene.
  
      The default implementation accepts the event and prepares the scene to
      accept drag move events.
  
      \sa QGraphicsItem::dragEnterEvent(), dragMoveEvent(), dragLeaveEvent(),
      dropEvent()
  */
  void QGraphicsScene::dragEnterEvent(QGraphicsSceneDragDropEvent *event)
  {
      Q_D(QGraphicsScene);
      d->dragDropItem = 0;
      d->lastDropAction = Qt::IgnoreAction;
      event->accept();
  }
  
  /*!
      This event handler, for event \a event, can be reimplemented in a subclass
      to receive drag move events for the scene.
  
      \sa QGraphicsItem::dragMoveEvent(), dragEnterEvent(), dragLeaveEvent(),
      dropEvent()
  */
  void QGraphicsScene::dragMoveEvent(QGraphicsSceneDragDropEvent *event)
  {
      Q_D(QGraphicsScene);
      event->ignore();
  
      if (!d->mouseGrabberItems.isEmpty()) {
          // Mouse grabbers that start drag events lose the mouse grab.
          d->clearMouseGrabber();
          d->mouseGrabberButtonDownPos.clear();
          d->mouseGrabberButtonDownScenePos.clear();
          d->mouseGrabberButtonDownScreenPos.clear();
      }
  
      bool eventDelivered = false;
  
      // Find the topmost enabled items under the cursor. They are all
      // candidates for accepting drag & drop events.
      foreach (QGraphicsItem *item, d->itemsAtPosition(event->screenPos(),
                                                       event->scenePos(),
                                                       event->widget())) {
          if (!item->isEnabled() || !item->acceptDrops())
              continue;
  
          if (item != d->dragDropItem) {
              // Enter the new drag drop item. If it accepts the event, we send
              // the leave to the parent item.
              QGraphicsSceneDragDropEvent dragEnter(QEvent::GraphicsSceneDragEnter);
              d->cloneDragDropEvent(&dragEnter, event);
              dragEnter.setDropAction(event->proposedAction());
              d->sendDragDropEvent(item, &dragEnter);
              event->setAccepted(dragEnter.isAccepted());
              event->setDropAction(dragEnter.dropAction());
              if (!event->isAccepted()) {
                  // Propagate to the item under
                  continue;
              }
  
              d->lastDropAction = event->dropAction();
  
              if (d->dragDropItem) {
                  // Leave the last drag drop item. A perfect implementation
                  // would set the position of this event to the point where
                  // this event and the last event intersect with the item's
                  // shape, but that's not easy to do. :-)
                  QGraphicsSceneDragDropEvent dragLeave(QEvent::GraphicsSceneDragLeave);
                  d->cloneDragDropEvent(&dragLeave, event);
                  d->sendDragDropEvent(d->dragDropItem, &dragLeave);
              }
  
              // We've got a new drag & drop item
              d->dragDropItem = item;
          }
  
          // Send the move event.
          event->setDropAction(d->lastDropAction);
          event->accept();
          d->sendDragDropEvent(item, event);
          if (event->isAccepted())
              d->lastDropAction = event->dropAction();
          eventDelivered = true;
          break;
      }
  
      if (!eventDelivered) {
          if (d->dragDropItem) {
              // Leave the last drag drop item
              QGraphicsSceneDragDropEvent dragLeave(QEvent::GraphicsSceneDragLeave);
              d->cloneDragDropEvent(&dragLeave, event);
              d->sendDragDropEvent(d->dragDropItem, &dragLeave);
              d->dragDropItem = 0;
          }
          // Propagate
          event->setDropAction(Qt::IgnoreAction);
      }
  }
  
  /*!
      This event handler, for event \a event, can be reimplemented in a subclass
      to receive drag leave events for the scene.
  
      \sa QGraphicsItem::dragLeaveEvent(), dragEnterEvent(), dragMoveEvent(),
      dropEvent()
  */
  void QGraphicsScene::dragLeaveEvent(QGraphicsSceneDragDropEvent *event)
  {
      Q_D(QGraphicsScene);
      if (d->dragDropItem) {
          // Leave the last drag drop item
          d->sendDragDropEvent(d->dragDropItem, event);
          d->dragDropItem = 0;
      }
  }
  
  /*!
      This event handler, for event \a event, can be reimplemented in a subclass
      to receive drop events for the scene.
  
      \sa QGraphicsItem::dropEvent(), dragEnterEvent(), dragMoveEvent(),
      dragLeaveEvent()
  */
  void QGraphicsScene::dropEvent(QGraphicsSceneDragDropEvent *event)
  {
      Q_UNUSED(event);
      Q_D(QGraphicsScene);
      if (d->dragDropItem) {
          // Drop on the last drag drop item
          d->sendDragDropEvent(d->dragDropItem, event);
          d->dragDropItem = 0;
      }
  }
  
  /*!
      This event handler, for event \a focusEvent, can be reimplemented in a
      subclass to receive focus in events.
  
      The default implementation sets focus on the scene, and then on the last
      focus item.
  
      \sa QGraphicsItem::focusOutEvent()
  */
  void QGraphicsScene::focusInEvent(QFocusEvent *focusEvent)
  {
      Q_D(QGraphicsScene);
  
      d->hasFocus = true;
      switch (focusEvent->reason()) {
      case Qt::TabFocusReason:
          if (!focusNextPrevChild(true))
              focusEvent->ignore();
          break;
      case Qt::BacktabFocusReason:
          if (!focusNextPrevChild(false))
              focusEvent->ignore();
          break;
      default:
          if (d->passiveFocusItem) {
              // Set focus on the last focus item
              setFocusItem(d->passiveFocusItem, focusEvent->reason());
          }
          break;
      }
  }
  
  /*!
      This event handler, for event \a focusEvent, can be reimplemented in a
      subclass to receive focus out events.
  
      The default implementation removes focus from any focus item, then removes
      focus from the scene.
  
      \sa QGraphicsItem::focusInEvent()
  */
  void QGraphicsScene::focusOutEvent(QFocusEvent *focusEvent)
  {
      Q_D(QGraphicsScene);
      d->hasFocus = false;
      d->passiveFocusItem = d->focusItem;
      setFocusItem(0, focusEvent->reason());
  
      // Remove all popups when the scene loses focus.
      if (!d->popupWidgets.isEmpty())
          d->removePopup(d->popupWidgets.first());
  }
  
  /*!
      This event handler, for event \a helpEvent, can be
      reimplemented in a subclass to receive help events. The events
      are of type QEvent::ToolTip, which are created when a tooltip is
      requested.
  
      The default implementation shows the tooltip of the topmost
      item, i.e., the item with the highest z-value, at the mouse
      cursor position. If no item has a tooltip set, this function
      does nothing.
  
     \sa QGraphicsItem::toolTip(), QGraphicsSceneHelpEvent
  */
  void QGraphicsScene::helpEvent(QGraphicsSceneHelpEvent *helpEvent)
  {
  #ifdef QT_NO_TOOLTIP
      Q_UNUSED(helpEvent);
  #else
      // Find the first item that does tooltips
      Q_D(QGraphicsScene);
      QList<QGraphicsItem *> itemsAtPos = d->itemsAtPosition(helpEvent->screenPos(),
                                                             helpEvent->scenePos(),
                                                             helpEvent->widget());
      QGraphicsItem *toolTipItem = 0;
      for (int i = 0; i < itemsAtPos.size(); ++i) {
          QGraphicsItem *tmp = itemsAtPos.at(i);
          if (tmp->d_func()->isProxyWidget()) {
              // if the item is a proxy widget, the event is forwarded to it
              sendEvent(tmp, helpEvent);
              if (helpEvent->isAccepted())
                  return;
          }
          if (!tmp->toolTip().isEmpty()) {
              toolTipItem = tmp;
              break;
          }
      }
  
      // Show or hide the tooltip
      QString text;
      QPoint point;
      if (toolTipItem && !toolTipItem->toolTip().isEmpty()) {
          text = toolTipItem->toolTip();
          point = helpEvent->screenPos();
      }
      QToolTip::showText(point, text, helpEvent->widget());
      helpEvent->setAccepted(!text.isEmpty());
  #endif
  }
  
  bool QGraphicsScenePrivate::itemAcceptsHoverEvents_helper(const QGraphicsItem *item) const
  {
      return (item->d_ptr->acceptsHover
              || (item->d_ptr->isWidget
                  && static_cast<const QGraphicsWidget *>(item)->d_func()->hasDecoration()))
             && !item->isBlockedByModalPanel();
  }
  
  /*!
      This event handler, for event \a hoverEvent, can be reimplemented in a
      subclass to receive hover enter events. The default implementation
      forwards the event to the topmost item that accepts hover events at the
      scene position from the event.
  
      \sa QGraphicsItem::hoverEvent(), QGraphicsItem::setAcceptHoverEvents()
  */
  bool QGraphicsScenePrivate::dispatchHoverEvent(QGraphicsSceneHoverEvent *hoverEvent)
  {
      if (allItemsIgnoreHoverEvents)
          return false;
  
      // Find the first item that accepts hover events, reusing earlier
      // calculated data is possible.
      if (cachedItemsUnderMouse.isEmpty()) {
          cachedItemsUnderMouse = itemsAtPosition(hoverEvent->screenPos(),
                                                  hoverEvent->scenePos(),
                                                  hoverEvent->widget());
      }
  
      QGraphicsItem *item = 0;
      for (int i = 0; i < cachedItemsUnderMouse.size(); ++i) {
          QGraphicsItem *tmp = cachedItemsUnderMouse.at(i);
          if (itemAcceptsHoverEvents_helper(tmp)) {
              item = tmp;
              break;
          }
      }
  
      // Find the common ancestor item for the new topmost hoverItem and the
      // last item in the hoverItem list.
      QGraphicsItem *commonAncestorItem = (item && !hoverItems.isEmpty()) ? item->commonAncestorItem(hoverItems.last()) : 0;
      while (commonAncestorItem && !itemAcceptsHoverEvents_helper(commonAncestorItem))
          commonAncestorItem = commonAncestorItem->parentItem();
      if (commonAncestorItem && commonAncestorItem->panel() != item->panel()) {
          // The common ancestor isn't in the same panel as the two hovered
          // items.
          commonAncestorItem = 0;
      }
  
      // Check if the common ancestor item is known.
      int index = commonAncestorItem ? hoverItems.indexOf(commonAncestorItem) : -1;
      // Send hover leaves to any existing hovered children of the common
      // ancestor item.
      for (int i = hoverItems.size() - 1; i > index; --i) {
          QGraphicsItem *lastItem = hoverItems.takeLast();
          if (itemAcceptsHoverEvents_helper(lastItem))
              sendHoverEvent(QEvent::GraphicsSceneHoverLeave, lastItem, hoverEvent);
      }
  
      // Item is a child of a known item. Generate enter events for the
      // missing links.
      QList<QGraphicsItem *> parents;
      QGraphicsItem *parent = item;
      while (parent && parent != commonAncestorItem) {
          parents.prepend(parent);
          if (parent->isPanel()) {
              // Stop at the panel - we don't deliver beyond this point.
              break;
          }
          parent = parent->parentItem();
      }
      for (int i = 0; i < parents.size(); ++i) {
          parent = parents.at(i);
          hoverItems << parent;
          if (itemAcceptsHoverEvents_helper(parent))
              sendHoverEvent(QEvent::GraphicsSceneHoverEnter, parent, hoverEvent);
      }
  
      // Generate a move event for the item itself
      if (item
          && !hoverItems.isEmpty()
          && item == hoverItems.last()) {
          sendHoverEvent(QEvent::GraphicsSceneHoverMove, item, hoverEvent);
          return true;
      }
      return false;
  }
  
  /*!
      \internal
  
      Handles all actions necessary to clean up the scene when the mouse leaves
      the view.
  */
  void QGraphicsScenePrivate::leaveScene(QWidget *viewport)
  {
  #ifndef QT_NO_TOOLTIP
      QToolTip::hideText();
  #endif
      QGraphicsView *view = qobject_cast<QGraphicsView *>(viewport->parent());
      // Send HoverLeave events to all existing hover items, topmost first.
      QGraphicsSceneHoverEvent hoverEvent;
      hoverEvent.setWidget(viewport);
  
      if (view) {
          QPoint cursorPos = QCursor::pos();
          hoverEvent.setScenePos(view->mapToScene(viewport->mapFromGlobal(cursorPos)));
          hoverEvent.setLastScenePos(hoverEvent.scenePos());
          hoverEvent.setScreenPos(cursorPos);
          hoverEvent.setLastScreenPos(hoverEvent.screenPos());
      }
  
      while (!hoverItems.isEmpty()) {
          QGraphicsItem *lastItem = hoverItems.takeLast();
          if (itemAcceptsHoverEvents_helper(lastItem))
              sendHoverEvent(QEvent::GraphicsSceneHoverLeave, lastItem, &hoverEvent);
      }
  }
  
  /*!
      This event handler, for event \a keyEvent, can be reimplemented in a
      subclass to receive keypress events. The default implementation forwards
      the event to current focus item.
  
      \sa QGraphicsItem::keyPressEvent(), focusItem()
  */
  void QGraphicsScene::keyPressEvent(QKeyEvent *keyEvent)
  {
      // ### Merge this function with keyReleaseEvent; they are identical
      // ### (except this comment).
      Q_D(QGraphicsScene);
      QGraphicsItem *item = !d->keyboardGrabberItems.isEmpty() ? d->keyboardGrabberItems.last() : 0;
      if (!item)
          item = focusItem();
      if (item) {
          QGraphicsItem *p = item;
          do {
              // Accept the event by default
              keyEvent->accept();
              // Send it; QGraphicsItem::keyPressEvent ignores it.  If the event
              // is filtered out, stop propagating it.
              if (p->isBlockedByModalPanel())
                  break;
              if (!d->sendEvent(p, keyEvent))
                  break;
          } while (!keyEvent->isAccepted() && !p->isPanel() && (p = p->parentItem()));
      } else {
          keyEvent->ignore();
      }
  }
  
  /*!
      This event handler, for event \a keyEvent, can be reimplemented in a
      subclass to receive key release events. The default implementation
      forwards the event to current focus item.
  
      \sa QGraphicsItem::keyReleaseEvent(), focusItem()
  */
  void QGraphicsScene::keyReleaseEvent(QKeyEvent *keyEvent)
  {
      // ### Merge this function with keyPressEvent; they are identical (except
      // ### this comment).
      Q_D(QGraphicsScene);
      QGraphicsItem *item = !d->keyboardGrabberItems.isEmpty() ? d->keyboardGrabberItems.last() : 0;
      if (!item)
          item = focusItem();
      if (item) {
          QGraphicsItem *p = item;
          do {
              // Accept the event by default
              keyEvent->accept();
              // Send it; QGraphicsItem::keyPressEvent ignores it.  If the event
              // is filtered out, stop propagating it.
              if (p->isBlockedByModalPanel())
                  break;
              if (!d->sendEvent(p, keyEvent))
                  break;
          } while (!keyEvent->isAccepted() && !p->isPanel() && (p = p->parentItem()));
      } else {
          keyEvent->ignore();
      }
  }
  
  /*!
      This event handler, for event \a mouseEvent, can be reimplemented
      in a subclass to receive mouse press events for the scene.
  
      The default implementation depends on the state of the scene. If
      there is a mouse grabber item, then the event is sent to the mouse
      grabber. Otherwise, it is forwarded to the topmost item that
      accepts mouse events at the scene position from the event, and
      that item promptly becomes the mouse grabber item.
  
      If there is no item at the given position on the scene, the
      selection area is reset, any focus item loses its input focus, and
      the event is then ignored.
  
      \sa QGraphicsItem::mousePressEvent(),
      QGraphicsItem::setAcceptedMouseButtons()
  */
  void QGraphicsScene::mousePressEvent(QGraphicsSceneMouseEvent *mouseEvent)
  {
      Q_D(QGraphicsScene);
      if (d->mouseGrabberItems.isEmpty()) {
          // Dispatch hover events
          QGraphicsSceneHoverEvent hover;
          _q_hoverFromMouseEvent(&hover, mouseEvent);
          d->dispatchHoverEvent(&hover);
      }
  
      d->mousePressEventHandler(mouseEvent);
  }
  
  /*!
      This event handler, for event \a mouseEvent, can be reimplemented
      in a subclass to receive mouse move events for the scene.
  
      The default implementation depends on the mouse grabber state. If there is
      a mouse grabber item, the event is sent to the mouse grabber.  If there
      are any items that accept hover events at the current position, the event
      is translated into a hover event and accepted; otherwise it's ignored.
  
      \sa QGraphicsItem::mousePressEvent(), QGraphicsItem::mouseReleaseEvent(),
      QGraphicsItem::mouseDoubleClickEvent(), QGraphicsItem::setAcceptedMouseButtons()
  */
  void QGraphicsScene::mouseMoveEvent(QGraphicsSceneMouseEvent *mouseEvent)
  {
      Q_D(QGraphicsScene);
      if (d->mouseGrabberItems.isEmpty()) {
          if (mouseEvent->buttons())
              return;
          QGraphicsSceneHoverEvent hover;
          _q_hoverFromMouseEvent(&hover, mouseEvent);
          mouseEvent->setAccepted(d->dispatchHoverEvent(&hover));
          return;
      }
  
      // Forward the event to the mouse grabber
      d->sendMouseEvent(mouseEvent);
      mouseEvent->accept();
  }
  
  /*!
      This event handler, for event \a mouseEvent, can be reimplemented
      in a subclass to receive mouse release events for the scene.
  
      The default implementation depends on the mouse grabber state.  If
      there is no mouse grabber, the event is ignored.  Otherwise, if
      there is a mouse grabber item, the event is sent to the mouse
      grabber. If this mouse release represents the last pressed button
      on the mouse, the mouse grabber item then loses the mouse grab.
  
      \sa QGraphicsItem::mousePressEvent(), QGraphicsItem::mouseMoveEvent(),
      QGraphicsItem::mouseDoubleClickEvent(), QGraphicsItem::setAcceptedMouseButtons()
  */
  void QGraphicsScene::mouseReleaseEvent(QGraphicsSceneMouseEvent *mouseEvent)
  {
      Q_D(QGraphicsScene);
      if (d->mouseGrabberItems.isEmpty()) {
          mouseEvent->ignore();
          return;
      }
  
      // Forward the event to the mouse grabber
      d->sendMouseEvent(mouseEvent);
      mouseEvent->accept();
  
      // Reset the mouse grabber when the last mouse button has been released.
      if (!mouseEvent->buttons()) {
          if (!d->mouseGrabberItems.isEmpty()) {
              d->lastMouseGrabberItem = d->mouseGrabberItems.last();
              if (d->lastMouseGrabberItemHasImplicitMouseGrab)
                  d->mouseGrabberItems.last()->ungrabMouse();
          } else {
              d->lastMouseGrabberItem = 0;
          }
  
          // Generate a hoverevent
          QGraphicsSceneHoverEvent hoverEvent;
          _q_hoverFromMouseEvent(&hoverEvent, mouseEvent);
          d->dispatchHoverEvent(&hoverEvent);
      }
  }
  
  /*!
      This event handler, for event \a mouseEvent, can be reimplemented
      in a subclass to receive mouse doubleclick events for the scene.
  
      If someone doubleclicks on the scene, the scene will first receive
      a mouse press event, followed by a release event (i.e., a click),
      then a doubleclick event, and finally a release event. If the
      doubleclick event is delivered to a different item than the one
      that received the first press and release, it will be delivered as
      a press event. However, tripleclick events are not delivered as
      doubleclick events in this case.
  
      The default implementation is similar to mousePressEvent().
  
      \sa QGraphicsItem::mousePressEvent(), QGraphicsItem::mouseMoveEvent(),
      QGraphicsItem::mouseReleaseEvent(), QGraphicsItem::setAcceptedMouseButtons()
  */
  void QGraphicsScene::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *mouseEvent)
  {
      Q_D(QGraphicsScene);
      d->mousePressEventHandler(mouseEvent);
  }
  
  /*!
      This event handler, for event \a wheelEvent, can be reimplemented in a
      subclass to receive mouse wheel events for the scene.
  
      By default, the event is delivered to the topmost visible item under the
      cursor. If ignored, the event propagates to the item beneath, and again
      until the event is accepted, or it reaches the scene. If no items accept
      the event, it is ignored.
  
      \sa QGraphicsItem::wheelEvent()
  */
  void QGraphicsScene::wheelEvent(QGraphicsSceneWheelEvent *wheelEvent)
  {
      Q_D(QGraphicsScene);
      QList<QGraphicsItem *> wheelCandidates = d->itemsAtPosition(wheelEvent->screenPos(),
                                                                  wheelEvent->scenePos(),
                                                                  wheelEvent->widget());
  
  #ifdef Q_WS_MAC
      // On Mac, ignore the event if the first item under the mouse is not the last opened
      // popup (or one of its descendant)
      if (!d->popupWidgets.isEmpty() && !wheelCandidates.isEmpty() && wheelCandidates.first() != d->popupWidgets.back() && !d->popupWidgets.back()->isAncestorOf(wheelCandidates.first())) {
          wheelEvent->accept();
          return;
      }
  #else
      // Find the first popup under the mouse (including the popup's descendants) starting from the last.
      // Remove all popups after the one found, or all or them if no popup is under the mouse.
      // Then continue with the event.
      QList<QGraphicsWidget *>::const_iterator iter = d->popupWidgets.end();
      while (--iter >= d->popupWidgets.begin() && !wheelCandidates.isEmpty()) {
          if (wheelCandidates.first() == *iter || (*iter)->isAncestorOf(wheelCandidates.first()))
              break;
          d->removePopup(*iter);
      }
  #endif
  
      bool hasSetFocus = false;
      foreach (QGraphicsItem *item, wheelCandidates) {
          if (!hasSetFocus && item->isEnabled()
              && ((item->flags() & QGraphicsItem::ItemIsFocusable) && item->d_ptr->mouseSetsFocus)) {
              if (item->isWidget() && static_cast<QGraphicsWidget *>(item)->focusPolicy() == Qt::WheelFocus) {
                  hasSetFocus = true;
                  if (item != focusItem())
                      setFocusItem(item, Qt::MouseFocusReason);
              }
          }
  
          wheelEvent->setPos(item->d_ptr->genericMapFromScene(wheelEvent->scenePos(),
                                                              wheelEvent->widget()));
          wheelEvent->accept();
          bool isPanel = item->isPanel();
          d->sendEvent(item, wheelEvent);
          if (isPanel || wheelEvent->isAccepted())
              break;
      }
  }
  
  /*!
      This event handler, for event \a event, can be reimplemented in a
      subclass to receive input method events for the scene.
  
      The default implementation forwards the event to the focusItem().
      If no item currently has focus or the current focus item does not
      accept input methods, this function does nothing.
  
      \sa QGraphicsItem::inputMethodEvent()
  */
  void QGraphicsScene::inputMethodEvent(QInputMethodEvent *event)
  {
      Q_D(QGraphicsScene);
      if (d->focusItem && (d->focusItem->flags() & QGraphicsItem::ItemAcceptsInputMethod))
          d->sendEvent(d->focusItem, event);
  }
  
  /*!
      Draws the background of the scene using \a painter, before any items and
      the foreground are drawn. Reimplement this function to provide a custom
      background for the scene.
  
      All painting is done in \e scene coordinates. The \a rect
      parameter is the exposed rectangle.
  
      If all you want is to define a color, texture, or gradient for the
      background, you can call setBackgroundBrush() instead.
  
      \sa drawForeground(), drawItems()
  */
  void QGraphicsScene::drawBackground(QPainter *painter, const QRectF &rect)
  {
      Q_D(QGraphicsScene);
  
      if (d->backgroundBrush.style() != Qt::NoBrush) {
          if (d->painterStateProtection)
              painter->save();
          painter->setBrushOrigin(0, 0);
          painter->fillRect(rect, backgroundBrush());
          if (d->painterStateProtection)
              painter->restore();
      }
  }
  
  /*!
      Draws the foreground of the scene using \a painter, after the background
      and all items have been drawn. Reimplement this function to provide a
      custom foreground for the scene.
  
      All painting is done in \e scene coordinates. The \a rect
      parameter is the exposed rectangle.
  
      If all you want is to define a color, texture or gradient for the
      foreground, you can call setForegroundBrush() instead.
  
      \sa drawBackground(), drawItems()
  */
  void QGraphicsScene::drawForeground(QPainter *painter, const QRectF &rect)
  {
      Q_D(QGraphicsScene);
  
      if (d->foregroundBrush.style() != Qt::NoBrush) {
          if (d->painterStateProtection)
              painter->save();
          painter->setBrushOrigin(0, 0);
          painter->fillRect(rect, foregroundBrush());
          if (d->painterStateProtection)
              painter->restore();
      }
  }
  
  static void _q_paintItem(QGraphicsItem *item, QPainter *painter,
                           const QStyleOptionGraphicsItem *option, QWidget *widget,
                           bool useWindowOpacity, bool painterStateProtection)
  {
      if (!item->isWidget()) {
          item->paint(painter, option, widget);
          return;
      }
      QGraphicsWidget *widgetItem = static_cast<QGraphicsWidget *>(item);
      QGraphicsProxyWidget *proxy = qobject_cast<QGraphicsProxyWidget *>(widgetItem);
      const qreal windowOpacity = (proxy && proxy->widget() && useWindowOpacity)
                                  ? proxy->widget()->windowOpacity() : qreal(1.0);
      const qreal oldPainterOpacity = painter->opacity();
  
      if (qFuzzyIsNull(windowOpacity))
          return;
      // Set new painter opacity.
      if (windowOpacity < 1.0)
          painter->setOpacity(oldPainterOpacity * windowOpacity);
  
      // set layoutdirection on the painter
      Qt::LayoutDirection oldLayoutDirection = painter->layoutDirection();
      painter->setLayoutDirection(widgetItem->layoutDirection());
  
      if (widgetItem->isWindow() && widgetItem->windowType() != Qt::Popup && widgetItem->windowType() != Qt::ToolTip
          && !(widgetItem->windowFlags() & Qt::FramelessWindowHint)) {
          if (painterStateProtection)
              painter->save();
          widgetItem->paintWindowFrame(painter, option, widget);
          if (painterStateProtection)
              painter->restore();
      } else if (widgetItem->autoFillBackground()) {
          painter->fillRect(option->exposedRect, widgetItem->palette().window());
      }
  
      widgetItem->paint(painter, option, widget);
  
      // Restore layoutdirection on the painter.
      painter->setLayoutDirection(oldLayoutDirection);
      // Restore painter opacity.
      if (windowOpacity < 1.0)
          painter->setOpacity(oldPainterOpacity);
  }
  
  static void _q_paintIntoCache(QPixmap *pix, QGraphicsItem *item, const QRegion &pixmapExposed,
                                const QTransform &itemToPixmap, QPainter::RenderHints renderHints,
                                const QStyleOptionGraphicsItem *option, bool painterStateProtection)
  {
      QPixmap subPix;
      QPainter pixmapPainter;
      QRect br = pixmapExposed.boundingRect();
  
      // Don't use subpixmap if we get a full update.
      if (pixmapExposed.isEmpty() || (pixmapExposed.rectCount() == 1 && br.contains(pix->rect()))) {
          pix->fill(Qt::transparent);
          pixmapPainter.begin(pix);
      } else {
          subPix = QPixmap(br.size());
          subPix.fill(Qt::transparent);
          pixmapPainter.begin(&subPix);
          pixmapPainter.translate(-br.topLeft());
          if (!pixmapExposed.isEmpty()) {
              // Applied to subPix; paint is adjusted to the coordinate space is
              // correct.
              pixmapPainter.setClipRegion(pixmapExposed);
          }
      }
  
      pixmapPainter.setRenderHints(pixmapPainter.renderHints(), false);
      pixmapPainter.setRenderHints(renderHints, true);
      pixmapPainter.setWorldTransform(itemToPixmap, true);
  
      // Render.
      _q_paintItem(item, &pixmapPainter, option, 0, false, painterStateProtection);
      pixmapPainter.end();
  
      if (!subPix.isNull()) {
          // Blit the subpixmap into the main pixmap.
          pixmapPainter.begin(pix);
          pixmapPainter.setCompositionMode(QPainter::CompositionMode_Source);
          pixmapPainter.setClipRegion(pixmapExposed);
          pixmapPainter.drawPixmap(br.topLeft(), subPix);
          pixmapPainter.end();
      }
  }
  
  // Copied from qpaintengine_vg.cpp
  // Returns true for 90, 180, and 270 degree rotations.
  static inline bool transformIsSimple(const QTransform& transform)
  {
      QTransform::TransformationType type = transform.type();
      if (type <= QTransform::TxScale) {
          return true;
      } else if (type == QTransform::TxRotate) {
          // Check for 90, and 270 degree rotations.
          qreal m11 = transform.m11();
          qreal m12 = transform.m12();
          qreal m21 = transform.m21();
          qreal m22 = transform.m22();
          if (m11 == 0.0f && m22 == 0.0f) {
              if (m12 == 1.0f && m21 == -1.0f)
                  return true; // 90 degrees.
              else if (m12 == -1.0f && m21 == 1.0f)
                  return true; // 270 degrees.
              else if (m12 == -1.0f && m21 == -1.0f)
                  return true; // 90 degrees inverted y.
              else if (m12 == 1.0f && m21 == 1.0f)
                  return true; // 270 degrees inverted y.
          }
      }
      return false;
  }
  
  /*!
      \internal
  
      Draws items directly, or using cache.
  */
  void QGraphicsScenePrivate::drawItemHelper(QGraphicsItem *item, QPainter *painter,
                                             const QStyleOptionGraphicsItem *option, QWidget *widget,
                                             bool painterStateProtection)
  {
      QGraphicsItemPrivate *itemd = item->d_ptr.data();
      QGraphicsItem::CacheMode cacheMode = QGraphicsItem::CacheMode(itemd->cacheMode);
  
      // Render directly, using no cache.
      if (cacheMode == QGraphicsItem::NoCache
  #ifdef Q_WS_X11
          || !X11->use_xrender
  #endif
          ) {
          _q_paintItem(static_cast<QGraphicsWidget *>(item), painter, option, widget, true, painterStateProtection);
          return;
      }
  
      const qreal oldPainterOpacity = painter->opacity();
      qreal newPainterOpacity = oldPainterOpacity;
      QGraphicsProxyWidget *proxy = item->isWidget() ? qobject_cast<QGraphicsProxyWidget *>(static_cast<QGraphicsWidget *>(item)) : 0;
      if (proxy && proxy->widget()) {
          const qreal windowOpacity = proxy->widget()->windowOpacity();
          if (windowOpacity < 1.0)
              newPainterOpacity *= windowOpacity;
      }
  
      // Item's (local) bounding rect
      QRectF brect = item->boundingRect();
      QRectF adjustedBrect(brect);
      _q_adjustRect(&adjustedBrect);
      if (adjustedBrect.isEmpty())
          return;
  
      // Fetch the off-screen transparent buffer and exposed area info.
      QPixmapCache::Key pixmapKey;
      QPixmap pix;
      bool pixmapFound;
      QGraphicsItemCache *itemCache = itemd->extraItemCache();
      if (cacheMode == QGraphicsItem::ItemCoordinateCache) {
          pixmapKey = itemCache->key;
      } else {
          pixmapKey = itemCache->deviceData.value(widget).key;
      }
  
      // Find pixmap in cache.
      pixmapFound = QPixmapCache::find(pixmapKey, &pix);
  
      // Render using item coordinate cache mode.
      if (cacheMode == QGraphicsItem::ItemCoordinateCache) {
          QSize pixmapSize;
          bool fixedCacheSize = false;
          QRect br = brect.toAlignedRect();
          if ((fixedCacheSize = itemCache->fixedSize.isValid())) {
              pixmapSize = itemCache->fixedSize;
          } else {
              pixmapSize = br.size();
          }
  
          // Create or recreate the pixmap.
          int adjust = itemCache->fixedSize.isValid() ? 0 : 2;
          QSize adjustSize(adjust*2, adjust*2);
          br.adjust(-adjust, -adjust, adjust, adjust);
          if (pix.isNull() || (!fixedCacheSize && (pixmapSize + adjustSize) != pix.size())) {
              pix = QPixmap(pixmapSize + adjustSize);
              itemCache->boundingRect = br;
              itemCache->exposed.clear();
              itemCache->allExposed = true;
          } else if (itemCache->boundingRect != br) {
              itemCache->boundingRect = br;
              itemCache->exposed.clear();
              itemCache->allExposed = true;
          }
  
          // Redraw any newly exposed areas.
          if (itemCache->allExposed || !itemCache->exposed.isEmpty()) {
  
              //We know that we will modify the pixmap, removing it from the cache
              //will detach the one we have and avoid a deep copy
              if (pixmapFound)
                  QPixmapCache::remove(pixmapKey);
  
              // Fit the item's bounding rect into the pixmap's coordinates.
              QTransform itemToPixmap;
              if (fixedCacheSize) {
                  const QPointF scale(pixmapSize.width() / brect.width(), pixmapSize.height() / brect.height());
                  itemToPixmap.scale(scale.x(), scale.y());
              }
              itemToPixmap.translate(-br.x(), -br.y());
  
              // Generate the item's exposedRect and map its list of expose
              // rects to device coordinates.
              styleOptionTmp = *option;
              QRegion pixmapExposed;
              QRectF exposedRect;
              if (!itemCache->allExposed) {
                  for (int i = 0; i < itemCache->exposed.size(); ++i) {
                      QRectF r = itemCache->exposed.at(i);
                      exposedRect |= r;
                      pixmapExposed += itemToPixmap.mapRect(r).toAlignedRect();
                  }
              } else {
                  exposedRect = brect;
              }
              styleOptionTmp.exposedRect = exposedRect;
  
              // Render.
              _q_paintIntoCache(&pix, item, pixmapExposed, itemToPixmap, painter->renderHints(),
                                &styleOptionTmp, painterStateProtection);
  
              // insert this pixmap into the cache.
              itemCache->key = QPixmapCache::insert(pix);
  
              // Reset expose data.
              itemCache->allExposed = false;
              itemCache->exposed.clear();
          }
  
          // Redraw the exposed area using the transformed painter. Depending on
          // the hardware, this may be a server-side operation, or an expensive
          // qpixmap-image-transform-pixmap roundtrip.
          if (newPainterOpacity != oldPainterOpacity) {
              painter->setOpacity(newPainterOpacity);
              painter->drawPixmap(br.topLeft(), pix);
              painter->setOpacity(oldPainterOpacity);
          } else {
              painter->drawPixmap(br.topLeft(), pix);
          }
          return;
      }
  
      // Render using device coordinate cache mode.
      if (cacheMode == QGraphicsItem::DeviceCoordinateCache) {
          // Find the item's bounds in device coordinates.
          QRectF deviceBounds = painter->worldTransform().mapRect(brect);
          QRect deviceRect = deviceBounds.toRect().adjusted(-1, -1, 1, 1);
          if (deviceRect.isEmpty())
              return;
          QRect viewRect = widget ? widget->rect() : QRect();
          if (widget && !viewRect.intersects(deviceRect))
              return;
  
          // Resort to direct rendering if the device rect exceeds the
          // (optional) maximum bounds. (QGraphicsSvgItem uses this).
          QSize maximumCacheSize =
              itemd->extra(QGraphicsItemPrivate::ExtraMaxDeviceCoordCacheSize).toSize();
          if (!maximumCacheSize.isEmpty()
              && (deviceRect.width() > maximumCacheSize.width()
                  || deviceRect.height() > maximumCacheSize.height())) {
              _q_paintItem(static_cast<QGraphicsWidget *>(item), painter, option, widget,
                           oldPainterOpacity != newPainterOpacity, painterStateProtection);
              return;
          }
  
          // Create or reuse offscreen pixmap, possibly scroll/blit from the old one.
          // If the world transform is rotated we always recreate the cache to avoid
          // wrong blending.
          bool pixModified = false;
          QGraphicsItemCache::DeviceData *deviceData = &itemCache->deviceData[widget];
          bool invertable = true;
          QTransform diff = deviceData->lastTransform.inverted(&invertable);
          if (invertable)
              diff *= painter->worldTransform();
          deviceData->lastTransform = painter->worldTransform();
          bool allowPartialCacheExposure = false;
          bool simpleTransform = invertable && diff.type() <= QTransform::TxTranslate
                                 && transformIsSimple(painter->worldTransform());
          if (!simpleTransform) {
              pixModified = true;
              itemCache->allExposed = true;
              itemCache->exposed.clear();
              deviceData->cacheIndent = QPoint();
              pix = QPixmap();
          } else if (!viewRect.isNull()) {
              allowPartialCacheExposure = deviceData->cacheIndent != QPoint();
          }
  
          // Allow partial cache exposure if the device rect isn't fully contained and
          // deviceRect is 20% taller or wider than the viewRect.
          if (!allowPartialCacheExposure && !viewRect.isNull() && !viewRect.contains(deviceRect)) {
              allowPartialCacheExposure = (viewRect.width() * 1.2 < deviceRect.width())
                                           || (viewRect.height() * 1.2 < deviceRect.height());
          }
  
          QRegion scrollExposure;
          if (allowPartialCacheExposure) {
              // Part of pixmap is drawn. Either device contains viewrect (big
              // item covers whole screen) or parts of device are outside the
              // viewport. In either case the device rect must be the intersect
              // between the two.
              int dx = deviceRect.left() < viewRect.left() ? viewRect.left() - deviceRect.left() : 0;
              int dy = deviceRect.top() < viewRect.top() ? viewRect.top() - deviceRect.top() : 0;
              QPoint newCacheIndent(dx, dy);
              deviceRect &= viewRect;
  
              if (pix.isNull()) {
                  deviceData->cacheIndent = QPoint();
                  itemCache->allExposed = true;
                  itemCache->exposed.clear();
                  pixModified = true;
              }
  
              // Copy / "scroll" the old pixmap onto the new ole and calculate
              // scrolled exposure.
              if (newCacheIndent != deviceData->cacheIndent || deviceRect.size() != pix.size()) {
                  QPoint diff = newCacheIndent - deviceData->cacheIndent;
                  QPixmap newPix(deviceRect.size());
                  // ### Investigate removing this fill (test with Plasma and
                  // graphicssystem raster).
                  newPix.fill(Qt::transparent);
                  if (!pix.isNull()) {
                      QPainter newPixPainter(&newPix);
                      newPixPainter.drawPixmap(-diff, pix);
                      newPixPainter.end();
                  }
                  QRegion exposed;
                  exposed += newPix.rect();
                  if (!pix.isNull())
                      exposed -= QRect(-diff, pix.size());
                  scrollExposure = exposed;
  
                  pix = newPix;
                  pixModified = true;
              }
              deviceData->cacheIndent = newCacheIndent;
          } else {
              // Full pixmap is drawn.
              deviceData->cacheIndent = QPoint();
  
              // Auto-adjust the pixmap size.
              if (deviceRect.size() != pix.size()) {
                  // exposed needs to cover the whole pixmap
                  pix = QPixmap(deviceRect.size());
                  pixModified = true;
                  itemCache->allExposed = true;
                  itemCache->exposed.clear();
              }
          }
  
          // Check for newly invalidated areas.
          if (itemCache->allExposed || !itemCache->exposed.isEmpty() || !scrollExposure.isEmpty()) {
              //We know that we will modify the pixmap, removing it from the cache
              //will detach the one we have and avoid a deep copy
              if (pixmapFound)
                  QPixmapCache::remove(pixmapKey);
  
              // Construct an item-to-pixmap transform.
              QPointF p = deviceRect.topLeft();
              QTransform itemToPixmap = painter->worldTransform();
              if (!p.isNull())
                  itemToPixmap *= QTransform::fromTranslate(-p.x(), -p.y());
  
              // Map the item's logical expose to pixmap coordinates.
              QRegion pixmapExposed = scrollExposure;
              if (!itemCache->allExposed) {
                  const QVector<QRectF> &exposed = itemCache->exposed;
                  for (int i = 0; i < exposed.size(); ++i)
                      pixmapExposed += itemToPixmap.mapRect(exposed.at(i)).toRect().adjusted(-1, -1, 1, 1);
              }
  
              // Calculate the style option's exposedRect.
              QRectF br;
              if (itemCache->allExposed) {
                  br = item->boundingRect();
              } else {
                  const QVector<QRectF> &exposed = itemCache->exposed;
                  for (int i = 0; i < exposed.size(); ++i)
                      br |= exposed.at(i);
                  QTransform pixmapToItem = itemToPixmap.inverted();
                  foreach (QRect r, scrollExposure.rects())
                      br |= pixmapToItem.mapRect(r);
              }
              styleOptionTmp = *option;
              styleOptionTmp.exposedRect = br.adjusted(-1, -1, 1, 1);
  
              // Render the exposed areas.
              _q_paintIntoCache(&pix, item, pixmapExposed, itemToPixmap, painter->renderHints(),
                                &styleOptionTmp, painterStateProtection);
  
              // Reset expose data.
              pixModified = true;
              itemCache->allExposed = false;
              itemCache->exposed.clear();
          }
  
          if (pixModified) {
              // Insert this pixmap into the cache.
              deviceData->key = QPixmapCache::insert(pix);
          }
  
          // Redraw the exposed area using an untransformed painter. This
          // effectively becomes a bitblit that does not transform the cache.
          QTransform restoreTransform = painter->worldTransform();
          painter->setWorldTransform(QTransform());
          if (newPainterOpacity != oldPainterOpacity) {
              painter->setOpacity(newPainterOpacity);
              painter->drawPixmap(deviceRect.topLeft(), pix);
              painter->setOpacity(oldPainterOpacity);
          } else {
              painter->drawPixmap(deviceRect.topLeft(), pix);
          }
          painter->setWorldTransform(restoreTransform);
          return;
      }
  }
  
  void QGraphicsScenePrivate::drawItems(QPainter *painter, const QTransform *const viewTransform,
                                        QRegion *exposedRegion, QWidget *widget)
  {
      // Make sure we don't have unpolished items before we draw.
      if (!unpolishedItems.isEmpty())
          _q_polishItems();
  
      updateAll = false;
      QRectF exposedSceneRect;
      if (exposedRegion && indexMethod != QGraphicsScene::NoIndex) {
          exposedSceneRect = exposedRegion->boundingRect().adjusted(-1, -1, 1, 1);
          if (viewTransform)
              exposedSceneRect = viewTransform->inverted().mapRect(exposedSceneRect);
      }
      const QList<QGraphicsItem *> tli = index->estimateTopLevelItems(exposedSceneRect, Qt::AscendingOrder);
      for (int i = 0; i < tli.size(); ++i)
          drawSubtreeRecursive(tli.at(i), painter, viewTransform, exposedRegion, widget);
  }
  
  void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter *painter,
                                                   const QTransform *const viewTransform,
                                                   QRegion *exposedRegion, QWidget *widget,
                                                   qreal parentOpacity, const QTransform *const effectTransform)
  {
      Q_ASSERT(item);
  
      if (!item->d_ptr->visible)
          return;
  
      const bool itemHasContents = !(item->d_ptr->flags & QGraphicsItem::ItemHasNoContents);
      const bool itemHasChildren = !item->d_ptr->children.isEmpty();
      if (!itemHasContents && !itemHasChildren)
          return; // Item has neither contents nor children!(?)
  
      const qreal opacity = item->d_ptr->combineOpacityFromParent(parentOpacity);
      const bool itemIsFullyTransparent = QGraphicsItemPrivate::isOpacityNull(opacity);
      if (itemIsFullyTransparent && (!itemHasChildren || item->d_ptr->childrenCombineOpacity()))
          return;
  
      QTransform transform(Qt::Uninitialized);
      QTransform *transformPtr = 0;
      bool translateOnlyTransform = false;
  #define ENSURE_TRANSFORM_PTR \
      if (!transformPtr) { \
          Q_ASSERT(!itemIsUntransformable); \
          if (viewTransform) { \
              transform = item->d_ptr->sceneTransform; \
              transform *= *viewTransform; \
              transformPtr = &transform; \
          } else { \
              transformPtr = &item->d_ptr->sceneTransform; \
              translateOnlyTransform = item->d_ptr->sceneTransformTranslateOnly; \
          } \
      }
  
      // Update the item's scene transform if the item is transformable;
      // otherwise calculate the full transform,
      bool wasDirtyParentSceneTransform = false;
      const bool itemIsUntransformable = item->d_ptr->itemIsUntransformable();
      if (itemIsUntransformable) {
          transform = item->deviceTransform(viewTransform ? *viewTransform : QTransform());
          transformPtr = &transform;
      } else if (item->d_ptr->dirtySceneTransform) {
          item->d_ptr->updateSceneTransformFromParent();
          Q_ASSERT(!item->d_ptr->dirtySceneTransform);
          wasDirtyParentSceneTransform = true;
      }
  
      const bool itemClipsChildrenToShape = (item->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape);
      bool drawItem = itemHasContents && !itemIsFullyTransparent;
      if (drawItem) {
          const QRectF brect = adjustedItemEffectiveBoundingRect(item);
          ENSURE_TRANSFORM_PTR
          QRect viewBoundingRect = translateOnlyTransform ? brect.translated(transformPtr->dx(), transformPtr->dy()).toAlignedRect()
                                                          : transformPtr->mapRect(brect).toAlignedRect();
          viewBoundingRect.adjust(-int(rectAdjust), -int(rectAdjust), rectAdjust, rectAdjust);
          if (widget)
              item->d_ptr->paintedViewBoundingRects.insert(widget, viewBoundingRect);
          drawItem = exposedRegion ? exposedRegion->intersects(viewBoundingRect)
                                   : !viewBoundingRect.normalized().isEmpty();
          if (!drawItem) {
              if (!itemHasChildren)
                  return;
              if (itemClipsChildrenToShape) {
                  if (wasDirtyParentSceneTransform)
                      item->d_ptr->invalidateChildrenSceneTransform();
                  return;
              }
          }
      } // else we know for sure this item has children we must process.
  
      if (itemHasChildren && itemClipsChildrenToShape)
          ENSURE_TRANSFORM_PTR;
  
  #ifndef QT_NO_GRAPHICSEFFECT
      if (item->d_ptr->graphicsEffect && item->d_ptr->graphicsEffect->isEnabled()) {
          ENSURE_TRANSFORM_PTR;
          QGraphicsItemPaintInfo info(viewTransform, transformPtr, effectTransform, exposedRegion, widget, &styleOptionTmp,
                                      painter, opacity, wasDirtyParentSceneTransform, itemHasContents && !itemIsFullyTransparent);
          QGraphicsEffectSource *source = item->d_ptr->graphicsEffect->d_func()->source;
          QGraphicsItemEffectSourcePrivate *sourced = static_cast<QGraphicsItemEffectSourcePrivate *>
                                                      (source->d_func());
          sourced->info = &info;
          const QTransform restoreTransform = painter->worldTransform();
          if (effectTransform)
              painter->setWorldTransform(*transformPtr * *effectTransform);
          else
              painter->setWorldTransform(*transformPtr);
          painter->setOpacity(opacity);
  
          if (sourced->currentCachedSystem() != Qt::LogicalCoordinates
              && sourced->lastEffectTransform != painter->worldTransform())
          {
              if (sourced->lastEffectTransform.type() <= QTransform::TxTranslate
                  && painter->worldTransform().type() <= QTransform::TxTranslate)
              {
                  QRectF sourceRect = sourced->boundingRect(Qt::DeviceCoordinates);
                  QRect effectRect = sourced->paddedEffectRect(Qt::DeviceCoordinates, sourced->currentCachedMode(), sourceRect);
  
                  sourced->setCachedOffset(effectRect.topLeft());
              } else {
                  sourced->invalidateCache(QGraphicsEffectSourcePrivate::TransformChanged);
              }
  
              sourced->lastEffectTransform = painter->worldTransform();
          }
  
          item->d_ptr->graphicsEffect->draw(painter);
          painter->setWorldTransform(restoreTransform);
          sourced->info = 0;
      } else
  #endif //QT_NO_GRAPHICSEFFECT
      {
          draw(item, painter, viewTransform, transformPtr, exposedRegion, widget, opacity,
               effectTransform, wasDirtyParentSceneTransform, drawItem);
      }
  }
  
  static inline void setClip(QPainter *painter, QGraphicsItem *item)
  {
      painter->save();
      QRectF clipRect;
      const QPainterPath clipPath(item->shape());
      if (QPathClipper::pathToRect(clipPath, &clipRect))
          painter->setClipRect(clipRect, Qt::IntersectClip);
      else
          painter->setClipPath(clipPath, Qt::IntersectClip);
  }
  
  static inline void setWorldTransform(QPainter *painter, const QTransform *const transformPtr,
                                       const QTransform *effectTransform)
  {
      Q_ASSERT(transformPtr);
      if (effectTransform)
          painter->setWorldTransform(*transformPtr * *effectTransform);
      else
          painter->setWorldTransform(*transformPtr);
  }
  
  void QGraphicsScenePrivate::draw(QGraphicsItem *item, QPainter *painter, const QTransform *const viewTransform,
                                   const QTransform *const transformPtr, QRegion *exposedRegion, QWidget *widget,
                                   qreal opacity, const QTransform *effectTransform,
                                   bool wasDirtyParentSceneTransform, bool drawItem)
  {
      const bool itemIsFullyTransparent = QGraphicsItemPrivate::isOpacityNull(opacity);
      const bool itemClipsChildrenToShape = (item->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape);
      const bool itemHasChildren = !item->d_ptr->children.isEmpty();
      bool setChildClip = itemClipsChildrenToShape;
      bool itemHasChildrenStackedBehind = false;
  
      int i = 0;
      if (itemHasChildren) {
          if (itemClipsChildrenToShape)
              setWorldTransform(painter, transformPtr, effectTransform);
  
          item->d_ptr->ensureSortedChildren();
          // Items with the 'ItemStacksBehindParent' flag are put in front of the list
          // so all we have to do is to check the first item.
          itemHasChildrenStackedBehind = (item->d_ptr->children.at(0)->d_ptr->flags
                                          & QGraphicsItem::ItemStacksBehindParent);
  
          if (itemHasChildrenStackedBehind) {
              if (itemClipsChildrenToShape) {
                  setClip(painter, item);
                  setChildClip = false;
              }
  
              // Draw children behind
              for (i = 0; i < item->d_ptr->children.size(); ++i) {
                  QGraphicsItem *child = item->d_ptr->children.at(i);
                  if (wasDirtyParentSceneTransform)
                      child->d_ptr->dirtySceneTransform = 1;
                  if (!(child->d_ptr->flags & QGraphicsItem::ItemStacksBehindParent))
                      break;
                  if (itemIsFullyTransparent && !(child->d_ptr->flags & QGraphicsItem::ItemIgnoresParentOpacity))
                      continue;
                  drawSubtreeRecursive(child, painter, viewTransform, exposedRegion, widget, opacity, effectTransform);
              }
          }
      }
  
      // Draw item
      if (drawItem) {
          Q_ASSERT(!itemIsFullyTransparent);
          Q_ASSERT(!(item->d_ptr->flags & QGraphicsItem::ItemHasNoContents));
          Q_ASSERT(transformPtr);
          item->d_ptr->initStyleOption(&styleOptionTmp, *transformPtr, exposedRegion
                                       ? *exposedRegion : QRegion(), exposedRegion == 0);
  
          const bool itemClipsToShape = item->d_ptr->flags & QGraphicsItem::ItemClipsToShape;
          bool restorePainterClip = false;
  
          if (!itemHasChildren || !itemClipsChildrenToShape) {
              // Item does not have children or clip children to shape.
              setWorldTransform(painter, transformPtr, effectTransform);
              if ((restorePainterClip = itemClipsToShape))
                  setClip(painter, item);
          } else if (itemHasChildrenStackedBehind){
              // Item clips children to shape and has children stacked behind, which means
              // the painter is already clipped to the item's shape.
              if (itemClipsToShape) {
                  // The clip is already correct. Ensure correct world transform.
                  setWorldTransform(painter, transformPtr, effectTransform);
              } else {
                  // Remove clip (this also ensures correct world transform).
                  painter->restore();
                  setChildClip = true;
              }
          } else if (itemClipsToShape) {
              // Item clips children and itself to shape. It does not have hildren stacked
              // behind, which means the clip has not yet been set. We set it now and re-use it
              // for the children.
              setClip(painter, item);
              setChildClip = false;
          }
  
          if (painterStateProtection && !restorePainterClip)
              painter->save();
  
          painter->setOpacity(opacity);
          if (!item->d_ptr->cacheMode && !item->d_ptr->isWidget)
              item->paint(painter, &styleOptionTmp, widget);
          else
              drawItemHelper(item, painter, &styleOptionTmp, widget, painterStateProtection);
  
          if (painterStateProtection || restorePainterClip)
              painter->restore();
  
          static int drawRect = qgetenv("QT_DRAW_SCENE_ITEM_RECTS").toInt();
          if (drawRect) {
              QPen oldPen = painter->pen();
              QBrush oldBrush = painter->brush();
              quintptr ptr = reinterpret_cast<quintptr>(item);
              const QColor color = QColor::fromHsv(ptr % 255, 255, 255);
              painter->setPen(color);
              painter->setBrush(Qt::NoBrush);
              painter->drawRect(adjustedItemBoundingRect(item));
              painter->setPen(oldPen);
              painter->setBrush(oldBrush);
          }
      }
  
      // Draw children in front
      if (itemHasChildren) {
          if (setChildClip)
              setClip(painter, item);
  
          for (; i < item->d_ptr->children.size(); ++i) {
              QGraphicsItem *child = item->d_ptr->children.at(i);
              if (wasDirtyParentSceneTransform)
                  child->d_ptr->dirtySceneTransform = 1;
              if (itemIsFullyTransparent && !(child->d_ptr->flags & QGraphicsItem::ItemIgnoresParentOpacity))
                  continue;
              drawSubtreeRecursive(child, painter, viewTransform, exposedRegion, widget, opacity, effectTransform);
          }
  
          // Restore child clip
          if (itemClipsChildrenToShape)
              painter->restore();
      }
  }
  
  void QGraphicsScenePrivate::markDirty(QGraphicsItem *item, const QRectF &rect, bool invalidateChildren,
                                        bool force, bool ignoreOpacity, bool removingItemFromScene,
                                        bool updateBoundingRect)
  {
      Q_ASSERT(item);
      if (updateAll)
          return;
  
      if (removingItemFromScene && !ignoreOpacity && !item->d_ptr->ignoreOpacity) {
          // If any of the item's ancestors ignore opacity, it means that the opacity
          // was set to 0 (and the update request has not yet been processed). That
          // also means that we have to ignore the opacity for the item itself; otherwise
          // things like: parent->setOpacity(0); scene->removeItem(child) won't work.
          // Note that we only do this when removing items from the scene. In all other
          // cases the ignoreOpacity bit propagates properly in processDirtyItems, but
          // since the item is removed immediately it won't be processed there.
          QGraphicsItem *p = item->d_ptr->parent;
          while (p) {
              if (p->d_ptr->ignoreOpacity) {
                  item->d_ptr->ignoreOpacity = true;
                  break;
              }
              p = p->d_ptr->parent;
          }
      }
  
      if (item->d_ptr->discardUpdateRequest(/*ignoreVisibleBit=*/force,
                                            /*ignoreDirtyBit=*/removingItemFromScene || invalidateChildren,
                                            /*ignoreOpacity=*/ignoreOpacity)) {
          if (item->d_ptr->dirty) {
              // The item is already marked as dirty and will be processed later. However,
              // we have to make sure ignoreVisible and ignoreOpacity are set properly;
              // otherwise things like: item->update(); item->hide() (force is now true)
              // won't work as expected.
              if (force)
                  item->d_ptr->ignoreVisible = 1;
              if (ignoreOpacity)
                  item->d_ptr->ignoreOpacity = 1;
          }
          return;
      }
  
      const bool fullItemUpdate = rect.isNull();
      if (!fullItemUpdate && rect.isEmpty())
          return;
  
      if (!processDirtyItemsEmitted) {
          QMetaMethod method = q_ptr->metaObject()->method(processDirtyItemsIndex);
          method.invoke(q_ptr, Qt::QueuedConnection);
  //        QMetaObject::invokeMethod(q_ptr, "_q_processDirtyItems", Qt::QueuedConnection);
          processDirtyItemsEmitted = true;
      }
  
      if (removingItemFromScene) {
          // Note that this function can be called from the item's destructor, so
          // do NOT call any virtual functions on it within this block.
          if (isSignalConnected(changedSignalIndex) || views.isEmpty()) {
              // This block of code is kept for compatibility. Since 4.5, by default
              // QGraphicsView does not connect the signal and we use the below
              // method of delivering updates.
              q_func()->update();
              return;
          }
  
          for (int i = 0; i < views.size(); ++i) {
              QGraphicsViewPrivate *viewPrivate = views.at(i)->d_func();
              QRect rect = item->d_ptr->paintedViewBoundingRects.value(viewPrivate->viewport);
              rect.translate(viewPrivate->dirtyScrollOffset);
              viewPrivate->updateRect(rect);
          }
          return;
      }
  
      bool hasNoContents = item->d_ptr->flags & QGraphicsItem::ItemHasNoContents;
      if (!hasNoContents) {
          item->d_ptr->dirty = 1;
          if (fullItemUpdate)
              item->d_ptr->fullUpdatePending = 1;
          else if (!item->d_ptr->fullUpdatePending)
              item->d_ptr->needsRepaint |= rect;
      } else if (item->d_ptr->graphicsEffect) {
          invalidateChildren = true;
      }
  
      if (invalidateChildren) {
          item->d_ptr->allChildrenDirty = 1;
          item->d_ptr->dirtyChildren = 1;
      }
  
      if (force)
          item->d_ptr->ignoreVisible = 1;
      if (ignoreOpacity)
          item->d_ptr->ignoreOpacity = 1;
  
      if (!updateBoundingRect)
          item->d_ptr->markParentDirty();
  }
  
  static inline bool updateHelper(QGraphicsViewPrivate *view, QGraphicsItemPrivate *item,
                                  const QRectF &rect, bool itemIsUntransformable)
  {
      Q_ASSERT(view);
      Q_ASSERT(item);
  
      QGraphicsItem *itemq = static_cast<QGraphicsItem *>(item->q_ptr);
      QGraphicsView *viewq = static_cast<QGraphicsView *>(view->q_ptr);
  
      if (itemIsUntransformable) {
          const QTransform xform = itemq->deviceTransform(viewq->viewportTransform());
          if (!item->hasBoundingRegionGranularity)
              return view->updateRectF(xform.mapRect(rect));
          return view->updateRegion(rect, xform);
      }
  
      if (item->sceneTransformTranslateOnly && view->identityMatrix) {
          const qreal dx = item->sceneTransform.dx();
          const qreal dy = item->sceneTransform.dy();
          QRectF r(rect);
          r.translate(dx - view->horizontalScroll(), dy - view->verticalScroll());
          return view->updateRectF(r);
      }
  
      if (!viewq->isTransformed()) {
          if (!item->hasBoundingRegionGranularity)
              return view->updateRectF(item->sceneTransform.mapRect(rect));
          return view->updateRegion(rect, item->sceneTransform);
      }
  
      QTransform xform = item->sceneTransform;
      xform *= viewq->viewportTransform();
      if (!item->hasBoundingRegionGranularity)
          return view->updateRectF(xform.mapRect(rect));
      return view->updateRegion(rect, xform);
  }
  
  void QGraphicsScenePrivate::processDirtyItemsRecursive(QGraphicsItem *item, bool dirtyAncestorContainsChildren,
                                                         qreal parentOpacity)
  {
      Q_Q(QGraphicsScene);
      Q_ASSERT(item);
      Q_ASSERT(!updateAll);
  
      if (!item->d_ptr->dirty && !item->d_ptr->dirtyChildren) {
          resetDirtyItem(item);
          return;
      }
  
      const bool itemIsHidden = !item->d_ptr->ignoreVisible && !item->d_ptr->visible;
      if (itemIsHidden) {
          resetDirtyItem(item, /*recursive=*/true);
          return;
      }
  
      bool itemHasContents = !(item->d_ptr->flags & QGraphicsItem::ItemHasNoContents);
      const bool itemHasChildren = !item->d_ptr->children.isEmpty();
      if (!itemHasContents) {
          if (!itemHasChildren) {
              resetDirtyItem(item);
              return; // Item has neither contents nor children!(?)
          }
          if (item->d_ptr->graphicsEffect)
              itemHasContents = true;
      }
  
      const qreal opacity = item->d_ptr->combineOpacityFromParent(parentOpacity);
      const bool itemIsFullyTransparent = !item->d_ptr->ignoreOpacity
                                          && QGraphicsItemPrivate::isOpacityNull(opacity);
      if (itemIsFullyTransparent && (!itemHasChildren || item->d_ptr->childrenCombineOpacity())) {
          resetDirtyItem(item, /*recursive=*/itemHasChildren);
          return;
      }
  
      bool wasDirtyParentSceneTransform = item->d_ptr->dirtySceneTransform;
      const bool itemIsUntransformable = item->d_ptr->itemIsUntransformable();
      if (wasDirtyParentSceneTransform && !itemIsUntransformable) {
          item->d_ptr->updateSceneTransformFromParent();
          Q_ASSERT(!item->d_ptr->dirtySceneTransform);
      }
  
      const bool wasDirtyParentViewBoundingRects = item->d_ptr->paintedViewBoundingRectsNeedRepaint;
      if (itemIsFullyTransparent || !itemHasContents || dirtyAncestorContainsChildren) {
          // Make sure we don't process invisible items or items with no content.
          item->d_ptr->dirty = 0;
          item->d_ptr->fullUpdatePending = 0;
          // Might have a dirty view bounding rect otherwise.
          if (itemIsFullyTransparent || !itemHasContents)
              item->d_ptr->paintedViewBoundingRectsNeedRepaint = 0;
      }
  
      if (!hasSceneRect && item->d_ptr->geometryChanged && item->d_ptr->visible) {
          // Update growingItemsBoundingRect.
          if (item->d_ptr->sceneTransformTranslateOnly) {
              growingItemsBoundingRect |= item->boundingRect().translated(item->d_ptr->sceneTransform.dx(),
                                                                          item->d_ptr->sceneTransform.dy());
          } else {
              growingItemsBoundingRect |= item->d_ptr->sceneTransform.mapRect(item->boundingRect());
          }
      }
  
      // Process item.
      if (item->d_ptr->dirty || item->d_ptr->paintedViewBoundingRectsNeedRepaint) {
          const bool useCompatUpdate = views.isEmpty() || isSignalConnected(changedSignalIndex);
          const QRectF itemBoundingRect = adjustedItemEffectiveBoundingRect(item);
  
          if (useCompatUpdate && !itemIsUntransformable && qFuzzyIsNull(item->boundingRegionGranularity())) {
              // This block of code is kept for compatibility. Since 4.5, by default
              // QGraphicsView does not connect the signal and we use the below
              // method of delivering updates.
              if (item->d_ptr->sceneTransformTranslateOnly) {
                  q->update(itemBoundingRect.translated(item->d_ptr->sceneTransform.dx(),
                                                        item->d_ptr->sceneTransform.dy()));
              } else {
                  QRectF rect = item->d_ptr->sceneTransform.mapRect(itemBoundingRect);
                  if (!rect.isEmpty())
                      q->update(rect);
              }
          } else {
              QRectF dirtyRect;
              bool uninitializedDirtyRect = true;
  
              for (int j = 0; j < views.size(); ++j) {
                  QGraphicsView *view = views.at(j);
                  QGraphicsViewPrivate *viewPrivate = view->d_func();
                  QRect &paintedViewBoundingRect = item->d_ptr->paintedViewBoundingRects[viewPrivate->viewport];
                  if (viewPrivate->fullUpdatePending
                      || viewPrivate->viewportUpdateMode == QGraphicsView::NoViewportUpdate) {
                      // Okay, if we have a full update pending or no viewport update, this item's
                      // paintedViewBoundingRect  will be updated correctly in the next paintEvent if
                      // it is inside the viewport, but for now we can pretend that it is outside.
                      paintedViewBoundingRect = QRect(-1, -1, -1, -1);
                      continue;
                  }
  
                  if (item->d_ptr->paintedViewBoundingRectsNeedRepaint) {
                      paintedViewBoundingRect.translate(viewPrivate->dirtyScrollOffset);
                      if (!viewPrivate->updateRect(paintedViewBoundingRect))
                          paintedViewBoundingRect = QRect(-1, -1, -1, -1); // Outside viewport.
                  }
  
                  if (!item->d_ptr->dirty)
                      continue;
  
                  if (!item->d_ptr->paintedViewBoundingRectsNeedRepaint
                      && paintedViewBoundingRect.x() == -1 && paintedViewBoundingRect.y() == -1
                      && paintedViewBoundingRect.width() == -1 && paintedViewBoundingRect.height() == -1) {
                      continue; // Outside viewport.
                  }
  
                  if (uninitializedDirtyRect) {
                      dirtyRect = itemBoundingRect;
                      if (!item->d_ptr->fullUpdatePending) {
                          _q_adjustRect(&item->d_ptr->needsRepaint);
                          dirtyRect &= item->d_ptr->needsRepaint;
                      }
                      uninitializedDirtyRect = false;
                  }
  
                  if (dirtyRect.isEmpty())
                      continue; // Discard updates outside the bounding rect.
  
                  if (!updateHelper(viewPrivate, item->d_ptr.data(), dirtyRect, itemIsUntransformable)
                      && item->d_ptr->paintedViewBoundingRectsNeedRepaint) {
                      paintedViewBoundingRect = QRect(-1, -1, -1, -1); // Outside viewport.
                  }
              }
          }
      }
  
      // Process children.
      if (itemHasChildren && item->d_ptr->dirtyChildren) {
          const bool itemClipsChildrenToShape = item->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape;
          // Items with no content are threated as 'dummy' items which means they are never drawn and
          // 'processed', so the painted view bounding rect is never up-to-date. This means that whenever
          // such an item changes geometry, its children have to take care of the update regardless
          // of whether the item clips children to shape or not.
          const bool bypassUpdateClip = !itemHasContents && wasDirtyParentViewBoundingRects;
          if (itemClipsChildrenToShape && !bypassUpdateClip) {
              // Make sure child updates are clipped to the item's bounding rect.
              for (int i = 0; i < views.size(); ++i)
                  views.at(i)->d_func()->setUpdateClip(item);
          }
          if (!dirtyAncestorContainsChildren) {
              dirtyAncestorContainsChildren = item->d_ptr->fullUpdatePending
                                              && itemClipsChildrenToShape;
          }
          const bool allChildrenDirty = item->d_ptr->allChildrenDirty;
          const bool parentIgnoresVisible = item->d_ptr->ignoreVisible;
          const bool parentIgnoresOpacity = item->d_ptr->ignoreOpacity;
          for (int i = 0; i < item->d_ptr->children.size(); ++i) {
              QGraphicsItem *child = item->d_ptr->children.at(i);
              if (wasDirtyParentSceneTransform)
                  child->d_ptr->dirtySceneTransform = 1;
              if (wasDirtyParentViewBoundingRects)
                  child->d_ptr->paintedViewBoundingRectsNeedRepaint = 1;
              if (parentIgnoresVisible)
                  child->d_ptr->ignoreVisible = 1;
              if (parentIgnoresOpacity)
                  child->d_ptr->ignoreOpacity = 1;
              if (allChildrenDirty) {
                  child->d_ptr->dirty = 1;
                  child->d_ptr->fullUpdatePending = 1;
                  child->d_ptr->dirtyChildren = 1;
                  child->d_ptr->allChildrenDirty = 1;
              }
              processDirtyItemsRecursive(child, dirtyAncestorContainsChildren, opacity);
          }
  
          if (itemClipsChildrenToShape) {
              // Reset updateClip.
              for (int i = 0; i < views.size(); ++i)
                  views.at(i)->d_func()->setUpdateClip(0);
          }
      } else if (wasDirtyParentSceneTransform) {
          item->d_ptr->invalidateChildrenSceneTransform();
      }
  
      resetDirtyItem(item);
  }
  
  /*!
      \obsolete
  
      Paints the given \a items using the provided \a painter, after the
      background has been drawn, and before the foreground has been
      drawn.  All painting is done in \e scene coordinates. Before
      drawing each item, the painter must be transformed using
      QGraphicsItem::sceneTransform().
  
      The \a options parameter is the list of style option objects for
      each item in \a items. The \a numItems parameter is the number of
      items in \a items and options in \a options. The \a widget
      parameter is optional; if specified, it should point to the widget
      that is being painted on.
  
      The default implementation prepares the painter matrix, and calls
      QGraphicsItem::paint() on all items. Reimplement this function to
      provide custom painting of all items for the scene; gaining
      complete control over how each item is drawn. In some cases this
      can increase drawing performance significantly.
  
      Example:
  
      \snippet doc/src/snippets/graphicssceneadditemsnippet.cpp 0
  
      Since Qt 4.6, this function is not called anymore unless
      the QGraphicsView::IndirectPainting flag is given as an Optimization
      flag.
  
      \sa drawBackground(), drawForeground()
  */
  void QGraphicsScene::drawItems(QPainter *painter,
                                 int numItems,
                                 QGraphicsItem *items[],
                                 const QStyleOptionGraphicsItem options[], QWidget *widget)
  {
      Q_D(QGraphicsScene);
      // Make sure we don't have unpolished items before we draw.
      if (!d->unpolishedItems.isEmpty())
          d->_q_polishItems();
  
      const qreal opacity = painter->opacity();
      QTransform viewTransform = painter->worldTransform();
      Q_UNUSED(options);
  
      // Determine view, expose and flags.
      QGraphicsView *view = widget ? qobject_cast<QGraphicsView *>(widget->parentWidget()) : 0;
      QRegion *expose = 0;
      const quint32 oldRectAdjust = d->rectAdjust;
      if (view) {
          d->updateAll = false;
          expose = &view->d_func()->exposedRegion;
          if (view->d_func()->optimizationFlags & QGraphicsView::DontAdjustForAntialiasing)
              d->rectAdjust = 1;
          else
              d->rectAdjust = 2;
      }
  
      // Find all toplevels, they are already sorted.
      QList<QGraphicsItem *> topLevelItems;
      for (int i = 0; i < numItems; ++i) {
          QGraphicsItem *item = items[i]->topLevelItem();
          if (!item->d_ptr->itemDiscovered) {
              topLevelItems << item;
              item->d_ptr->itemDiscovered = 1;
              d->drawSubtreeRecursive(item, painter, &viewTransform, expose, widget);
          }
      }
  
      d->rectAdjust = oldRectAdjust;
      // Reset discovery bits.
      for (int i = 0; i < topLevelItems.size(); ++i)
          topLevelItems.at(i)->d_ptr->itemDiscovered = 0;
  
      painter->setWorldTransform(viewTransform);
      painter->setOpacity(opacity);
  }
  
  /*!
      \since 4.4
  
      Finds a new widget to give the keyboard focus to, as appropriate for Tab
      and Shift+Tab, and returns true if it can find a new widget, or false if
      it cannot. If \a next is true, this function searches forward; if \a next
      is false, it searches backward.
  
      You can reimplement this function in a subclass of QGraphicsScene to
      provide fine-grained control over how tab focus passes inside your
      scene. The default implementation is based on the tab focus chain defined
      by QGraphicsWidget::setTabOrder().
  */
  bool QGraphicsScene::focusNextPrevChild(bool next)
  {
      Q_D(QGraphicsScene);
  
      QGraphicsItem *item = focusItem();
      if (item && !item->isWidget()) {
          // Tab out of the scene.
          return false;
      }
      if (!item) {
          if (d->lastFocusItem && !d->lastFocusItem->isWidget()) {
              // Restore focus to the last focusable non-widget item that had
              // focus.
              setFocusItem(d->lastFocusItem, next ? Qt::TabFocusReason : Qt::BacktabFocusReason);
              return true;
          }
      }
      if (!d->tabFocusFirst) {
          // No widgets...
          return false;
      }
  
      // The item must be a widget.
      QGraphicsWidget *widget = 0;
      if (!item) {
          widget = next ? d->tabFocusFirst : d->tabFocusFirst->d_func()->focusPrev;
      } else {
          QGraphicsWidget *test = static_cast<QGraphicsWidget *>(item);
          widget = next ? test->d_func()->focusNext : test->d_func()->focusPrev;
          if ((next && widget == d->tabFocusFirst) || (!next && widget == d->tabFocusFirst->d_func()->focusPrev))
              return false;
      }
      QGraphicsWidget *widgetThatHadFocus = widget;
  
      // Run around the focus chain until we find a widget that can take tab focus.
      do {
          if (widget->flags() & QGraphicsItem::ItemIsFocusable
              && widget->isEnabled() && widget->isVisibleTo(0)
              && (widget->focusPolicy() & Qt::TabFocus)
              && (!item || !item->isPanel() || item->isAncestorOf(widget))
              ) {
              setFocusItem(widget, next ? Qt::TabFocusReason : Qt::BacktabFocusReason);
              return true;
          }
          widget = next ? widget->d_func()->focusNext : widget->d_func()->focusPrev;
          if ((next && widget == d->tabFocusFirst) || (!next && widget == d->tabFocusFirst->d_func()->focusPrev))
              return false;
      } while (widget != widgetThatHadFocus);
  
      return false;
  }
  
  /*!
      \fn QGraphicsScene::changed(const QList<QRectF> &region)
  
      This signal is emitted by QGraphicsScene when control reaches the
      event loop, if the scene content changes. The \a region parameter
      contains a list of scene rectangles that indicate the area that
      has been changed.
  
      \sa QGraphicsView::updateScene()
  */
  
  /*!
      \fn QGraphicsScene::sceneRectChanged(const QRectF &rect)
  
      This signal is emitted by QGraphicsScene whenever the scene rect changes.
      The \a rect parameter is the new scene rectangle.
  
      \sa QGraphicsView::updateSceneRect()
  */
  
  /*!
      \fn QGraphicsScene::selectionChanged()
      \since 4.3
  
      This signal is emitted by QGraphicsScene whenever the selection
      changes. You can call selectedItems() to get the new list of selected
      items.
  
      The selection changes whenever an item is selected or unselected, a
      selection area is set, cleared or otherwise changed, if a preselected item
      is added to the scene, or if a selected item is removed from the scene.
  
      QGraphicsScene emits this signal only once for group selection operations.
      For example, if you set a selection area, select or unselect a
      QGraphicsItemGroup, or if you add or remove from the scene a parent item
      that contains several selected items, selectionChanged() is emitted only
      once after the operation has completed (instead of once for each item).
  
      \sa setSelectionArea(), selectedItems(), QGraphicsItem::setSelected()
  */
  
  /*!
      \since 4.4
  
      Returns the scene's style, or the same as QApplication::style() if the
      scene has not been explicitly assigned a style.
  
      \sa setStyle()
  */
  QStyle *QGraphicsScene::style() const
  {
      Q_D(const QGraphicsScene);
      // ### This function, and the use of styles in general, is non-reentrant.
      return d->style ? d->style : QApplication::style();
  }
  
  /*!
      \since 4.4
  
      Sets or replaces the style of the scene to \a style, and reparents the
      style to this scene. Any previously assigned style is deleted. The scene's
      style defaults to QApplication::style(), and serves as the default for all
      QGraphicsWidget items in the scene.
  
      Changing the style, either directly by calling this function, or
      indirectly by calling QApplication::setStyle(), will automatically update
      the style for all widgets in the scene that do not have a style explicitly
      assigned to them.
  
      If \a style is 0, QGraphicsScene will revert to QApplication::style().
  
      \sa style()
  */
  void QGraphicsScene::setStyle(QStyle *style)
  {
      Q_D(QGraphicsScene);
      // ### This function, and the use of styles in general, is non-reentrant.
      if (style == d->style)
          return;
  
      // Delete the old style,
      delete d->style;
      if ((d->style = style))
          d->style->setParent(this);
  
      // Notify the scene.
      QEvent event(QEvent::StyleChange);
      QApplication::sendEvent(this, &event);
  
      // Notify all widgets that don't have a style explicitly set.
      foreach (QGraphicsItem *item, items()) {
          if (item->isWidget()) {
              QGraphicsWidget *widget = static_cast<QGraphicsWidget *>(item);
              if (!widget->testAttribute(Qt::WA_SetStyle))
                  QApplication::sendEvent(widget, &event);
          }
      }
  }
  
  /*!
      \property QGraphicsScene::font
      \since 4.4
      \brief the scene's default font
  
      This property provides the scene's font. The scene font defaults to,
      and resolves all its entries from, QApplication::font.
  
      If the scene's font changes, either directly through setFont() or
      indirectly when the application font changes, QGraphicsScene first
      sends itself a \l{QEvent::FontChange}{FontChange} event, and it then
      sends \l{QEvent::FontChange}{FontChange} events to all top-level
      widget items in the scene. These items respond by resolving their own
      fonts to the scene, and they then notify their children, who again
      notify their children, and so on, until all widget items have updated
      their fonts.
  
      Changing the scene font, (directly or indirectly through
      QApplication::setFont(),) automatically schedules a redraw the entire
      scene.
  
      \sa QWidget::font, QApplication::setFont(), palette, style()
  */
  QFont QGraphicsScene::font() const
  {
      Q_D(const QGraphicsScene);
      return d->font;
  }
  void QGraphicsScene::setFont(const QFont &font)
  {
      Q_D(QGraphicsScene);
      QFont naturalFont = QApplication::font();
      naturalFont.resolve(0);
      QFont resolvedFont = font.resolve(naturalFont);
      d->setFont_helper(resolvedFont);
  }
  
  /*!
      \property QGraphicsScene::palette
      \since 4.4
      \brief the scene's default palette
  
      This property provides the scene's palette. The scene palette defaults to,
      and resolves all its entries from, QApplication::palette.
  
      If the scene's palette changes, either directly through setPalette() or
      indirectly when the application palette changes, QGraphicsScene first
      sends itself a \l{QEvent::PaletteChange}{PaletteChange} event, and it then
      sends \l{QEvent::PaletteChange}{PaletteChange} events to all top-level
      widget items in the scene. These items respond by resolving their own
      palettes to the scene, and they then notify their children, who again
      notify their children, and so on, until all widget items have updated
      their palettes.
  
      Changing the scene palette, (directly or indirectly through
      QApplication::setPalette(),) automatically schedules a redraw the entire
      scene.
  
      \sa QWidget::palette, QApplication::setPalette(), font, style()
  */
  QPalette QGraphicsScene::palette() const
  {
      Q_D(const QGraphicsScene);
      return d->palette;
  }
  void QGraphicsScene::setPalette(const QPalette &palette)
  {
      Q_D(QGraphicsScene);
      QPalette naturalPalette = QApplication::palette();
      naturalPalette.resolve(0);
      QPalette resolvedPalette = palette.resolve(naturalPalette);
      d->setPalette_helper(resolvedPalette);
  }
  
  /*!
      \since 4.6
  
      Returns true if the scene is active (e.g., it's viewed by
      at least one QGraphicsView that is active); otherwise returns false.
  
      \sa QGraphicsItem::isActive(), QWidget::isActiveWindow()
  */
  bool QGraphicsScene::isActive() const
  {
      Q_D(const QGraphicsScene);
      return d->activationRefCount > 0;
  }
  
  /*!
      \since 4.6
      Returns the current active panel, or 0 if no panel is currently active.
  
      \sa QGraphicsScene::setActivePanel()
  */
  QGraphicsItem *QGraphicsScene::activePanel() const
  {
      Q_D(const QGraphicsScene);
      return d->activePanel;
  }
  
  /*!
      \since 4.6
      Activates \a item, which must be an item in this scene. You
      can also pass 0 for \a item, in which case QGraphicsScene will
      deactivate any currently active panel.
  
      If the scene is currently inactive, \a item remains inactive until the
      scene becomes active (or, ir \a item is 0, no item will be activated).
  
      \sa activePanel(), isActive(), QGraphicsItem::isActive()
  */
  void QGraphicsScene::setActivePanel(QGraphicsItem *item)
  {
      Q_D(QGraphicsScene);
      d->setActivePanelHelper(item, false);
  }
  
  /*!
      \since 4.4
  
      Returns the current active window, or 0 if no window is currently
      active.
  
      \sa QGraphicsScene::setActiveWindow()
  */
  QGraphicsWidget *QGraphicsScene::activeWindow() const
  {
      Q_D(const QGraphicsScene);
      if (d->activePanel && d->activePanel->isWindow())
          return static_cast<QGraphicsWidget *>(d->activePanel);
      return 0;
  }
  
  /*!
      \since 4.4
      Activates \a widget, which must be a widget in this scene. You can also
      pass 0 for \a widget, in which case QGraphicsScene will deactivate any
      currently active window.
  
      \sa activeWindow(), QGraphicsWidget::isActiveWindow()
  */
  void QGraphicsScene::setActiveWindow(QGraphicsWidget *widget)
  {
      if (widget && widget->scene() != this) {
          qWarning("QGraphicsScene::setActiveWindow: widget %p must be part of this scene",
                   widget);
          return;
      }
  
      // Activate the widget's panel (all windows are panels).
      QGraphicsItem *panel = widget ? widget->panel() : 0;
      setActivePanel(panel);
  
      // Raise
      if (panel) {
          QList<QGraphicsItem *> siblingWindows;
          QGraphicsItem *parent = panel->parentItem();
          // Raise ### inefficient for toplevels
          foreach (QGraphicsItem *sibling, parent ? parent->children() : items()) {
              if (sibling != panel && sibling->isWindow())
                  siblingWindows << sibling;
          }
  
          // Find the highest z value.
          qreal z = panel->zValue();
          for (int i = 0; i < siblingWindows.size(); ++i)
              z = qMax(z, siblingWindows.at(i)->zValue());
  
          // This will probably never overflow.
          const qreal litt = qreal(0.001);
          panel->setZValue(z + litt);
      }
  }
  
  /*!
      \since 4.6
  
      Sends event \a event to item \a item through possible event filters.
  
      The event is sent only if the item is enabled.
  
      Returns \c false if the event was filtered or if the item is disabled.
      Otherwise returns the value that was returned from the event handler.
  
      \sa QGraphicsItem::sceneEvent(), QGraphicsItem::sceneEventFilter()
  */
  bool QGraphicsScene::sendEvent(QGraphicsItem *item, QEvent *event)
  {
      Q_D(QGraphicsScene);
      if (!item) {
          qWarning("QGraphicsScene::sendEvent: cannot send event to a null item");
          return false;
      }
      if (item->scene() != this) {
          qWarning("QGraphicsScene::sendEvent: item %p's scene (%p)"
                   " is different from this scene (%p)",
                   item, item->scene(), this);
          return false;
      }
      return d->sendEvent(item, event);
  }
  
  void QGraphicsScenePrivate::addView(QGraphicsView *view)
  {
      views << view;
  #ifndef QT_NO_GESTURES
      foreach (Qt::GestureType gesture, grabbedGestures.keys())
          view->viewport()->grabGesture(gesture);
  #endif
  }
  
  void QGraphicsScenePrivate::removeView(QGraphicsView *view)
  {
      views.removeAll(view);
  }
  
  void QGraphicsScenePrivate::updateTouchPointsForItem(QGraphicsItem *item, QTouchEvent *touchEvent)
  {
      QList<QTouchEvent::TouchPoint> touchPoints = touchEvent->touchPoints();
      for (int i = 0; i < touchPoints.count(); ++i) {
          QTouchEvent::TouchPoint &touchPoint = touchPoints[i];
          touchPoint.setRect(item->mapFromScene(touchPoint.sceneRect()).boundingRect());
          touchPoint.setStartPos(item->d_ptr->genericMapFromScene(touchPoint.startScenePos(), touchEvent->widget()));
          touchPoint.setLastPos(item->d_ptr->genericMapFromScene(touchPoint.lastScenePos(), touchEvent->widget()));
      }
      touchEvent->setTouchPoints(touchPoints);
  }
  
  int QGraphicsScenePrivate::findClosestTouchPointId(const QPointF &scenePos)
  {
      int closestTouchPointId = -1;
      qreal closestDistance = qreal(0.);
      foreach (const QTouchEvent::TouchPoint &touchPoint, sceneCurrentTouchPoints) {
          qreal distance = QLineF(scenePos, touchPoint.scenePos()).length();
          if (closestTouchPointId == -1|| distance < closestDistance) {
              closestTouchPointId = touchPoint.id();
              closestDistance = distance;
          }
      }
      return closestTouchPointId;
  }
  
  void QGraphicsScenePrivate::touchEventHandler(QTouchEvent *sceneTouchEvent)
  {
      typedef QPair<Qt::TouchPointStates, QList<QTouchEvent::TouchPoint> > StatesAndTouchPoints;
      QHash<QGraphicsItem *, StatesAndTouchPoints> itemsNeedingEvents;
  
      for (int i = 0; i < sceneTouchEvent->touchPoints().count(); ++i) {
          const QTouchEvent::TouchPoint &touchPoint = sceneTouchEvent->touchPoints().at(i);
  
          // update state
          QGraphicsItem *item = 0;
          if (touchPoint.state() == Qt::TouchPointPressed) {
              if (sceneTouchEvent->deviceType() == QTouchEvent::TouchPad) {
                  // on touch-pad devices, send all touch points to the same item
                  item = itemForTouchPointId.isEmpty()
                         ? 0
                         : itemForTouchPointId.constBegin().value();
              }
  
              if (!item) {
                  // determine which item this touch point will go to
                  cachedItemsUnderMouse = itemsAtPosition(touchPoint.screenPos().toPoint(),
                                                          touchPoint.scenePos(),
                                                          sceneTouchEvent->widget());
                  item = cachedItemsUnderMouse.isEmpty() ? 0 : cachedItemsUnderMouse.first();
              }
  
              if (sceneTouchEvent->deviceType() == QTouchEvent::TouchScreen) {
                  // on touch-screens, combine this touch point with the closest one we find
                  int closestTouchPointId = findClosestTouchPointId(touchPoint.scenePos());
                  QGraphicsItem *closestItem = itemForTouchPointId.value(closestTouchPointId);
                  if (!item || (closestItem && cachedItemsUnderMouse.contains(closestItem)))
                      item = closestItem;
              }
              if (!item)
                  continue;
  
              itemForTouchPointId.insert(touchPoint.id(), item);
              sceneCurrentTouchPoints.insert(touchPoint.id(), touchPoint);
          } else if (touchPoint.state() == Qt::TouchPointReleased) {
              item = itemForTouchPointId.take(touchPoint.id());
              if (!item)
                  continue;
  
              sceneCurrentTouchPoints.remove(touchPoint.id());
          } else {
              item = itemForTouchPointId.value(touchPoint.id());
              if (!item)
                  continue;
              Q_ASSERT(sceneCurrentTouchPoints.contains(touchPoint.id()));
              sceneCurrentTouchPoints[touchPoint.id()] = touchPoint;
          }
  
          StatesAndTouchPoints &statesAndTouchPoints = itemsNeedingEvents[item];
          statesAndTouchPoints.first |= touchPoint.state();
          statesAndTouchPoints.second.append(touchPoint);
      }
  
      if (itemsNeedingEvents.isEmpty()) {
          sceneTouchEvent->accept();
          return;
      }
  
      bool ignoreSceneTouchEvent = true;
      QHash<QGraphicsItem *, StatesAndTouchPoints>::ConstIterator it = itemsNeedingEvents.constBegin();
      const QHash<QGraphicsItem *, StatesAndTouchPoints>::ConstIterator end = itemsNeedingEvents.constEnd();
      for (; it != end; ++it) {
          QGraphicsItem *item = it.key();
  
          (void) item->isBlockedByModalPanel(&item);
  
          // determine event type from the state mask
          QEvent::Type eventType;
          switch (it.value().first) {
          case Qt::TouchPointPressed:
              // all touch points have pressed state
              eventType = QEvent::TouchBegin;
              break;
          case Qt::TouchPointReleased:
              // all touch points have released state
              eventType = QEvent::TouchEnd;
              break;
          case Qt::TouchPointStationary:
              // don't send the event if nothing changed
              continue;
          default:
              // all other combinations
              eventType = QEvent::TouchUpdate;
              break;
          }
  
          QTouchEvent touchEvent(eventType);
          touchEvent.setWidget(sceneTouchEvent->widget());
          touchEvent.setDeviceType(sceneTouchEvent->deviceType());
          touchEvent.setModifiers(sceneTouchEvent->modifiers());
          touchEvent.setTouchPointStates(it.value().first);
          touchEvent.setTouchPoints(it.value().second);
  
          switch (touchEvent.type()) {
          case QEvent::TouchBegin:
          {
              // if the TouchBegin handler recurses, we assume that means the event
              // has been implicitly accepted and continue to send touch events
              item->d_ptr->acceptedTouchBeginEvent = true;
              bool res = sendTouchBeginEvent(item, &touchEvent)
                         && touchEvent.isAccepted();
              if (!res) {
                  // forget about these touch points, we didn't handle them
                  for (int i = 0; i < touchEvent.touchPoints().count(); ++i) {
                      const QTouchEvent::TouchPoint &touchPoint = touchEvent.touchPoints().at(i);
                      itemForTouchPointId.remove(touchPoint.id());
                      sceneCurrentTouchPoints.remove(touchPoint.id());
                  }
                  ignoreSceneTouchEvent = false;
              }
              break;
          }
          default:
              if (item->d_ptr->acceptedTouchBeginEvent) {
                  updateTouchPointsForItem(item, &touchEvent);
                  (void) sendEvent(item, &touchEvent);
                  ignoreSceneTouchEvent = false;
              }
              break;
          }
      }
      sceneTouchEvent->setAccepted(ignoreSceneTouchEvent);
  }
  
  bool QGraphicsScenePrivate::sendTouchBeginEvent(QGraphicsItem *origin, QTouchEvent *touchEvent)
  {
      Q_Q(QGraphicsScene);
  
      if (cachedItemsUnderMouse.isEmpty() || cachedItemsUnderMouse.first() != origin) {
          const QTouchEvent::TouchPoint &firstTouchPoint = touchEvent->touchPoints().first();
          cachedItemsUnderMouse = itemsAtPosition(firstTouchPoint.screenPos().toPoint(),
                                                  firstTouchPoint.scenePos(),
                                                  touchEvent->widget());
      }
      Q_ASSERT(cachedItemsUnderMouse.first() == origin);
  
      // Set focus on the topmost enabled item that can take focus.
      bool setFocus = false;
  
      foreach (QGraphicsItem *item, cachedItemsUnderMouse) {
          if (item->isEnabled() && ((item->flags() & QGraphicsItem::ItemIsFocusable) && item->d_ptr->mouseSetsFocus)) {
              if (!item->isWidget() || ((QGraphicsWidget *)item)->focusPolicy() & Qt::ClickFocus) {
                  setFocus = true;
                  if (item != q->focusItem())
                      q->setFocusItem(item, Qt::MouseFocusReason);
                  break;
              }
          }
          if (item->isPanel())
              break;
          if (item->d_ptr->flags & QGraphicsItem::ItemStopsClickFocusPropagation)
              break;
          if (item->d_ptr->flags & QGraphicsItem::ItemStopsFocusHandling) {
              // Make sure we don't clear focus.
              setFocus = true;
              break;
          }
      }
  
      // If nobody could take focus, clear it.
      if (!stickyFocus && !setFocus)
          q->setFocusItem(0, Qt::MouseFocusReason);
  
      bool res = false;
      bool eventAccepted = touchEvent->isAccepted();
      foreach (QGraphicsItem *item, cachedItemsUnderMouse) {
          // first, try to deliver the touch event
          updateTouchPointsForItem(item, touchEvent);
          bool acceptTouchEvents = item->acceptTouchEvents();
          touchEvent->setAccepted(acceptTouchEvents);
          res = acceptTouchEvents && sendEvent(item, touchEvent);
          eventAccepted = touchEvent->isAccepted();
          if (itemForTouchPointId.value(touchEvent->touchPoints().first().id()) == 0) {
              // item was deleted
              item = 0;
          } else {
              item->d_ptr->acceptedTouchBeginEvent = (res && eventAccepted);
          }
          touchEvent->spont = false;
          if (res && eventAccepted) {
              // the first item to accept the TouchBegin gets an implicit grab.
              for (int i = 0; i < touchEvent->touchPoints().count(); ++i) {
                  const QTouchEvent::TouchPoint &touchPoint = touchEvent->touchPoints().at(i);
                  itemForTouchPointId[touchPoint.id()] = item; // can be zero
              }
              break;
          }
          if (item && item->isPanel())
              break;
      }
  
      touchEvent->setAccepted(eventAccepted);
      return res;
  }
  
  void QGraphicsScenePrivate::enableTouchEventsOnViews()
  {
      foreach (QGraphicsView *view, views)
          view->viewport()->setAttribute(Qt::WA_AcceptTouchEvents, true);
  }
  
  void QGraphicsScenePrivate::updateInputMethodSensitivityInViews()
  {
      for (int i = 0; i < views.size(); ++i)
          views.at(i)->d_func()->updateInputMethodSensitivity();
  }
  
  void QGraphicsScenePrivate::enterModal(QGraphicsItem *panel, QGraphicsItem::PanelModality previousModality)
  {
      Q_Q(QGraphicsScene);
      Q_ASSERT(panel && panel->isPanel());
  
      QGraphicsItem::PanelModality panelModality = panel->d_ptr->panelModality;
      if (previousModality != QGraphicsItem::NonModal) {
          // the panel is changing from one modality type to another... temporarily set it back so
          // that blockedPanels is populated correctly
          panel->d_ptr->panelModality = previousModality;
      }
  
      QSet<QGraphicsItem *> blockedPanels;
      QList<QGraphicsItem *> items = q->items(); // ### store panels separately
      for (int i = 0; i < items.count(); ++i) {
          QGraphicsItem *item = items.at(i);
          if (item->isPanel() && item->isBlockedByModalPanel())
              blockedPanels.insert(item);
      }
      // blockedPanels contains all currently blocked panels
  
      if (previousModality != QGraphicsItem::NonModal) {
          // reset the modality to the proper value, since we changed it above
          panel->d_ptr->panelModality = panelModality;
          // remove this panel so that it will be reinserted at the front of the stack
          modalPanels.removeAll(panel);
      }
  
      modalPanels.prepend(panel);
  
      if (!hoverItems.isEmpty()) {
          // send GraphicsSceneHoverLeave events to newly blocked hoverItems
          QGraphicsSceneHoverEvent hoverEvent;
          hoverEvent.setScenePos(lastSceneMousePos);
          dispatchHoverEvent(&hoverEvent);
      }
  
      if (!mouseGrabberItems.isEmpty() && lastMouseGrabberItemHasImplicitMouseGrab) {
          QGraphicsItem *item = mouseGrabberItems.last();
          if (item->isBlockedByModalPanel())
              ungrabMouse(item, /*itemIsDying =*/ false);
      }
  
      QEvent windowBlockedEvent(QEvent::WindowBlocked);
      QEvent windowUnblockedEvent(QEvent::WindowUnblocked);
      for (int i = 0; i < items.count(); ++i) {
          QGraphicsItem *item = items.at(i);
          if (item->isPanel()) {
              if (!blockedPanels.contains(item) && item->isBlockedByModalPanel()) {
                  // send QEvent::WindowBlocked to newly blocked panels
                  sendEvent(item, &windowBlockedEvent);
              } else if (blockedPanels.contains(item) && !item->isBlockedByModalPanel()) {
                  // send QEvent::WindowUnblocked to unblocked panels when downgrading
                  // a panel from SceneModal to PanelModal
                  sendEvent(item, &windowUnblockedEvent);
              }
          }
      }
  }
  
  void QGraphicsScenePrivate::leaveModal(QGraphicsItem *panel)
  {
      Q_Q(QGraphicsScene);
      Q_ASSERT(panel && panel->isPanel());
  
      QSet<QGraphicsItem *> blockedPanels;
      QList<QGraphicsItem *> items = q->items(); // ### same as above
      for (int i = 0; i < items.count(); ++i) {
          QGraphicsItem *item = items.at(i);
          if (item->isPanel() && item->isBlockedByModalPanel())
              blockedPanels.insert(item);
      }
  
      modalPanels.removeAll(panel);
  
      QEvent e(QEvent::WindowUnblocked);
      for (int i = 0; i < items.count(); ++i) {
          QGraphicsItem *item = items.at(i);
          if (item->isPanel() && blockedPanels.contains(item) && !item->isBlockedByModalPanel())
              sendEvent(item, &e);
      }
  
      // send GraphicsSceneHoverEnter events to newly unblocked items
      QGraphicsSceneHoverEvent hoverEvent;
      hoverEvent.setScenePos(lastSceneMousePos);
      dispatchHoverEvent(&hoverEvent);
  }
  
  #ifndef QT_NO_GESTURES
  void QGraphicsScenePrivate::gestureTargetsAtHotSpots(const QSet<QGesture *> &gestures,
                                                Qt::GestureFlag flag,
                                                QHash<QGraphicsObject *, QSet<QGesture *> > *targets,
                                                QSet<QGraphicsObject *> *itemsSet,
                                                QSet<QGesture *> *normal,
                                                QSet<QGesture *> *conflicts)
  {
      QSet<QGesture *> normalGestures; // that are not in conflicted state.
      foreach (QGesture *gesture, gestures) {
          if (!gesture->hasHotSpot())
              continue;
          const Qt::GestureType gestureType = gesture->gestureType();
          QList<QGraphicsItem *> items = itemsAtPosition(QPoint(), gesture->d_func()->sceneHotSpot, 0);
          for (int j = 0; j < items.size(); ++j) {
              QGraphicsItem *item = items.at(j);
  
              // Check if the item is blocked by a modal panel and use it as
              // a target instead of this item.
              (void) item->isBlockedByModalPanel(&item);
  
              if (QGraphicsObject *itemobj = item->toGraphicsObject()) {
                  QGraphicsItemPrivate *d = item->QGraphicsItem::d_func();
                  QMap<Qt::GestureType, Qt::GestureFlags>::const_iterator it =
                          d->gestureContext.find(gestureType);
                  if (it != d->gestureContext.end() && (!flag || (it.value() & flag))) {
                      if (normalGestures.contains(gesture)) {
                          normalGestures.remove(gesture);
                          if (conflicts)
                              conflicts->insert(gesture);
                      } else {
                          normalGestures.insert(gesture);
                      }
                      if (targets)
                          (*targets)[itemobj].insert(gesture);
                      if (itemsSet)
                          (*itemsSet).insert(itemobj);
                  }
              }
              // Don't propagate through panels.
              if (item->isPanel())
                  break;
          }
      }
      if (normal)
          *normal = normalGestures;
  }
  
  void QGraphicsScenePrivate::gestureEventHandler(QGestureEvent *event)
  {
      QWidget *viewport = event->widget();
      if (!viewport)
          return;
      QGraphicsView *graphicsView = qobject_cast<QGraphicsView *>(viewport->parent());
      if (!graphicsView)
          return;
  
      QList<QGesture *> allGestures = event->gestures();
      G_DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:"
              << "Gestures:" <<  allGestures;
  
      QSet<QGesture *> startedGestures;
      QPoint delta = viewport->mapFromGlobal(QPoint());
      QTransform toScene = QTransform::fromTranslate(delta.x(), delta.y())
                           * graphicsView->viewportTransform().inverted();
      foreach (QGesture *gesture, allGestures) {
          // cache scene coordinates of the hot spot
          if (gesture->hasHotSpot()) {
              gesture->d_func()->sceneHotSpot = toScene.map(gesture->hotSpot());
          } else {
              gesture->d_func()->sceneHotSpot = QPointF();
          }
  
          QGraphicsObject *target = gestureTargets.value(gesture, 0);
          if (!target) {
              // when we are not in started mode but don't have a target
              // then the only one interested in gesture is the view/scene
              if (gesture->state() == Qt::GestureStarted)
                  startedGestures.insert(gesture);
          }
      }
  
      if (!startedGestures.isEmpty()) {
          QSet<QGesture *> normalGestures; // that have just one target
          QSet<QGesture *> conflictedGestures; // that have multiple possible targets
          gestureTargetsAtHotSpots(startedGestures, Qt::GestureFlag(0), &cachedItemGestures, 0,
                                   &normalGestures, &conflictedGestures);
          cachedTargetItems = cachedItemGestures.keys();
          qSort(cachedTargetItems.begin(), cachedTargetItems.end(), qt_closestItemFirst);
          G_DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:"
                  << "Normal gestures:" << normalGestures
                  << "Conflicting gestures:" << conflictedGestures;
  
          // deliver conflicted gestures as override events AND remember
          // initial gesture targets
          if (!conflictedGestures.isEmpty()) {
              for (int i = 0; i < cachedTargetItems.size(); ++i) {
                  QWeakPointer<QGraphicsObject> item = cachedTargetItems.at(i);
  
                  // get gestures to deliver to the current item
                  QSet<QGesture *> gestures = conflictedGestures & cachedItemGestures.value(item.data());
                  if (gestures.isEmpty())
                      continue;
  
                  G_DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:"
                          << "delivering override to"
                          << item.data() << gestures;
                  // send gesture override
                  QGestureEvent ev(gestures.toList());
                  ev.t = QEvent::GestureOverride;
                  ev.setWidget(event->widget());
                  // mark event and individual gestures as ignored
                  ev.ignore();
                  foreach(QGesture *g, gestures)
                      ev.setAccepted(g, false);
                  sendEvent(item.data(), &ev);
                  // mark all accepted gestures to deliver them as normal gesture events
                  foreach (QGesture *g, gestures) {
                      if (ev.isAccepted() || ev.isAccepted(g)) {
                          conflictedGestures.remove(g);
                          // mark the item as a gesture target
                          if (item) {
                              gestureTargets.insert(g, item.data());
                              QHash<QGraphicsObject *, QSet<QGesture *> >::iterator it, e;
                              it = cachedItemGestures.begin();
                              e = cachedItemGestures.end();
                              for(; it != e; ++it)
                                  it.value().remove(g);
                              cachedItemGestures[item.data()].insert(g);
                          }
                          G_DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:"
                                  << "override was accepted:"
                                  << g << item.data();
                      }
                      // remember the first item that received the override event
                      // as it most likely become a target if no one else accepts
                      // the override event
                      if (!gestureTargets.contains(g) && item)
                          gestureTargets.insert(g, item.data());
  
                  }
                  if (conflictedGestures.isEmpty())
                      break;
              }
          }
          // remember the initial target item for each gesture that was not in
          // the conflicted state.
          if (!normalGestures.isEmpty()) {
              for (int i = 0; i < cachedTargetItems.size() && !normalGestures.isEmpty(); ++i) {
                  QGraphicsObject *item = cachedTargetItems.at(i);
  
                  // get gestures to deliver to the current item
                  foreach (QGesture *g, cachedItemGestures.value(item)) {
                      if (!gestureTargets.contains(g)) {
                          gestureTargets.insert(g, item);
                          normalGestures.remove(g);
                      }
                  }
              }
          }
      }
  
  
      // deliver all gesture events
      QSet<QGesture *> undeliveredGestures;
      QSet<QGesture *> parentPropagatedGestures;
      foreach (QGesture *gesture, allGestures) {
          if (QGraphicsObject *target = gestureTargets.value(gesture, 0)) {
              cachedItemGestures[target].insert(gesture);
              cachedTargetItems.append(target);
              undeliveredGestures.insert(gesture);
              QGraphicsItemPrivate *d = target->QGraphicsItem::d_func();
              const Qt::GestureFlags flags = d->gestureContext.value(gesture->gestureType());
              if (flags & Qt::IgnoredGesturesPropagateToParent)
                  parentPropagatedGestures.insert(gesture);
          } else {
              G_DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:"
                      << "no target for" << gesture << "at"
                      << gesture->hotSpot() << gesture->d_func()->sceneHotSpot;
          }
      }
      qSort(cachedTargetItems.begin(), cachedTargetItems.end(), qt_closestItemFirst);
      for (int i = 0; i < cachedTargetItems.size(); ++i) {
          QWeakPointer<QGraphicsObject> receiver = cachedTargetItems.at(i);
          QSet<QGesture *> gestures =
                  undeliveredGestures & cachedItemGestures.value(receiver.data());
          gestures -= cachedAlreadyDeliveredGestures.value(receiver.data());
  
          if (gestures.isEmpty())
              continue;
  
          cachedAlreadyDeliveredGestures[receiver.data()] += gestures;
          const bool isPanel = receiver.data()->isPanel();
  
          G_DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:"
                  << "delivering to"
                  << receiver.data() << gestures;
          QGestureEvent ev(gestures.toList());
          ev.setWidget(event->widget());
          sendEvent(receiver.data(), &ev);
          QSet<QGesture *> ignoredGestures;
          foreach (QGesture *g, gestures) {
              if (!ev.isAccepted() && !ev.isAccepted(g)) {
                  // if the gesture was ignored by its target, we will update the
                  // targetItems list with a possible target items (items that
                  // want to receive partial gestures).
                  // ### wont' work if the target was destroyed in the event
                  //     we will just stop delivering it.
                  if (receiver && receiver.data() == gestureTargets.value(g, 0))
                      ignoredGestures.insert(g);
              } else {
                  if (receiver && g->state() == Qt::GestureStarted) {
                      // someone accepted the propagated initial GestureStarted
                      // event, let it be the new target for all following events.
                      gestureTargets[g] = receiver.data();
                  }
                  undeliveredGestures.remove(g);
              }
          }
          if (undeliveredGestures.isEmpty())
              break;
  
          // ignoredGestures list is only filled when delivering to the gesture
          // target item, so it is safe to assume item == target.
          if (!ignoredGestures.isEmpty() && !isPanel) {
              // look for new potential targets for gestures that were ignored
              // and should be propagated.
  
              QSet<QGraphicsObject *> targetsSet = cachedTargetItems.toSet();
  
              if (receiver) {
                  // first if the gesture should be propagated to parents only
                  for (QSet<QGesture *>::iterator it = ignoredGestures.begin();
                       it != ignoredGestures.end();) {
                      if (parentPropagatedGestures.contains(*it)) {
                          QGesture *gesture = *it;
                          const Qt::GestureType gestureType = gesture->gestureType();
                          QGraphicsItem *item = receiver.data();
                          while (item) {
                              if (QGraphicsObject *obj = item->toGraphicsObject()) {
                                  if (item->d_func()->gestureContext.contains(gestureType)) {
                                      targetsSet.insert(obj);
                                      cachedItemGestures[obj].insert(gesture);
                                  }
                              }
                              if (item->isPanel())
                                  break;
                              item = item->parentItem();
                          }
  
                          it = ignoredGestures.erase(it);
                          continue;
                      }
                      ++it;
                  }
              }
  
              gestureTargetsAtHotSpots(ignoredGestures, Qt::ReceivePartialGestures,
                                       &cachedItemGestures, &targetsSet, 0, 0);
  
              cachedTargetItems = targetsSet.toList();
              qSort(cachedTargetItems.begin(), cachedTargetItems.end(), qt_closestItemFirst);
              G_DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:"
                      << "new targets:" << cachedTargetItems;
              i = -1; // start delivery again
              continue;
          }
      }
  
      foreach (QGesture *g, startedGestures) {
          if (g->gestureCancelPolicy() == QGesture::CancelAllInContext) {
              G_DEBUG() << "lets try to cancel some";
              // find gestures in context in Qt::GestureStarted or Qt::GestureUpdated state and cancel them
              cancelGesturesForChildren(g);
          }
      }
  
      // forget about targets for gestures that have ended
      foreach (QGesture *g, allGestures) {
          switch (g->state()) {
          case Qt::GestureFinished:
          case Qt::GestureCanceled:
              gestureTargets.remove(g);
              break;
          default:
              break;
          }
      }
  
      cachedTargetItems.clear();
      cachedItemGestures.clear();
      cachedAlreadyDeliveredGestures.clear();
  }
  
  void QGraphicsScenePrivate::cancelGesturesForChildren(QGesture *original)
  {
      Q_ASSERT(original);
      QGraphicsItem *originalItem = gestureTargets.value(original);
      if (originalItem == 0) // we only act on accepted gestures, which implies it has a target.
          return;
  
      // iterate over all active gestures and for each find the owner
      // if the owner is part of our sub-hierarchy, cancel it.
  
      QSet<QGesture *> canceledGestures;
      QHash<QGesture *, QGraphicsObject *>::Iterator iter = gestureTargets.begin();
      while (iter != gestureTargets.end()) {
          QGraphicsObject *item = iter.value();
          // note that we don't touch the gestures for our originalItem
          if (item != originalItem && originalItem->isAncestorOf(item)) {
              G_DEBUG() << "  found a gesture to cancel" << iter.key();
              iter.key()->d_func()->state = Qt::GestureCanceled;
              canceledGestures << iter.key();
          }
          ++iter;
      }
  
      // sort them per target item by cherry picking from almostCanceledGestures and delivering
      QSet<QGesture *> almostCanceledGestures = canceledGestures;
      QSet<QGesture *>::Iterator setIter;
      while (!almostCanceledGestures.isEmpty()) {
          QGraphicsObject *target = 0;
          QSet<QGesture*> gestures;
          setIter = almostCanceledGestures.begin();
          // sort per target item
          while (setIter != almostCanceledGestures.end()) {
              QGraphicsObject *item = gestureTargets.value(*setIter);
              if (target == 0)
                  target = item;
              if (target == item) {
                  gestures << *setIter;
                  setIter = almostCanceledGestures.erase(setIter);
              } else {
                  ++setIter;
              }
          }
          Q_ASSERT(target);
  
          QList<QGesture *> list = gestures.toList();
          QGestureEvent ev(list);
          sendEvent(target, &ev);
  
          foreach (QGesture *g, list) {
              if (ev.isAccepted() || ev.isAccepted(g))
                  gestures.remove(g);
          }
  
          foreach (QGesture *g, gestures) {
              if (!g->hasHotSpot())
                  continue;
  
              QList<QGraphicsItem *> items = itemsAtPosition(QPoint(), g->d_func()->sceneHotSpot, 0);
              for (int j = 0; j < items.size(); ++j) {
                  QGraphicsObject *item = items.at(j)->toGraphicsObject();
                  if (!item)
                      continue;
                  QGraphicsItemPrivate *d = item->QGraphicsItem::d_func();
                  if (d->gestureContext.contains(g->gestureType())) {
                      QList<QGesture *> list;
                      list << g;
                      QGestureEvent ev(list);
                      sendEvent(item, &ev);
                      if (ev.isAccepted() || ev.isAccepted(g))
                          break; // successfully delivered
                  }
              }
          }
      }
  
      QGestureManager *gestureManager = QApplicationPrivate::instance()->gestureManager;
      Q_ASSERT(gestureManager); // it would be very odd if we got called without a manager.
      for (setIter = canceledGestures.begin(); setIter != canceledGestures.end(); ++setIter) {
          gestureManager->recycle(*setIter);
          gestureTargets.remove(*setIter);
      }
  }
  
  void QGraphicsScenePrivate::grabGesture(QGraphicsItem *, Qt::GestureType gesture)
  {
      (void)QGestureManager::instance(); // create a gesture manager
      if (!grabbedGestures[gesture]++) {
          foreach (QGraphicsView *view, views)
              view->viewport()->grabGesture(gesture);
      }
  }
  
  void QGraphicsScenePrivate::ungrabGesture(QGraphicsItem *item, Qt::GestureType gesture)
  {
      // we know this can only be an object
      Q_ASSERT(item->d_ptr->isObject);
      QGraphicsObject *obj = static_cast<QGraphicsObject *>(item);
      QGestureManager::instance()->cleanupCachedGestures(obj, gesture);
      if (!--grabbedGestures[gesture]) {
          foreach (QGraphicsView *view, views)
              view->viewport()->ungrabGesture(gesture);
      }
  }
  #endif // QT_NO_GESTURES
  
  QT_END_NAMESPACE
  
  #include "moc_qgraphicsscene.cpp"
  
  #endif // QT_NO_GRAPHICSVIEW
  