Index: trunk/src/gui/graphicsview/qgraphicsitem.cpp
===================================================================
--- trunk/src/gui/graphicsview/qgraphicsitem.cpp	(revision 5)
+++ trunk/src/gui/graphicsview/qgraphicsitem.cpp	(revision 561)
@@ -2,5 +2,6 @@
 **
 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
-** Contact: Qt Software Information (qt-info@nokia.com)
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
 **
 ** This file is part of the QtGui module of the Qt Toolkit.
@@ -21,8 +22,7 @@
 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
 **
-** In addition, as a special exception, Nokia gives you certain
-** additional rights. These rights are described in the Nokia Qt LGPL
-** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
-** package.
+** In addition, as a special exception, Nokia gives you certain additional
+** rights.  These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
 **
 ** GNU General Public License Usage
@@ -34,6 +34,6 @@
 ** met: http://www.gnu.org/copyleft/gpl.html.
 **
-** If you are unsure which license is appropriate for your use, please
-** contact the sales department at qt-sales@nokia.com.
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
 ** $QT_END_LICENSE$
 **
@@ -45,5 +45,5 @@
     items in a QGraphicsScene.
     \since 4.2
-    \ingroup multimedia
+
     \ingroup graphicsview-api
 
@@ -53,5 +53,5 @@
     QGraphicsItem is part of \l{The Graphics View Framework}
 
-    \img graphicsview-items.png
+    \image graphicsview-items.png
 
     For convenience, Qt provides a set of standard graphics items for the most
@@ -92,17 +92,19 @@
     \snippet doc/src/snippets/code/src_gui_graphicsview_qgraphicsitem.cpp 0
 
-    The boundingRect() function has many different purposes. QGraphicsScene
-    bases its item index on boundingRect(), and QGraphicsView uses it both for
-    culling invisible items, and for determining the area that needs to be
-    recomposed when drawing overlapping items. In addition, QGraphicsItem's
-    collision detection mechanisms use boundingRect() to provide an efficient
-    cut-off. The fine grained collision algorithm in collidesWithItem() is based
-    on calling shape(), which returns an accurate outline of the item's shape
-    as a QPainterPath.
-
-    QGraphicsScene expects all items boundingRect() and shape() to remain
-    unchanged unless it is notified. If you want to change an item's geometry
-    in any way, you must first call prepareGeometryChange() to allow
-    QGraphicsScene to update its bookkeeping.
+    The boundingRect() function has many different purposes.
+    QGraphicsScene bases its item index on boundingRect(), and
+    QGraphicsView uses it both for culling invisible items, and for
+    determining the area that needs to be recomposed when drawing
+    overlapping items. In addition, QGraphicsItem's collision
+    detection mechanisms use boundingRect() to provide an efficient
+    cut-off. The fine grained collision algorithm in
+    collidesWithItem() is based on calling shape(), which returns an
+    accurate outline of the item's shape as a QPainterPath.
+
+    QGraphicsScene expects all items boundingRect() and shape() to
+    remain unchanged unless it is notified. If you want to change an
+    item's geometry in any way, you must first call
+    prepareGeometryChange() to allow QGraphicsScene to update its
+    bookkeeping.
 
     Collision detection can be done in two ways:
@@ -110,10 +112,11 @@
     \list 1
 
-    \o Reimplement shape() to return an accurate shape for your item, and rely
-    on the default implementation of collidesWithItem() to do shape-shape
-    intersection. This can be rather expensive if the shapes are complex.
-
-    \o Reimplement collidesWithItem() to provide your own custom item and shape
-    collision algorithm.
+    \o Reimplement shape() to return an accurate shape for your item,
+    and rely on the default implementation of collidesWithItem() to do
+    shape-shape intersection. This can be rather expensive if the
+    shapes are complex.
+
+    \o Reimplement collidesWithItem() to provide your own custom item
+    and shape collision algorithm.
 
     \endlist
@@ -131,19 +134,41 @@
     \img graphicsview-parentchild.png
 
-    QGraphicsItem supports affine transformations in addition to its base
-    position, pos(). To change the item's transformation, you can either pass
-    a transformation matrix to setTransform(), or call one of the convenience
-    functions rotate(), scale(), translate(), or shear(). Item transformations
-    accumulate from parent to child, so if both a parent and child item are
-    rotated 90 degrees, the child's total transformation will be 180 degrees.
-    Similarly, if the item's parent is scaled to 2x its original size, its
-    children will also be twice as large. An item's transformation does not
-    affect its own local geometry; all geometry functions (e.g., contains(),
-    update(), and all the mapping functions) still operate in local
-    coordinates. For convenience, QGraphicsItem provides the functions
-    sceneTransform(), which returns the item's total transformation matrix
-    (including its position and all parents' positions and transformations),
-    and scenePos(), which returns its position in scene coordinates. To reset
-    an item's matrix, call resetTransform().
+    \section1 Transformation
+
+    QGraphicsItem supports projective transformations in addition to its base
+    position, pos(). There are several ways to change an item's transformation.
+    For simple transformations, you can call either of the convenience
+    functions setRotation() or setScale(), or you can pass any transformation
+    matrix to setTransform(). For advanced transformation control you also have
+    the option of setting several combined transformations by calling
+    setTransformations().
+
+    Item transformations accumulate from parent to child, so if both a parent
+    and child item are rotated 90 degrees, the child's total transformation
+    will be 180 degrees. Similarly, if the item's parent is scaled to 2x its
+    original size, its children will also be twice as large. An item's
+    transformation does not affect its own local geometry; all geometry
+    functions (e.g., contains(), update(), and all the mapping functions) still
+    operate in local coordinates. For convenience, QGraphicsItem provides the
+    functions sceneTransform(), which returns the item's total transformation
+    matrix (including its position and all parents' positions and
+    transformations), and scenePos(), which returns its position in scene
+    coordinates. To reset an item's matrix, call resetTransform().
+
+    Certain transformation operations produce a different outcome depending on
+    the order in which they are applied. For example, if you scale an
+    transform, and then rotate it, you may get a different result than if the
+    transform was rotated first. However, the order you set the transformation
+    properties on QGraphicsItem does not affect the resulting transformation;
+    QGraphicsItem always applies the properties in a fixed, defined order:
+
+    \list
+    \o The item's base transform is applied (transform())
+    \o The item's transformations list is applied in order (transformations())
+    \o The item is rotated relative to its transform origin point (rotation(), transformOriginPoint())
+    \o The item is scaled relative to its transform origin point (scale(), transformOriginPoint())
+    \endlist
+
+    \section1 Painting
 
     The paint() function is called by QGraphicsView to paint the item's
@@ -162,4 +187,49 @@
     drawn before their children.
 
+    \section1 Sorting
+
+    All items are drawn in a defined, stable order, and this same order decides
+    which items will receive mouse input first when you click on the scene.
+    Normally you don't have to worry about sorting, as the items follow a
+    "natural order", following the logical structure of the scene.
+
+    An item's children are stacked on top of the parent, and sibling items are
+    stacked by insertion order (i.e., in the same order that they were either
+    added to the scene, or added to the same parent). If you add item A, and
+    then B, then B will be on top of A. If you then add C, the items' stacking
+    order will be A, then B, then C.
+
+    \image graphicsview-zorder.png
+
+    This example shows the stacking order of all limbs of the robot from the
+    \l{graphicsview/dragdroprobot}{Drag and Drop Robot} example. The torso is
+    the root item (all other items are children or descendants of the torso),
+    so it is drawn first. Next, the head is drawn, as it is the first item in
+    the torso's list of children. Then the upper left arm is drawn. As the
+    lower arm is a child of the upper arm, the lower arm is then drawn,
+    followed by the upper arm's next sibling, which is the upper right arm, and
+    so on.
+
+    For advanced users, there are ways to alter how your items are sorted:
+
+    \list
+    \o You can call setZValue() on an item to explicitly stack it on top of, or
+    under, other sibling items. The default Z value for an item is 0. Items
+    with the same Z value are stacked by insertion order.
+
+    \o You can call stackBefore() to reorder the list of children. This will
+    directly modify the insertion order.
+
+    \o You can set the ItemStacksBehindParent flag to stack a child item behind
+    its parent.
+    \endlist
+
+    The stacking order of two sibling items also counts for each item's
+    children and descendant items. So if one item is on top of another, then
+    all its children will also be on top of all the other item's children as
+    well.
+
+    \section1 Events
+
     QGraphicsItem receives events from QGraphicsScene through the virtual
     function sceneEvent(). This function distributes the most common events
@@ -172,5 +242,5 @@
     hover enter, move and leave events
     \o inputMethodEvent() handles input events, for accessibility support
-    \o keyPressEvent() and keyReleaseEvent handle key press and release events
+    \o keyPressEvent() and keyReleaseEvent() handle key press and release events
     \o mousePressEvent(), mouseMoveEvent(), mouseReleaseEvent(), and
     mouseDoubleClickEvent() handles mouse press, move, release, click and
@@ -178,12 +248,13 @@
     \endlist
 
-    You can filter events for any other item by installing event
-    filters. This functionaly is separate from from Qt's regular
-    event filters (see QObject::installEventFilter()), which only
-    work on subclasses of QObject. After installing your item as an
-    event filter for another item by calling
-    installSceneEventFilter(), the filtered events will be received
-    by the virtual function sceneEventFilter(). You can remove item
-    event filters by calling removeSceneEventFilter().
+    You can filter events for any other item by installing event filters. This
+    functionality is separate from Qt's regular event filters (see
+    QObject::installEventFilter()), which only work on subclasses of QObject. After
+    installing your item as an event filter for another item by calling
+    installSceneEventFilter(), the filtered events will be received by the virtual
+    function sceneEventFilter(). You can remove item event filters by calling
+    removeSceneEventFilter().
+
+    \section1 Custom Data
 
     Sometimes it's useful to register custom data with an item, be it a custom
@@ -275,4 +346,51 @@
     drop shadow effects and for decoration objects that follow the parent
     item's geometry without drawing on top of it.
+
+    \value ItemUsesExtendedStyleOption The item makes use of either
+    \l{QStyleOptionGraphicsItem::}{exposedRect} or
+    \l{QStyleOptionGraphicsItem::}{matrix} in QStyleOptionGraphicsItem. By default,
+    the \l{QStyleOptionGraphicsItem::}{exposedRect} is initialized to the item's
+    boundingRect() and the \l{QStyleOptionGraphicsItem::}{matrix} is untransformed.
+    You can enable this flag for the style options to be set up with more
+    fine-grained values.
+    Note that QStyleOptionGraphicsItem::levelOfDetail is unaffected by this flag
+    and always initialized to 1. Use
+    QStyleOptionGraphicsItem::levelOfDetailFromTransform() if you need a higher
+    value.
+
+    \value ItemHasNoContents The item does not paint anything (i.e., calling
+    paint() on the item has no effect). You should set this flag on items that
+    do not need to be painted to ensure that Graphics View avoids unnecessary
+    painting preparations. This flag was introduced in Qt 4.6.
+
+    \value ItemSendsGeometryChanges The item enables itemChange()
+    notifications for ItemPositionChange, ItemPositionHasChanged,
+    ItemMatrixChange, ItemTransformChange, and ItemTransformHasChanged. For
+    performance reasons, these notifications are disabled by default. You must
+    enable this flag to receive notifications for position and transform
+    changes. This flag was introduced in Qt 4.6.
+
+    \value ItemAcceptsInputMethod The item supports input methods typically
+    used for Asian languages.
+    This flag was introduced in Qt 4.6.
+
+    \value ItemNegativeZStacksBehindParent The item automatically stacks behind
+    it's parent if it's z-value is negative. This flag enables setZValue() to
+    toggle ItemStacksBehindParent.
+
+    \value ItemIsPanel The item is a panel. A panel provides activation and
+    contained focus handling. Only one panel can be active at a time (see
+    QGraphicsItem::isActive()). When no panel is active, QGraphicsScene
+    activates all non-panel items. Window items (i.e.,
+    QGraphicsItem::isWindow() returns true) are panels. This flag was
+    introduced in Qt 4.6.
+
+    \omitvalue ItemIsFocusScope \omit Internal only (for now). \endomit
+
+    \value ItemSendsScenePositionChanges The item enables itemChange()
+    notifications for ItemScenePositionHasChanged. For performance reasons,
+    these notifications are disabled by default. You must enable this flag
+    to receive notifications for scene position changes. This flag was
+    introduced in Qt 4.6.
 */
 
@@ -313,39 +431,43 @@
 
     \value ItemPositionChange The item's position changes. This notification
-    is only sent when the item's local position changes, relative to its
-    parent, has changed (i.e., as a result of calling setPos() or
-    moveBy()). The value argument is the new position (i.e., a QPointF).  You
-    can call pos() to get the original position. Do not call setPos() or
-    moveBy() in itemChange() as this notification is delivered; instead, you
-    can return the new, adjusted position from itemChange(). After this
-    notification, QGraphicsItem immediately sends the ItemPositionHasChanged
-    notification if the position changed.
+    is sent if the ItemSendsGeometryChanges flag is enabled, and when the
+    item's local position changes, relative to its parent (i.e., as a result
+    of calling setPos() or moveBy()). The value argument is the new position
+    (i.e., a QPointF).  You can call pos() to get the original position. Do
+    not call setPos() or moveBy() in itemChange() as this notification is
+    delivered; instead, you can return the new, adjusted position from
+    itemChange(). After this notification, QGraphicsItem immediately sends the
+    ItemPositionHasChanged notification if the position changed.
 
     \value ItemPositionHasChanged The item's position has changed. This
-    notification is only sent after the item's local position, relative to its
-    parent, has changed. The value argument is the new position (the same as
-    pos()), and QGraphicsItem ignores the return value for this notification
-    (i.e., a read-only notification).
+    notification is sent if the ItemSendsGeometryChanges flag is enabled, and
+    after the item's local position, relative to its parent, has changed. The
+    value argument is the new position (the same as pos()), and QGraphicsItem
+    ignores the return value for this notification (i.e., a read-only
+    notification).
 
     \value ItemTransformChange The item's transformation matrix changes. This
-    notification is only sent when the item's local transformation matrix
-    changes (i.e., as a result of calling setTransform(), or one of the
-    convenience transformation functions, such as rotate()). The value
-    argument is the new matrix (i.e., a QTransform); to get the old matrix,
-    call transform(). Do not call setTransform() or any of the transformation
-    convenience functions in itemChange() as this notification is delivered;
-    instead, you can return the new matrix from itemChange().
+    notification is send if the ItemSendsGeometryChanges flag is enabled, and
+    when the item's local transformation matrix changes (i.e., as a result of
+    calling setTransform(). The value argument is the new matrix (i.e., a
+    QTransform); to get the old matrix, call transform(). Do not call
+    setTransform() or set any of the transformation properties in itemChange()
+    as this notification is delivered; instead, you can return the new matrix
+    from itemChange().  This notification is not sent if you change the
+    transformation properties.
 
     \value ItemTransformHasChanged The item's transformation matrix has
-    changed.  This notification is only sent after the item's local
-    trasformation matrix has changed. The value argument is the new matrix
+    changed either because setTransform is called, or one of the
+    transformation properties is changed. This notification is sent if the
+    ItemSendsGeometryChanges flag is enabled, and after the item's local
+    transformation matrix has changed. The value argument is the new matrix
     (same as transform()), and QGraphicsItem ignores the return value for this
     notification (i.e., a read-only notification).
 
-    \value ItemSelectedChange The item's selected state changes. If the item
-    is presently selected, it will become unselected, and vice verca. The
-    value argument is the new selected state (i.e., true or false). Do not
-    call setSelected() in itemChange() as this notification is delivered();
-    instead, you can return the new selected state from itemChange().
+    \value ItemSelectedChange The item's selected state changes. If the item is
+    presently selected, it will become unselected, and vice verca. The value
+    argument is the new selected state (i.e., true or false). Do not call
+    setSelected() in itemChange() as this notification is delivered; instead, you
+    can return the new selected state from itemChange().
 
     \value ItemSelectedHasChanged The item's selected state has changed. The
@@ -447,4 +569,12 @@
     argument is the new opacity (i.e., a double). Do not call setOpacity() as
     this notification is delivered. The return value is ignored.
+
+    \value ItemScenePositionHasChanged The item's scene position has changed.
+    This notification is sent if the ItemSendsScenePositionChanges flag is
+    enabled, and after the item's scene position has changed (i.e., the
+    position or transformation of the item itself or the position or
+    transformation of any ancestor has changed). The value argument is the
+    new scene position (the same as scenePos()), and QGraphicsItem ignores
+    the return value for this notification (i.e., a read-only notification).
 */
 
@@ -492,4 +622,20 @@
 */
 
+/*!
+    \enum QGraphicsItem::PanelModality
+    \since 4.6
+
+    This enum specifies the behavior of a modal panel. A modal panel
+    is one that blocks input to other panels. Note that items that
+    are children of a modal panel are not blocked.
+
+    The values are:
+    \value NonModal   The panel is not modal and does not block input to other panels.
+    \value PanelModal The panel is modal to a single item hierarchy and blocks input to its parent pane, all grandparent panels, and all siblings of its parent and grandparent panels.
+    \value SceneModal The window is modal to the entire scene and blocks input to all panels.
+
+    \sa QGraphicsItem::setPanelModality(), QGraphicsItem::panelModality(), QGraphicsItem::ItemIsPanel
+*/
+
 #include "qgraphicsitem.h"
 
@@ -502,4 +648,5 @@
 #include "qgraphicswidget.h"
 #include "qgraphicsproxywidget.h"
+#include "qgraphicsscenebsptreeindex_p.h"
 #include <QtCore/qbitarray.h>
 #include <QtCore/qdebug.h>
@@ -516,4 +663,6 @@
 #include <QtGui/qstyleoption.h>
 #include <QtGui/qevent.h>
+#include <QtGui/qinputcontext.h>
+#include <QtGui/qgraphicseffect.h>
 
 #include <private/qgraphicsitem_p.h>
@@ -522,19 +671,16 @@
 #include <private/qtextdocumentlayout_p.h>
 #include <private/qtextengine_p.h>
+#include <private/qwidget_p.h>
+
+#ifdef Q_WS_X11
+#include <private/qt_x11_p.h>
+#include <private/qpixmap_x11_p.h>
+#endif
+
+#include <private/qgesturemanager_p.h>
 
 #include <math.h>
 
 QT_BEGIN_NAMESPACE
-
-// QRectF::intersects() returns false always if either the source or target
-// rectangle's width or height are 0. This works around that problem.
-static inline void _q_adjustRect(QRectF *rect)
-{
-    Q_ASSERT(rect);
-    if (!rect->width())
-        rect->adjust(-0.00001, 0, 0.00001, 0);
-    if (!rect->height())
-        rect->adjust(0, -0.00001, 0, 0.00001);
-}
 
 static inline void _q_adjustRect(QRect *rect)
@@ -556,27 +702,4 @@
 };
 Q_GLOBAL_STATIC(QGraphicsItemCustomDataStore, qt_dataStore)
-
-/*!
-    \internal
-
-    Removes the first instance of \a child from \a children. This is a
-    heuristic approach that assumes that it's common to remove items from the
-    start or end of the list.
-*/
-static void qt_graphicsitem_removeChild(QGraphicsItem *child, QList<QGraphicsItem *> *children)
-{
-    const int n = children->size();
-    for (int i = 0; i < (n + 1) / 2; ++i) {
-        if (children->at(i) == child) {
-            children->removeAt(i);
-            return;
-        }
-        int j = n - i - 1;
-        if (children->at(j) == child) {
-            children->removeAt(j);
-            return;
-        }
-    }
-}
 
 /*!
@@ -622,4 +745,8 @@
         // disabled \a childFlag, or has been reparented.
         switch (int(childFlag)) {
+        case -2:
+            flag = AncestorFiltersChildEvents;
+            enabled = q->filtersChildEvents();
+            break;
         case -1:
             flag = AncestorHandlesChildEvents;
@@ -629,5 +756,4 @@
             flag = AncestorClipsChildren;
             enabled = flags & QGraphicsItem::ItemClipsChildrenToShape;
-            invalidateCachedClipPathRecursively(/*childrenOnly=*/true);
             break;
         case QGraphicsItem::ItemIgnoresTransformations:
@@ -639,16 +765,20 @@
         }
 
-        // Inherit the enabled-state from our parents.
-        if ((parent && ((parent->d_ptr->ancestorFlags & flag)
-                        || (int(parent->d_ptr->flags & childFlag) == childFlag)
-                        || (childFlag == -1 && parent->d_ptr->handlesChildEvents)))) {
-            enabled = true;
-            ancestorFlags |= flag;
+        if (parent) {
+            // Inherit the enabled-state from our parents.
+            if ((parent->d_ptr->ancestorFlags & flag)
+                    || (int(parent->d_ptr->flags & childFlag) == childFlag)
+                        || (childFlag == -1 && parent->d_ptr->handlesChildEvents)
+                        || (childFlag == -2 && parent->d_ptr->filtersDescendantEvents)) {
+                enabled = true;
+                ancestorFlags |= flag;
+            } else {
+                ancestorFlags &= ~flag;
+            }
+        } else {
+            // Top-level root items don't have any ancestors, so there are no
+            // ancestor flags either.
+            ancestorFlags = 0;
         }
-
-        // Top-level root items don't have any ancestors, so there are no
-        // ancestor flags either.
-        if (!parent)
-            ancestorFlags = 0;
     } else {
         // Don't set or propagate the ancestor flag if it's already correct.
@@ -663,5 +793,7 @@
 
         // Don't process children if the item has the main flag set on itself.
-        if ((childFlag != -1 &&  int(flags & childFlag) == childFlag) || (int(childFlag) == -1 && handlesChildEvents))
+        if ((childFlag != -1 &&  int(flags & childFlag) == childFlag)
+            || (int(childFlag) == -1 && handlesChildEvents)
+            || (int(childFlag) == -2 && filtersDescendantEvents))
             return;
     }
@@ -755,10 +887,77 @@
     \internal
 
-    Returns true if this item or any of its ancestors are untransformable.
-*/
-bool QGraphicsItemPrivate::itemIsUntransformable() const
-{
-    return (flags & QGraphicsItem::ItemIgnoresTransformations)
-        || (ancestorFlags & AncestorIgnoresTransformations);
+    Combines this item's position and transform onto \a transform.
+
+    If you need to change this function (e.g., adding more transformation
+    modes / options), make sure to change all places marked with COMBINE.
+*/
+void QGraphicsItemPrivate::combineTransformToParent(QTransform *x, const QTransform *viewTransform) const
+{
+    // COMBINE
+    if (viewTransform && itemIsUntransformable()) {
+        *x = q_ptr->deviceTransform(*viewTransform);
+    } else {
+        if (transformData)
+            *x *= transformData->computedFullTransform();
+        if (!pos.isNull())
+            *x *= QTransform::fromTranslate(pos.x(), pos.y());
+    }
+}
+
+/*!
+    \internal
+
+    Combines this item's position and transform onto \a transform.
+
+    If you need to change this function (e.g., adding more transformation
+    modes / options), make sure to change QGraphicsItem::deviceTransform() as
+    well.
+*/
+void QGraphicsItemPrivate::combineTransformFromParent(QTransform *x, const QTransform *viewTransform) const
+{
+    // COMBINE
+    if (viewTransform && itemIsUntransformable()) {
+        *x = q_ptr->deviceTransform(*viewTransform);
+    } else {
+        x->translate(pos.x(), pos.y());
+        if (transformData)
+            *x = transformData->computedFullTransform(x);
+    }
+}
+
+void QGraphicsItemPrivate::updateSceneTransformFromParent()
+{
+    if (parent) {
+        Q_ASSERT(!parent->d_ptr->dirtySceneTransform);
+        if (parent->d_ptr->sceneTransformTranslateOnly) {
+            sceneTransform = QTransform::fromTranslate(parent->d_ptr->sceneTransform.dx() + pos.x(),
+                                                       parent->d_ptr->sceneTransform.dy() + pos.y());
+        } else {
+            sceneTransform = parent->d_ptr->sceneTransform;
+            sceneTransform.translate(pos.x(), pos.y());
+        }
+        if (transformData) {
+            sceneTransform = transformData->computedFullTransform(&sceneTransform);
+            sceneTransformTranslateOnly = (sceneTransform.type() <= QTransform::TxTranslate);
+        } else {
+            sceneTransformTranslateOnly = parent->d_ptr->sceneTransformTranslateOnly;
+        }
+    } else if (!transformData) {
+        sceneTransform = QTransform::fromTranslate(pos.x(), pos.y());
+        sceneTransformTranslateOnly = 1;
+    } else if (transformData->onlyTransform) {
+        sceneTransform = transformData->transform;
+        if (!pos.isNull())
+            sceneTransform *= QTransform::fromTranslate(pos.x(), pos.y());
+        sceneTransformTranslateOnly = (sceneTransform.type() <= QTransform::TxTranslate);
+    } else if (pos.isNull()) {
+        sceneTransform = transformData->computedFullTransform();
+        sceneTransformTranslateOnly = (sceneTransform.type() <= QTransform::TxTranslate);
+    } else {
+        sceneTransform = QTransform::fromTranslate(pos.x(), pos.y());
+        sceneTransform = transformData->computedFullTransform(&sceneTransform);
+        sceneTransformTranslateOnly = (sceneTransform.type() <= QTransform::TxTranslate);
+    }
+    dirtySceneTransform = 0;
 }
 
@@ -782,4 +981,269 @@
     \internal
 
+    Make sure not to trigger any pure virtual function calls (e.g.,
+    prepareGeometryChange) if the item is in its destructor, i.e.
+    inDestructor is 1.
+*/
+void QGraphicsItemPrivate::setParentItemHelper(QGraphicsItem *newParent)
+{
+    Q_Q(QGraphicsItem);
+    if (newParent == q) {
+        qWarning("QGraphicsItem::setParentItem: cannot assign %p as a parent of itself", this);
+        return;
+    }
+    if (newParent == parent)
+        return;
+
+    const QVariant newParentVariant(q->itemChange(QGraphicsItem::ItemParentChange,
+                                                  qVariantFromValue<QGraphicsItem *>(newParent)));
+    newParent = qVariantValue<QGraphicsItem *>(newParentVariant);
+    if (newParent == parent)
+        return;
+
+    if (scene) {
+        // Deliver the change to the index
+        scene->d_func()->index->itemChange(q, QGraphicsItem::ItemParentChange, newParentVariant);
+
+        // Disable scene pos notifications for old ancestors
+        if (scenePosDescendants || (flags & QGraphicsItem::ItemSendsScenePositionChanges))
+            scene->d_func()->setScenePosItemEnabled(q, false);
+    }
+
+    if (subFocusItem && parent) {
+        // Make sure none of the old parents point to this guy.
+        subFocusItem->d_ptr->clearSubFocus(parent);
+    }
+
+    // We anticipate geometry changes. If the item is deleted, it will be
+    // removed from the index at a later stage, and the whole scene will be
+    // updated.
+    if (!inDestructor)
+        q_ptr->prepareGeometryChange();
+
+    const QVariant thisPointerVariant(qVariantFromValue<QGraphicsItem *>(q));
+    if (parent) {
+        // Remove from current parent
+        parent->d_ptr->removeChild(q);
+        parent->itemChange(QGraphicsItem::ItemChildRemovedChange, thisPointerVariant);
+    }
+
+    // Update toplevelitem list. If this item is being deleted, its parent
+    // will be 0 but we don't want to register/unregister it in the TLI list.
+    if (scene && !inDestructor) {
+        if (parent && !newParent) {
+            scene->d_func()->registerTopLevelItem(q);
+        } else if (!parent && newParent) {
+            scene->d_func()->unregisterTopLevelItem(q);
+        }
+    }
+
+    // Ensure any last parent focus scope does not point to this item or any of
+    // its descendents.
+    QGraphicsItem *p = parent;
+    QGraphicsItem *parentFocusScopeItem = 0;
+    while (p) {
+        if (p->flags() & QGraphicsItem::ItemIsFocusScope) {
+            // If this item's focus scope's focus scope item points
+            // to this item or a descendent, then clear it.
+            QGraphicsItem *fsi = p->d_ptr->focusScopeItem;
+            if (q_ptr == fsi || q_ptr->isAncestorOf(fsi)) {
+                parentFocusScopeItem = fsi;
+                p->d_ptr->focusScopeItem = 0;
+            }
+            break;
+        }
+        p = p->d_ptr->parent;
+    }
+
+    // Update focus scope item ptr in new scope.
+    QGraphicsItem *newFocusScopeItem = subFocusItem ? subFocusItem : parentFocusScopeItem;
+    if (newFocusScopeItem && newParent) {
+        if (subFocusItem) {
+            // Find the subFocusItem's topmost focus scope.
+            QGraphicsItem *ancestorScope = 0;
+            QGraphicsItem *p = subFocusItem->d_ptr->parent;
+            while (p) {
+                if (p->flags() & QGraphicsItem::ItemIsFocusScope)
+                    ancestorScope = p;
+                if (p->isPanel())
+                    break;
+                p = p->parentItem();
+            }
+            if (ancestorScope)
+                newFocusScopeItem = ancestorScope;
+        }
+
+        QGraphicsItem *p = newParent;
+        while (p) {
+            if (p->flags() & QGraphicsItem::ItemIsFocusScope) {
+                p->d_ptr->focusScopeItem = newFocusScopeItem;
+                // Ensure the new item is no longer the subFocusItem. The
+                // only way to set focus on a child of a focus scope is
+                // by setting focus on the scope itself.
+                if (subFocusItem && !p->focusItem())
+                    subFocusItem->d_ptr->clearSubFocus();
+                break;
+            }
+            p = p->d_ptr->parent;
+        }
+    }
+
+    if ((parent = newParent)) {
+        bool implicitUpdate = false;
+        if (parent->d_func()->scene && parent->d_func()->scene != scene) {
+            // Move this item to its new parent's scene
+            parent->d_func()->scene->addItem(q);
+            implicitUpdate = true;
+        } else if (!parent->d_func()->scene && scene) {
+            // Remove this item from its former scene
+            scene->removeItem(q);
+        }
+
+        parent->d_ptr->addChild(q);
+        parent->itemChange(QGraphicsItem::ItemChildAddedChange, thisPointerVariant);
+        if (scene) {
+            if (!implicitUpdate)
+                scene->d_func()->markDirty(q_ptr);
+
+            // Re-enable scene pos notifications for new ancestors
+            if (scenePosDescendants || (flags & QGraphicsItem::ItemSendsScenePositionChanges))
+                scene->d_func()->setScenePosItemEnabled(q, true);
+        }
+
+        // Inherit ancestor flags from the new parent.
+        updateAncestorFlag(QGraphicsItem::GraphicsItemFlag(-2));
+        updateAncestorFlag(QGraphicsItem::GraphicsItemFlag(-1));
+        updateAncestorFlag(QGraphicsItem::ItemClipsChildrenToShape);
+        updateAncestorFlag(QGraphicsItem::ItemIgnoresTransformations);
+
+        // Update item visible / enabled.
+        if (parent->isVisible() != visible) {
+            if (!parent->isVisible() || !explicitlyHidden)
+                setVisibleHelper(parent->isVisible(), /* explicit = */ false, /* update = */ !implicitUpdate);
+        }
+        if (parent->isEnabled() != enabled) {
+            if (!parent->isEnabled() || !explicitlyDisabled)
+                setEnabledHelper(parent->isEnabled(), /* explicit = */ false, /* update = */ !implicitUpdate);
+        }
+
+        // Auto-activate if visible and the parent is active.
+        if (q->isVisible() && parent->isActive())
+            q->setActive(true);
+    } else {
+        // Inherit ancestor flags from the new parent.
+        updateAncestorFlag(QGraphicsItem::GraphicsItemFlag(-2));
+        updateAncestorFlag(QGraphicsItem::GraphicsItemFlag(-1));
+        updateAncestorFlag(QGraphicsItem::ItemClipsChildrenToShape);
+        updateAncestorFlag(QGraphicsItem::ItemIgnoresTransformations);
+
+        if (!inDestructor) {
+            // Update item visible / enabled.
+            if (!visible && !explicitlyHidden)
+                setVisibleHelper(true, /* explicit = */ false);
+            if (!enabled && !explicitlyDisabled)
+                setEnabledHelper(true, /* explicit = */ false);
+
+            // If the item is being deleted, the whole scene will be updated.
+            if (scene)
+                scene->d_func()->markDirty(q_ptr);
+        }
+    }
+
+    // Resolve depth.
+    invalidateDepthRecursively();
+    dirtySceneTransform = 1;
+
+    // Restore the sub focus chain.
+    if (subFocusItem) {
+        subFocusItem->d_ptr->setSubFocus(newParent);
+        if (parent && parent->isActive())
+            subFocusItem->setFocus();
+    }
+
+    // Deliver post-change notification
+    q->itemChange(QGraphicsItem::ItemParentHasChanged, newParentVariant);
+
+    if (isObject)
+        emit static_cast<QGraphicsObject *>(q)->parentChanged();
+}
+
+/*!
+    \internal
+
+    Returns the bounding rect of this item's children (excluding itself).
+*/
+void QGraphicsItemPrivate::childrenBoundingRectHelper(QTransform *x, QRectF *rect)
+{
+    for (int i = 0; i < children.size(); ++i) {
+        QGraphicsItem *child = children.at(i);
+        QGraphicsItemPrivate *childd = child->d_ptr.data();
+        bool hasPos = !childd->pos.isNull();
+        if (hasPos || childd->transformData) {
+            // COMBINE
+            QTransform matrix = childd->transformToParent();
+            if (x)
+                matrix *= *x;
+            *rect |= matrix.mapRect(child->boundingRect());
+            if (!childd->children.isEmpty())
+                childd->childrenBoundingRectHelper(&matrix, rect);
+        } else {
+            if (x)
+                *rect |= x->mapRect(child->boundingRect());
+            else
+                *rect |= child->boundingRect();
+            if (!childd->children.isEmpty())
+                childd->childrenBoundingRectHelper(x, rect);
+        }
+    }
+}
+
+void QGraphicsItemPrivate::initStyleOption(QStyleOptionGraphicsItem *option, const QTransform &worldTransform,
+                                           const QRegion &exposedRegion, bool allItems) const
+{
+    Q_ASSERT(option);
+    Q_Q(const QGraphicsItem);
+
+    // Initialize standard QStyleOption values.
+    const QRectF brect = q->boundingRect();
+    option->state = QStyle::State_None;
+    option->rect = brect.toRect();
+    option->levelOfDetail = 1;
+    option->exposedRect = brect;
+    if (selected)
+        option->state |= QStyle::State_Selected;
+    if (enabled)
+        option->state |= QStyle::State_Enabled;
+    if (q->hasFocus())
+        option->state |= QStyle::State_HasFocus;
+    if (scene) {
+        if (scene->d_func()->hoverItems.contains(q_ptr))
+            option->state |= QStyle::State_MouseOver;
+        if (q == scene->mouseGrabberItem())
+            option->state |= QStyle::State_Sunken;
+    }
+
+    if (!(flags & QGraphicsItem::ItemUsesExtendedStyleOption))
+        return;
+
+    // Initialize QStyleOptionGraphicsItem specific values (matrix, exposedRect).
+    option->matrix = worldTransform.toAffine(); //### discards perspective
+
+    if (!allItems) {
+        // Determine the item's exposed area
+        option->exposedRect = QRectF();
+        const QTransform reverseMap = worldTransform.inverted();
+        const QVector<QRect> exposedRects(exposedRegion.rects());
+        for (int i = 0; i < exposedRects.size(); ++i) {
+            option->exposedRect |= reverseMap.mapRect(QRectF(exposedRects.at(i)));
+            if (option->exposedRect.contains(brect))
+                break;
+        }
+        option->exposedRect &= brect;
+    }
+}
+
+/*!
+    \internal
+
     Empty all cached pixmaps from the pixmap cache.
 */
@@ -787,4 +1251,5 @@
 {
     QPixmapCache::remove(key);
+    key = QPixmapCache::Key();
     QMutableMapIterator<QPaintDevice *, DeviceData> it(deviceData);
     while (it.hasNext()) {
@@ -799,5 +1264,6 @@
 
 /*!
-    Constructs a QGraphicsItem with the given \a parent.
+    Constructs a QGraphicsItem with the given \a parent item.
+    It does not modify the parent object returned by QObject::parent().
 
     If \a parent is 0, you can add the item to a scene by calling
@@ -851,29 +1317,52 @@
     associated with a scene, the item will be removed from the scene before it
     is deleted.
+
+    \note It is more efficient to remove the item from the QGraphicsScene before
+    destroying the item.
 */
 QGraphicsItem::~QGraphicsItem()
 {
+    if (d_ptr->isObject)
+        QObjectPrivate::get(static_cast<QGraphicsObject *>(this))->wasDeleted = true;
+    d_ptr->inDestructor = 1;
+    d_ptr->removeExtraItemCache();
+
     clearFocus();
-    d_ptr->removeExtraItemCache();
-
-    QVariant variant;
-    foreach (QGraphicsItem *child, d_ptr->children) {
-        if (QGraphicsItem *parent = child->parentItem()) {
-            qVariantSetValue<QGraphicsItem *>(variant, child);
-            parent->itemChange(ItemChildRemovedChange, variant);
+
+    // Update focus scope item ptr.
+    QGraphicsItem *p = d_ptr->parent;
+    while (p) {
+        if (p->flags() & ItemIsFocusScope) {
+            if (p->d_ptr->focusScopeItem == this)
+                p->d_ptr->focusScopeItem = 0;
+            break;
         }
-        delete child;
-    }
-    d_ptr->children.clear();
-
-    if (QGraphicsItem *parent = parentItem()) {
-        qVariantSetValue<QGraphicsItem *>(variant, this);
-        parent->itemChange(ItemChildRemovedChange, variant);
-        qt_graphicsitem_removeChild(this, &parent->d_func()->children);
-    }
-    if (d_ptr->scene)
-        d_ptr->scene->d_func()->_q_removeItemLater(this);
-
-    delete d_ptr;
+        p = p->d_ptr->parent;
+    }
+
+    if (!d_ptr->children.isEmpty()) {
+        while (!d_ptr->children.isEmpty())
+            delete d_ptr->children.first();
+        Q_ASSERT(d_ptr->children.isEmpty());
+    }
+
+    if (d_ptr->scene) {
+        d_ptr->scene->d_func()->removeItemHelper(this);
+    } else {
+        d_ptr->resetFocusProxy();
+        d_ptr->setParentItemHelper(0);
+    }
+
+#ifndef QT_NO_GRAPHICSEFFECT
+    delete d_ptr->graphicsEffect;
+#endif //QT_NO_GRAPHICSEFFECT
+    if (d_ptr->transformData) {
+        for(int i = 0; i < d_ptr->transformData->graphicsTransforms.size(); ++i) {
+            QGraphicsTransform *t = d_ptr->transformData->graphicsTransforms.at(i);
+            static_cast<QGraphicsTransformPrivate *>(t->d_ptr.data())->item = 0;
+            delete t;
+        }
+    }
+    delete d_ptr->transformData;
 
     qt_dataStore()->data.remove(this);
@@ -932,5 +1421,5 @@
     parent, 0 is returned.
 
-    \sa setParentItem(), children()
+    \sa setParentItem(), childItems()
 */
 QGraphicsItem *QGraphicsItem::parentItem() const
@@ -955,4 +1444,18 @@
 
 /*!
+    \since 4.6
+
+    Returns a pointer to the item's parent, cast to a QGraphicsObject. returns 0 if the parent item
+    is not a QGraphicsObject.
+
+    \sa parentItem(), childItems()
+*/
+QGraphicsObject *QGraphicsItem::parentObject() const
+{
+    QGraphicsItem *p = d_ptr->parent;
+    return (p && p->d_ptr->isObject) ? static_cast<QGraphicsObject *>(p) : 0;
+}
+
+/*!
     \since 4.4
 
@@ -996,9 +1499,46 @@
 QGraphicsWidget *QGraphicsItem::window() const
 {
-    if (isWidget() && static_cast<const QGraphicsWidget *>(this)->isWindow())
-        return static_cast<QGraphicsWidget *>(const_cast<QGraphicsItem *>(this));
-    if (QGraphicsWidget *parent = parentWidget())
-        return parent->window();
+    QGraphicsItem *p = panel();
+    if (p && p->isWindow())
+        return static_cast<QGraphicsWidget *>(p);
     return 0;
+}
+
+/*!
+    \since 4.6
+
+    Returns the item's panel, or 0 if this item does not have a panel. If the
+    item is a panel, it will return itself. Otherwise it will return the
+    closest ancestor that is a panel.
+
+    \sa isPanel(), ItemIsPanel
+*/
+QGraphicsItem *QGraphicsItem::panel() const
+{
+    if (d_ptr->flags & ItemIsPanel)
+        return const_cast<QGraphicsItem *>(this);
+    return d_ptr->parent ? d_ptr->parent->panel() : 0;
+}
+
+/*!
+  \since 4.6
+
+  Return the graphics item cast to a QGraphicsObject, if the class is actually a
+  graphics object, 0 otherwise.
+*/
+QGraphicsObject *QGraphicsItem::toGraphicsObject()
+{
+    return d_ptr->isObject ? static_cast<QGraphicsObject *>(this) : 0;
+}
+
+/*!
+  \since 4.6
+
+  Return the graphics item cast to a QGraphicsObject, if the class is actually a
+  graphics object, 0 otherwise.
+*/
+const QGraphicsObject *QGraphicsItem::toGraphicsObject() const
+{
+    return d_ptr->isObject ? static_cast<const QGraphicsObject *>(this) : 0;
 }
 
@@ -1012,100 +1552,11 @@
     item to the scene yourself.
 
-    \sa parentItem(), children()
+    Calling this function on an item that is an ancestor of \a parent have undefined behaviour.
+
+    \sa parentItem(), childItems()
 */
 void QGraphicsItem::setParentItem(QGraphicsItem *parent)
 {
-    if (parent == this) {
-        qWarning("QGraphicsItem::setParentItem: cannot assign %p as a parent of itself", this);
-        return;
-    }
-    if (parent == d_ptr->parent)
-        return;
-    const QVariant newParentVariant(itemChange(ItemParentChange, qVariantFromValue<QGraphicsItem *>(parent)));
-    parent = qVariantValue<QGraphicsItem *>(newParentVariant);
-    if (parent == d_ptr->parent)
-        return;
-
-    if (QGraphicsWidget *w = d_ptr->isWidget ? static_cast<QGraphicsWidget *>(this) : parentWidget()) {
-        // Update the child focus chain; when reparenting a widget that has a
-        // focus child, ensure that that focus child clears its focus child
-        // chain from our parents before it's reparented.
-        if (QGraphicsWidget *focusChild = w->focusWidget())
-            focusChild->clearFocus();
-    }
-
-    // We anticipate geometry changes
-    prepareGeometryChange();
-
-    const QVariant thisPointerVariant(qVariantFromValue<QGraphicsItem *>(this));
-    if (d_ptr->parent) {
-        // Remove from current parent
-        qt_graphicsitem_removeChild(this, &d_ptr->parent->d_func()->children);
-        d_ptr->parent->itemChange(ItemChildRemovedChange, thisPointerVariant);
-    }
-
-    if ((d_ptr->parent = parent)) {
-        bool implicitUpdate = false;
-        if (parent->d_func()->scene && parent->d_func()->scene != d_ptr->scene) {
-            // Move this item to its new parent's scene
-            parent->d_func()->scene->addItem(this);
-            implicitUpdate = true;
-        } else if (!parent->d_func()->scene && d_ptr->scene) {
-            // Remove this item from its former scene
-            d_ptr->scene->removeItem(this);
-        }
-
-        d_ptr->parent->d_func()->children << this;
-        d_ptr->parent->itemChange(ItemChildAddedChange, thisPointerVariant);
-        if (!implicitUpdate)
-            d_ptr->updateHelper(QRectF(), false, true);
-
-        // Inherit ancestor flags from the new parent.
-        d_ptr->updateAncestorFlag(QGraphicsItem::GraphicsItemFlag(-1));
-        d_ptr->updateAncestorFlag(ItemClipsChildrenToShape);
-        d_ptr->updateAncestorFlag(ItemIgnoresTransformations);
-
-        // Update item visible / enabled.
-        if (d_ptr->parent->isVisible() != d_ptr->visible) {
-            if (!d_ptr->parent->isVisible() || !d_ptr->explicitlyHidden)
-                d_ptr->setVisibleHelper(d_ptr->parent->isVisible(), /* explicit = */ false, /* update = */ !implicitUpdate);
-        }
-        if (d_ptr->parent->isEnabled() != d_ptr->enabled) {
-            if (!d_ptr->parent->isEnabled() || !d_ptr->explicitlyDisabled)
-                d_ptr->setEnabledHelper(d_ptr->parent->isEnabled(), /* explicit = */ false, /* update = */ !implicitUpdate);
-        }
-
-    } else {
-        // Inherit ancestor flags from the new parent.
-        d_ptr->updateAncestorFlag(QGraphicsItem::GraphicsItemFlag(-1));
-        d_ptr->updateAncestorFlag(ItemClipsChildrenToShape);
-        d_ptr->updateAncestorFlag(ItemIgnoresTransformations);
-
-        // Update item visible / enabled.
-        if (!d_ptr->visible && !d_ptr->explicitlyHidden)
-            d_ptr->setVisibleHelper(true, /* explicit = */ false);
-        if (!d_ptr->enabled && !d_ptr->explicitlyDisabled)
-            d_ptr->setEnabledHelper(true, /* explicit = */ false);
-
-        d_ptr->updateHelper(QRectF(), false, true);
-    }
-
-    if (d_ptr->scene) {
-        // Invalidate any sort caching; arrival of a new item means we need to
-        // resort.
-        d_ptr->scene->d_func()->invalidateSortCache();
-    }
-
-    // Resolve opacity.
-    d_ptr->updateEffectiveOpacity();
-
-    // Resolve depth.
-    d_ptr->resolveDepth(parent ? parent->d_ptr->depth : -1);
-
-    // Invalidate transform cache.
-    d_ptr->invalidateSceneTransformCache();
-
-    // Deliver post-change notification
-    itemChange(QGraphicsItem::ItemParentHasChanged, newParentVariant);
+    d_ptr->setParentItemHelper(parent);
 }
 
@@ -1125,11 +1576,14 @@
     \since 4.4
 
-    Returns a list of this item's children. The items are returned in no
-    particular order.
-
-    \sa setParentItem()
+    Returns a list of this item's children.
+
+    The items are sorted by stacking order. This takes into account both the
+    items' insertion order and their Z-values.
+
+    \sa setParentItem(), zValue(), {QGraphicsItem#Sorting}{Sorting}
 */
 QList<QGraphicsItem *> QGraphicsItem::childItems() const
 {
+    const_cast<QGraphicsItem *>(this)->d_ptr->ensureSortedChildren();
     return d_ptr->children;
 }
@@ -1155,4 +1609,15 @@
 {
     return isWidget() && (static_cast<const QGraphicsWidget *>(this)->windowType() & Qt::Window);
+}
+
+/*!
+    \since 4.6
+    Returns true if the item is a panel; otherwise returns false.
+
+    \sa QGraphicsItem::panel(), ItemIsPanel
+*/
+bool QGraphicsItem::isPanel() const
+{
+    return d_ptr->flags & ItemIsPanel;
 }
 
@@ -1212,5 +1677,7 @@
     item is automatically unselected.
 
-    By default, no flags are enabled.
+    By default, no flags are enabled. (QGraphicsWidget enables the
+    ItemSendsGeometryChanges flag by default in order to track position
+    changes.)
 
     \sa flags(), setFlag()
@@ -1218,4 +1685,7 @@
 void QGraphicsItem::setFlags(GraphicsItemFlags flags)
 {
+    if (isWindow())
+        flags |= ItemIsPanel;
+
     // Notify change and check for adjustment.
     if (quint32(d_ptr->flags) == quint32(flags))
@@ -1224,10 +1694,12 @@
     if (quint32(d_ptr->flags) == quint32(flags))
         return;
+    if (d_ptr->scene)
+        d_ptr->scene->d_func()->index->itemChange(this, ItemFlagsChange, quint32(flags));
 
     // Flags that alter the geometry of the item (or its children).
-    int geomChangeFlagsMask = (ItemClipsChildrenToShape | ItemClipsToShape | ItemIgnoresTransformations);
-    bool fullUpdate = (flags & geomChangeFlagsMask) != (d_ptr->flags & geomChangeFlagsMask);
+    const quint32 geomChangeFlagsMask = (ItemClipsChildrenToShape | ItemClipsToShape | ItemIgnoresTransformations | ItemIsSelectable);
+    bool fullUpdate = (quint32(flags) & geomChangeFlagsMask) != (d_ptr->flags & geomChangeFlagsMask);
     if (fullUpdate)
-        d_ptr->fullUpdateHelper(false, true);
+        d_ptr->paintedViewBoundingRectsNeedRepaint = 1;
 
     // Keep the old flags to compare the diff.
@@ -1236,9 +1708,4 @@
     // Update flags.
     d_ptr->flags = flags;
-
-    // Reresolve effective opacity if the opacity flags change.
-    static const quint32 opacityFlagsMask = ItemIgnoresParentOpacity | ItemDoesntPropagateOpacityToChildren;
-    if ((flags & opacityFlagsMask) != (oldFlags & opacityFlagsMask))
-        d_ptr->updateEffectiveOpacity();
 
     if (!(d_ptr->flags & ItemIsFocusable) && hasFocus()) {
@@ -1260,7 +1727,4 @@
     }
 
-    if ((flags & ItemClipsToShape) != (oldFlags & ItemClipsToShape))
-        d_ptr->invalidateCachedClipPath();
-
     if ((flags & ItemIgnoresTransformations) != (oldFlags & ItemIgnoresTransformations)) {
         // Item children clipping changes. Propagate the ancestor flag to
@@ -1269,6 +1733,42 @@
     }
 
-    // ### Why updateHelper?
-    d_ptr->updateHelper(QRectF(), false, true);
+    if ((flags & ItemStacksBehindParent) != (oldFlags & ItemStacksBehindParent)) {
+        // Ensure child item sorting is up to date when toggling this flag.
+        if (d_ptr->parent)
+            d_ptr->parent->d_ptr->needSortChildren = 1;
+        else if (d_ptr->scene)
+            d_ptr->scene->d_func()->needSortTopLevelItems = 1;
+    }
+
+    if ((flags & ItemAcceptsInputMethod) != (oldFlags & ItemAcceptsInputMethod)) {
+        // Update input method sensitivity in any views.
+        if (d_ptr->scene)
+            d_ptr->scene->d_func()->updateInputMethodSensitivityInViews();
+    }
+
+    if ((flags & ItemNegativeZStacksBehindParent) != (oldFlags & ItemNegativeZStacksBehindParent)) {
+        // Update stack-behind.
+        setFlag(ItemStacksBehindParent, d_ptr->z < qreal(0.0));
+    }
+
+    if ((d_ptr->panelModality != NonModal)
+        && d_ptr->scene
+        && (flags & ItemIsPanel) != (oldFlags & ItemIsPanel)) {
+        // update the panel's modal state
+        if (flags & ItemIsPanel)
+            d_ptr->scene->d_func()->enterModal(this);
+        else
+            d_ptr->scene->d_func()->leaveModal(this);
+    }
+
+    if (d_ptr->scene) {
+        if ((flags & ItemSendsScenePositionChanges) != (oldFlags & ItemSendsScenePositionChanges)) {
+            if (flags & ItemSendsScenePositionChanges)
+                d_ptr->scene->d_func()->registerScenePosItem(this);
+            else
+                d_ptr->scene->d_func()->unregisterScenePosItem(this);
+        }
+        d_ptr->scene->d_func()->markDirty(this, QRectF(), /*invalidateChildren=*/true);
+    }
 
     // Notify change.
@@ -1333,10 +1833,4 @@
 
         if (mode == ItemCoordinateCache) {
-            if (cache->key.isEmpty()) {
-                // Generate new simple pixmap cache key.
-                QString tmp;
-                tmp.sprintf("qgv-%p", this);
-                cache->key = tmp;
-            }
             if (lastMode == mode && cache->fixedSize == logicalCacheSize)
                 noVisualChange = true;
@@ -1348,4 +1842,85 @@
 }
 
+/*!
+    \since 4.6
+
+    Returns the modality for this item.
+*/
+QGraphicsItem::PanelModality QGraphicsItem::panelModality() const
+{
+    return d_ptr->panelModality;
+}
+
+/*!
+    \since 4.6
+
+    Sets the modality for this item to \a panelModality.
+
+    Changing the modality of a visible item takes effect immediately.
+*/
+void QGraphicsItem::setPanelModality(PanelModality panelModality)
+{
+    if (d_ptr->panelModality == panelModality)
+        return;
+
+    PanelModality previousModality = d_ptr->panelModality;
+    bool enterLeaveModal = (isPanel() && d_ptr->scene && isVisible());
+    if (enterLeaveModal && panelModality == NonModal)
+        d_ptr->scene->d_func()->leaveModal(this);
+    d_ptr->panelModality = panelModality;
+    if (enterLeaveModal && d_ptr->panelModality != NonModal)
+        d_ptr->scene->d_func()->enterModal(this, previousModality);
+}
+
+/*!
+    \since 4.6
+
+    Returns true if this item is blocked by a modal panel, false otherwise. If \a blockingPanel is
+    non-zero, \a blockingPanel will be set to the modal panel that is blocking this item. If this
+    item is not blocked, \a blockingPanel will not be set by this function.
+
+    This function always returns false for items not in a scene.
+
+    \sa panelModality() setPanelModality() PanelModality
+*/
+bool QGraphicsItem::isBlockedByModalPanel(QGraphicsItem **blockingPanel) const
+{
+    if (!d_ptr->scene)
+        return false;
+
+
+    QGraphicsItem *dummy = 0;
+    if (!blockingPanel)
+        blockingPanel = &dummy;
+
+    QGraphicsScenePrivate *scene_d = d_ptr->scene->d_func();
+    if (scene_d->modalPanels.isEmpty())
+        return false;
+
+    // ###
+    if (!scene_d->popupWidgets.isEmpty() && scene_d->popupWidgets.first() == this)
+        return false;
+
+    for (int i = 0; i < scene_d->modalPanels.count(); ++i) {
+        QGraphicsItem *modalPanel = scene_d->modalPanels.at(i);
+        if (modalPanel->panelModality() == QGraphicsItem::SceneModal) {
+            // Scene modal panels block all non-descendents.
+            if (modalPanel != this && !modalPanel->isAncestorOf(this)) {
+                *blockingPanel = modalPanel;
+                return true;
+            }
+        } else {
+            // Window modal panels block ancestors and siblings/cousins.
+            if (modalPanel != this
+                && !modalPanel->isAncestorOf(this)
+                && commonAncestorItem(modalPanel)) {
+                *blockingPanel = modalPanel;
+                return true;
+            }
+        }
+    }
+    return false;
+}
+
 #ifndef QT_NO_TOOLTIP
 /*!
@@ -1416,5 +1991,7 @@
     d_ptr->hasCursor = 1;
     if (d_ptr->scene) {
+        d_ptr->scene->d_func()->allItemsUseDefaultCursor = false;
         foreach (QGraphicsView *view, d_ptr->scene->views()) {
+            view->viewport()->setMouseTracking(true);
             // Note: Some of this logic is duplicated in QGraphicsView's mouse events.
             if (view->underMouse()) {
@@ -1523,4 +2100,8 @@
         return;
 
+    // Don't show child if parent is not visible
+    if (parent && newVisible && !parent->d_ptr->visible)
+        return;
+
     // Modify the property.
     const QVariant newVisibleVariant(q_ptr->itemChange(QGraphicsItem::ItemVisibleChange,
@@ -1536,5 +2117,6 @@
         if (c)
             c->purge();
-        updateHelper(QRectF(), /* force = */ true);
+        if (scene)
+            scene->d_func()->markDirty(q_ptr, QRectF(), /*invalidateChildren=*/false, /*force=*/true);
     }
 
@@ -1546,10 +2128,12 @@
             if (scene->d_func()->keyboardGrabberItems.contains(q))
                 q->ungrabKeyboard();
+            if (q->isPanel() && panelModality != QGraphicsItem::NonModal)
+                scene->d_func()->leaveModal(q_ptr);
         }
         if (q_ptr->hasFocus() && scene) {
-            // Hiding the closest non-window ancestor of the focus item
+            // Hiding the closest non-panel ancestor of the focus item
             QGraphicsItem *focusItem = scene->focusItem();
             bool clear = true;
-            if (isWidget && !focusItem->isWindow()) {
+            if (isWidget && !focusItem->isPanel()) {
                 do {
                     if (focusItem == q_ptr) {
@@ -1557,5 +2141,5 @@
                         break;
                     }
-                } while ((focusItem = focusItem->parentWidget()) && !focusItem->isWindow());
+                } while ((focusItem = focusItem->parentWidget()) && !focusItem->isPanel());
             }
             if (clear)
@@ -1565,8 +2149,15 @@
             q_ptr->setSelected(false);
     } else {
-        if (isWidget && scene) {
-            QGraphicsWidget *widget = static_cast<QGraphicsWidget *>(q_ptr);
-            if (widget->windowType() == Qt::Popup)
-                scene->d_func()->addPopup(widget);
+        geometryChanged = 1;
+        paintedViewBoundingRectsNeedRepaint = 1;
+        if (scene) {
+            if (isWidget) {
+                QGraphicsWidget *widget = static_cast<QGraphicsWidget *>(q_ptr);
+                if (widget->windowType() == Qt::Popup)
+                    scene->d_func()->addPopup(widget);
+            }
+            if (q->isPanel() && panelModality != QGraphicsItem::NonModal) {
+                scene->d_func()->enterModal(q_ptr);
+            }
         }
     }
@@ -1579,14 +2170,45 @@
     }
 
+    // Update activation
+    if (scene && q->isPanel()) {
+        if (newVisible) {
+            if (parent && parent->isActive())
+                q->setActive(true);
+        } else {
+            if (q->isActive())
+                scene->setActivePanel(parent);
+        }
+    }
+
     // Enable subfocus
-    if (newVisible && isWidget) {
-        QGraphicsWidget *widget = static_cast<QGraphicsWidget *>(q_ptr);
-        QGraphicsWidget *fw = widget->focusWidget();
-        if (fw && fw != scene->focusItem())
-            scene->setFocusItem(fw);
+    if (scene && newVisible) {
+        QGraphicsItem *p = parent;
+        bool done = false;
+        while (p) {
+            if (p->flags() & QGraphicsItem::ItemIsFocusScope) {
+                QGraphicsItem *fsi = p->d_ptr->focusScopeItem;
+                if (q_ptr == fsi || q_ptr->isAncestorOf(fsi)) {
+                    done = true;
+                    while (fsi->d_ptr->focusScopeItem && fsi->d_ptr->focusScopeItem->isVisible())
+                        fsi = fsi->d_ptr->focusScopeItem;
+                    scene->setFocusItem(fsi);
+                }
+                break;
+            }
+            p = p->d_ptr->parent;
+        }
+        if (!done) {
+            QGraphicsItem *fi = subFocusItem;
+            if (fi && fi != scene->focusItem()) {
+                scene->setFocusItem(fi);
+            }
+        }
     }
 
     // Deliver post-change notification.
     q_ptr->itemChange(QGraphicsItem::ItemVisibleHasChanged, newVisibleVariant);
+
+    if (isObject)
+        emit static_cast<QGraphicsObject *>(q_ptr)->visibleChanged();
 }
 
@@ -1674,9 +2296,9 @@
             q_ptr->ungrabMouse();
         if (q_ptr->hasFocus()) {
-            // Disabling the closest non-window ancestor of the focus item
+            // Disabling the closest non-panel ancestor of the focus item
             // causes focus to pop to the next item, otherwise it's cleared.
             QGraphicsItem *focusItem = scene->focusItem();
             bool clear = true;
-            if (isWidget && !focusItem->isWindow() && q_ptr->isAncestorOf(focusItem)) {
+            if (isWidget && !focusItem->isPanel() && q_ptr->isAncestorOf(focusItem)) {
                 do {
                     if (focusItem == q_ptr) {
@@ -1684,5 +2306,5 @@
                         break;
                     }
-                } while ((focusItem = focusItem->parentWidget()) && !focusItem->isWindow());
+                } while ((focusItem = focusItem->parentWidget()) && !focusItem->isPanel());
             }
             if (clear)
@@ -1700,5 +2322,5 @@
     // Schedule redraw.
     if (update)
-        updateHelper();
+        q_ptr->update();
 
     foreach (QGraphicsItem *child, children) {
@@ -1709,4 +2331,7 @@
     // Deliver post-change notification.
     q_ptr->itemChange(QGraphicsItem::ItemEnabledHasChanged, newEnabledVariant);
+
+    if (isObject)
+        emit static_cast<QGraphicsObject *>(q_ptr)->enabledChanged();
 }
 
@@ -1801,6 +2426,5 @@
     d_ptr->selected = newSelected;
 
-    d_ptr->updateHelper();
-
+    update();
     if (d_ptr->scene) {
         QGraphicsScenePrivate *sceneD = d_ptr->scene->d_func();
@@ -1839,10 +2463,5 @@
 qreal QGraphicsItem::opacity() const
 {
-    if (d_ptr->hasOpacity) {
-        QVariant o = d_ptr->extra(QGraphicsItemPrivate::ExtraOpacity);
-        if (!o.isNull())
-            return o.toDouble();
-    }
-    return qreal(1.0);
+    return d_ptr->opacity;
 }
 
@@ -1860,9 +2479,5 @@
 qreal QGraphicsItem::effectiveOpacity() const
 {
-    if (!d_ptr->hasEffectiveOpacity)
-        return qreal(1.0);
-
-    QVariant effectiveOpacity = d_ptr->extra(QGraphicsItemPrivate::ExtraEffectiveOpacity);
-    return effectiveOpacity.isNull() ? qreal(1.0) : qreal(effectiveOpacity.toDouble());
+    return d_ptr->effectiveOpacity();
 }
 
@@ -1892,35 +2507,174 @@
 {
     // Notify change.
-    const QVariant newOpacityVariant(itemChange(ItemOpacityChange, double(opacity)));
-    qreal newOpacity = newOpacityVariant.toDouble();
-
-    // Normalize.
-    newOpacity = qBound<qreal>(0.0, newOpacity, 1.0);
+    const QVariant newOpacityVariant(itemChange(ItemOpacityChange, opacity));
+
+    // Normalized opacity
+    qreal newOpacity = qBound(qreal(0), newOpacityVariant.toReal(), qreal(1));
 
     // No change? Done.
-    if (qFuzzyCompare(newOpacity, this->opacity()))
+    if (newOpacity == d_ptr->opacity)
         return;
 
-    // Assign local opacity.
-    if (qFuzzyCompare(newOpacity, qreal(1.0))) {
-        // Opaque, unset opacity.
-        d_ptr->hasOpacity = 0;
-        d_ptr->unsetExtra(QGraphicsItemPrivate::ExtraOpacity);
-    } else {
-        d_ptr->hasOpacity = 1;
-        d_ptr->setExtra(QGraphicsItemPrivate::ExtraOpacity, double(newOpacity));
-    }
-
-    // Resolve effective opacity.
-    if (QGraphicsItem *p = d_ptr->parent)
-        d_ptr->resolveEffectiveOpacity(p->effectiveOpacity());
-    else
-        d_ptr->resolveEffectiveOpacity(1.0);
+    d_ptr->opacity = newOpacity;
 
     // Notify change.
-    itemChange(ItemOpacityHasChanged, newOpacity);
+    itemChange(ItemOpacityHasChanged, newOpacityVariant);
 
     // Update.
-    d_ptr->fullUpdateHelper();
+    if (d_ptr->scene) {
+#ifndef QT_NO_GRAPHICSEFFECT
+        d_ptr->invalidateGraphicsEffectsRecursively();
+#endif //QT_NO_GRAPHICSEFFECT
+        d_ptr->scene->d_func()->markDirty(this, QRectF(),
+                                          /*invalidateChildren=*/true,
+                                          /*force=*/false,
+                                          /*ignoreOpacity=*/true);
+    }
+
+    if (d_ptr->isObject)
+        emit static_cast<QGraphicsObject *>(this)->opacityChanged();
+}
+
+/*!
+    Returns a pointer to this item's effect if it has one; otherwise 0.
+
+    \since 4.6
+*/
+#ifndef QT_NO_GRAPHICSEFFECT
+QGraphicsEffect *QGraphicsItem::graphicsEffect() const
+{
+    return d_ptr->graphicsEffect;
+}
+
+/*!
+    Sets \a effect as the item's effect. If there already is an effect installed
+    on this item, QGraphicsItem will delete the existing effect before installing
+    the new \a effect.
+
+    If \a effect is the installed on a different item, setGraphicsEffect() will remove
+    the effect from the item and install it on this item.
+
+    QGraphicsItem takes ownership of \a effect.
+
+    \note This function will apply the effect on itself and all its children.
+
+    \since 4.6
+*/
+void QGraphicsItem::setGraphicsEffect(QGraphicsEffect *effect)
+{
+    if (d_ptr->graphicsEffect == effect)
+        return;
+
+    if (d_ptr->graphicsEffect) {
+        delete d_ptr->graphicsEffect;
+        d_ptr->graphicsEffect = 0;
+    }
+
+    if (effect) {
+        // Set new effect.
+        QGraphicsEffectSourcePrivate *sourced = new QGraphicsItemEffectSourcePrivate(this);
+        QGraphicsEffectSource *source = new QGraphicsEffectSource(*sourced);
+        d_ptr->graphicsEffect = effect;
+        effect->d_func()->setGraphicsEffectSource(source);
+        prepareGeometryChange();
+    }
+}
+#endif //QT_NO_GRAPHICSEFFECT
+
+/*!
+    \internal
+    \since 4.6
+    Returns the effective bounding rect of the given item space rect.
+    If the item has no effect, the rect is returned unmodified.
+    If the item has an effect, the effective rect can be extend beyond the
+    item's bounding rect, depending on the effect.
+
+    \sa boundingRect()
+*/
+QRectF QGraphicsItemPrivate::effectiveBoundingRect(const QRectF &rect) const
+{
+#ifndef QT_NO_GRAPHICSEFFECT
+    Q_Q(const QGraphicsItem);
+    QGraphicsEffect *effect = graphicsEffect;
+    if (scene && effect && effect->isEnabled()) {
+        QRectF sceneRect = q->mapRectToScene(rect);
+        QRectF sceneEffectRect;
+        foreach (QGraphicsView *view, scene->views()) {
+            QRectF deviceRect = view->d_func()->mapRectFromScene(sceneRect);
+            QRect deviceEffectRect = effect->boundingRectFor(deviceRect).toAlignedRect();
+            sceneEffectRect |= view->d_func()->mapRectToScene(deviceEffectRect);
+        }
+        return q->mapRectFromScene(sceneEffectRect);
+    }
+#endif //QT_NO_GRAPHICSEFFECT
+    return rect;
+}
+
+/*!
+    \internal
+    \since 4.6
+    Returns the effective bounding rect of the item.
+    If the item has no effect, this is the same as the item's bounding rect.
+    If the item has an effect, the effective rect can be larger than the item's
+    bouding rect, depending on the effect.
+
+    \sa boundingRect()
+*/
+QRectF QGraphicsItemPrivate::effectiveBoundingRect() const
+{
+#ifndef QT_NO_GRAPHICSEFFECT
+    Q_Q(const QGraphicsItem);
+    QRectF brect = effectiveBoundingRect(q_ptr->boundingRect());
+    if (ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren)
+        return brect;
+
+    const QGraphicsItem *effectParent = parent;
+    while (effectParent) {
+        QGraphicsEffect *effect = effectParent->d_ptr->graphicsEffect;
+        if (scene && effect && effect->isEnabled()) {
+            const QRectF brectInParentSpace = q->mapRectToItem(effectParent, brect);
+            const QRectF effectRectInParentSpace = effectParent->d_ptr->effectiveBoundingRect(brectInParentSpace);
+            brect = effectParent->mapRectToItem(q, effectRectInParentSpace);
+        }
+        if (effectParent->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren)
+            return brect;
+        effectParent = effectParent->d_ptr->parent;
+    }
+
+    return brect;
+#else //QT_NO_GRAPHICSEFFECT
+    return q_ptr->boundingRect();
+#endif //QT_NO_GRAPHICSEFFECT
+
+}
+
+/*!
+    \internal
+    \since 4.6
+    Returns the effective bounding rect of this item in scene coordinates,
+    by combining sceneTransform() with boundingRect(), taking into account
+    the effect that the item might have.
+
+    If the item has no effect, this is the same as sceneBoundingRect().
+
+    \sa effectiveBoundingRect(), sceneBoundingRect()
+*/
+QRectF QGraphicsItemPrivate::sceneEffectiveBoundingRect() const
+{
+    // Find translate-only offset
+    // COMBINE
+    QPointF offset;
+    const QGraphicsItem *parentItem = q_ptr;
+    const QGraphicsItemPrivate *itemd;
+    do {
+        itemd = parentItem->d_ptr.data();
+        if (itemd->transformData)
+            break;
+        offset += itemd->pos;
+    } while ((parentItem = itemd->parent));
+
+    QRectF br = effectiveBoundingRect();
+    br.translate(offset);
+    return !parentItem ? br : parentItem->sceneTransform().mapRect(br);
 }
 
@@ -2035,8 +2789,8 @@
     children's areas.
 
-    If a parent item handles child events (setHandlesChildEvents()), it will
-    receive hover move, drag move, and drop events as the cursor passes
-    through its children, but it does not receive hover enter and hover leave,
-    nor drag enter and drag leave events on behalf of its children.
+    If a parent item handles child events, it will receive hover move,
+    drag move, and drop events as the cursor passes through its
+    children, but it does not receive hover enter and hover leave, nor
+    drag enter and drag leave events on behalf of its children.
 
     A QGraphicsWidget with window decorations will accept hover events
@@ -2048,5 +2802,11 @@
 void QGraphicsItem::setAcceptHoverEvents(bool enabled)
 {
+    if (d_ptr->acceptsHover == quint32(enabled))
+        return;
     d_ptr->acceptsHover = quint32(enabled);
+    if (d_ptr->acceptsHover && d_ptr->scene && d_ptr->scene->d_func()->allItemsIgnoreHoverEvents) {
+        d_ptr->scene->d_func()->allItemsIgnoreHoverEvents = false;
+        d_ptr->scene->d_func()->enableMouseTrackingOnViews();
+    }
 }
 
@@ -2058,8 +2818,76 @@
 void QGraphicsItem::setAcceptsHoverEvents(bool enabled)
 {
-    d_ptr->acceptsHover = quint32(enabled);
-}
-
-/*!
+    setAcceptHoverEvents(enabled);
+}
+
+/*! \since 4.6
+
+    Returns true if an item accepts \l{QTouchEvent}{touch events};
+    otherwise, returns false. By default, items do not accept touch events.
+
+    \sa setAcceptTouchEvents()
+*/
+bool QGraphicsItem::acceptTouchEvents() const
+{
+    return d_ptr->acceptTouchEvents;
+}
+
+/*!
+    \since 4.6
+
+    If \a enabled is true, this item will accept \l{QTouchEvent}{touch events};
+    otherwise, it will ignore them. By default, items do not accept
+    touch events.
+*/
+void QGraphicsItem::setAcceptTouchEvents(bool enabled)
+{
+    if (d_ptr->acceptTouchEvents == quint32(enabled))
+        return;
+    d_ptr->acceptTouchEvents = quint32(enabled);
+    if (d_ptr->acceptTouchEvents && d_ptr->scene && d_ptr->scene->d_func()->allItemsIgnoreTouchEvents) {
+        d_ptr->scene->d_func()->allItemsIgnoreTouchEvents = false;
+        d_ptr->scene->d_func()->enableTouchEventsOnViews();
+    }
+}
+
+/*!
+    \since 4.6
+
+    Returns true if this item filters child events (i.e., all events
+    intended for any of its children are instead sent to this item);
+    otherwise, false is returned.
+
+    The default value is false; child events are not filtered.
+
+    \sa setFiltersChildEvents()
+*/
+bool QGraphicsItem::filtersChildEvents() const
+{
+    return d_ptr->filtersDescendantEvents;
+}
+
+/*!
+    \since 4.6
+
+    If \a enabled is true, this item is set to filter all events for
+    all its children (i.e., all events intented for any of its
+    children are instead sent to this item); otherwise, if \a enabled
+    is false, this item will only handle its own events. The default
+    value is false.
+
+    \sa filtersChildEvents()
+*/
+void QGraphicsItem::setFiltersChildEvents(bool enabled)
+{
+    if (d_ptr->filtersDescendantEvents == enabled)
+        return;
+
+    d_ptr->filtersDescendantEvents = enabled;
+    d_ptr->updateAncestorFlag(QGraphicsItem::GraphicsItemFlag(-2));
+}
+
+/*!
+    \obsolete
+
     Returns true if this item handles child events (i.e., all events
     intended for any of its children are instead sent to this item);
@@ -2082,4 +2910,6 @@
 
 /*!
+    \obsolete
+
     If \a enabled is true, this item is set to handle all events for
     all its children (i.e., all events intented for any of its
@@ -2107,44 +2937,143 @@
     d_ptr->updateAncestorFlag(QGraphicsItem::GraphicsItemFlag(-1));
 }
-
-/*!
-    Returns true if this item has keyboard input focus; otherwise, returns
-    false.
-
-    \sa QGraphicsScene::focusItem(), setFocus(), QGraphicsScene::setFocusItem()
+/*!
+    \since 4.6
+    Returns true if this item is active; otherwise returns false.
+
+    An item can only be active if the scene is active. An item is active
+    if it is, or is a descendent of, an active panel. Items in non-active
+    panels are not active.
+
+    Items that are not part of a panel follow scene activation when the
+    scene has no active panel.
+
+    Only active items can gain input focus.
+
+    \sa QGraphicsScene::isActive(), QGraphicsScene::activePanel(), panel(), isPanel()
+*/
+bool QGraphicsItem::isActive() const
+{
+    if (!d_ptr->scene || !d_ptr->scene->isActive())
+        return false;
+    return panel() == d_ptr->scene->activePanel();
+}
+
+/*!
+    \since 4.6
+
+    If \a active is true, and the scene is active, this item's panel will be
+    activated. Otherwise, the panel is deactivated.
+
+    If the item is not part of an active scene, \a active will decide what
+    happens to the panel when the scene becomes active or the item is added to
+    the scene. If true, the item's panel will be activated when the item is
+    either added to the scene or the scene is activated. Otherwise, the item
+    will stay inactive independent of the scene's activated state.
+
+    \sa isPanel(), QGraphicsScene::setActivePanel(), QGraphicsScene::isActive()
+*/
+void QGraphicsItem::setActive(bool active)
+{
+    d_ptr->explicitActivate = 1;
+    d_ptr->wantsActive = active;
+    if (d_ptr->scene) {
+        if (active) {
+            // Activate this item.
+            d_ptr->scene->setActivePanel(this);
+        } else {
+            // Deactivate this item, and reactivate the last active item
+            // (if any).
+            QGraphicsItem *lastActive = d_ptr->scene->d_func()->lastActivePanel;
+            d_ptr->scene->setActivePanel(lastActive != this ? lastActive : 0);
+        }
+    }
+}
+
+/*!
+    Returns true if this item is active, and it or its \l{focusProxy()}{focus
+    proxy} has keyboard input focus; otherwise, returns false.
+
+    \sa focusItem(), setFocus(), QGraphicsScene::setFocusItem(), isActive()
 */
 bool QGraphicsItem::hasFocus() const
 {
-    return (d_ptr->scene && d_ptr->scene->focusItem() == this);
+    if (d_ptr->focusProxy)
+        return d_ptr->focusProxy->hasFocus();
+    return isActive() && (d_ptr->scene && d_ptr->scene->focusItem() == this);
 }
 
 /*!
     Gives keyboard input focus to this item. The \a focusReason argument will
-    be passed into any focus event generated by this function; it is used to
-    give an explanation of what caused the item to get focus.
-
-    Only items that set the ItemIsFocusable flag can accept keyboard focus.
-
-    If this item is not visible (i.e., isVisible() returns false), not
-    enabled, not associated with a scene, or if it already has input focus,
-    this function will do nothing.
-
-    As a result of calling this function, this item will receive a focus in
-    event with \a focusReason. If another item already has focus, that item
-    will first receive a focus out event indicating that it has lost input
+    be passed into any \l{QFocusEvent}{focus event} generated by this function;
+    it is used to give an explanation of what caused the item to get focus.
+
+    Only enabled items that set the ItemIsFocusable flag can accept keyboard
     focus.
 
-    \sa clearFocus(), hasFocus()
+    If this item is not visible, not active, or not associated with a scene,
+    it will not gain immediate input focus. However, it will be registered as
+    the preferred focus item for its subtree of items, should it later become
+    visible.
+
+    As a result of calling this function, this item will receive a
+    \l{focusInEvent()}{focus in event} with \a focusReason. If another item
+    already has focus, that item will first receive a \l{focusOutEvent()}
+    {focus out event} indicating that it has lost input focus.
+
+    \sa clearFocus(), hasFocus(), focusItem(), focusProxy()
 */
 void QGraphicsItem::setFocus(Qt::FocusReason focusReason)
 {
-    if (!d_ptr->scene || !isEnabled() || hasFocus() || !(d_ptr->flags & ItemIsFocusable))
+    d_ptr->setFocusHelper(focusReason, /* climb = */ true);
+}
+
+/*!
+    \internal
+*/
+void QGraphicsItemPrivate::setFocusHelper(Qt::FocusReason focusReason, bool climb)
+{
+    // Disabled / unfocusable items cannot accept focus.
+    if (!q_ptr->isEnabled() || !(flags & QGraphicsItem::ItemIsFocusable))
         return;
-    if (isVisible()) {
-        // Visible items immediately gain focus from scene.
-        d_ptr->scene->setFocusItem(this, focusReason);
-    } else if (d_ptr->isWidget) {
-        // Just set up subfocus.
-        static_cast<QGraphicsWidget *>(this)->d_func()->setFocusWidget();
+
+    // Find focus proxy.
+    QGraphicsItem *f = q_ptr;
+    while (f->d_ptr->focusProxy)
+        f = f->d_ptr->focusProxy;
+
+    // Return if it already has focus.
+    if (scene && scene->focusItem() == f)
+        return;
+
+    // Update focus scope item ptr.
+    QGraphicsItem *p = parent;
+    while (p) {
+        if (p->flags() & QGraphicsItem::ItemIsFocusScope) {
+            p->d_ptr->focusScopeItem = q_ptr;
+            if (!p->focusItem()) {
+                // If you call setFocus on a child of a focus scope that
+                // doesn't currently have a focus item, then stop.
+                return;
+            }
+            break;
+        }
+        p = p->d_ptr->parent;
+    }
+
+    if (climb) {
+        while (f->d_ptr->focusScopeItem && f->d_ptr->focusScopeItem->isVisible())
+            f = f->d_ptr->focusScopeItem;
+    }
+
+    // Update the child focus chain.
+    f->d_ptr->setSubFocus();
+
+    // Update the scene's focus item.
+    if (scene) {
+        QGraphicsItem *p = q_ptr->panel();
+        if ((!p && scene->isActive()) || (p && p->isActive())) {
+            // Visible items immediately gain focus from scene.
+            scene->d_func()->setFocusItemHelper(f, focusReason);
+        }
     }
 }
@@ -2153,24 +3082,118 @@
     Takes keyboard input focus from the item.
 
-    If it has focus, a focus out event is sent to this item to tell it that it
-    is about to lose the focus.
+    If it has focus, a \l{focusOutEvent()}{focus out event} is sent to this
+    item to tell it that it is about to lose the focus.
 
     Only items that set the ItemIsFocusable flag, or widgets that set an
     appropriate focus policy, can accept keyboard focus.
 
-    \sa setFocus(), QGraphicsWidget::focusPolicy
+    \sa setFocus(), hasFocus(), QGraphicsWidget::focusPolicy
 */
 void QGraphicsItem::clearFocus()
 {
-    if (!d_ptr->scene)
-        return;
-    if (d_ptr->isWidget) {
-        // Invisible widget items with focus must explicitly clear subfocus.
-        static_cast<QGraphicsWidget *>(this)->d_func()->clearFocusWidget();
-    }
-    if (d_ptr->scene->focusItem() == this) {
+    // Pass focus to the closest parent focus scope.
+    if (!d_ptr->inDestructor) {
+        QGraphicsItem *p = d_ptr->parent;
+        while (p) {
+            if (p->flags() & ItemIsFocusScope) {
+                p->d_ptr->setFocusHelper(Qt::OtherFocusReason, /* climb = */ false);
+                return;
+            }
+            p = p->d_ptr->parent;
+        }
+    }
+
+    // Invisible items with focus must explicitly clear subfocus.
+    d_ptr->clearSubFocus(this);
+
+    if (hasFocus()) {
         // If this item has the scene's input focus, clear it.
         d_ptr->scene->setFocusItem(0);
     }
+}
+
+/*!
+    \since 4.6
+
+    Returns this item's focus proxy, or 0 if this item has no
+    focus proxy.
+
+    \sa setFocusProxy(), setFocus(), hasFocus()
+*/
+QGraphicsItem *QGraphicsItem::focusProxy() const
+{
+    return d_ptr->focusProxy;
+}
+
+/*!
+    \since 4.6
+
+    Sets the item's focus proxy to \a item.
+
+    If an item has a focus proxy, the focus proxy will receive
+    input focus when the item gains input focus. The item itself
+    will still have focus (i.e., hasFocus() will return true),
+    but only the focus proxy will receive the keyboard input.
+
+    A focus proxy can itself have a focus proxy, and so on. In
+    such case, keyboard input will be handled by the outermost
+    focus proxy.
+
+    The focus proxy \a item must belong to the same scene as
+    this item.
+
+    \sa focusProxy(), setFocus(), hasFocus()
+*/
+void QGraphicsItem::setFocusProxy(QGraphicsItem *item)
+{
+    if (item == d_ptr->focusProxy)
+        return;
+    if (item == this) {
+        qWarning("QGraphicsItem::setFocusProxy: cannot assign self as focus proxy");
+        return;
+    }
+    if (item) {
+        if (item->d_ptr->scene != d_ptr->scene) {
+            qWarning("QGraphicsItem::setFocusProxy: focus proxy must be in same scene");
+            return;
+        }
+        for (QGraphicsItem *f = item->focusProxy(); f != 0; f = f->focusProxy()) {
+            if (f == this) {
+                qWarning("QGraphicsItem::setFocusProxy: %p is already in the focus proxy chain", item);
+                return;
+            }
+        }
+    }
+
+    QGraphicsItem *lastFocusProxy = d_ptr->focusProxy;
+    if (lastFocusProxy)
+        lastFocusProxy->d_ptr->focusProxyRefs.removeOne(&d_ptr->focusProxy);
+    d_ptr->focusProxy = item;
+    if (item)
+        item->d_ptr->focusProxyRefs << &d_ptr->focusProxy;
+}
+
+/*!
+    \since 4.6
+
+    If this item, a child or descendant of this item currently has input
+    focus, this function will return a pointer to that item. If
+    no descendant has input focus, 0 is returned.
+
+    \sa hasFocus(), setFocus(), QWidget::focusWidget()
+*/
+QGraphicsItem *QGraphicsItem::focusItem() const
+{
+    return d_ptr->subFocusItem;
+}
+
+/*!
+    \internal
+
+    Returns this item's focus scope item.
+*/
+QGraphicsItem *QGraphicsItem::focusScopeItem() const
+{
+    return d_ptr->focusScopeItem;
 }
 
@@ -2310,5 +3333,5 @@
     item's position in scene coordinates, regardless of its parent.
 
-    \sa x(), y(), setPos(), matrix(), {The Graphics View Coordinate System}
+    \sa x(), y(), setPos(), transform(), {The Graphics View Coordinate System}
 */
 QPointF QGraphicsItem::pos() const
@@ -2326,4 +3349,20 @@
 
 /*!
+    \since 4.6
+
+    Set's the \a x coordinate of the item's position. Equivalent to
+    calling setPos(x, y()).
+
+    \sa x(), setPos()
+*/
+void QGraphicsItem::setX(qreal x)
+{
+    if (d_ptr->inDestructor)
+        return;
+
+    d_ptr->setPosHelper(QPointF(x, d_ptr->pos.y()));
+}
+
+/*!
     \fn QGraphicsItem::y() const
 
@@ -2332,4 +3371,20 @@
     \sa x()
 */
+
+/*!
+    \since 4.6
+
+    Set's the \a y coordinate of the item's position. Equivalent to
+    calling setPos(x(), y).
+
+    \sa x(), setPos()
+*/
+void QGraphicsItem::setY(qreal y)
+{
+    if (d_ptr->inDestructor)
+        return;
+
+    d_ptr->setPosHelper(QPointF(d_ptr->pos.x(), y));
+}
 
 /*!
@@ -2347,33 +3402,34 @@
     \internal
 
-    Sets the position \a pos and notifies the change. If \a update is true,
-    the item is also updated; otherwise it is not updated before and after the
-    change.
+    Sets the position \a pos.
 */
 void QGraphicsItemPrivate::setPosHelper(const QPointF &pos)
 {
     Q_Q(QGraphicsItem);
-    if (this->pos == pos)
-        return;
-
-    // Notify the item that the position is changing.
-    const QVariant newPosVariant(q->itemChange(QGraphicsItem::ItemPositionChange, pos));
-    QPointF newPos = newPosVariant.toPointF();
-    if (newPos == this->pos)
-        return;
-
-    // Update and repositition.
     inSetPosHelper = 1;
-    updateCachedClipPathFromSetPosHelper(newPos);
-    if (scene) {
-        fullUpdateHelper(true);
+    if (scene)
         q->prepareGeometryChange();
-    }
-    this->pos = newPos;
-    invalidateSceneTransformCache();
-
-    // Send post-notification.
-    q->itemChange(QGraphicsItem::ItemPositionHasChanged, newPosVariant);
+    QPointF oldPos = this->pos;
+    this->pos = pos;
+    dirtySceneTransform = 1;
     inSetPosHelper = 0;
+    if (isObject) {
+        if (pos.x() != oldPos.x())
+            emit static_cast<QGraphicsObject *>(q_ptr)->xChanged();
+        if (pos.y() != oldPos.y())
+            emit static_cast<QGraphicsObject *>(q_ptr)->yChanged();
+    }
+}
+
+/*!
+    \internal
+
+    Sets the transform \a transform.
+*/
+void QGraphicsItemPrivate::setTransformHelper(const QTransform &transform)
+{
+    q_ptr->prepareGeometryChange();
+    transformData->transform = transform;
+    dirtySceneTransform = 1;
 }
 
@@ -2390,5 +3446,28 @@
 void QGraphicsItem::setPos(const QPointF &pos)
 {
-    d_ptr->setPosHelper(pos);
+    if (d_ptr->pos == pos)
+        return;
+
+    if (d_ptr->inDestructor)
+        return;
+
+    // Update and repositition.
+    if (!(d_ptr->flags & ItemSendsGeometryChanges)) {
+        d_ptr->setPosHelper(pos);
+        return;
+    }
+
+    // Notify the item that the position is changing.
+    const QVariant newPosVariant(itemChange(ItemPositionChange, qVariantFromValue<QPointF>(pos)));
+    QPointF newPos = newPosVariant.toPointF();
+    if (newPos == d_ptr->pos)
+        return;
+
+    // Update and repositition.
+    d_ptr->setPosHelper(newPos);
+
+    // Send post-notification.
+    itemChange(QGraphicsItem::ItemPositionHasChanged, newPosVariant);
+    d_ptr->sendScenePosChange();
 }
 
@@ -2463,6 +3542,10 @@
     \since 4.3
 
-    Returns this item's transformation matrix. If no matrix has been set, the
-    identity matrix is returned.
+    Returns this item's transformation matrix.
+
+    The transformation matrix is combined with the item's rotation(), scale()
+    and transformations() into a combined transformations for the item.
+
+    The default transformation matrix is an identity matrix.
 
     \sa setTransform(), sceneTransform()
@@ -2470,8 +3553,224 @@
 QTransform QGraphicsItem::transform() const
 {
-    if (!d_ptr->hasTransform)
+    if (!d_ptr->transformData)
         return QTransform();
-    return qVariantValue<QTransform>(d_ptr->extra(QGraphicsItemPrivate::ExtraTransform));
-}
+    return d_ptr->transformData->transform;
+}
+
+/*!
+    \since 4.6
+
+    Returns the clockwise rotation, in degrees, around the Z axis. The default
+    value is 0 (i.e., the item is not rotated).
+
+    The rotation is combined with the item's scale(), transform() and
+    transformations() to map the item's coordinate system to the parent item.
+
+    \sa setRotation(), transformOriginPoint(), {Transformations}
+*/
+qreal QGraphicsItem::rotation() const
+{
+    if (!d_ptr->transformData)
+        return 0;
+    return d_ptr->transformData->rotation;
+}
+
+/*!
+    \since 4.6
+
+    Sets the clockwise rotation \a angle, in degrees, around the Z axis. The
+    default value is 0 (i.e., the item is not rotated). Assigning a negative
+    value will rotate the item counter-clockwise. Normally the rotation angle
+    is in the range (-360, 360), but it's also possible to assign values
+    outside of this range (e.g., a rotation of 370 degrees is the same as a
+    rotation of 10 degrees).
+
+    The item is rotated around its transform origin point, which by default
+    is (0, 0). You can select a different transformation origin by calling
+    setTransformOriginPoint().
+
+    The rotation is combined with the item's scale(), transform() and
+    transformations() to map the item's coordinate system to the parent item.
+
+    \sa rotation(), setTransformOriginPoint(), {Transformations}
+*/
+void QGraphicsItem::setRotation(qreal angle)
+{
+    prepareGeometryChange();
+    if (!d_ptr->transformData)
+        d_ptr->transformData = new QGraphicsItemPrivate::TransformData;
+    d_ptr->transformData->rotation = angle;
+    d_ptr->transformData->onlyTransform = false;
+    d_ptr->dirtySceneTransform = 1;
+
+    if (d_ptr->isObject)
+        emit static_cast<QGraphicsObject *>(this)->rotationChanged();
+}
+
+/*!
+    \since 4.6
+
+    Returns the scale factor of the item. The default scale factor is 1.0
+    (i.e., the item is not scaled).
+
+    The scale is combined with the item's rotation(), transform() and
+    transformations() to map the item's coordinate system to the parent item.
+
+    \sa setScale(), rotation(), {Transformations}
+*/
+qreal QGraphicsItem::scale() const
+{
+    if (!d_ptr->transformData)
+        return 1.;
+    return d_ptr->transformData->scale;
+}
+
+/*!
+    \since 4.6
+
+    Sets the scale \a factor of the item. The default scale factor is 1.0
+    (i.e., the item is not scaled). A scale factor of 0.0 will collapse the
+    item to a single point. If you provide a negative scale factor, the
+    item will be flipped and mirrored (i.e., rotated 180 degrees).
+
+    The item is scaled around its transform origin point, which by default
+    is (0, 0). You can select a different transformation origin by calling
+    setTransformOriginPoint().
+
+    The scale is combined with the item's rotation(), transform() and
+    transformations() to map the item's coordinate system to the parent item.
+
+    \sa scale(), setTransformOriginPoint(), {Transformations}
+*/
+void QGraphicsItem::setScale(qreal factor)
+{
+    prepareGeometryChange();
+    if (!d_ptr->transformData)
+        d_ptr->transformData = new QGraphicsItemPrivate::TransformData;
+    d_ptr->transformData->scale = factor;
+    d_ptr->transformData->onlyTransform = false;
+    d_ptr->dirtySceneTransform = 1;
+
+    if (d_ptr->isObject)
+        emit static_cast<QGraphicsObject *>(this)->scaleChanged();
+}
+
+
+/*!
+    \since 4.6
+
+    Returns a list of graphics transforms that currently apply to this item.
+
+    QGraphicsTransform is for applying and controlling a chain of individual
+    transformation operations on an item. It's particularily useful in
+    animations, where each transform operation needs to be interpolated
+    independently, or differently.
+
+    The transformations are combined with the item's rotation(), scale() and
+    transform() to map the item's coordinate system to the parent item.
+
+    \sa scale(), rotation(), transformOriginPoint(), {Transformations}
+*/
+QList<QGraphicsTransform *> QGraphicsItem::transformations() const
+{
+    if (!d_ptr->transformData)
+        return QList<QGraphicsTransform *>();
+    return d_ptr->transformData->graphicsTransforms;
+}
+
+/*!
+    \since 4.6
+
+    Sets a list of graphics \a transformations (QGraphicsTransform) that
+    currently apply to this item.
+
+    If all you want is to rotate or scale an item, you should call setRotation()
+    or setScale() instead. If you want to set an arbitrary transformation on
+    an item, you can call setTransform().
+
+    QGraphicsTransform is for applying and controlling a chain of individual
+    transformation operations on an item. It's particularily useful in
+    animations, where each transform operation needs to be interpolated
+    independently, or differently.
+
+    The transformations are combined with the item's rotation(), scale() and
+    transform() to map the item's coordinate system to the parent item.
+
+    \sa scale(), setTransformOriginPoint(), {Transformations}
+*/
+void QGraphicsItem::setTransformations(const QList<QGraphicsTransform *> &transformations)
+{
+    prepareGeometryChange();
+    if (!d_ptr->transformData)
+        d_ptr->transformData = new QGraphicsItemPrivate::TransformData;
+    d_ptr->transformData->graphicsTransforms = transformations;
+    for (int i = 0; i < transformations.size(); ++i)
+        transformations.at(i)->d_func()->setItem(this);
+    d_ptr->transformData->onlyTransform = false;
+    d_ptr->dirtySceneTransform = 1;
+}
+
+/*!
+    \internal
+*/
+void QGraphicsItemPrivate::appendGraphicsTransform(QGraphicsTransform *t)
+{
+    if (!transformData)
+        transformData = new QGraphicsItemPrivate::TransformData;
+    if (!transformData->graphicsTransforms.contains(t))
+        transformData->graphicsTransforms.append(t);
+
+    Q_Q(QGraphicsItem);
+    t->d_func()->setItem(q);
+    transformData->onlyTransform = false;
+    dirtySceneTransform = 1;
+}
+
+/*!
+    \since 4.6
+
+    Returns the origin point for the transformation in item coordinates.
+
+    The default is QPointF(0,0).
+
+    \sa setTransformOriginPoint(), {Transformations}
+*/
+QPointF QGraphicsItem::transformOriginPoint() const
+{
+    if (!d_ptr->transformData)
+        return QPointF(0,0);
+    return QPointF(d_ptr->transformData->xOrigin, d_ptr->transformData->yOrigin);
+}
+
+/*!
+    \since 4.6
+
+    Sets the \a origin point for the transformation in item coordinates.
+
+    \sa transformOriginPoint(), {Transformations}
+*/
+void QGraphicsItem::setTransformOriginPoint(const QPointF &origin)
+{
+    prepareGeometryChange();
+    if (!d_ptr->transformData)
+        d_ptr->transformData = new QGraphicsItemPrivate::TransformData;
+    d_ptr->transformData->xOrigin = origin.x();
+    d_ptr->transformData->yOrigin = origin.y();
+    d_ptr->transformData->onlyTransform = false;
+    d_ptr->dirtySceneTransform = 1;
+}
+
+/*!
+    \fn void QGraphicsItem::setTransformOriginPoint(qreal x, qreal y)
+
+    \since 4.6
+    \overload
+
+    Sets the origin point for the transformation in item coordinates.
+    This is equivalent to calling setTransformOriginPoint(QPointF(\a x, \a y)).
+
+    \sa setTransformOriginPoint(), {Transformations}
+*/
+
 
 /*!
@@ -2484,5 +3783,6 @@
 QMatrix QGraphicsItem::sceneMatrix() const
 {
-    return sceneTransform().toAffine();
+    d_ptr->ensureSceneTransform();
+    return d_ptr->sceneTransform.toAffine();
 }
 
@@ -2501,49 +3801,12 @@
 
     Unlike transform(), which returns only an item's local transformation, this
-    function includes the item's (and any parents') position.
-
-    \sa transform(), setTransform(), scenePos(), {The Graphics View Coordinate System}
+    function includes the item's (and any parents') position, and all the transfomation properties.
+
+    \sa transform(), setTransform(), scenePos(), {The Graphics View Coordinate System}, {Transformations}
 */
 QTransform QGraphicsItem::sceneTransform() const
 {
-    // Check if there's any entry in the transform cache.
-    QGraphicsScenePrivate *sd = d_ptr->scene ? d_ptr->scene->d_func() : 0;
-    int index = d_ptr->sceneTransformIndex;
-    if (sd && index != -1 && sd->validTransforms.testBit(index))
-        return sd->sceneTransformCache[index];
-
-    // Calculate local transform.
-    QTransform m;
-    if (d_ptr->hasTransform) {
-        m = transform();
-        if (!d_ptr->pos.isNull())
-            m *= QTransform::fromTranslate(d_ptr->pos.x(), d_ptr->pos.y());
-    } else if (!d_ptr->pos.isNull()) {
-        m = QTransform::fromTranslate(d_ptr->pos.x(), d_ptr->pos.y());
-    }
-
-    // Combine with parent and add to cache.
-    if (d_ptr->parent) {
-        m *= d_ptr->parent->sceneTransform();
-        // Don't cache toplevels
-        if (sd) {
-            if (index == -1) {
-                if (!sd->freeSceneTransformSlots.isEmpty()) {
-                    index = sd->freeSceneTransformSlots.last();
-                    sd->freeSceneTransformSlots.pop_back();
-                } else {
-                    index = sd->sceneTransformCache.size();
-                }
-                d_ptr->sceneTransformIndex = index;
-                if (index >= sd->validTransforms.size()) {
-                    sd->validTransforms.resize(index + 1);
-                    sd->sceneTransformCache.resize(index + 1);
-                }
-            }
-            sd->validTransforms.setBit(index, 1);
-            sd->sceneTransformCache[index] = m;
-        }
-    }
-    return m;
+    d_ptr->ensureSceneTransform();
+    return d_ptr->sceneTransform;
 }
 
@@ -2573,4 +3836,10 @@
 QTransform QGraphicsItem::deviceTransform(const QTransform &viewportTransform) const
 {
+    // Ensure we return the standard transform if we're not untransformable.
+    if (!d_ptr->itemIsUntransformable()) {
+        d_ptr->ensureSceneTransform();
+        return d_ptr->sceneTransform * viewportTransform;
+    }
+
     // Find the topmost item that ignores view transformations.
     const QGraphicsItem *untransformedAncestor = this;
@@ -2590,16 +3859,16 @@
 
     // First translate the base untransformable item.
-    QPointF mappedPoint = (untransformedAncestor->sceneTransform() * viewportTransform).map(QPointF(0, 0));
-    QTransform matrix;
-    matrix.translate(mappedPoint.x(), mappedPoint.y());
-    matrix = untransformedAncestor->transform() * matrix;
+    untransformedAncestor->d_ptr->ensureSceneTransform();
+    QPointF mappedPoint = (untransformedAncestor->d_ptr->sceneTransform * viewportTransform).map(QPointF(0, 0));
+
+    // COMBINE
+    QTransform matrix = QTransform::fromTranslate(mappedPoint.x(), mappedPoint.y());
+    if (untransformedAncestor->d_ptr->transformData)
+        matrix = untransformedAncestor->d_ptr->transformData->computedFullTransform(&matrix);
 
     // Then transform and translate all children.
     for (int i = 0; i < parents.size(); ++i) {
         const QGraphicsItem *parent = parents.at(i);
-        QPointF pos = parent->pos();
-        QTransform moveMatrix;
-        moveMatrix.translate(pos.x(), pos.y());
-        matrix = (parent->transform() * moveMatrix) * matrix;
+        parent->d_ptr->combineTransformFromParent(&matrix);
     }
 
@@ -2644,10 +3913,7 @@
         if (ok)
             *ok = true;
-        const QPointF &itemPos = d_ptr->pos;
-        if (itemPos.isNull())
-            return d_ptr->hasTransform ? transform() : QTransform();
-        if (d_ptr->hasTransform)
-            return transform() * QTransform::fromTranslate(itemPos.x(), itemPos.y());
-        return QTransform::fromTranslate(itemPos.x(), itemPos.y());
+        QTransform x;
+        d_ptr->combineTransformFromParent(&x);
+        return x;
     }
 
@@ -2655,24 +3921,20 @@
     if (otherParent == this) {
         const QPointF &otherPos = other->d_ptr->pos;
-        if (other->d_ptr->hasTransform) {
-            QTransform otherToParent = other->transform();
-            if (!otherPos.isNull())
-                otherToParent *= QTransform::fromTranslate(otherPos.x(), otherPos.y());
+        if (other->d_ptr->transformData) {
+            QTransform otherToParent;
+            other->d_ptr->combineTransformFromParent(&otherToParent);
             return otherToParent.inverted(ok);
-        } else {
-            if (ok)
-                *ok = true;
-            return QTransform::fromTranslate(-otherPos.x(), -otherPos.y());
         }
+        if (ok)
+            *ok = true;
+        return QTransform::fromTranslate(-otherPos.x(), -otherPos.y());
     }
 
     // Siblings
     if (parent == otherParent) {
-        bool hasTr = d_ptr->hasTransform;
-        bool otherHasTr = other->d_ptr->hasTransform;
+        // COMBINE
         const QPointF &itemPos = d_ptr->pos;
         const QPointF &otherPos = other->d_ptr->pos;
-
-        if (!hasTr && !otherHasTr) {
+        if (!d_ptr->transformData && !other->d_ptr->transformData) {
             QPointF delta = itemPos - otherPos;
             if (ok)
@@ -2681,12 +3943,8 @@
         }
 
-        QTransform itemToParent = QTransform::fromTranslate(itemPos.x(), itemPos.y());
-        if (hasTr)
-            itemToParent = itemPos.isNull() ? transform() : transform() * itemToParent;
-
-        QTransform otherToParent = QTransform::fromTranslate(otherPos.x(), otherPos.y());
-        if (otherHasTr)
-            otherToParent = otherPos.isNull() ? other->transform() : other->transform() * otherToParent;
-
+        QTransform itemToParent;
+        d_ptr->combineTransformFromParent(&itemToParent);
+        QTransform otherToParent;
+        other->d_ptr->combineTransformFromParent(&otherToParent);
         return itemToParent * otherToParent.inverted(ok);
     }
@@ -2695,6 +3953,9 @@
     // ancestor, then the only way is to combine their scene transforms.
     const QGraphicsItem *commonAncestor = commonAncestorItem(other);
-    if (!commonAncestor)
-        return sceneTransform() * other->sceneTransform().inverted(ok);
+    if (!commonAncestor) {
+        d_ptr->ensureSceneTransform();
+        other->d_ptr->ensureSceneTransform();
+        return d_ptr->sceneTransform * other->d_ptr->sceneTransform.inverted(ok);
+    }
 
     // If the two items are cousins (in sibling branches), map both to the
@@ -2703,7 +3964,6 @@
     if (cousins) {
         bool good = false;
-        QTransform thisToScene;
-        QTransform otherToScene;
-        thisToScene = itemTransform(commonAncestor, &good);
+        QTransform thisToScene = itemTransform(commonAncestor, &good);
+        QTransform otherToScene(Qt::Uninitialized);
         if (good)
             otherToScene = other->itemTransform(commonAncestor, &good);
@@ -2724,9 +3984,5 @@
     const QGraphicsItem *p = child;
     do {
-        const QGraphicsItemPrivate *pd = p->d_ptr;
-        if (pd->hasTransform)
-            x *= p->transform();
-        if (!pd->pos.isNull())
-            x *= QTransform::fromTranslate(pd->pos.x(), pd->pos.y());
+        p->d_ptr.data()->combineTransformToParent(&x);
     } while ((p = p->d_ptr->parent) && p != root);
     if (parentOfOther)
@@ -2746,35 +4002,32 @@
     Use setTransform() instead.
 
-    \sa transform(), rotate(), scale(), shear(), translate(), {The Graphics View Coordinate System}
+    \sa transform(), {The Graphics View Coordinate System}
 */
 void QGraphicsItem::setMatrix(const QMatrix &matrix, bool combine)
 {
-    QTransform oldTransform = this->transform();
-    QTransform newTransform;
-    if (!combine)
-        newTransform = QTransform(matrix);
-    else
-        newTransform = QTransform(matrix) * oldTransform;
-    if (oldTransform == newTransform)
+    if (!d_ptr->transformData)
+        d_ptr->transformData = new QGraphicsItemPrivate::TransformData;
+
+    QTransform newTransform(combine ? QTransform(matrix) * d_ptr->transformData->transform : QTransform(matrix));
+    if (d_ptr->transformData->transform == newTransform)
         return;
 
-    // Notify the item that the matrix is changing.
-    QVariant newTransformVariant(itemChange(ItemMatrixChange,
-                                            qVariantFromValue<QMatrix>(newTransform.toAffine())));
-    newTransform = QTransform(qVariantValue<QMatrix>(newTransformVariant));
-    if (oldTransform == newTransform)
+    // Update and set the new transformation.
+    if (!(d_ptr->flags & ItemSendsGeometryChanges)) {
+        d_ptr->setTransformHelper(newTransform);
         return;
+    }
+
+    // Notify the item that the transformation matrix is changing.
+    const QVariant newMatrixVariant = qVariantFromValue<QMatrix>(newTransform.toAffine());
+    newTransform = QTransform(qVariantValue<QMatrix>(itemChange(ItemMatrixChange, newMatrixVariant)));
+    if (d_ptr->transformData->transform == newTransform)
+        return;
 
     // Update and set the new transformation.
-    d_ptr->fullUpdateHelper(true, true);
-    prepareGeometryChange();
-    d_ptr->hasTransform = !newTransform.isIdentity();
-    d_ptr->setExtra(QGraphicsItemPrivate::ExtraTransform, newTransform);
-    d_ptr->invalidateSceneTransformCache();
+    d_ptr->setTransformHelper(newTransform);
 
     // Send post-notification.
-    // NB! We have to change the value from QMatrix to QTransform.
-    qVariantSetValue<QTransform>(newTransformVariant, newTransform);
-    itemChange(ItemTransformHasChanged, newTransformVariant);
+    itemChange(ItemTransformHasChanged, qVariantFromValue<QTransform>(newTransform));
 }
 
@@ -2794,16 +4047,24 @@
     from scene coordinates to item coordinates.
 
-    \sa transform(), rotate(), scale(), shear(), translate(), {The Graphics View Coordinate System}
+    The transformation matrix is combined with the item's rotation(), scale()
+    and transformations() into a combined transformation that maps the item's
+    coordinate system to its parent.
+
+    \sa transform(), setRotation(), setScale(), setTransformOriginPoint(), {The Graphics View Coordinate System}, {Transformations}
 */
 void QGraphicsItem::setTransform(const QTransform &matrix, bool combine)
 {
-    QTransform oldTransform = this->transform();
-    QTransform newTransform;
-    if (!combine)
-        newTransform = matrix;
-    else
-        newTransform = matrix * oldTransform;
-    if (oldTransform == newTransform)
+    if (!d_ptr->transformData)
+        d_ptr->transformData = new QGraphicsItemPrivate::TransformData;
+
+    QTransform newTransform(combine ? matrix * d_ptr->transformData->transform : matrix);
+    if (d_ptr->transformData->transform == newTransform)
         return;
+
+    // Update and set the new transformation.
+    if (!(d_ptr->flags & ItemSendsGeometryChanges)) {
+        d_ptr->setTransformHelper(newTransform);
+        return;
+    }
 
     // Notify the item that the transformation matrix is changing.
@@ -2811,16 +4072,13 @@
                                                   qVariantFromValue<QTransform>(newTransform)));
     newTransform = qVariantValue<QTransform>(newTransformVariant);
-    if (oldTransform == newTransform)
+    if (d_ptr->transformData->transform == newTransform)
         return;
 
     // Update and set the new transformation.
-    d_ptr->fullUpdateHelper(true, true);
-    prepareGeometryChange();
-    d_ptr->hasTransform = !newTransform.isIdentity();
-    d_ptr->setExtra(QGraphicsItemPrivate::ExtraTransform, newTransform);
-    d_ptr->invalidateSceneTransformCache();
+    d_ptr->setTransformHelper(newTransform);
 
     // Send post-notification.
     itemChange(ItemTransformHasChanged, newTransformVariant);
+    d_ptr->sendScenePosChange();
 }
 
@@ -2838,6 +4096,7 @@
     \since 4.3
 
-    Resets this item's transformation matrix to the identity matrix. This is
-    equivalent to calling \c setTransform(QTransform()).
+    Resets this item's transformation matrix to the identity matrix or
+    all the transformation properties to their default values.
+    This is equivalent to calling \c setTransform(QTransform()).
 
     \sa setTransform(), transform()
@@ -2849,4 +4108,14 @@
 
 /*!
+    \obsolete
+
+    Use
+
+    \code
+    setRotation(rotation() + angle);
+    \endcode
+
+    instead.
+
     Rotates the current item transformation \a angle degrees clockwise around
     its origin. To translate around an arbitrary point (x, y), you need to
@@ -2865,4 +4134,14 @@
 
 /*!
+    \obsolete
+
+    Use
+
+    \code
+    setTransform(QTransform::fromScale(sx, sy), true);
+    \endcode
+
+    instead.
+
     Scales the current item transformation by (\a sx, \a sy) around its
     origin. To scale from an arbitrary point (x, y), you need to combine
@@ -2873,5 +4152,5 @@
     \snippet doc/src/snippets/code/src_gui_graphicsview_qgraphicsitem.cpp 7
 
-    \sa setTransform(), transform(), rotate(), shear(), translate()
+    \sa setTransform(), transform()
 */
 void QGraphicsItem::scale(qreal sx, qreal sy)
@@ -2881,7 +4160,17 @@
 
 /*!
+    \obsolete
+
+    Use
+
+    \code
+    setTransform(QTransform().shear(sh, sv), true);
+    \endcode
+
+    instead.
+
     Shears the current item transformation by (\a sh, \a sv).
 
-    \sa setTransform(), transform(), rotate(), scale(), translate()
+    \sa setTransform(), transform()
 */
 void QGraphicsItem::shear(qreal sh, qreal sv)
@@ -2891,4 +4180,13 @@
 
 /*!
+    \obsolete
+
+    Use setPos() or setTransformOriginPoint() instead. For identical
+    behavior, use
+
+    \code
+    setTransform(QTransform::fromTranslate(dx, dy), true);
+    \endcode
+
     Translates the current item transformation by (\a dx, \a dy).
 
@@ -2897,5 +4195,5 @@
     which is conceptually separate from its position.
 
-    \sa setTransform(), transform(), rotate(), scale(), shear()
+    \sa setTransform(), transform()
 */
 void QGraphicsItem::translate(qreal dx, qreal dy)
@@ -2927,10 +4225,10 @@
 
 /*!
-    Returns the Z-value, or the elevation, of the item. The Z-value decides
-    the stacking order of sibling (neighboring) items.
+    Returns the Z-value of the item. The Z-value affects the stacking order of
+    sibling (neighboring) items.
 
     The default Z-value is 0.
 
-    \sa setZValue()
+    \sa setZValue(), {QGraphicsItem#Sorting}{Sorting}, stackBefore(), ItemStacksBehindParent
 */
 qreal QGraphicsItem::zValue() const
@@ -2940,25 +4238,10 @@
 
 /*!
-    Sets the Z-value, or the elevation, of the item, to \a z. The elevation
-    decides the stacking order of sibling (neighboring) items. An item of high
-    Z-value will be drawn on top of an item with a lower Z-value if they
-    share the same parent item. In addition, children of an item will always be drawn
-    on top of the parent, regardless of the child's Z-value. Sibling items
-    that share the same Z-value will be drawn in an undefined order, although
-    the order will stay the same for as long as the items live.
-
-    \img graphicsview-zorder.png
-
-    Children of different parents are stacked according to the Z-value of
-    each item's ancestor item which is an immediate child of the two
-    items' closest common ancestor. For example, a robot item might
-    define a torso item as the parent of a head item, two arm items,
-    and two upper-leg items. The upper-leg items would each be parents
-    of one lower-leg item, and each lower-leg item would be parents of
-    one foot item.  The stacking order of the feet is the same as the
-    stacking order of each foot's ancestor that is an immediate child
-    of the two feet's common ancestor (i.e., the torso item); so the
-    feet are stacked in the same order as the upper-leg items,
-    regardless of each foot's Z-value.
+    Sets the Z-value of the item to \a z. The Z value decides the stacking
+    order of sibling (neighboring) items. A sibling item of high Z value will
+    always be drawn on top of another sibling item with a lower Z value.
+
+    If you restore the Z value, the item's insertion order will decide its
+    stacking order.
 
     The Z-value does not affect the item's size in any way.
@@ -2966,22 +4249,135 @@
     The default Z-value is 0.
 
-    \sa zValue()
+    \sa zValue(), {QGraphicsItem#Sorting}{Sorting}, stackBefore(), ItemStacksBehindParent
 */
 void QGraphicsItem::setZValue(qreal z)
 {
-    const QVariant newZVariant(itemChange(ItemZValueChange, double(z)));
-    qreal newZ = qreal(newZVariant.toDouble());
+    const QVariant newZVariant(itemChange(ItemZValueChange, z));
+    qreal newZ = newZVariant.toReal();
     if (newZ == d_ptr->z)
         return;
-    d_ptr->z = z;
-    d_ptr->fullUpdateHelper();
 
     if (d_ptr->scene) {
-        // Invalidate any sort caching; arrival of a new item means we need to
-        // resort.
-        d_ptr->scene->d_func()->invalidateSortCache();
-    }
+        // Z Value has changed, we have to notify the index.
+        d_ptr->scene->d_func()->index->itemChange(this, ItemZValueChange, newZVariant);
+    }
+
+    d_ptr->z = newZ;
+    if (d_ptr->parent)
+        d_ptr->parent->d_ptr->needSortChildren = 1;
+    else if (d_ptr->scene)
+        d_ptr->scene->d_func()->needSortTopLevelItems = 1;
+
+    if (d_ptr->scene)
+        d_ptr->scene->d_func()->markDirty(this, QRectF(), /*invalidateChildren=*/true);
 
     itemChange(ItemZValueHasChanged, newZVariant);
+
+    if (d_ptr->flags & ItemNegativeZStacksBehindParent)
+        setFlag(QGraphicsItem::ItemStacksBehindParent, z < qreal(0.0));
+
+    if (d_ptr->isObject)
+        emit static_cast<QGraphicsObject *>(this)->zChanged();
+}
+
+/*!
+    \internal
+
+    Ensures that the list of children is sorted by insertion order, and that
+    the siblingIndexes are packed (no gaps), and start at 0.
+
+    ### This function is almost identical to
+    QGraphicsScenePrivate::ensureSequentialTopLevelSiblingIndexes().
+*/
+void QGraphicsItemPrivate::ensureSequentialSiblingIndex()
+{
+    if (!sequentialOrdering) {
+        qSort(children.begin(), children.end(), insertionOrder);
+        sequentialOrdering = 1;
+        needSortChildren = 1;
+    }
+    if (holesInSiblingIndex) {
+        holesInSiblingIndex = 0;
+        for (int i = 0; i < children.size(); ++i)
+            children[i]->d_ptr->siblingIndex = i;
+    }
+}
+
+/*!
+    \internal
+*/
+inline void QGraphicsItemPrivate::sendScenePosChange()
+{
+    Q_Q(QGraphicsItem);
+    if (scene) {
+        if (flags & QGraphicsItem::ItemSendsScenePositionChanges)
+            q->itemChange(QGraphicsItem::ItemScenePositionHasChanged, q->scenePos());
+        if (scenePosDescendants) {
+            foreach (QGraphicsItem *item, scene->d_func()->scenePosItems) {
+                if (q->isAncestorOf(item))
+                    item->itemChange(QGraphicsItem::ItemScenePositionHasChanged, item->scenePos());
+            }
+        }
+    }
+}
+
+/*!
+    \since 4.6
+
+    Stacks this item before \a sibling, which must be a sibling item (i.e., the
+    two items must share the same parent item, or must both be toplevel items).
+    The \a sibling must have the same Z value as this item, otherwise calling
+    this function will have no effect.
+
+    By default, all sibling items are stacked by insertion order (i.e., the
+    first item you add is drawn before the next item you add). If two items' Z
+    values are different, then the item with the highest Z value is drawn on
+    top. When the Z values are the same, the insertion order will decide the
+    stacking order.
+
+    \sa setZValue(), ItemStacksBehindParent, {QGraphicsItem#Sorting}{Sorting}
+*/
+void QGraphicsItem::stackBefore(const QGraphicsItem *sibling)
+{
+    if (sibling == this)
+        return;
+    if (!sibling || d_ptr->parent != sibling->parentItem()) {
+        qWarning("QGraphicsItem::stackUnder: cannot stack under %p, which must be a sibling", sibling);
+        return;
+    }
+    QList<QGraphicsItem *> *siblings = d_ptr->parent
+                                       ? &d_ptr->parent->d_ptr->children
+                                       : (d_ptr->scene ? &d_ptr->scene->d_func()->topLevelItems : 0);
+    if (!siblings) {
+        qWarning("QGraphicsItem::stackUnder: cannot stack under %p, which must be a sibling", sibling);
+        return;
+    }
+
+    // First, make sure that the sibling indexes have no holes. This also
+    // marks the children list for sorting.
+    if (d_ptr->parent)
+        d_ptr->parent->d_ptr->ensureSequentialSiblingIndex();
+    else
+        d_ptr->scene->d_func()->ensureSequentialTopLevelSiblingIndexes();
+
+    // Only move items with the same Z value, and that need moving.
+    int siblingIndex = sibling->d_ptr->siblingIndex;
+    int myIndex = d_ptr->siblingIndex;
+    if (myIndex >= siblingIndex) {
+        siblings->move(myIndex, siblingIndex);
+        // Fixup the insertion ordering.
+        for (int i = 0; i < siblings->size(); ++i) {
+            int &index = siblings->at(i)->d_ptr->siblingIndex;
+            if (i != siblingIndex && index >= siblingIndex && index <= myIndex)
+                ++index;
+        }
+        d_ptr->siblingIndex = siblingIndex;
+        for (int i = 0; i < siblings->size(); ++i) {
+            int &index = siblings->at(i)->d_ptr->siblingIndex;
+            if (i != siblingIndex && index >= siblingIndex && index <= myIndex)
+                siblings->at(i)->d_ptr->siblingOrderChange();
+        }
+        d_ptr->siblingOrderChange();
+    }
 }
 
@@ -3005,13 +4401,11 @@
 QRectF QGraphicsItem::childrenBoundingRect() const
 {
-    QRectF childRect;
-    foreach (QGraphicsItem *child, children()) {
-        QPointF childPos = child->pos();
-        QTransform matrix = child->transform();
-        if (!childPos.isNull())
-            matrix *= QTransform::fromTranslate(childPos.x(), childPos.y());
-        childRect |= matrix.mapRect(child->boundingRect() | child->childrenBoundingRect());
-    }
-    return childRect;
+    if (!d_ptr->dirtyChildrenBoundingRect)
+        return d_ptr->childrenBoundingRect;
+
+    d_ptr->childrenBoundingRect = QRectF();
+    d_ptr->childrenBoundingRectHelper(0, &d_ptr->childrenBoundingRect);
+    d_ptr->dirtyChildrenBoundingRect = 0;
+    return d_ptr->childrenBoundingRect;
 }
 
@@ -3026,5 +4420,5 @@
     Although the item's shape can be arbitrary, the bounding rect is
     always rectangular, and it is unaffected by the items'
-    transformation (scale(), rotate(), etc.).
+    transformation.
 
     If you want to change the item's bounding rectangle, you must first call
@@ -3058,10 +4452,11 @@
 {
     // Find translate-only offset
+    // COMBINE
     QPointF offset;
     const QGraphicsItem *parentItem = this;
     const QGraphicsItemPrivate *itemd;
     do {
-        itemd = parentItem->d_ptr;
-        if (itemd->hasTransform)
+        itemd = parentItem->d_ptr.data();
+        if (itemd->transformData)
             break;
         offset += itemd->pos;
@@ -3070,5 +4465,11 @@
     QRectF br = boundingRect();
     br.translate(offset);
-    return !parentItem ? br : parentItem->sceneTransform().mapRect(br);
+    if (!parentItem)
+        return br;
+    if (parentItem->d_ptr->hasTranslateOnlySceneTransform()) {
+        br.translate(parentItem->d_ptr->sceneTransform.dx(), parentItem->d_ptr->sceneTransform.dy());
+        return br;
+    }
+    return parentItem->d_ptr->sceneTransform.mapRect(br);
 }
 
@@ -3142,20 +4543,10 @@
 {
     Q_D(const QGraphicsItem);
-    if (!d->dirtyClipPath)
-        return d->emptyClipPath ? QPainterPath() : d->cachedClipPath;
-
-    if (!isClipped()) {
-        d_ptr->setCachedClipPath(QPainterPath());
-        return d->cachedClipPath;
-    }
+    if (!isClipped())
+        return QPainterPath();
 
     const QRectF thisBoundingRect(boundingRect());
-    if (thisBoundingRect.isEmpty()) {
-        if (d_ptr->flags & ItemClipsChildrenToShape)
-            d_ptr->setEmptyCachedClipPathRecursively();
-        else
-            d_ptr->setEmptyCachedClipPath();
+    if (thisBoundingRect.isEmpty())
         return QPainterPath();
-    }
 
     QPainterPath clip;
@@ -3168,38 +4559,16 @@
 
         // Intersect any in-between clips starting at the top and moving downwards.
-        bool foundValidClipPath = false;
         while ((parent = parent->d_ptr->parent)) {
             if (parent->d_ptr->flags & ItemClipsChildrenToShape) {
                 // Map clip to the current parent and intersect with its shape/clipPath
                 clip = lastParent->itemTransform(parent).map(clip);
-                if ((foundValidClipPath = !parent->d_ptr->dirtyClipPath && parent->isClipped())) {
-                    if (parent->d_ptr->emptyClipPath) {
-                        if (d_ptr->flags & ItemClipsChildrenToShape)
-                            d_ptr->setEmptyCachedClipPathRecursively();
-                        else
-                            d_ptr->setEmptyCachedClipPath();
-                        return QPainterPath();
-                    }
-                    clip = clip.intersected(parent->d_ptr->cachedClipPath);
-                    if (!(parent->d_ptr->flags & ItemClipsToShape))
-                        clip = clip.intersected(parent->shape());
-                } else {
-                    clip = clip.intersected(parent->shape());
-                }
-
-                if (clip.isEmpty()) {
-                    if (d_ptr->flags & ItemClipsChildrenToShape)
-                        d_ptr->setEmptyCachedClipPathRecursively();
-                    else
-                        d_ptr->setEmptyCachedClipPath();
+                clip = clip.intersected(parent->shape());
+                if (clip.isEmpty())
                     return clip;
-                }
                 lastParent = parent;
             }
 
-            if (!(parent->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren)
-                || foundValidClipPath) {
+            if (!(parent->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren))
                 break;
-            }
         }
 
@@ -3214,5 +4583,4 @@
         clip = clip.intersected(shape());
 
-    d_ptr->setCachedClipPath(clip);
     return clip;
 }
@@ -3236,8 +4604,14 @@
 
 /*!
-    Returns true if this item collides with \a other; otherwise returns false.
-    The ways items collide is determined by \a mode. The default value for \a
-    mode is Qt::IntersectsItemShape; \a other collides with this item if it
-    either intersects, contains, or is contained by this item's shape.
+
+    Returns true if this item collides with \a other; otherwise
+    returns false.
+
+    The \a mode is applied to \a other, and the resulting shape or
+    bounding rectangle is then compared to this item's shape. The
+    default value for \a mode is Qt::IntersectsItemShape; \a other
+    collides with this item if it either intersects, contains, or is
+    contained by this item's shape (see Qt::ItemSelectionMode for
+    details).
 
     The default implementation is based on shape intersection, and it calls
@@ -3294,4 +4668,9 @@
     intersects, contains, or is contained by this item's shape.
 
+    Note that this function checks whether the item's shape or
+    bounding rectangle (depending on \a mode) is contained within \a
+    path, and not whether \a path is contained within the items shape
+    or bounding rectangle.
+
     \sa collidesWithItem(), contains(), shape()
 */
@@ -3334,9 +4713,10 @@
     Returns a list of all items that collide with this item.
 
-    The way collisions are detected is determined by \a mode. The default
-    value for \a mode is Qt::IntersectsItemShape; All items whose shape
-    intersects or is contained by this item's shape are returned.
-
-    \sa QGraphicsScene::collidingItems(), collidesWithItem()
+    The way collisions are detected is determined by applying \a mode
+    to items that are compared to this item, i.e., each item's shape
+    or bounding rectangle is checked against this item's shape. The
+    default value for \a mode is Qt::IntersectsItemShape.
+
+    \sa collidesWithItem()
 */
 QList<QGraphicsItem *> QGraphicsItem::collidingItems(Qt::ItemSelectionMode mode) const
@@ -3433,5 +4813,5 @@
     if (!item)
         return false;
-    return QGraphicsScenePrivate::closestItemFirst_withoutCache(item, this)
+    return qt_closestItemFirst(item, this)
         && qt_QGraphicsItem_isObscured(this, item, boundingRect());
 }
@@ -3518,6 +4898,5 @@
 
     // Transform QRegion back to device space
-    QTransform unscale;
-    unscale.scale(1 / granularity, 1 / granularity);
+    QTransform unscale = QTransform::fromScale(1 / granularity, 1 / granularity);
     QRegion r;
     QBitmap colorMask = QBitmap::fromImage(mask.createMaskFromColor(0));
@@ -3615,5 +4994,5 @@
     All painting is done in local coordinates.
 
-    \sa setCacheMode(), QPen::width(), {Item Coordinates}
+    \sa setCacheMode(), QPen::width(), {Item Coordinates}, ItemUsesExtendedStyleOption
 */
 
@@ -3622,38 +5001,55 @@
     Returns true if we can discard an update request; otherwise false.
 */
-bool QGraphicsItemPrivate::discardUpdateRequest(bool ignoreClipping,
-                                                bool ignoreVisibleBit,
-                                                bool ignoreDirtyBit) const
+bool QGraphicsItemPrivate::discardUpdateRequest(bool ignoreVisibleBit, bool ignoreDirtyBit,
+                                                bool ignoreOpacity) const
 {
     // No scene, or if the scene is updating everything, means we have nothing
     // to do. The only exception is if the scene tracks the growing scene rect.
-    return (!visible && !ignoreVisibleBit)
-           || (dirty && !ignoreDirtyBit)
-           || !scene
-           || (scene->d_func()->updateAll && scene->d_func()->hasSceneRect)
-           || (!ignoreClipping && (childrenClippedToShape() && isClippedAway()))
-           || (childrenCombineOpacity() && isFullyTransparent());
+    return !scene
+           || (!visible && !ignoreVisibleBit && !this->ignoreVisible)
+           || (!ignoreDirtyBit && fullUpdatePending)
+           || (!ignoreOpacity && !this->ignoreOpacity && childrenCombineOpacity() && isFullyTransparent());
 }
 
 /*!
     \internal
-
-    Asks the scene to mark this item's scene rect as dirty, requesting a
-    redraw.  This does not invalidate any cache.
-
-    The \a force argument is for the update call in setVisible(), which is the
-    only case where the item's background should be marked as dirty even when
-    the item isn't visible.
-*/
-void QGraphicsItemPrivate::updateHelper(const QRectF &rect, bool force, bool maybeDirtyClipPath)
-{
-    // No scene, or if the scene is updating everything, means we have nothing
-    // to do. The only exception is if the scene tracks the growing scene rect.
-    if (discardUpdateRequest(/*ignoreClipping=*/maybeDirtyClipPath, /*ignoreVisibleBit=*/force))
+*/
+int QGraphicsItemPrivate::depth() const
+{
+    if (itemDepth == -1)
+        const_cast<QGraphicsItemPrivate *>(this)->resolveDepth();
+
+    return itemDepth;
+}
+
+/*!
+    \internal
+*/
+#ifndef QT_NO_GRAPHICSEFFECT
+void QGraphicsItemPrivate::invalidateGraphicsEffectsRecursively()
+{
+    QGraphicsItemPrivate *itemPrivate = this;
+    do {
+        if (itemPrivate->graphicsEffect) {
+            itemPrivate->notifyInvalidated = 1;
+
+            if (!itemPrivate->updateDueToGraphicsEffect)
+                static_cast<QGraphicsItemEffectSourcePrivate *>(itemPrivate->graphicsEffect->d_func()->source->d_func())->invalidateCache();
+        }
+    } while ((itemPrivate = itemPrivate->parent ? itemPrivate->parent->d_ptr.data() : 0));
+}
+#endif //QT_NO_GRAPHICSEFFECT
+
+/*!
+    \internal
+*/
+void QGraphicsItemPrivate::invalidateDepthRecursively()
+{
+    if (itemDepth == -1)
         return;
 
-    if (rect.isNull())
-        dirty = 1;
-    scene->itemUpdated(q_ptr, rect);
+    itemDepth = -1;
+    for (int i = 0; i < children.size(); ++i)
+        children.at(i)->d_ptr->invalidateDepthRecursively();
 }
 
@@ -3661,75 +5057,15 @@
     \internal
 
-    Propagates updates to \a item and all its children.
-*/
-void QGraphicsItemPrivate::fullUpdateHelper(bool childrenOnly, bool maybeDirtyClipPath)
-{
-    if (discardUpdateRequest(/*ignoreClipping=*/maybeDirtyClipPath,
-                             /*ignoreVisibleBit=*/false,
-                             /*ignoreDirtyBit=*/true)) {
-        return;
-    }
-
-    if (!childrenOnly && !dirty) {
-        // Effectively the same as updateHelper(QRectF(), false, maybeDirtyClipPath).
-        dirty = 1;
-        scene->itemUpdated(q_ptr, QRectF());
-    }
-
-    if (dirtyChildren || childrenClippedToShape()) {
-        // Unnecessary to update children as well.
-        return;
-    }
-
-    if (ancestorFlags & AncestorClipsChildren) {
-        Q_Q(QGraphicsItem);
-        // Check if we can avoid updating all children.
-        QGraphicsItem *p = parent;
-        QRectF br = q->boundingRect();
-        while (p) {
-            if (p->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape) {
-                bool ok;
-                QTransform x = q->itemTransform(p, &ok);
-                if (!ok)
-                    break;
-                if (x.mapRect(br).contains(p->boundingRect()))
-                    return;
-            }
-            p = p->d_ptr->parent;
-            if (!p || !(p->d_ptr->ancestorFlags & AncestorClipsChildren))
-                break;
-            // ### check one level only
-            break;
-        }
-    }
-    foreach (QGraphicsItem *child, children)
-        child->d_ptr->fullUpdateHelper(false, maybeDirtyClipPath);
-    dirtyChildren = 1;
-}
-
-static inline bool qt_allChildrenCombineOpacity(QGraphicsItem *parent)
-{
-    Q_ASSERT(parent);
-    if (parent->flags() & QGraphicsItem::ItemDoesntPropagateOpacityToChildren)
-        return false;
-
-    const QList<QGraphicsItem *> children(parent->childItems());
-    for (int i = 0; i < children.size(); ++i) {
-        if (children.at(i)->flags() & QGraphicsItem::ItemIgnoresParentOpacity)
-            return false;
-    }
-    return true;
-}
-
-void QGraphicsItemPrivate::updateEffectiveOpacity()
-{
-    Q_Q(QGraphicsItem);
-    if (parent) {
-        resolveEffectiveOpacity(parent->effectiveOpacity());
-        parent->d_ptr->allChildrenCombineOpacity = qt_allChildrenCombineOpacity(parent);
-    } else {
-        resolveEffectiveOpacity(1.0);
-    }
-    allChildrenCombineOpacity = qt_allChildrenCombineOpacity(q);
+    Resolves the stacking depth of this object and all its ancestors.
+*/
+void QGraphicsItemPrivate::resolveDepth()
+{
+    if (!parent)
+        itemDepth = 0;
+    else {
+        if (parent->d_ptr->itemDepth == -1)
+            parent->d_ptr->resolveDepth();
+        itemDepth = parent->d_ptr->itemDepth + 1;
+    }
 }
 
@@ -3737,37 +5073,15 @@
     \internal
 
-    Resolves and propagates this item's effective opacity to its children.
-*/
-void QGraphicsItemPrivate::resolveEffectiveOpacity(qreal parentEffectiveOpacity)
-{
-    Q_Q(QGraphicsItem);
-    QGraphicsItem::GraphicsItemFlags myFlags = q->flags();
-    QGraphicsItem::GraphicsItemFlags parentFlags = parent ? parent->flags() : QGraphicsItem::GraphicsItemFlags(0);
-
-    // My local opacity is always part of my effective opacity.
-    qreal myEffectiveOpacity = q->opacity();
-
-    // If I have a parent, and I don't ignore my parent's opacity, and my
-    // parent propagates to me, then combine my local opacity with my parent's
-    // effective opacity into my effective opacity.
-    if (parent
-        && !(myFlags & QGraphicsItem::ItemIgnoresParentOpacity)
-        && !(parentFlags & QGraphicsItem::ItemDoesntPropagateOpacityToChildren)) {
-        myEffectiveOpacity *= parentEffectiveOpacity;
-    }
-
-    // Set this item's resolved opacity.
-    if (qFuzzyCompare(myEffectiveOpacity, qreal(1.0))) {
-        // Opaque, unset effective opacity.
-        hasEffectiveOpacity = 0;
-        unsetExtra(ExtraEffectiveOpacity);
-    } else {
-        hasEffectiveOpacity = 1;
-        setExtra(ExtraEffectiveOpacity, myEffectiveOpacity);
-    }
-
-    // Resolve children always.
-    for (int i = 0; i < children.size(); ++i)
-        children.at(i)->d_ptr->resolveEffectiveOpacity(myEffectiveOpacity);
+    ### This function is almost identical to
+    QGraphicsScenePrivate::registerTopLevelItem().
+*/
+void QGraphicsItemPrivate::addChild(QGraphicsItem *child)
+{
+    // Remove all holes from the sibling index list. Now the max index
+    // number is equal to the size of the children list.
+    ensureSequentialSiblingIndex();
+    needSortChildren = 1; // ### maybe 0
+    child->d_ptr->siblingIndex = children.size();
+    children.append(child);
 }
 
@@ -3775,11 +5089,21 @@
     \internal
 
-    Resolves the stacking depth of this object and all its children.
-*/
-void QGraphicsItemPrivate::resolveDepth(int parentDepth)
-{
-    depth = parentDepth + 1;
-    for (int i = 0; i < children.size(); ++i)
-        children.at(i)->d_ptr->resolveDepth(depth);
+    ### This function is almost identical to
+    QGraphicsScenePrivate::unregisterTopLevelItem().
+*/
+void QGraphicsItemPrivate::removeChild(QGraphicsItem *child)
+{
+    // When removing elements in the middle of the children list,
+    // there will be a "gap" in the list of sibling indexes (0,1,3,4).
+    if (!holesInSiblingIndex)
+        holesInSiblingIndex = child->d_ptr->siblingIndex != children.size() - 1;
+    if (sequentialOrdering && !holesInSiblingIndex)
+        children.removeAt(child->d_ptr->siblingIndex);
+    else
+        children.removeOne(child);
+    // NB! Do not use children.removeAt(child->d_ptr->siblingIndex) because
+    // the child is not guaranteed to be at the index after the list is sorted.
+    // (see ensureSortedChildren()).
+    child->d_ptr->siblingIndex = -1;
 }
 
@@ -3787,14 +5111,12 @@
     \internal
 */
-void QGraphicsItemPrivate::invalidateSceneTransformCache()
-{
-    if (!scene || (parent && sceneTransformIndex == -1))
-        return;
-    if (sceneTransformIndex != -1)
-        scene->d_func()->validTransforms.setBit(sceneTransformIndex, 0);
-    for (int i = 0; i < children.size(); ++i)
-        children.at(i)->d_ptr->invalidateSceneTransformCache();
-}
-
+QGraphicsItemCache *QGraphicsItemPrivate::maybeExtraItemCache() const
+{
+    return (QGraphicsItemCache *)qVariantValue<void *>(extra(ExtraCacheData));
+}
+
+/*!
+    \internal
+*/
 QGraphicsItemCache *QGraphicsItemPrivate::extraItemCache() const
 {
@@ -3808,4 +5130,7 @@
 }
 
+/*!
+    \internal
+*/
 void QGraphicsItemPrivate::removeExtraItemCache()
 {
@@ -3818,105 +5143,107 @@
 }
 
-void QGraphicsItemPrivate::setEmptyCachedClipPathRecursively(const QRectF &emptyIfOutsideThisRect)
-{
-    setEmptyCachedClipPath();
-
-    const bool checkRect = !emptyIfOutsideThisRect.isNull()
-                           && !(flags & QGraphicsItem::ItemClipsChildrenToShape);
-    for (int i = 0; i < children.size(); ++i) {
-        if (!checkRect) {
-            children.at(i)->d_ptr->setEmptyCachedClipPathRecursively();
-            continue;
+// Traverses all the ancestors up to the top-level and updates the pointer to
+// always point to the top-most item that has a dirty scene transform.
+// It then backtracks to the top-most dirty item and start calculating the
+// scene transform by combining the item's transform (+pos) with the parent's
+// cached scene transform (which we at this point know for sure is valid).
+void QGraphicsItemPrivate::ensureSceneTransformRecursive(QGraphicsItem **topMostDirtyItem)
+{
+    Q_ASSERT(topMostDirtyItem);
+
+    if (dirtySceneTransform)
+        *topMostDirtyItem = q_ptr;
+
+    if (parent)
+        parent->d_ptr->ensureSceneTransformRecursive(topMostDirtyItem);
+
+    if (*topMostDirtyItem == q_ptr) {
+        if (!dirtySceneTransform)
+            return; // OK, neither my ancestors nor I have dirty scene transforms.
+        *topMostDirtyItem = 0;
+    } else if (*topMostDirtyItem) {
+        return; // Continue backtrack.
+    }
+
+    // This item and all its descendants have dirty scene transforms.
+    // We're about to validate this item's scene transform, so we have to
+    // invalidate all the children; otherwise there's no way for the descendants
+    // to detect that the ancestor has changed.
+    invalidateChildrenSceneTransform();
+
+    // COMBINE my transform with the parent's scene transform.
+    updateSceneTransformFromParent();
+    Q_ASSERT(!dirtySceneTransform);
+}
+
+/*!
+    \internal
+*/
+void QGraphicsItemPrivate::setSubFocus(QGraphicsItem *rootItem)
+{
+    // Update focus child chain. Stop at panels, or if this item
+    // is hidden, stop at the first item with a visible parent.
+    QGraphicsItem *parent = rootItem ? rootItem : q_ptr;
+    do {
+        // Clear any existing ancestor's subFocusItem.
+        if (parent != q_ptr && parent->d_ptr->subFocusItem) {
+            if (parent->d_ptr->subFocusItem == q_ptr)
+                break;
+            parent->d_ptr->subFocusItem->d_ptr->clearSubFocus();
         }
-
-        QGraphicsItem *child = children.at(i);
-        const QRectF rect = child->mapRectFromParent(emptyIfOutsideThisRect);
-        if (rect.intersects(child->boundingRect()))
-            child->d_ptr->invalidateCachedClipPathRecursively(false, rect);
-        else
-            child->d_ptr->setEmptyCachedClipPathRecursively(rect);
-    }
-}
-
-void QGraphicsItemPrivate::invalidateCachedClipPathRecursively(bool childrenOnly, const QRectF &emptyIfOutsideThisRect)
-{
-    if (!childrenOnly)
-        invalidateCachedClipPath();
-
-    const bool checkRect = !emptyIfOutsideThisRect.isNull();
-    for (int i = 0; i < children.size(); ++i) {
-        if (!checkRect) {
-            children.at(i)->d_ptr->invalidateCachedClipPathRecursively(false);
-            continue;
-        }
-
-        QGraphicsItem *child = children.at(i);
-        const QRectF rect = child->mapRectFromParent(emptyIfOutsideThisRect);
-        if (rect.intersects(child->boundingRect()))
-            child->d_ptr->invalidateCachedClipPathRecursively(false, rect);
-        else
-            child->d_ptr->setEmptyCachedClipPathRecursively(rect);
-    }
-}
-
-void QGraphicsItemPrivate::updateCachedClipPathFromSetPosHelper(const QPointF &newPos)
-{
-    Q_ASSERT(inSetPosHelper);
-
-    if (!(ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren))
-        return; // Not clipped by any ancestor.
-
-    // Find closest clip ancestor and transform.
-    Q_Q(QGraphicsItem);
-    QTransform thisToParentTransform = hasTransform
-                                       ? q->transform() * QTransform::fromTranslate(newPos.x(), newPos.y())
-                                       : QTransform::fromTranslate(newPos.x(), newPos.y());
-    QGraphicsItem *clipParent = parent;
-    while (clipParent && !(clipParent->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape)) {
-        if (clipParent->d_ptr->hasTransform)
-            thisToParentTransform *= clipParent->transform();
-        if (!clipParent->d_ptr->pos.isNull()) {
-            thisToParentTransform *= QTransform::fromTranslate(clipParent->d_ptr->pos.x(),
-                                                               clipParent->d_ptr->pos.y());
-        }
-        clipParent = clipParent->d_ptr->parent;
-    }
-
-    // thisToParentTransform is now the same as q->itemTransform(clipParent), except
-    // that the new position (which is not yet set on the item) is taken into account.
-    Q_ASSERT(clipParent);
-    Q_ASSERT(clipParent->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape);
-
-    // From here everything is calculated in clip parent's coordinates.
-    const QRectF parentBoundingRect(clipParent->boundingRect());
-    const QRectF thisBoundingRect(thisToParentTransform.mapRect(q->boundingRect()));
-
-    if (!parentBoundingRect.intersects(thisBoundingRect)) {
-        // Item is moved outside the clip parent's bounding rect,
-        // i.e. it is fully clipped and the clip path is empty.
-        if (flags & QGraphicsItem::ItemClipsChildrenToShape)
-            setEmptyCachedClipPathRecursively();
-        else
-            setEmptyCachedClipPathRecursively(thisToParentTransform.inverted().mapRect(parentBoundingRect));
-        return;
-    }
-
-    const QPainterPath parentClip(clipParent->isClipped() ? clipParent->clipPath() : clipParent->shape());
-    if (parentClip.contains(thisBoundingRect))
-        return; // Item is inside the clip parent's shape. No update required.
-
-    const QRectF parentClipRect(parentClip.controlPointRect());
-    if (!parentClipRect.intersects(thisBoundingRect)) {
-        // Item is moved outside the clip parent's shape,
-        // i.e. it is fully clipped and the clip path is empty.
-        if (flags & QGraphicsItem::ItemClipsChildrenToShape)
-            setEmptyCachedClipPathRecursively();
-        else
-            setEmptyCachedClipPathRecursively(thisToParentTransform.inverted().mapRect(parentClipRect));
-    } else {
-        // Item is partially inside the clip parent's shape,
-        // i.e. the cached clip path must be invalidated.
-        invalidateCachedClipPathRecursively(false, thisToParentTransform.inverted().mapRect(parentClipRect));
-    }
+        parent->d_ptr->subFocusItem = q_ptr;
+        parent->d_ptr->subFocusItemChange();
+    } while (!parent->isPanel() && (parent = parent->d_ptr->parent) && (visible || !parent->d_ptr->visible));
+
+    if (scene && !scene->isActive())
+        scene->d_func()->lastFocusItem = subFocusItem;
+}
+
+/*!
+    \internal
+*/
+void QGraphicsItemPrivate::clearSubFocus(QGraphicsItem *rootItem)
+{
+    // Reset sub focus chain.
+    QGraphicsItem *parent = rootItem ? rootItem : q_ptr;
+    do {
+        if (parent->d_ptr->subFocusItem != q_ptr)
+            break;
+        parent->d_ptr->subFocusItem = 0;
+        parent->d_ptr->subFocusItemChange();
+    } while (!parent->isPanel() && (parent = parent->d_ptr->parent));
+}
+
+/*!
+    \internal
+
+    Sets the focusProxy pointer to 0 for all items that have this item as their
+    focusProxy. ### Qt 5: Use QPointer instead.
+*/
+void QGraphicsItemPrivate::resetFocusProxy()
+{
+    for (int i = 0; i < focusProxyRefs.size(); ++i)
+        *focusProxyRefs.at(i) = 0;
+    focusProxyRefs.clear();
+}
+
+/*!
+    \internal
+
+    Subclasses can reimplement this function to be notified when subFocusItem
+    changes.
+*/
+void QGraphicsItemPrivate::subFocusItemChange()
+{
+}
+
+/*!
+    \internal
+
+    Subclasses can reimplement this function to be notified when its
+    siblingIndex order is changed.
+*/
+void QGraphicsItemPrivate::siblingOrderChange()
+{
 }
 
@@ -3954,32 +5281,31 @@
         return;
 
+    // Make sure we notify effects about invalidated source.
+#ifndef QT_NO_GRAPHICSEFFECT
+    d_ptr->invalidateGraphicsEffectsRecursively();
+#endif //QT_NO_GRAPHICSEFFECT
+
     if (CacheMode(d_ptr->cacheMode) != NoCache) {
+        // Invalidate cache.
         QGraphicsItemCache *cache = d_ptr->extraItemCache();
-        if (d_ptr->discardUpdateRequest(/* ignoreVisibleBit = */ false,
-                                        /* ignoreClipping = */ false,
-                                        /* ignoreDirtyBit = */ true)) {
-            return;
-        }
-
-        // Invalidate cache.
-        if (rect.isNull()) {
-            cache->allExposed = true;
-            cache->exposed.clear();
-        } else {
-            cache->exposed.append(rect);
+        if (!cache->allExposed) {
+            if (rect.isNull()) {
+                cache->allExposed = true;
+                cache->exposed.clear();
+            } else {
+                cache->exposed.append(rect);
+            }
         }
         // Only invalidate cache; item is already dirty.
-        if (d_ptr->dirty)
+        if (d_ptr->fullUpdatePending)
             return;
-    } else if (d_ptr->discardUpdateRequest()) {
+    }
+
+    if (d_ptr->discardUpdateRequest())
         return;
-    }
-
-    // Effectively the same as updateHelper(rect);
-    if (rect.isNull())
-        d_ptr->dirty = 1;
-    d_ptr->scene->itemUpdated(this, rect);
-}
-
+
+    if (d_ptr->scene)
+        d_ptr->scene->d_func()->markDirty(this, rect);
+}
 
 /*!
@@ -4010,9 +5336,43 @@
         return;
     if (d->cacheMode != NoCache) {
-        // ### This is very slow, and can be done much better. If the cache is
-        // local and matches the below criteria for rotation and scaling, we
-        // can easily scroll. And if the cache is in device coordinates, we
-        // can scroll both the viewport and the cache.
-        update(rect);
+        QGraphicsItemCache *c;
+        bool scrollCache = qFuzzyIsNull(dx - int(dx)) && qFuzzyIsNull(dy - int(dy))
+                           && (c = (QGraphicsItemCache *)qVariantValue<void *>(d_ptr->extra(QGraphicsItemPrivate::ExtraCacheData)))
+                           && (d->cacheMode == ItemCoordinateCache && !c->fixedSize.isValid());
+        if (scrollCache) {
+            QPixmap pix;
+            if (QPixmapCache::find(c->key, &pix)) {
+                // Adjust with 2 pixel margin. Notice the loss of precision
+                // when converting to QRect.
+                int adjust = 2;
+                QRectF br = boundingRect().adjusted(-adjust, -adjust, adjust, adjust);
+                QRect irect = rect.toRect().translated(-br.x(), -br.y());
+
+                pix.scroll(dx, dy, irect);
+
+                QPixmapCache::replace(c->key, pix);
+
+                // Translate the existing expose.
+                foreach (QRectF exposedRect, c->exposed)
+                    c->exposed += exposedRect.translated(dx, dy) & rect;
+
+                // Calculate exposure.
+                QRegion exposed;
+                QRect r = rect.toRect();
+                exposed += r;
+                exposed -= r.translated(dx, dy);
+                foreach (QRect rect, exposed.rects())
+                    update(rect);
+                d->scene->d_func()->markDirty(this);
+            } else {
+                update(rect);
+            }
+        } else {
+            // ### This is very slow, and can be done much better. If the cache is
+            // local and matches the below criteria for rotation and scaling, we
+            // can easily scroll. And if the cache is in device coordinates, we
+            // can scroll both the viewport and the cache.
+            update(rect);
+        }
         return;
     }
@@ -4033,11 +5393,5 @@
         static const QLineF right(0, 0, 1, 0);
 
-        QTransform deviceTr;
-        if (d->itemIsUntransformable()) {
-            deviceTr = deviceTransform(view->viewportTransform());
-        } else {
-            deviceTr = sceneTransform() * view->viewportTransform();
-        }
-
+        QTransform deviceTr = deviceTransform(view->viewportTransform());
         QRect deviceScrollRect = deviceTr.mapRect(scrollRect).toRect();
         QLineF v1 = deviceTr.map(right);
@@ -4171,5 +5525,8 @@
 QPointF QGraphicsItem::mapToParent(const QPointF &point) const
 {
-    return d_ptr->pos + (d_ptr->hasTransform ? transform().map(point) : point);
+    // COMBINE
+    if (!d_ptr->transformData)
+        return point + d_ptr->pos;
+    return d_ptr->transformToParent().map(point);
 }
 
@@ -4191,5 +5548,7 @@
 QPointF QGraphicsItem::mapToScene(const QPointF &point) const
 {
-    return sceneTransform().map(point);
+    if (d_ptr->hasTranslateOnlySceneTransform())
+        return QPointF(point.x() + d_ptr->sceneTransform.dx(), point.y() + d_ptr->sceneTransform.dy());
+    return d_ptr->sceneTransform.map(point);
 }
 
@@ -4236,7 +5595,8 @@
 QPolygonF QGraphicsItem::mapToParent(const QRectF &rect) const
 {
-    QPolygonF p = !d_ptr->hasTransform ? rect : transform().map(rect);
-    p.translate(d_ptr->pos);
-    return p;
+    // COMBINE
+    if (!d_ptr->transformData)
+        return rect.translated(d_ptr->pos);
+    return d_ptr->transformToParent().map(rect);
 }
 
@@ -4257,5 +5617,7 @@
 QPolygonF QGraphicsItem::mapToScene(const QRectF &rect) const
 {
-    return sceneTransform().map(rect);
+    if (d_ptr->hasTranslateOnlySceneTransform())
+        return rect.translated(d_ptr->sceneTransform.dx(), d_ptr->sceneTransform.dy());
+    return d_ptr->sceneTransform.map(rect);
 }
 
@@ -4305,6 +5667,8 @@
 QRectF QGraphicsItem::mapRectToParent(const QRectF &rect) const
 {
-    QRectF r = !d_ptr->hasTransform ? rect : transform().mapRect(rect);
-    return r.translated(d_ptr->pos);
+    // COMBINE
+    if (!d_ptr->transformData)
+        return rect.translated(d_ptr->pos);
+    return d_ptr->transformToParent().mapRect(rect);
 }
 
@@ -4328,5 +5692,7 @@
 QRectF QGraphicsItem::mapRectToScene(const QRectF &rect) const
 {
-    return sceneTransform().mapRect(rect);
+    if (d_ptr->hasTranslateOnlySceneTransform())
+        return rect.translated(d_ptr->sceneTransform.dx(), d_ptr->sceneTransform.dy());
+    return d_ptr->sceneTransform.mapRect(rect);
 }
 
@@ -4377,6 +5743,8 @@
 QRectF QGraphicsItem::mapRectFromParent(const QRectF &rect) const
 {
-    QRectF r = rect.translated(-d_ptr->pos);
-    return d_ptr->hasTransform ? transform().inverted().mapRect(r) : r;
+    // COMBINE
+    if (!d_ptr->transformData)
+        return rect.translated(-d_ptr->pos);
+    return d_ptr->transformToParent().inverted().mapRect(rect);
 }
 
@@ -4400,5 +5768,7 @@
 QRectF QGraphicsItem::mapRectFromScene(const QRectF &rect) const
 {
-    return sceneTransform().inverted().mapRect(rect);
+    if (d_ptr->hasTranslateOnlySceneTransform())
+        return rect.translated(-d_ptr->sceneTransform.dx(), -d_ptr->sceneTransform.dy());
+    return d_ptr->sceneTransform.inverted().mapRect(rect);
 }
 
@@ -4437,7 +5807,8 @@
 QPolygonF QGraphicsItem::mapToParent(const QPolygonF &polygon) const
 {
-    QPolygonF p = !d_ptr->hasTransform ? polygon : transform().map(polygon);
-    p.translate(d_ptr->pos);
-    return p;
+    // COMBINE
+    if (!d_ptr->transformData)
+        return polygon.translated(d_ptr->pos);
+    return d_ptr->transformToParent().map(polygon);
 }
 
@@ -4451,5 +5822,7 @@
 QPolygonF QGraphicsItem::mapToScene(const QPolygonF &polygon) const
 {
-    return sceneTransform().map(polygon);
+    if (d_ptr->hasTranslateOnlySceneTransform())
+        return polygon.translated(d_ptr->sceneTransform.dx(), d_ptr->sceneTransform.dy());
+    return d_ptr->sceneTransform.map(polygon);
 }
 
@@ -4481,8 +5854,8 @@
 QPainterPath QGraphicsItem::mapToParent(const QPainterPath &path) const
 {
-    QTransform x = QTransform::fromTranslate(d_ptr->pos.x(), d_ptr->pos.y());
-    if (d_ptr->hasTransform)
-        x = transform() * x;
-    return x.map(path);
+    // COMBINE
+    if (!d_ptr->transformData)
+        return path.translated(d_ptr->pos);
+    return d_ptr->transformToParent().map(path);
 }
 
@@ -4496,5 +5869,7 @@
 QPainterPath QGraphicsItem::mapToScene(const QPainterPath &path) const
 {
-    return sceneTransform().map(path);
+    if (d_ptr->hasTranslateOnlySceneTransform())
+        return path.translated(d_ptr->sceneTransform.dx(), d_ptr->sceneTransform.dy());
+    return d_ptr->sceneTransform.map(path);
 }
 
@@ -4533,6 +5908,7 @@
 QPointF QGraphicsItem::mapFromParent(const QPointF &point) const
 {
-    if (d_ptr->hasTransform)
-        return transform().inverted().map(point - d_ptr->pos);
+    // COMBINE
+    if (d_ptr->transformData)
+        return d_ptr->transformToParent().inverted().map(point);
     return point - d_ptr->pos;
 }
@@ -4556,5 +5932,7 @@
 QPointF QGraphicsItem::mapFromScene(const QPointF &point) const
 {
-    return sceneTransform().inverted().map(point);
+    if (d_ptr->hasTranslateOnlySceneTransform())
+        return QPointF(point.x() - d_ptr->sceneTransform.dx(), point.y() - d_ptr->sceneTransform.dy());
+    return d_ptr->sceneTransform.inverted().map(point);
 }
 
@@ -4601,6 +5979,8 @@
 QPolygonF QGraphicsItem::mapFromParent(const QRectF &rect) const
 {
-    QRectF r = rect.translated(-d_ptr->pos);
-    return d_ptr->hasTransform ? transform().inverted().map(r) : r;
+    // COMBINE
+    if (!d_ptr->transformData)
+        return rect.translated(-d_ptr->pos);
+    return d_ptr->transformToParent().inverted().map(rect);
 }
 
@@ -4622,5 +6002,7 @@
 QPolygonF QGraphicsItem::mapFromScene(const QRectF &rect) const
 {
-    return sceneTransform().inverted().map(rect);
+    if (d_ptr->hasTranslateOnlySceneTransform())
+        return rect.translated(-d_ptr->sceneTransform.dx(), -d_ptr->sceneTransform.dy());
+    return d_ptr->sceneTransform.inverted().map(rect);
 }
 
@@ -4657,7 +6039,8 @@
 QPolygonF QGraphicsItem::mapFromParent(const QPolygonF &polygon) const
 {
-    QPolygonF p = polygon;
-    p.translate(-d_ptr->pos);
-    return d_ptr->hasTransform ? transform().inverted().map(p) : p;
+    // COMBINE
+    if (!d_ptr->transformData)
+        return polygon.translated(-d_ptr->pos);
+    return d_ptr->transformToParent().inverted().map(polygon);
 }
 
@@ -4671,5 +6054,7 @@
 QPolygonF QGraphicsItem::mapFromScene(const QPolygonF &polygon) const
 {
-    return sceneTransform().inverted().map(polygon);
+    if (d_ptr->hasTranslateOnlySceneTransform())
+        return polygon.translated(-d_ptr->sceneTransform.dx(), -d_ptr->sceneTransform.dy());
+    return d_ptr->sceneTransform.inverted().map(polygon);
 }
 
@@ -4699,7 +6084,8 @@
 QPainterPath QGraphicsItem::mapFromParent(const QPainterPath &path) const
 {
-    if (d_ptr->parent)
-        return d_ptr->parent->itemTransform(this).map(path);
-    return mapFromScene(path);
+    // COMBINE
+    if (!d_ptr->transformData)
+            return path.translated(-d_ptr->pos);
+    return d_ptr->transformToParent().inverted().map(path);
 }
 
@@ -4713,5 +6099,7 @@
 QPainterPath QGraphicsItem::mapFromScene(const QPainterPath &path) const
 {
-    return sceneTransform().inverted().map(path);
+    if (d_ptr->hasTranslateOnlySceneTransform())
+        return path.translated(-d_ptr->sceneTransform.dx(), -d_ptr->sceneTransform.dy());
+    return d_ptr->sceneTransform.inverted().map(path);
 }
 
@@ -4725,4 +6113,6 @@
 {
     if (!child || child == this)
+        return false;
+    if (child->d_ptr->depth() < d_ptr->depth())
         return false;
     const QGraphicsItem *ancestor = child;
@@ -4750,6 +6140,6 @@
     const QGraphicsItem *thisw = this;
     const QGraphicsItem *otherw = other;
-    int thisDepth = d_ptr->depth;
-    int otherDepth = other->d_ptr->depth;
+    int thisDepth = d_ptr->depth();
+    int otherDepth = other->d_ptr->depth();
     while (thisDepth > otherDepth) {
         thisw = thisw->d_ptr->parent;
@@ -5050,4 +6440,17 @@
         inputMethodEvent(static_cast<QInputMethodEvent *>(event));
         break;
+    case QEvent::WindowActivate:
+    case QEvent::WindowDeactivate:
+        // Propagate panel activation.
+        if (d_ptr->scene) {
+            for (int i = 0; i < d_ptr->children.size(); ++i) {
+                QGraphicsItem *child = d_ptr->children.at(i);
+                if (child->isVisible() && !child->isPanel()) {
+                    if (!(child->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorHandlesChildEvents))
+                        d_ptr->scene->sendEvent(child, event);
+                }
+            }
+        }
+        break;
     default:
         return false;
@@ -5189,9 +6592,10 @@
     ensureVisible().
 
-    \sa focusOutEvent(), sceneEvent()
+    \sa focusOutEvent(), sceneEvent(), setFocus()
 */
 void QGraphicsItem::focusInEvent(QFocusEvent *event)
 {
     Q_UNUSED(event);
+    update();
 }
 
@@ -5200,9 +6604,10 @@
     focus out events for this item. The default implementation does nothing.
 
-    \sa focusInEvent(), sceneEvent()
+    \sa focusInEvent(), sceneEvent(), setFocus()
 */
 void QGraphicsItem::focusOutEvent(QFocusEvent *event)
 {
     Q_UNUSED(event);
+    update();
 }
 
@@ -5219,5 +6624,5 @@
 {
     Q_UNUSED(event);
-    d_ptr->updateHelper();
+    update();
 }
 
@@ -5247,5 +6652,5 @@
 {
     Q_UNUSED(event);
-    d_ptr->updateHelper();
+    update();
 }
 
@@ -5337,5 +6742,5 @@
         // Qt::Popup closes when you click outside.
         QGraphicsWidget *w = static_cast<QGraphicsWidget *>(this);
-        if (w->windowFlags() & Qt::Popup) {
+        if ((w->windowFlags() & Qt::Popup) == Qt::Popup) {
             event->accept();
             if (!w->rect().contains(event->pos()))
@@ -5584,5 +6989,5 @@
     property is queried.
 
-    \sa inputMethodEvent()
+    \sa inputMethodEvent(), QInputMethodEvent, QInputContext
 */
 QVariant QGraphicsItem::inputMethodQuery(Qt::InputMethodQuery query) const
@@ -5600,4 +7005,37 @@
 
 /*!
+    Returns the current input method hints of this item.
+
+    Input method hints are only relevant for input items.
+    The hints are used by the input method to indicate how it should operate.
+    For example, if the Qt::ImhNumbersOnly flag is set, the input method may change
+    its visual components to reflect that only numbers can be entered.
+
+    The effect may vary between input method implementations.
+
+    \since 4.6
+
+    \sa setInputMethodHints(), inputMethodQuery(), QInputContext
+*/
+Qt::InputMethodHints QGraphicsItem::inputMethodHints() const
+{
+    Q_D(const QGraphicsItem);
+    return d->imHints;
+}
+
+/*!
+    Sets the current input method hints of this item to \a hints.
+
+    \since 4.6
+
+    \sa inputMethodHints(), inputMethodQuery(), QInputContext
+*/
+void QGraphicsItem::setInputMethodHints(Qt::InputMethodHints hints)
+{
+    Q_D(QGraphicsItem);
+    d->imHints = hints;
+}
+
+/*!
     This virtual function is called by QGraphicsItem to notify custom items
     that some part of the item's state changes. By reimplementing this
@@ -5676,6 +7114,5 @@
     }
     if (d_ptr->scene)
-        d_ptr->scene->d_func()->addToIndex(this);
-    d_ptr->updateHelper();
+        d_ptr->scene->d_func()->index->addItem(this);
 }
 
@@ -5693,7 +7130,6 @@
         return;
     }
-    d_ptr->updateHelper();
     if (d_ptr->scene)
-        d_ptr->scene->d_func()->removeFromIndex(this);
+        d_ptr->scene->d_func()->index->removeItem(this);
 }
 
@@ -5713,17 +7149,44 @@
 void QGraphicsItem::prepareGeometryChange()
 {
+    if (d_ptr->inDestructor)
+        return;
     if (d_ptr->scene) {
-        d_ptr->updateHelper(QRectF(), false, /*maybeDirtyClipPath=*/!d_ptr->inSetPosHelper);
+        d_ptr->scene->d_func()->dirtyGrowingItemsBoundingRect = true;
+        d_ptr->geometryChanged = 1;
+        d_ptr->paintedViewBoundingRectsNeedRepaint = 1;
+        d_ptr->notifyBoundingRectChanged = !d_ptr->inSetPosHelper;
+
         QGraphicsScenePrivate *scenePrivate = d_ptr->scene->d_func();
-        scenePrivate->removeFromIndex(this);
-    }
-
-    if (d_ptr->inSetPosHelper)
-        return;
-
-    if (d_ptr->flags & ItemClipsChildrenToShape)
-        d_ptr->invalidateCachedClipPathRecursively();
-    else
-        d_ptr->invalidateCachedClipPath();
+        scenePrivate->index->prepareBoundingRectChange(this);
+        scenePrivate->markDirty(this, QRectF(), /*invalidateChildren=*/true);
+
+        // For compatibility reasons, we have to update the item's old geometry
+        // if someone is connected to the changed signal or the scene has no views.
+        // Note that this has to be done *after* markDirty to ensure that
+        // _q_processDirtyItems is called before _q_emitUpdated.
+        if (scenePrivate->isSignalConnected(scenePrivate->changedSignalIndex)
+            || scenePrivate->views.isEmpty()) {
+            if (d_ptr->hasTranslateOnlySceneTransform()) {
+                d_ptr->scene->update(boundingRect().translated(d_ptr->sceneTransform.dx(),
+                                                               d_ptr->sceneTransform.dy()));
+            } else {
+                d_ptr->scene->update(d_ptr->sceneTransform.mapRect(boundingRect()));
+            }
+        }
+    }
+
+    QGraphicsItem *parent = this;
+    while ((parent = parent->d_ptr->parent)) {
+        QGraphicsItemPrivate *parentp = parent->d_ptr.data();
+        parentp->dirtyChildrenBoundingRect = 1;
+        // ### Only do this if the parent's effect applies to the entire subtree.
+        parentp->notifyBoundingRectChanged = 1;
+#ifndef QT_NO_GRAPHICSEFFECT
+        if (parentp->scene && parentp->graphicsEffect) {
+            parentp->notifyInvalidated = 1;
+            static_cast<QGraphicsItemEffectSourcePrivate *>(parentp->graphicsEffect->d_func()->source->d_func())->invalidateCache();
+        }
+#endif
+    }
 }
 
@@ -5740,5 +7203,5 @@
 {
     const QRectF murect = painter->transform().mapRect(QRectF(0, 0, 1, 1));
-    if (qFuzzyCompare(qMax(murect.width(), murect.height()) + 1, 1))
+    if (qFuzzyIsNull(qMax(murect.width(), murect.height())))
         return;
 
@@ -5790,9 +7253,267 @@
 
 /*!
+    \class QGraphicsObject
+    \brief The QGraphicsObject class provides a base class for all graphics items that
+    require signals, slots and properties.
+    \since 4.6
+    \ingroup graphicsview-api
+
+    The class extends a QGraphicsItem with QObject's signal/slot and property mechanisms.
+    It maps many of QGraphicsItem's basic setters and getters to properties and adds notification
+    signals for many of them.
+
+    \section1 Parents and Children
+
+    Each graphics object can be constructed with a parent item. This ensures that the
+    item will be destroyed when its parent item is destroyed. Although QGraphicsObject
+    inherits from both QObject and QGraphicsItem, you should use the functions provided
+    by QGraphicsItem, \e not QObject, to manage the relationships between parent and
+    child items.
+
+    The relationships between items can be explored using the parentItem() and childItems()
+    functions. In the hierarchy of items in a scene, the parentObject() and parentWidget()
+    functions are the equivalent of the QWidget::parent() and QWidget::parentWidget()
+    functions for QWidget subclasses.
+
+    \sa QGraphicsWidget
+*/
+
+/*!
+    Constructs a QGraphicsObject with \a parent.
+*/
+QGraphicsObject::QGraphicsObject(QGraphicsItem *parent)
+        : QGraphicsItem(parent)
+{
+    QGraphicsItem::d_ptr->isObject = true;
+}
+
+/*!
+  \internal
+*/
+QGraphicsObject::QGraphicsObject(QGraphicsItemPrivate &dd, QGraphicsItem *parent, QGraphicsScene *scene)
+    : QGraphicsItem(dd, parent, scene)
+{
+    QGraphicsItem::d_ptr->isObject = true;
+}
+
+/*!
+    Subscribes the graphics object to the given \a gesture with specific \a flags.
+
+    \sa ungrabGesture(), QGestureEvent
+*/
+void QGraphicsObject::grabGesture(Qt::GestureType gesture, Qt::GestureFlags flags)
+{
+    QGraphicsItemPrivate * const d = QGraphicsItem::d_func();
+    d->gestureContext.insert(gesture, flags);
+    (void)QGestureManager::instance(); // create a gesture manager
+}
+
+/*!
+    Unsubscribes the graphics object from the given \a gesture.
+
+    \sa grabGesture(), QGestureEvent
+*/
+void QGraphicsObject::ungrabGesture(Qt::GestureType gesture)
+{
+    QGraphicsItemPrivate * const d = QGraphicsItem::d_func();
+    if (d->gestureContext.remove(gesture)) {
+        QGestureManager *manager = QGestureManager::instance();
+        manager->cleanupCachedGestures(this, gesture);
+    }
+}
+
+/*!
+  \property QGraphicsObject::parent
+  \brief the parent of the item
+
+  \note The item's parent is set independently of the parent object returned
+  by QObject::parent().
+
+  \sa QGraphicsItem::setParentItem(), QGraphicsItem::parentObject()
+*/
+
+/*!
+  \property QGraphicsObject::opacity
+  \brief the opacity of the item
+
+  \sa QGraphicsItem::setOpacity(), QGraphicsItem::opacity()
+*/
+
+/*!
+  \fn QGraphicsObject::opacityChanged()
+
+  This signal gets emitted whenever the opacity of the item changes
+
+  \sa QGraphicsItem::opacity()
+*/
+
+/*!
+  \fn QGraphicsObject::parentChanged()
+
+  This signal gets emitted whenever the parent of the item changes
+*/
+
+/*!
+  \property QGraphicsObject::pos
+  \brief the position of the item
+
+  Describes the items position.
+
+  \sa QGraphicsItem::setPos(), QGraphicsItem::pos()
+*/
+
+/*!
+  \property QGraphicsObject::x
+  \brief the x position of the item
+
+  Describes the items x position.
+
+  \sa QGraphicsItem::setX(), setPos(), xChanged()
+*/
+
+/*!
+  \fn QGraphicsObject::xChanged()
+
+  This signal gets emitted whenever the x position of the item changes
+
+  \sa pos()
+*/
+
+/*!
+  \property QGraphicsObject::y
+  \brief the y position of the item
+
+  Describes the items y position.
+
+  \sa QGraphicsItem::setY(), setPos(), yChanged()
+*/
+
+/*!
+  \fn QGraphicsObject::yChanged()
+
+  This signal gets emitted whenever the y position of the item changes.
+
+  \sa pos()
+*/
+
+/*!
+  \property QGraphicsObject::z
+  \brief the z value of the item
+
+  Describes the items z value.
+
+  \sa QGraphicsItem::setZValue(), zValue(), zChanged()
+*/
+
+/*!
+  \fn QGraphicsObject::zChanged()
+
+  This signal gets emitted whenever the z value of the item changes.
+
+  \sa pos()
+*/
+
+/*!
+  \property QGraphicsObject::rotation
+  This property holds the rotation of the item in degrees.
+
+  This specifies how many degrees to rotate the item around its transformOrigin.
+  The default rotation is 0 degrees (i.e. not rotated at all).
+*/
+
+/*!
+  \fn QGraphicsObject::rotationChanged()
+
+  This signal gets emitted whenever the roation of the item changes.
+*/
+
+/*!
+  \property QGraphicsObject::scale
+  This property holds the scale of the item.
+
+  A scale of less than 1 means the item will be displayed smaller than
+  normal, and a scale of greater than 1 means the item will be
+  displayed larger than normal.  A negative scale means the item will
+  be mirrored.
+
+  By default, items are displayed at a scale of 1 (i.e. at their
+  normal size).
+
+  Scaling is from the item's transformOrigin.
+*/
+
+/*!
+  \fn void QGraphicsObject::scaleChanged()
+
+  This signal is emitted when the scale of the item changes.
+*/
+
+
+/*!
+  \property QGraphicsObject::enabled
+  \brief whether the item is enabled or not
+
+  This property is declared in QGraphicsItem.
+
+  By default, this property is true.
+
+  \sa QGraphicsItem::isEnabled(), QGraphicsItem::setEnabled()
+  \sa QGraphicsObject::enabledChanged()
+*/
+
+/*!
+  \fn void QGraphicsObject::enabledChanged()
+
+  This signal gets emitted whenever the item get's enabled or disabled.
+
+  \sa isEnabled()
+*/
+
+/*!
+  \property QGraphicsObject::visible
+  \brief whether the item is visible or not
+
+  This property is declared in QGraphicsItem.
+
+  By default, this property is true.
+
+  \sa QGraphicsItem::isVisible(), QGraphicsItem::setVisible(), visibleChanged()
+*/
+
+/*!
+  \fn QGraphicsObject::visibleChanged()
+
+  This signal gets emitted whenever the visibility of the item changes
+
+  \sa visible
+*/
+
+/*!
+  \fn const QObjectList &QGraphicsObject::children() const
+  \internal
+
+  This function returns the same value as QObject::children(). It's
+  provided to differentiate between the obsolete member
+  QGraphicsItem::children() and QObject::children(). QGraphicsItem now
+  provides childItems() instead.
+*/
+
+/*!
+  \property QGraphicsObject::transformOriginPoint
+  \brief the transformation origin
+
+  This property sets a specific point in the items coordiante system as the
+  origin for scale and rotation.
+
+  \sa scale, rotation, QGraphicsItem::transformOriginPoint()
+*/
+
+
+/*!
     \class QAbstractGraphicsShapeItem
     \brief The QAbstractGraphicsShapeItem class provides a common base for
     all path items.
     \since 4.2
-    \ingroup multimedia
+    \ingroup graphicsview-api
 
     This class does not fully implement an item by itself; in particular, it
@@ -5929,5 +7650,4 @@
     can add to a QGraphicsScene.
     \since 4.2
-    \ingroup multimedia
     \ingroup graphicsview-api
 
@@ -6132,5 +7852,4 @@
     can add to a QGraphicsScene.
     \since 4.2
-    \ingroup multimedia
     \ingroup graphicsview-api
 
@@ -6377,5 +8096,4 @@
     can add to a QGraphicsScene.
     \since 4.2
-    \ingroup multimedia
     \ingroup graphicsview-api
 
@@ -6694,5 +8412,4 @@
     can add to a QGraphicsScene.
     \since 4.2
-    \ingroup multimedia
     \ingroup graphicsview-api
 
@@ -6928,5 +8645,4 @@
     QGraphicsScene.
     \since 4.2
-    \ingroup multimedia
     \ingroup graphicsview-api
 
@@ -7190,5 +8906,4 @@
     a QGraphicsScene.
     \since 4.2
-    \ingroup multimedia
     \ingroup graphicsview-api
 
@@ -7379,5 +9094,4 @@
     Q_D(QGraphicsPixmapItem);
     if (mode != d->transformationMode) {
-        d_ptr->updateHelper();
         d->transformationMode = mode;
         update();
@@ -7427,8 +9141,12 @@
 {
     Q_D(const QGraphicsPixmapItem);
-    qreal pw = 1.0;
     if (d->pixmap.isNull())
         return QRectF();
-    return QRectF(d->offset, d->pixmap.size()).adjusted(-pw/2, -pw/2, pw/2, pw/2);
+    if (d->flags & ItemIsSelectable) {
+        qreal pw = 1.0;
+        return QRectF(d->offset, d->pixmap.size()).adjusted(-pw/2, -pw/2, pw/2, pw/2);
+    } else {
+        return QRectF(d->offset, d->pixmap.size());
+    }
 }
 
@@ -7467,7 +9185,5 @@
                            (d->transformationMode == Qt::SmoothTransformation));
 
-    QRectF exposed = option->exposedRect.adjusted(-1, -1, 1, 1);
-    exposed &= QRectF(d->offset.x(), d->offset.y(), d->pixmap.width(), d->pixmap.height());
-    painter->drawPixmap(exposed, d->pixmap, exposed.translated(-d->offset));
+    painter->drawPixmap(d->offset, d->pixmap);
 
     if (option->state & QStyle::State_Selected)
@@ -7557,5 +9273,4 @@
     a QGraphicsScene to display formatted text.
     \since 4.2
-    \ingroup multimedia
     \ingroup graphicsview-api
 
@@ -7592,5 +9307,5 @@
 public:
     QGraphicsTextItemPrivate()
-        : control(0), pageNumber(0), useDefaultImpl(false), tabChangesFocus(false)
+        : control(0), pageNumber(0), useDefaultImpl(false), tabChangesFocus(false), clickCausedFocus(0)
     { }
 
@@ -7613,6 +9328,9 @@
     bool tabChangesFocus;
 
+    uint clickCausedFocus : 1;
+
     QGraphicsTextItem *qq;
 };
+
 
 /*!
@@ -7628,5 +9346,5 @@
 #endif
     )
-    : QGraphicsItem(parent, scene), dd(new QGraphicsTextItemPrivate)
+    : QGraphicsObject(*new QGraphicsItemPrivate, parent, scene), dd(new QGraphicsTextItemPrivate)
 {
     dd->qq = this;
@@ -7635,4 +9353,5 @@
     setAcceptDrops(true);
     setAcceptHoverEvents(true);
+    setFlags(ItemUsesExtendedStyleOption);
 }
 
@@ -7649,9 +9368,10 @@
 #endif
     )
-    : QGraphicsItem(parent, scene), dd(new QGraphicsTextItemPrivate)
+    : QGraphicsObject(*new QGraphicsItemPrivate, parent, scene), dd(new QGraphicsTextItemPrivate)
 {
     dd->qq = this;
     setAcceptDrops(true);
     setAcceptHoverEvents(true);
+    setFlag(ItemUsesExtendedStyleOption);
 }
 
@@ -7743,6 +9463,9 @@
     QTextControl *c = dd->textControl();
     QPalette pal = c->palette();
+    QColor old = pal.color(QPalette::Text);
     pal.setColor(QPalette::Text, col);
     c->setPalette(pal);
+    if (old != col)
+        update();
 }
 
@@ -7915,5 +9638,42 @@
         }
     }
-    return QGraphicsItem::sceneEvent(event);
+    bool result = QGraphicsItem::sceneEvent(event);
+
+    // Ensure input context is updated.
+    switch (event->type()) {
+    case QEvent::ContextMenu:
+    case QEvent::FocusIn:
+    case QEvent::FocusOut:
+    case QEvent::GraphicsSceneDragEnter:
+    case QEvent::GraphicsSceneDragLeave:
+    case QEvent::GraphicsSceneDragMove:
+    case QEvent::GraphicsSceneDrop:
+    case QEvent::GraphicsSceneHoverEnter:
+    case QEvent::GraphicsSceneHoverLeave:
+    case QEvent::GraphicsSceneHoverMove:
+    case QEvent::GraphicsSceneMouseDoubleClick:
+    case QEvent::GraphicsSceneMousePress:
+    case QEvent::GraphicsSceneMouseMove:
+    case QEvent::GraphicsSceneMouseRelease:
+    case QEvent::KeyPress:
+    case QEvent::KeyRelease:
+        // Reset the focus widget's input context, regardless
+        // of how this item gained or lost focus.
+        if (QWidget *fw = qApp->focusWidget()) {
+#ifndef QT_NO_IM
+            if (QInputContext *qic = fw->inputContext()) {
+                if (event->type() == QEvent::FocusIn || event->type() == QEvent::FocusOut)
+                    qic->reset();
+                else
+                    qic->update();
+            }
+#endif //QT_NO_IM
+        }
+        break;
+    default:
+        break;
+    }
+
+    return result;
 }
 
@@ -7924,19 +9684,20 @@
 {
     if ((QGraphicsItem::d_ptr->flags & (ItemIsSelectable | ItemIsMovable))
-	&& (event->buttons() & Qt::LeftButton) && dd->_q_mouseOnEdge(event)) {
-	// User left-pressed on edge of selectable/movable item, use
-	// base impl.
-	dd->useDefaultImpl = true;
+        && (event->buttons() & Qt::LeftButton) && dd->_q_mouseOnEdge(event)) {
+        // User left-pressed on edge of selectable/movable item, use
+        // base impl.
+        dd->useDefaultImpl = true;
     } else if (event->buttons() == event->button()
-	       && dd->control->textInteractionFlags() == Qt::NoTextInteraction) {
-	// User pressed first button on non-interactive item.
-	dd->useDefaultImpl = true;
+               && dd->control->textInteractionFlags() == Qt::NoTextInteraction) {
+        // User pressed first button on non-interactive item.
+        dd->useDefaultImpl = true;
     }
     if (dd->useDefaultImpl) {
         QGraphicsItem::mousePressEvent(event);
-	if (!event->isAccepted())
-	    dd->useDefaultImpl = false;
+        if (!event->isAccepted())
+            dd->useDefaultImpl = false;
         return;
     }
+
     dd->sendControlEvent(event);
 }
@@ -7951,4 +9712,5 @@
         return;
     }
+
     dd->sendControlEvent(event);
 }
@@ -7961,14 +9723,20 @@
     if (dd->useDefaultImpl) {
         QGraphicsItem::mouseReleaseEvent(event);
-	if (dd->control->textInteractionFlags() == Qt::NoTextInteraction
-	    && !event->buttons()) {
-	    // User released last button on non-interactive item.
+        if (dd->control->textInteractionFlags() == Qt::NoTextInteraction
+            && !event->buttons()) {
+            // User released last button on non-interactive item.
             dd->useDefaultImpl = false;
-	} else  if ((event->buttons() & Qt::LeftButton) == 0) {
-	    // User released the left button on an interactive item.
+        } else  if ((event->buttons() & Qt::LeftButton) == 0) {
+            // User released the left button on an interactive item.
             dd->useDefaultImpl = false;
-	}
+        }
         return;
     }
+
+    QWidget *widget = event->widget();
+    if (widget && (dd->control->textInteractionFlags() & Qt::TextEditable) && boundingRect().contains(event->pos())) {
+        qt_widget_private(widget)->handleSoftwareInputPanel(event->button(), dd->clickCausedFocus);
+    }
+    dd->clickCausedFocus = 0;
     dd->sendControlEvent(event);
 }
@@ -8022,4 +9790,7 @@
 {
     dd->sendControlEvent(event);
+    if (event->reason() == Qt::MouseFocusReason) {
+        dd->clickCausedFocus = 1;
+    }
     update();
 }
@@ -8258,7 +10029,7 @@
     input.
 
-    The default for a QGraphicsTextItem is Qt::NoTextInteraction. Setting a
-    value different to Qt::NoTextInteraction will also set the ItemIsFocusable
-    QGraphicsItem flag.
+    The default for a QGraphicsTextItem is Qt::NoTextInteraction. This function
+    also affects the ItemIsFocusable QGraphicsItem flag by setting it if \a flags
+    is different from Qt::NoTextInteraction and clearing it otherwise.
 
     By default, the text is read-only. To transform the item into an editor,
@@ -8268,7 +10039,8 @@
 {
     if (flags == Qt::NoTextInteraction)
-        setFlags(this->flags() & ~QGraphicsItem::ItemIsFocusable);
+        setFlags(this->flags() & ~(QGraphicsItem::ItemIsFocusable | QGraphicsItem::ItemAcceptsInputMethod));
     else
-        setFlags(this->flags() | QGraphicsItem::ItemIsFocusable);
+        setFlags(this->flags() | QGraphicsItem::ItemIsFocusable | QGraphicsItem::ItemAcceptsInputMethod);
+
     dd->textControl()->setTextInteractionFlags(flags);
 }
@@ -8419,5 +10191,4 @@
     that you can add to a QGraphicsScene.
     \since 4.2
-    \ingroup multimedia
     \ingroup graphicsview-api
 
@@ -8655,5 +10426,4 @@
     one.
     \since 4.2
-    \ingroup multimedia
     \ingroup graphicsview-api
 
@@ -8670,11 +10440,8 @@
 
     The boundingRect() function of QGraphicsItemGroup returns the
-    bounding rectangle of all items in the item group. In addition,
-    item groups have handlesChildEvents() enabled by default, so all
-    events sent to a member of the group go to the item group (i.e.,
-    selecting one item in a group will select them all).
-    QGraphicsItemGroup ignores the ItemIgnoresTransformations flag on its
-    children (i.e., with respect to the geometry of the group item, the
-    children are treated as if they were transformable).
+    bounding rectangle of all items in the item group.
+    QGraphicsItemGroup ignores the ItemIgnoresTransformations flag on
+    its children (i.e., with respect to the geometry of the group
+    item, the children are treated as if they were transformable).
 
     There are two ways to construct an item group. The easiest and
@@ -8761,17 +10528,38 @@
     }
 
-    QTransform oldSceneMatrix = item->sceneTransform();
+    // COMBINE
+    bool ok;
+    QTransform itemTransform = item->itemTransform(this, &ok);
+
+    if (!ok) {
+        qWarning("QGraphicsItemGroup::addToGroup: could not find a valid transformation from item to group coordinates");
+        return;
+    }
+
+    QTransform newItemTransform(itemTransform);
     item->setPos(mapFromItem(item, 0, 0));
     item->setParentItem(this);
-    QTransform newItemTransform(oldSceneMatrix);
-    newItemTransform *= sceneTransform().inverted();
+
+    // removing position from translation component of the new transform
     if (!item->pos().isNull())
         newItemTransform *= QTransform::fromTranslate(-item->x(), -item->y());
+
+    // removing additional transformations properties applied with itemTransform()
+    QPointF origin = item->transformOriginPoint();
+    QMatrix4x4 m;
+    QList<QGraphicsTransform*> transformList = item->transformations();
+    for (int i = 0; i < transformList.size(); ++i)
+        transformList.at(i)->applyTo(&m);
+    newItemTransform *= m.toTransform().inverted();
+    newItemTransform.translate(origin.x(), origin.y());
+    newItemTransform.rotate(-item->rotation());
+    newItemTransform.scale(1/item->scale(), 1/item->scale());
+    newItemTransform.translate(-origin.x(), -origin.y());
+
+    // ### Expensive, we could maybe use dirtySceneTransform bit for optimization
+
     item->setTransform(newItemTransform);
     item->d_func()->setIsMemberOfGroup(true);
     prepareGeometryChange();
-    QTransform itemTransform(item->transform());
-    if (!item->pos().isNull())
-        itemTransform *= QTransform::fromTranslate(item->x(), item->y());
     d->itemsBoundingRect |= itemTransform.mapRect(item->boundingRect() | item->childrenBoundingRect());
     update();
@@ -8795,9 +10583,37 @@
 
     QGraphicsItem *newParent = d_ptr->parent;
+
+    // COMBINE
+    bool ok;
+    QTransform itemTransform;
+    if (newParent)
+        itemTransform = item->itemTransform(newParent, &ok);
+    else
+        itemTransform = item->sceneTransform();
+
     QPointF oldPos = item->mapToItem(newParent, 0, 0);
     item->setParentItem(newParent);
-    // ### This function should remap the item's matrix to keep the item's
-    // transformation unchanged relative to the scene.
     item->setPos(oldPos);
+
+    // removing position from translation component of the new transform
+    if (!item->pos().isNull())
+        itemTransform *= QTransform::fromTranslate(-item->x(), -item->y());
+
+    // removing additional transformations properties applied
+    // with itemTransform() or sceneTransform()
+    QPointF origin = item->transformOriginPoint();
+    QMatrix4x4 m;
+    QList<QGraphicsTransform*> transformList = item->transformations();
+    for (int i = 0; i < transformList.size(); ++i)
+        transformList.at(i)->applyTo(&m);
+    itemTransform *= m.toTransform().inverted();
+    itemTransform.translate(origin.x(), origin.y());
+    itemTransform.rotate(-item->rotation());
+    itemTransform.scale(1 / item->scale(), 1 / item->scale());
+    itemTransform.translate(-origin.x(), -origin.y());
+
+    // ### Expensive, we could maybe use dirtySceneTransform bit for optimization
+
+    item->setTransform(itemTransform);
     item->d_func()->setIsMemberOfGroup(item->group() != 0);
 
@@ -8856,4 +10672,159 @@
 }
 
+#ifndef QT_NO_GRAPHICSEFFECT
+QRectF QGraphicsItemEffectSourcePrivate::boundingRect(Qt::CoordinateSystem system) const
+{
+    const bool deviceCoordinates = (system == Qt::DeviceCoordinates);
+    if (!info && deviceCoordinates) {
+        // Device coordinates without info not yet supported.
+        qWarning("QGraphicsEffectSource::boundingRect: Not yet implemented, lacking device context");
+        return QRectF();
+    }
+
+    QRectF rect = item->boundingRect();
+    if (!item->d_ptr->children.isEmpty())
+        rect |= item->childrenBoundingRect();
+
+    if (deviceCoordinates) {
+        Q_ASSERT(info->painter);
+        rect = info->painter->worldTransform().mapRect(rect);
+    }
+
+    return rect;
+}
+
+void QGraphicsItemEffectSourcePrivate::draw(QPainter *painter)
+{
+    if (!info) {
+        qWarning("QGraphicsEffectSource::draw: Can only begin as a result of QGraphicsEffect::draw");
+        return;
+    }
+
+    Q_ASSERT(item->d_ptr->scene);
+    QGraphicsScenePrivate *scened = item->d_ptr->scene->d_func();
+    if (painter == info->painter) {
+        scened->draw(item, painter, info->viewTransform, info->transformPtr, info->exposedRegion,
+                     info->widget, info->opacity, info->effectTransform, info->wasDirtySceneTransform,
+                     info->drawItem);
+    } else {
+        QTransform effectTransform = info->painter->worldTransform().inverted();
+        effectTransform *= painter->worldTransform();
+        scened->draw(item, painter, info->viewTransform, info->transformPtr, info->exposedRegion,
+                     info->widget, info->opacity, &effectTransform, info->wasDirtySceneTransform,
+                     info->drawItem);
+    }
+}
+
+QPixmap QGraphicsItemEffectSourcePrivate::pixmap(Qt::CoordinateSystem system, QPoint *offset,
+                                                 QGraphicsEffect::PixmapPadMode mode) const
+{
+    const bool deviceCoordinates = (system == Qt::DeviceCoordinates);
+    if (!info && deviceCoordinates) {
+        // Device coordinates without info not yet supported.
+        qWarning("QGraphicsEffectSource::pixmap: Not yet implemented, lacking device context");
+        return QPixmap();
+    }
+    if (!item->d_ptr->scene)
+        return QPixmap();
+    QGraphicsScenePrivate *scened = item->d_ptr->scene->d_func();
+
+    const QRectF sourceRect = boundingRect(system);
+    QRectF effectRectF;
+
+    bool unpadded = false;
+    if (mode == QGraphicsEffect::PadToEffectiveBoundingRect) {
+        if (info) {
+            effectRectF = item->graphicsEffect()->boundingRectFor(boundingRect(Qt::DeviceCoordinates));
+            unpadded = (effectRectF.size() == sourceRect.size());
+            if (info && system == Qt::LogicalCoordinates)
+                effectRectF = info->painter->worldTransform().inverted().mapRect(effectRectF);
+        } else {
+            // no choice but to send a logical coordinate bounding rect to boundingRectFor
+            effectRectF = item->graphicsEffect()->boundingRectFor(sourceRect);
+        }
+    } else if (mode == QGraphicsEffect::PadToTransparentBorder) {
+        // adjust by 1.5 to account for cosmetic pens
+        effectRectF = sourceRect.adjusted(-1.5, -1.5, 1.5, 1.5);
+    } else {
+        effectRectF = sourceRect;
+        unpadded = true;
+    }
+
+    QRect effectRect = effectRectF.toAlignedRect();
+
+    if (offset)
+        *offset = effectRect.topLeft();
+
+    bool untransformed = !deviceCoordinates
+            || info->painter->worldTransform().type() <= QTransform::TxTranslate;
+    if (untransformed && unpadded && isPixmap()) {
+        if (offset)
+            *offset = boundingRect(system).topLeft().toPoint();
+        return static_cast<QGraphicsPixmapItem *>(item)->pixmap();
+    }
+
+    if (deviceCoordinates) {
+        // Clip to viewport rect.
+        int left, top, right, bottom;
+        effectRect.getCoords(&left, &top, &right, &bottom);
+        if (left < 0) {
+            if (offset)
+                offset->rx() += -left;
+            effectRect.setX(0);
+        }
+        if (top < 0) {
+            if (offset)
+                offset->ry() += -top;
+            effectRect.setY(0);
+        }
+        // NB! We use +-1 for historical reasons (see QRect documentation).
+        QPaintDevice *device = info->painter->device();
+        const int deviceWidth = device->width();
+        const int deviceHeight = device->height();
+        if (right + 1 > deviceWidth)
+            effectRect.setRight(deviceWidth - 1);
+        if (bottom + 1 > deviceHeight)
+            effectRect.setBottom(deviceHeight -1);
+
+    }
+    if (effectRect.isEmpty())
+        return QPixmap();
+
+    QPixmap pixmap(effectRect.size());
+    pixmap.fill(Qt::transparent);
+    QPainter pixmapPainter(&pixmap);
+    pixmapPainter.setRenderHints(info ? info->painter->renderHints() : QPainter::TextAntialiasing);
+
+    QTransform effectTransform = QTransform::fromTranslate(-effectRect.x(), -effectRect.y());
+    if (deviceCoordinates && info->effectTransform)
+        effectTransform *= *info->effectTransform;
+
+    if (!info) {
+        // Logical coordinates without info.
+        QTransform sceneTransform = item->sceneTransform();
+        QTransform newEffectTransform = sceneTransform.inverted();
+        newEffectTransform *= effectTransform;
+        scened->draw(item, &pixmapPainter, 0, &sceneTransform, 0, 0, qreal(1.0),
+                     &newEffectTransform, false, true);
+    } else if (deviceCoordinates) {
+        // Device coordinates with info.
+        scened->draw(item, &pixmapPainter, info->viewTransform, info->transformPtr, info->exposedRegion,
+                     info->widget, info->opacity, &effectTransform, info->wasDirtySceneTransform,
+                     info->drawItem);
+    } else {
+        // Item coordinates with info.
+        QTransform newEffectTransform = info->transformPtr->inverted();
+        newEffectTransform *= effectTransform;
+        scened->draw(item, &pixmapPainter, info->viewTransform, info->transformPtr, info->exposedRegion,
+                     info->widget, info->opacity, &newEffectTransform, info->wasDirtySceneTransform,
+                     info->drawItem);
+    }
+
+    pixmapPainter.end();
+
+    return pixmap;
+}
+#endif //QT_NO_GRAPHICSEFFECT
+
 #ifndef QT_NO_DEBUG_STREAM
 QDebug operator<<(QDebug debug, QGraphicsItem *item)
@@ -8864,16 +10835,31 @@
     }
 
-    QStringList flags;
-    if (item->isVisible()) flags << QLatin1String("isVisible");
-    if (item->isEnabled()) flags << QLatin1String("isEnabled");
-    if (item->isSelected()) flags << QLatin1String("isSelected");
-    if (item->hasFocus()) flags << QLatin1String("HasFocus");
-
-    debug << "QGraphicsItem(this =" << ((void*)item)
-          << ", parent =" << ((void*)item->parentItem())
+    if (QGraphicsObject *o = item->toGraphicsObject())
+        debug << o->metaObject()->className();
+    else
+        debug << "QGraphicsItem";
+    debug << "(this =" << (void*)item
+          << ", parent =" << (void*)item->parentItem()
           << ", pos =" << item->pos()
-          << ", z =" << item->zValue() << ", flags = {"
-          << flags.join(QLatin1String("|")) << " })";
+          << ", z =" << item->zValue() << ", flags = "
+          << item->flags() << ")";
     return debug;
+}
+
+QDebug operator<<(QDebug debug, QGraphicsObject *item)
+{
+    if (!item) {
+        debug << "QGraphicsObject(0)";
+        return debug;
+    }
+
+    debug.nospace() << item->metaObject()->className() << '(' << (void*)item;
+    if (!item->objectName().isEmpty())
+        debug << ", name = " << item->objectName();
+    debug.nospace() << ", parent = " << ((void*)item->parentItem())
+          << ", pos = " << item->pos()
+          << ", z = " << item->zValue() << ", flags = "
+          << item->flags() << ')';
+    return debug.space();
 }
 
@@ -8963,4 +10949,7 @@
         str = "ItemOpacityHasChanged";
         break;
+    case QGraphicsItem::ItemScenePositionHasChanged:
+        str = "ItemScenePositionHasChanged";
+        break;
     }
     debug << str;
@@ -8999,4 +10988,28 @@
         str = "ItemStacksBehindParent";
         break;
+    case QGraphicsItem::ItemUsesExtendedStyleOption:
+        str = "ItemUsesExtendedStyleOption";
+        break;
+    case QGraphicsItem::ItemHasNoContents:
+        str = "ItemHasNoContents";
+        break;
+    case QGraphicsItem::ItemSendsGeometryChanges:
+        str = "ItemSendsGeometryChanges";
+        break;
+    case QGraphicsItem::ItemAcceptsInputMethod:
+        str = "ItemAcceptsInputMethod";
+        break;
+    case QGraphicsItem::ItemNegativeZStacksBehindParent:
+        str = "ItemNegativeZStacksBehindParent";
+        break;
+    case QGraphicsItem::ItemIsPanel:
+        str = "ItemIsPanel";
+        break;
+    case QGraphicsItem::ItemIsFocusScope:
+        str = "ItemIsFocusScope";
+        break;
+    case QGraphicsItem::ItemSendsScenePositionChanges:
+        str = "ItemSendsScenePositionChanges";
+        break;
     }
     debug << str;
@@ -9006,15 +11019,15 @@
 QDebug operator<<(QDebug debug, QGraphicsItem::GraphicsItemFlags flags)
 {
-    debug << "(";
+    debug << '(';
     bool f = false;
-    for (int i = 0; i < 9; ++i) {
+    for (int i = 0; i < 16; ++i) {
         if (flags & (1 << i)) {
             if (f)
-                debug << "|";
+                debug << '|';
             f = true;
             debug << QGraphicsItem::GraphicsItemFlag(int(flags & (1 << i)));
         }
     }
-    debug << ")";
+    debug << ')';
     return debug;
 }
