Ignore:
Timestamp:
May 5, 2011, 5:36:53 AM (14 years ago)
Author:
Dmitry A. Kuminov
Message:

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

Location:
trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk

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

    r769 r846  
    11/****************************************************************************
    22**
    3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
     3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
    44** All rights reserved.
    55** Contact: Nokia Corporation (qt-info@nokia.com)
     
    5151    with QGraphicsView for visualizing graphical items, such as lines,
    5252    rectangles, text, or even custom items, on a 2D surface. QGraphicsScene is
    53     part of \l{The Graphics View Framework}.
     53    part of the \l{Graphics View Framework}.
    5454
    5555    QGraphicsScene also provides functionality that lets you efficiently
     
    229229#include <QtCore/qtimer.h>
    230230#include <QtCore/qvarlengtharray.h>
     231#include <QtCore/QMetaMethod>
    231232#include <QtGui/qapplication.h>
    232233#include <QtGui/qdesktopwidget.h>
     
    278279}
    279280
    280 int QGraphicsScenePrivate::changedSignalIndex;
    281 
    282281/*!
    283282    \internal
     
    292291      calledEmitUpdated(false),
    293292      processDirtyItemsEmitted(false),
    294       selectionChanging(0),
    295293      needSortTopLevelItems(true),
    296294      holesInTopLevelSiblingIndex(false),
     
    299297      stickyFocus(false),
    300298      hasFocus(false),
     299      lastMouseGrabberItemHasImplicitMouseGrab(false),
     300      allItemsIgnoreHoverEvents(true),
     301      allItemsUseDefaultCursor(true),
     302      painterStateProtection(true),
     303      sortCacheEnabled(false),
     304      allItemsIgnoreTouchEvents(true),
     305      selectionChanging(0),
     306      rectAdjust(2),
    301307      focusItem(0),
    302308      lastFocusItem(0),
     
    307313      childExplicitActivation(0),
    308314      lastMouseGrabberItem(0),
    309       lastMouseGrabberItemHasImplicitMouseGrab(false),
    310315      dragDropItem(0),
    311316      enterWidget(0),
    312317      lastDropAction(Qt::IgnoreAction),
    313       allItemsIgnoreHoverEvents(true),
    314       allItemsUseDefaultCursor(true),
    315       painterStateProtection(true),
    316       sortCacheEnabled(false),
    317       style(0),
    318       allItemsIgnoreTouchEvents(true)
     318      style(0)
    319319{
    320320}
     
    330330
    331331    // Keep this index so we can check for connected slots later on.
    332     if (!changedSignalIndex) {
    333         changedSignalIndex = signalIndex("changed(QList<QRectF>)");
    334     }
     332    changedSignalIndex = signalIndex("changed(QList<QRectF>)");
     333    processDirtyItemsIndex = q->metaObject()->indexOfSlot("_q_processDirtyItems()");
     334    polishItemsIndex = q->metaObject()->indexOfSlot("_q_polishItems()");
     335
    335336    qApp->d_func()->scene_list.append(q);
    336337    q->update();
     
    690691        lastMouseGrabberItem = 0;
    691692
     693    // Reset the current drop item
     694    if (item == dragDropItem)
     695        dragDropItem = 0;
     696
    692697    // Reenable selectionChanged() for individual items
    693698    --selectionChanging;
     
    695700        emit q->selectionChanged();
    696701
     702#ifndef QT_NO_GESTURES
    697703    QHash<QGesture *, QGraphicsObject *>::iterator it;
    698704    for (it = gestureTargets.begin(); it != gestureTargets.end();) {
     
    702708            ++it;
    703709    }
     710
     711    QGraphicsObject *dummy = static_cast<QGraphicsObject *>(item);
     712    cachedTargetItems.removeOne(dummy);
     713    cachedItemGestures.remove(dummy);
     714    cachedAlreadyDeliveredGestures.remove(dummy);
     715
     716    foreach (Qt::GestureType gesture, item->d_ptr->gestureContext.keys())
     717        ungrabGesture(item, gesture);
     718#endif // QT_NO_GESTURES
    704719}
    705720
     
    816831#endif //QT_NO_IM
    817832    }
     833
     834    // This handles the case that the item has been removed from the
     835    // scene in response to the FocusOut event.
     836    if (item && item->scene() != q)
     837        item = 0;
    818838
    819839    if (item)
     
    871891        }
    872892        if (!itemIsDying && widget->isVisible()) {
    873             widget->hide();
    874             widget->QGraphicsItem::d_ptr->explicitlyHidden = 0;
     893            widget->QGraphicsItem::d_ptr->setVisibleHelper(false, /* explicit = */ false);
    875894        }
    876895    }
     
    10561075    Returns all items for the screen position in \a event.
    10571076*/
    1058 QList<QGraphicsItem *> QGraphicsScenePrivate::itemsAtPosition(const QPoint &screenPos,
     1077QList<QGraphicsItem *> QGraphicsScenePrivate::itemsAtPosition(const QPoint &/*screenPos*/,
    10591078                                                              const QPointF &scenePos,
    10601079                                                              QWidget *widget) const
     
    10651084        return q->items(scenePos, Qt::IntersectsItemShape, Qt::DescendingOrder, QTransform());
    10661085
    1067     const QRectF pointRect(QPointF(widget->mapFromGlobal(screenPos)), QSizeF(1, 1));
     1086    const QRectF pointRect(scenePos, QSizeF(1, 1));
    10681087    if (!view->isTransformed())
    10691088        return q->items(pointRect, Qt::IntersectsItemShape, Qt::DescendingOrder);
    10701089
    10711090    const QTransform viewTransform = view->viewportTransform();
    1072     if (viewTransform.type() <= QTransform::TxScale) {
    1073         return q->items(viewTransform.inverted().mapRect(pointRect), Qt::IntersectsItemShape,
    1074                         Qt::DescendingOrder, viewTransform);
    1075     }
    1076     return q->items(viewTransform.inverted().map(pointRect), Qt::IntersectsItemShape,
     1091    return q->items(pointRect, Qt::IntersectsItemShape,
    10771092                    Qt::DescendingOrder, viewTransform);
    10781093}
     
    11691184{
    11701185    if (QGraphicsObject *object = item->toGraphicsObject()) {
     1186#ifndef QT_NO_GESTURES
    11711187        QGestureManager *gestureManager = QApplicationPrivate::instance()->gestureManager;
    11721188        if (gestureManager) {
     
    11741190                return true;
    11751191        }
     1192#endif // QT_NO_GESTURES
    11761193    }
    11771194
     
    13121329            break;
    13131330        }
    1314         if (item->isEnabled() && ((item->flags() & QGraphicsItem::ItemIsFocusable) && item->d_ptr->mouseSetsFocus)) {
     1331        if (item->isEnabled() && ((item->flags() & QGraphicsItem::ItemIsFocusable))) {
    13151332            if (!item->isWidget() || ((QGraphicsWidget *)item)->focusPolicy() & Qt::ClickFocus) {
    13161333                setFocus = true;
    1317                 if (item != q->focusItem())
     1334                if (item != q->focusItem() && item->d_ptr->mouseSetsFocus)
    13181335                    q->setFocusItem(item, Qt::MouseFocusReason);
    13191336                break;
    13201337            }
    13211338        }
     1339        if (item->d_ptr->flags & QGraphicsItem::ItemStopsClickFocusPropagation)
     1340            break;
    13221341        if (item->isPanel())
    13231342            break;
     
    17411760
    17421761    // Transform the painter.
    1743     painter->setClipRect(targetRect);
     1762    painter->setClipRect(targetRect, Qt::IntersectClip);
    17441763    QTransform painterTransform;
    17451764    painterTransform *= QTransform()
     
    25342553    }
    25352554
    2536     if (d->unpolishedItems.isEmpty())
    2537         QMetaObject::invokeMethod(this, "_q_polishItems", Qt::QueuedConnection);
    2538     d->unpolishedItems.append(item);
    2539     item->d_ptr->pendingPolish = true;
     2555    // QDeclarativeItems do not rely on initial itemChanged message, as the componentComplete
     2556    // function allows far more opportunity for delayed-construction optimization.
     2557    if (!item->d_ptr->isDeclarativeItem) {
     2558        if (d->unpolishedItems.isEmpty()) {
     2559            QMetaMethod method = metaObject()->method(d->polishItemsIndex);
     2560            method.invoke(this, Qt::QueuedConnection);
     2561        }
     2562        d->unpolishedItems.append(item);
     2563        item->d_ptr->pendingPolish = true;
     2564    }
    25402565
    25412566    // Detach this item from its parent if the parent's scene is different
     
    25842609        d->enableTouchEventsOnViews();
    25852610    }
     2611
     2612#ifndef QT_NO_GESTURES
     2613    foreach (Qt::GestureType gesture, item->d_ptr->gestureContext.keys())
     2614        d->grabGesture(item, gesture);
     2615#endif
    25862616
    25872617    // Update selection lists
     
    32123242            for (int i = 0; i < d->views.size(); ++i) {
    32133243                QGraphicsView *view = d->views.at(i);
    3214                 view->d_func()->updateRegion(QRegion(view->mapFromScene(rect).boundingRect()));
     3244                if (view->isTransformed())
     3245                    view->d_func()->updateRectF(view->viewportTransform().mapRect(rect));
     3246                else
     3247                    view->d_func()->updateRectF(rect);
    32153248            }
    32163249        } else {
     
    35023535        d->touchEventHandler(static_cast<QTouchEvent *>(event));
    35033536        break;
     3537#ifndef QT_NO_GESTURES
    35043538    case QEvent::Gesture:
    35053539    case QEvent::GestureOverride:
    35063540        d->gestureEventHandler(static_cast<QGestureEvent *>(event));
    35073541        break;
     3542#endif // QT_NO_GESTURES
    35083543    default:
    35093544        return QObject::event(event);
     
    41314166                                                                wheelEvent->widget());
    41324167
     4168#ifdef Q_WS_MAC
     4169    // On Mac, ignore the event if the first item under the mouse is not the last opened
     4170    // popup (or one of its descendant)
     4171    if (!d->popupWidgets.isEmpty() && !wheelCandidates.isEmpty() && wheelCandidates.first() != d->popupWidgets.back() && !d->popupWidgets.back()->isAncestorOf(wheelCandidates.first())) {
     4172        wheelEvent->accept();
     4173        return;
     4174    }
     4175#else
     4176    // Find the first popup under the mouse (including the popup's descendants) starting from the last.
     4177    // Remove all popups after the one found, or all or them if no popup is under the mouse.
     4178    // Then continue with the event.
     4179    QList<QGraphicsWidget *>::const_iterator iter = d->popupWidgets.end();
     4180    while (--iter >= d->popupWidgets.begin() && !wheelCandidates.isEmpty()) {
     4181        if (wheelCandidates.first() == *iter || (*iter)->isAncestorOf(wheelCandidates.first()))
     4182            break;
     4183        d->removePopup(*iter);
     4184    }
     4185#endif
     4186
    41334187    bool hasSetFocus = false;
    41344188    foreach (QGraphicsItem *item, wheelCandidates) {
     
    42544308        if (painterStateProtection)
    42554309            painter->restore();
     4310    } else if (widgetItem->autoFillBackground()) {
     4311        painter->fillRect(option->exposedRect, widgetItem->palette().window());
    42564312    }
    42574313
     
    43074363}
    43084364
     4365// Copied from qpaintengine_vg.cpp
     4366// Returns true for 90, 180, and 270 degree rotations.
     4367static inline bool transformIsSimple(const QTransform& transform)
     4368{
     4369    QTransform::TransformationType type = transform.type();
     4370    if (type == QTransform::TxNone || type == QTransform::TxTranslate) {
     4371        return true;
     4372    } else if (type == QTransform::TxScale) {
     4373        // Check for 0 and 180 degree rotations.
     4374        // (0 might happen after 4 rotations of 90 degrees).
     4375        qreal m11 = transform.m11();
     4376        qreal m12 = transform.m12();
     4377        qreal m21 = transform.m21();
     4378        qreal m22 = transform.m22();
     4379        if (m12 == 0.0f && m21 == 0.0f) {
     4380            if (m11 == 1.0f && m22 == 1.0f)
     4381                return true; // 0 degrees
     4382            else if (m11 == -1.0f && m22 == -1.0f)
     4383                return true; // 180 degrees.
     4384            if(m11 == 1.0f && m22 == -1.0f)
     4385                return true; // 0 degrees inverted y.
     4386            else if(m11 == -1.0f && m22 == 1.0f)
     4387                return true; // 180 degrees inverted y.
     4388        }
     4389    } else if (type == QTransform::TxRotate) {
     4390        // Check for 90, and 270 degree rotations.
     4391        qreal m11 = transform.m11();
     4392        qreal m12 = transform.m12();
     4393        qreal m21 = transform.m21();
     4394        qreal m22 = transform.m22();
     4395        if (m11 == 0.0f && m22 == 0.0f) {
     4396            if (m12 == 1.0f && m21 == -1.0f)
     4397                return true; // 90 degrees.
     4398            else if (m12 == -1.0f && m21 == 1.0f)
     4399                return true; // 270 degrees.
     4400            else if (m12 == -1.0f && m21 == -1.0f)
     4401                return true; // 90 degrees inverted y.
     4402            else if (m12 == 1.0f && m21 == 1.0f)
     4403                return true; // 270 degrees inverted y.
     4404        }
     4405    }
     4406    return false;
     4407}
     4408
    43094409/*!
    43104410    \internal
     
    43514451    QGraphicsItemCache *itemCache = itemd->extraItemCache();
    43524452    if (cacheMode == QGraphicsItem::ItemCoordinateCache) {
    4353         if (itemCache->boundingRect != brect.toRect()) {
    4354             itemCache->boundingRect = brect.toRect();
    4355             itemCache->allExposed = true;
    4356             itemCache->exposed.clear();
    4357         }
    43584453        pixmapKey = itemCache->key;
    43594454    } else {
     
    43684463        QSize pixmapSize;
    43694464        bool fixedCacheSize = false;
    4370         QRectF brectAligned = brect.toAlignedRect();
     4465        QRect br = brect.toAlignedRect();
    43714466        if ((fixedCacheSize = itemCache->fixedSize.isValid())) {
    43724467            pixmapSize = itemCache->fixedSize;
    43734468        } else {
    4374             pixmapSize = brectAligned.size().toSize();
     4469            pixmapSize = br.size();
    43754470        }
    43764471
     
    43784473        int adjust = itemCache->fixedSize.isValid() ? 0 : 2;
    43794474        QSize adjustSize(adjust*2, adjust*2);
    4380         QRectF br = brectAligned.adjusted(-adjust, -adjust, adjust, adjust);
     4475        br.adjust(-adjust, -adjust, adjust, adjust);
    43814476        if (pix.isNull() || (!fixedCacheSize && (pixmapSize + adjustSize) != pix.size())) {
    43824477            pix = QPixmap(pixmapSize + adjustSize);
     4478            itemCache->boundingRect = br;
     4479            itemCache->exposed.clear();
     4480            itemCache->allExposed = true;
     4481        } else if (itemCache->boundingRect != br) {
     4482            itemCache->boundingRect = br;
    43834483            itemCache->exposed.clear();
    43844484            itemCache->allExposed = true;
     
    44344534        if (newPainterOpacity != oldPainterOpacity) {
    44354535            painter->setOpacity(newPainterOpacity);
    4436             painter->drawPixmap(br, pix, QRectF(QPointF(), pix.size()));
     4536            painter->drawPixmap(br.topLeft(), pix);
    44374537            painter->setOpacity(oldPainterOpacity);
    44384538        } else {
    4439             painter->drawPixmap(br, pix, QRectF(QPointF(), pix.size()));
     4539            painter->drawPixmap(br.topLeft(), pix);
    44404540        }
    44414541        return;
     
    44754575            diff *= painter->worldTransform();
    44764576        deviceData->lastTransform = painter->worldTransform();
    4477         if (!invertable
    4478             || diff.type() > QTransform::TxTranslate
    4479             || painter->worldTransform().type() > QTransform::TxScale) {
     4577        bool allowPartialCacheExposure = false;
     4578        bool simpleTransform = invertable && diff.type() <= QTransform::TxTranslate
     4579                               && transformIsSimple(painter->worldTransform());
     4580        if (!simpleTransform) {
    44804581            pixModified = true;
    44814582            itemCache->allExposed = true;
    44824583            itemCache->exposed.clear();
     4584            deviceData->cacheIndent = QPoint();
    44834585            pix = QPixmap();
    4484         }
    4485 
    4486         // ### This is a pretty bad way to determine when to start partial
    4487         // exposure for DeviceCoordinateCache but it's the least intrusive
    4488         // approach for now.
    4489 #if 0
    4490         // Only if the device rect isn't fully contained.
    4491         bool allowPartialCacheExposure = !viewRect.contains(deviceRect);
    4492 #else
    4493         // Only if deviceRect is 20% taller or wider than the desktop.
    4494         bool allowPartialCacheExposure = false;
    4495         if (widget) {
    4496             QRect desktopRect = QApplication::desktop()->availableGeometry(widget);
    4497             allowPartialCacheExposure = (desktopRect.width() * 1.2 < deviceRect.width()
    4498                                          || desktopRect.height() * 1.2 < deviceRect.height());
    4499         }
    4500 #endif
     4586        } else if (!viewRect.isNull()) {
     4587            allowPartialCacheExposure = deviceData->cacheIndent != QPoint();
     4588        }
     4589
     4590        // Allow partial cache exposure if the device rect isn't fully contained and
     4591        // deviceRect is 20% taller or wider than the viewRect.
     4592        if (!allowPartialCacheExposure && !viewRect.isNull() && !viewRect.contains(deviceRect)) {
     4593            allowPartialCacheExposure = (viewRect.width() * 1.2 < deviceRect.width())
     4594                                         || (viewRect.height() * 1.2 < deviceRect.height());
     4595        }
     4596
    45014597        QRegion scrollExposure;
    4502         if (deviceData->cacheIndent != QPoint() || allowPartialCacheExposure) {
     4598        if (allowPartialCacheExposure) {
    45034599            // Part of pixmap is drawn. Either device contains viewrect (big
    45044600            // item covers whole screen) or parts of device are outside the
     
    46944790        const QRectF brect = adjustedItemEffectiveBoundingRect(item);
    46954791        ENSURE_TRANSFORM_PTR
    4696         QRect viewBoundingRect = translateOnlyTransform ? brect.translated(transformPtr->dx(), transformPtr->dy()).toRect()
    4697                                                         : transformPtr->mapRect(brect).toRect();
     4792        QRect viewBoundingRect = translateOnlyTransform ? brect.translated(transformPtr->dx(), transformPtr->dy()).toAlignedRect()
     4793                                                        : transformPtr->mapRect(brect).toAlignedRect();
     4794        viewBoundingRect.adjust(-int(rectAdjust), -int(rectAdjust), rectAdjust, rectAdjust);
    46984795        if (widget)
    46994796            item->d_ptr->paintedViewBoundingRects.insert(widget, viewBoundingRect);
    4700         viewBoundingRect.adjust(-1, -1, 1, 1);
    47014797        drawItem = exposedRegion ? exposedRegion->intersects(viewBoundingRect)
    47024798                                 : !viewBoundingRect.normalized().isEmpty();
     
    47194815        ENSURE_TRANSFORM_PTR;
    47204816        QGraphicsItemPaintInfo info(viewTransform, transformPtr, effectTransform, exposedRegion, widget, &styleOptionTmp,
    4721                                     painter, opacity, wasDirtyParentSceneTransform, drawItem);
     4817                                    painter, opacity, wasDirtyParentSceneTransform, itemHasContents && !itemIsFullyTransparent);
    47224818        QGraphicsEffectSource *source = item->d_ptr->graphicsEffect->d_func()->source;
    47234819        QGraphicsItemEffectSourcePrivate *sourced = static_cast<QGraphicsItemEffectSourcePrivate *>
     
    47594855}
    47604856
     4857static inline void setClip(QPainter *painter, QGraphicsItem *item)
     4858{
     4859    painter->save();
     4860    QRectF clipRect;
     4861    const QPainterPath clipPath(item->shape());
     4862    if (QPathClipper::pathToRect(clipPath, &clipRect))
     4863        painter->setClipRect(clipRect, Qt::IntersectClip);
     4864    else
     4865        painter->setClipPath(clipPath, Qt::IntersectClip);
     4866}
     4867
     4868static inline void setWorldTransform(QPainter *painter, const QTransform *const transformPtr,
     4869                                     const QTransform *effectTransform)
     4870{
     4871    Q_ASSERT(transformPtr);
     4872    if (effectTransform)
     4873        painter->setWorldTransform(*transformPtr * *effectTransform);
     4874    else
     4875        painter->setWorldTransform(*transformPtr);
     4876}
     4877
    47614878void QGraphicsScenePrivate::draw(QGraphicsItem *item, QPainter *painter, const QTransform *const viewTransform,
    47624879                                 const QTransform *const transformPtr, QRegion *exposedRegion, QWidget *widget,
     
    47674884    const bool itemClipsChildrenToShape = (item->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape);
    47684885    const bool itemHasChildren = !item->d_ptr->children.isEmpty();
     4886    bool setChildClip = itemClipsChildrenToShape;
     4887    bool itemHasChildrenStackedBehind = false;
    47694888
    47704889    int i = 0;
    47714890    if (itemHasChildren) {
     4891        if (itemClipsChildrenToShape)
     4892            setWorldTransform(painter, transformPtr, effectTransform);
     4893
    47724894        item->d_ptr->ensureSortedChildren();
    4773 
    4774         if (itemClipsChildrenToShape) {
    4775             painter->save();
    4776             Q_ASSERT(transformPtr);
    4777             if (effectTransform)
    4778                 painter->setWorldTransform(*transformPtr * *effectTransform);
    4779             else
    4780                 painter->setWorldTransform(*transformPtr);
    4781             QRectF clipRect;
    4782             const QPainterPath clipPath(item->shape());
    4783             if (QPathClipper::pathToRect(clipPath, &clipRect))
    4784                 painter->setClipRect(clipRect, Qt::IntersectClip);
    4785             else
    4786                 painter->setClipPath(clipPath, Qt::IntersectClip);
    4787         }
    4788 
    4789         // Draw children behind
    4790         for (i = 0; i < item->d_ptr->children.size(); ++i) {
    4791             QGraphicsItem *child = item->d_ptr->children.at(i);
    4792             if (wasDirtyParentSceneTransform)
    4793                 child->d_ptr->dirtySceneTransform = 1;
    4794             if (!(child->d_ptr->flags & QGraphicsItem::ItemStacksBehindParent))
    4795                 break;
    4796             if (itemIsFullyTransparent && !(child->d_ptr->flags & QGraphicsItem::ItemIgnoresParentOpacity))
    4797                 continue;
    4798             drawSubtreeRecursive(child, painter, viewTransform, exposedRegion, widget, opacity, effectTransform);
     4895        // Items with the 'ItemStacksBehindParent' flag are put in front of the list
     4896        // so all we have to do is to check the first item.
     4897        itemHasChildrenStackedBehind = (item->d_ptr->children.at(0)->d_ptr->flags
     4898                                        & QGraphicsItem::ItemStacksBehindParent);
     4899
     4900        if (itemHasChildrenStackedBehind) {
     4901            if (itemClipsChildrenToShape) {
     4902                setClip(painter, item);
     4903                setChildClip = false;
     4904            }
     4905
     4906            // Draw children behind
     4907            for (i = 0; i < item->d_ptr->children.size(); ++i) {
     4908                QGraphicsItem *child = item->d_ptr->children.at(i);
     4909                if (wasDirtyParentSceneTransform)
     4910                    child->d_ptr->dirtySceneTransform = 1;
     4911                if (!(child->d_ptr->flags & QGraphicsItem::ItemStacksBehindParent))
     4912                    break;
     4913                if (itemIsFullyTransparent && !(child->d_ptr->flags & QGraphicsItem::ItemIgnoresParentOpacity))
     4914                    continue;
     4915                drawSubtreeRecursive(child, painter, viewTransform, exposedRegion, widget, opacity, effectTransform);
     4916            }
    47994917        }
    48004918    }
     
    48094927
    48104928        const bool itemClipsToShape = item->d_ptr->flags & QGraphicsItem::ItemClipsToShape;
    4811         const bool savePainter = itemClipsToShape || painterStateProtection;
    4812         if (savePainter)
     4929        bool restorePainterClip = false;
     4930
     4931        if (!itemHasChildren || !itemClipsChildrenToShape) {
     4932            // Item does not have children or clip children to shape.
     4933            setWorldTransform(painter, transformPtr, effectTransform);
     4934            if ((restorePainterClip = itemClipsToShape))
     4935                setClip(painter, item);
     4936        } else if (itemHasChildrenStackedBehind){
     4937            // Item clips children to shape and has children stacked behind, which means
     4938            // the painter is already clipped to the item's shape.
     4939            if (itemClipsToShape) {
     4940                // The clip is already correct. Ensure correct world transform.
     4941                setWorldTransform(painter, transformPtr, effectTransform);
     4942            } else {
     4943                // Remove clip (this also ensures correct world transform).
     4944                painter->restore();
     4945                setChildClip = true;
     4946            }
     4947        } else if (itemClipsToShape) {
     4948            // Item clips children and itself to shape. It does not have hildren stacked
     4949            // behind, which means the clip has not yet been set. We set it now and re-use it
     4950            // for the children.
     4951            setClip(painter, item);
     4952            setChildClip = false;
     4953        }
     4954
     4955        if (painterStateProtection && !restorePainterClip)
    48134956            painter->save();
    48144957
    4815         if (!itemHasChildren || !itemClipsChildrenToShape) {
    4816             if (effectTransform)
    4817                 painter->setWorldTransform(*transformPtr * *effectTransform);
    4818             else
    4819                 painter->setWorldTransform(*transformPtr);
    4820         }
    4821 
    4822         if (itemClipsToShape) {
    4823             QRectF clipRect;
    4824             const QPainterPath clipPath(item->shape());
    4825             if (QPathClipper::pathToRect(clipPath, &clipRect))
    4826                 painter->setClipRect(clipRect, Qt::IntersectClip);
    4827             else
    4828                 painter->setClipPath(clipPath, Qt::IntersectClip);
    4829         }
    48304958        painter->setOpacity(opacity);
    4831 
    48324959        if (!item->d_ptr->cacheMode && !item->d_ptr->isWidget)
    48334960            item->paint(painter, &styleOptionTmp, widget);
     
    48354962            drawItemHelper(item, painter, &styleOptionTmp, widget, painterStateProtection);
    48364963
    4837         if (savePainter)
     4964        if (painterStateProtection || restorePainterClip)
    48384965            painter->restore();
    48394966    }
     
    48414968    // Draw children in front
    48424969    if (itemHasChildren) {
     4970        if (setChildClip)
     4971            setClip(painter, item);
     4972
    48434973        for (; i < item->d_ptr->children.size(); ++i) {
    48444974            QGraphicsItem *child = item->d_ptr->children.at(i);
     
    48494979            drawSubtreeRecursive(child, painter, viewTransform, exposedRegion, widget, opacity, effectTransform);
    48504980        }
    4851     }
    4852 
    4853     // Restore child clip
    4854     if (itemHasChildren && itemClipsChildrenToShape)
    4855         painter->restore();
     4981
     4982        // Restore child clip
     4983        if (itemClipsChildrenToShape)
     4984            painter->restore();
     4985    }
    48564986}
    48574987
     
    48634993    if (updateAll)
    48644994        return;
     4995
     4996    if (removingItemFromScene && !ignoreOpacity && !item->d_ptr->ignoreOpacity) {
     4997        // If any of the item's ancestors ignore opacity, it means that the opacity
     4998        // was set to 0 (and the update request has not yet been processed). That
     4999        // also means that we have to ignore the opacity for the item itself; otherwise
     5000        // things like: parent->setOpacity(0); scene->removeItem(child) won't work.
     5001        // Note that we only do this when removing items from the scene. In all other
     5002        // cases the ignoreOpacity bit propagates properly in processDirtyItems, but
     5003        // since the item is removed immediately it won't be processed there.
     5004        QGraphicsItem *p = item->d_ptr->parent;
     5005        while (p) {
     5006            if (p->d_ptr->ignoreOpacity) {
     5007                item->d_ptr->ignoreOpacity = true;
     5008                break;
     5009            }
     5010            p = p->d_ptr->parent;
     5011        }
     5012    }
    48655013
    48665014    if (item->d_ptr->discardUpdateRequest(/*ignoreVisibleBit=*/force,
     
    48855033
    48865034    if (!processDirtyItemsEmitted) {
    4887         QMetaObject::invokeMethod(q_ptr, "_q_processDirtyItems", Qt::QueuedConnection);
     5035        QMetaMethod method = q_ptr->metaObject()->method(processDirtyItemsIndex);
     5036        method.invoke(q_ptr, Qt::QueuedConnection);
     5037//        QMetaObject::invokeMethod(q_ptr, "_q_processDirtyItems", Qt::QueuedConnection);
    48885038        processDirtyItemsEmitted = true;
    48895039    }
     
    49095059    }
    49105060
    4911     bool hasNoContents = item->d_ptr->flags & QGraphicsItem::ItemHasNoContents
    4912                          && !item->d_ptr->graphicsEffect;
     5061    bool hasNoContents = item->d_ptr->flags & QGraphicsItem::ItemHasNoContents;
    49135062    if (!hasNoContents) {
    49145063        item->d_ptr->dirty = 1;
     
    49175066        else if (!item->d_ptr->fullUpdatePending)
    49185067            item->d_ptr->needsRepaint |= rect;
     5068    } else if (item->d_ptr->graphicsEffect) {
     5069        invalidateChildren = true;
    49195070    }
    49205071
     
    49455096        const QTransform xform = itemq->deviceTransform(viewq->viewportTransform());
    49465097        if (!item->hasBoundingRegionGranularity)
    4947             return view->updateRect(xform.mapRect(rect).toRect());
    4948         return view->updateRegion(xform.map(QRegion(rect.toRect())));
     5098            return view->updateRectF(xform.mapRect(rect));
     5099        return view->updateRegion(rect, xform);
    49495100    }
    49505101
     
    49525103        const qreal dx = item->sceneTransform.dx();
    49535104        const qreal dy = item->sceneTransform.dy();
    4954         if (!item->hasBoundingRegionGranularity) {
    4955             QRectF r(rect);
    4956             r.translate(dx - view->horizontalScroll(), dy - view->verticalScroll());
    4957             return view->updateRect(r.toRect());
    4958         }
    4959         QRegion r(rect.toRect());
    4960         r.translate(qRound(dx) - view->horizontalScroll(), qRound(dy) - view->verticalScroll());
    4961         return view->updateRegion(r);
     5105        QRectF r(rect);
     5106        r.translate(dx - view->horizontalScroll(), dy - view->verticalScroll());
     5107        return view->updateRectF(r);
    49625108    }
    49635109
    49645110    if (!viewq->isTransformed()) {
    49655111        if (!item->hasBoundingRegionGranularity)
    4966             return view->updateRect(item->sceneTransform.mapRect(rect).toRect());
    4967         return view->updateRegion(item->sceneTransform.map(QRegion(rect.toRect())));
     5112            return view->updateRectF(item->sceneTransform.mapRect(rect));
     5113        return view->updateRegion(rect, item->sceneTransform);
    49685114    }
    49695115
     
    49715117    xform *= viewq->viewportTransform();
    49725118    if (!item->hasBoundingRegionGranularity)
    4973         return view->updateRect(xform.mapRect(rect).toRect());
    4974     return view->updateRegion(xform.map(QRegion(rect.toRect())));
     5119        return view->updateRectF(xform.mapRect(rect));
     5120    return view->updateRegion(rect, xform);
    49755121}
    49765122
     
    50525198                                                      item->d_ptr->sceneTransform.dy()));
    50535199            } else {
    5054                 q->update(item->d_ptr->sceneTransform.mapRect(itemBoundingRect));
     5200                QRectF rect = item->d_ptr->sceneTransform.mapRect(itemBoundingRect);
     5201                if (!rect.isEmpty())
     5202                    q->update(rect);
    50555203            }
    50565204        } else {
     
    51085256    // Process children.
    51095257    if (itemHasChildren && item->d_ptr->dirtyChildren) {
     5258        const bool itemClipsChildrenToShape = item->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape;
     5259        // Items with no content are threated as 'dummy' items which means they are never drawn and
     5260        // 'processed', so the painted view bounding rect is never up-to-date. This means that whenever
     5261        // such an item changes geometry, its children have to take care of the update regardless
     5262        // of whether the item clips children to shape or not.
     5263        const bool bypassUpdateClip = !itemHasContents && wasDirtyParentViewBoundingRects;
     5264        if (itemClipsChildrenToShape && !bypassUpdateClip) {
     5265            // Make sure child updates are clipped to the item's bounding rect.
     5266            for (int i = 0; i < views.size(); ++i)
     5267                views.at(i)->d_func()->setUpdateClip(item);
     5268        }
    51105269        if (!dirtyAncestorContainsChildren) {
    51115270            dirtyAncestorContainsChildren = item->d_ptr->fullUpdatePending
    5112                                             && (item->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape);
     5271                                            && itemClipsChildrenToShape;
    51135272        }
    51145273        const bool allChildrenDirty = item->d_ptr->allChildrenDirty;
     
    51335292            processDirtyItemsRecursive(child, dirtyAncestorContainsChildren, opacity);
    51345293        }
     5294
     5295        if (itemClipsChildrenToShape) {
     5296            // Reset updateClip.
     5297            for (int i = 0; i < views.size(); ++i)
     5298                views.at(i)->d_func()->setUpdateClip(0);
     5299        }
    51355300    } else if (wasDirtyParentSceneTransform) {
    51365301        item->d_ptr->invalidateChildrenSceneTransform();
     
    51815346        d->_q_polishItems();
    51825347
    5183     d->updateAll = false;
     5348    const qreal opacity = painter->opacity();
    51845349    QTransform viewTransform = painter->worldTransform();
    51855350    Q_UNUSED(options);
     
    51885353    QGraphicsView *view = widget ? qobject_cast<QGraphicsView *>(widget->parentWidget()) : 0;
    51895354    QRegion *expose = 0;
    5190     if (view)
     5355    const quint32 oldRectAdjust = d->rectAdjust;
     5356    if (view) {
     5357        d->updateAll = false;
    51915358        expose = &view->d_func()->exposedRegion;
     5359        if (view->d_func()->optimizationFlags & QGraphicsView::DontAdjustForAntialiasing)
     5360            d->rectAdjust = 1;
     5361        else
     5362            d->rectAdjust = 2;
     5363    }
    51925364
    51935365    // Find all toplevels, they are already sorted.
     
    52025374    }
    52035375
     5376    d->rectAdjust = oldRectAdjust;
    52045377    // Reset discovery bits.
    52055378    for (int i = 0; i < topLevelItems.size(); ++i)
     
    52075380
    52085381    painter->setWorldTransform(viewTransform);
     5382    painter->setOpacity(opacity);
    52095383}
    52105384
     
    55785752{
    55795753    views << view;
     5754#ifndef QT_NO_GESTURES
     5755    foreach (Qt::GestureType gesture, grabbedGestures.keys())
     5756        view->viewport()->grabGesture(gesture);
     5757#endif
    55805758}
    55815759
     
    56385816
    56395817            if (sceneTouchEvent->deviceType() == QTouchEvent::TouchScreen) {
    5640                 // on touch-screens, combine this touch point with the closest one we find if it
    5641                 // is a a direct descendent or ancestor (
     5818                // on touch-screens, combine this touch point with the closest one we find
    56425819                int closestTouchPointId = findClosestTouchPointId(touchPoint.scenePos());
    56435820                QGraphicsItem *closestItem = itemForTouchPointId.value(closestTouchPointId);
    5644                 if (!item
    5645                     || (closestItem
    5646                         && (item->isAncestorOf(closestItem)
    5647                             || closestItem->isAncestorOf(item)))) {
     5821                if (!item || (closestItem && cachedItemsUnderMouse.contains(closestItem)))
    56485822                    item = closestItem;
    5649                 }
    56505823            }
    56515824            if (!item)
     
    59076080}
    59086081
    5909 void QGraphicsScenePrivate::getGestureTargets(const QSet<QGesture *> &gestures,
    5910                                               QWidget *viewport,
    5911                                               QMap<Qt::GestureType, QGesture *> *conflictedGestures,
    5912                                               QList<QList<QGraphicsObject *> > *conflictedItems,
    5913                                               QHash<QGesture *, QGraphicsObject *> *normalGestures)
    5914 {
     6082#ifndef QT_NO_GESTURES
     6083void QGraphicsScenePrivate::gestureTargetsAtHotSpots(const QSet<QGesture *> &gestures,
     6084                                              Qt::GestureFlag flag,
     6085                                              QHash<QGraphicsObject *, QSet<QGesture *> > *targets,
     6086                                              QSet<QGraphicsObject *> *itemsSet,
     6087                                              QSet<QGesture *> *normal,
     6088                                              QSet<QGesture *> *conflicts)
     6089{
     6090    QSet<QGesture *> normalGestures; // that are not in conflicted state.
    59156091    foreach (QGesture *gesture, gestures) {
    5916         Qt::GestureType gestureType = gesture->gestureType();
    5917         if (gesture->hasHotSpot()) {
    5918             QPoint screenPos = gesture->hotSpot().toPoint();
    5919             QList<QGraphicsItem *> items = itemsAtPosition(screenPos, QPointF(), viewport);
    5920             QList<QGraphicsObject *> result;
    5921             for (int j = 0; j < items.size(); ++j) {
    5922                 QGraphicsItem *item = items.at(j);
    5923 
    5924                 // Check if the item is blocked by a modal panel and use it as
    5925                 // a target instead of this item.
    5926                 (void) item->isBlockedByModalPanel(&item);
    5927 
    5928                 if (QGraphicsObject *itemobj = item->toGraphicsObject()) {
    5929                     QGraphicsItemPrivate *d = item->d_func();
    5930                     if (d->gestureContext.contains(gestureType)) {
    5931                         result.append(itemobj);
     6092        if (!gesture->hasHotSpot())
     6093            continue;
     6094        const Qt::GestureType gestureType = gesture->gestureType();
     6095        QList<QGraphicsItem *> items = itemsAtPosition(QPoint(), gesture->d_func()->sceneHotSpot, 0);
     6096        for (int j = 0; j < items.size(); ++j) {
     6097            QGraphicsItem *item = items.at(j);
     6098
     6099            // Check if the item is blocked by a modal panel and use it as
     6100            // a target instead of this item.
     6101            (void) item->isBlockedByModalPanel(&item);
     6102
     6103            if (QGraphicsObject *itemobj = item->toGraphicsObject()) {
     6104                QGraphicsItemPrivate *d = item->QGraphicsItem::d_func();
     6105                QMap<Qt::GestureType, Qt::GestureFlags>::const_iterator it =
     6106                        d->gestureContext.find(gestureType);
     6107                if (it != d->gestureContext.end() && (!flag || (it.value() & flag))) {
     6108                    if (normalGestures.contains(gesture)) {
     6109                        normalGestures.remove(gesture);
     6110                        if (conflicts)
     6111                            conflicts->insert(gesture);
     6112                    } else {
     6113                        normalGestures.insert(gesture);
    59326114                    }
     6115                    if (targets)
     6116                        (*targets)[itemobj].insert(gesture);
     6117                    if (itemsSet)
     6118                        (*itemsSet).insert(itemobj);
    59336119                }
    5934                 // Don't propagate through panels.
    5935                 if (item->isPanel())
    5936                     break;
    59376120            }
    5938             DEBUG() << "QGraphicsScenePrivate::getGestureTargets:"
    5939                     << gesture << result;
    5940             if (result.size() == 1) {
    5941                 normalGestures->insert(gesture, result.first());
    5942             } else if (!result.isEmpty()) {
    5943                 conflictedGestures->insert(gestureType, gesture);
    5944                 conflictedItems->append(result);
    5945             }
    5946         }
    5947     }
     6121            // Don't propagate through panels.
     6122            if (item->isPanel())
     6123                break;
     6124        }
     6125    }
     6126    if (normal)
     6127        *normal = normalGestures;
    59486128}
    59496129
     
    59536133    if (!viewport)
    59546134        return;
     6135    QGraphicsView *graphicsView = qobject_cast<QGraphicsView *>(viewport->parent());
     6136    if (!graphicsView)
     6137        return;
     6138
    59556139    QList<QGesture *> allGestures = event->gestures();
    59566140    DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:"
    5957             << "Delivering gestures:" <<  allGestures;
    5958 
    5959     typedef QHash<QGraphicsObject *, QList<QGesture *> > GesturesPerItem;
    5960     GesturesPerItem gesturesPerItem;
     6141            << "Gestures:" <<  allGestures;
    59616142
    59626143    QSet<QGesture *> startedGestures;
     6144    QPoint delta = viewport->mapFromGlobal(QPoint());
     6145    QTransform toScene = QTransform::fromTranslate(delta.x(), delta.y())
     6146                         * graphicsView->viewportTransform().inverted();
    59636147    foreach (QGesture *gesture, allGestures) {
     6148        // cache scene coordinates of the hot spot
     6149        if (gesture->hasHotSpot()) {
     6150            gesture->d_func()->sceneHotSpot = toScene.map(gesture->hotSpot());
     6151        } else {
     6152            gesture->d_func()->sceneHotSpot = QPointF();
     6153        }
     6154
    59646155        QGraphicsObject *target = gestureTargets.value(gesture, 0);
    59656156        if (!target) {
     
    59686159            if (gesture->state() == Qt::GestureStarted)
    59696160                startedGestures.insert(gesture);
    5970         } else {
    5971             gesturesPerItem[target].append(gesture);
    5972         }
    5973     }
    5974 
    5975     QMap<Qt::GestureType, QGesture *> conflictedGestures;
    5976     QList<QList<QGraphicsObject *> > conflictedItems;
    5977     QHash<QGesture *, QGraphicsObject *> normalGestures;
    5978     getGestureTargets(startedGestures, viewport, &conflictedGestures, &conflictedItems,
    5979                       &normalGestures);
    5980     DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:"
    5981             << "Conflicting gestures:" <<  conflictedGestures.values() << conflictedItems;
    5982     Q_ASSERT((conflictedGestures.isEmpty() && conflictedItems.isEmpty()) ||
    5983               (!conflictedGestures.isEmpty() && !conflictedItems.isEmpty()));
    5984 
    5985     // gestures that were sent as override events, but no one accepted them
    5986     QHash<QGesture *, QGraphicsObject *> ignoredConflictedGestures;
    5987 
    5988     // deliver conflicted gestures as override events first
    5989     while (!conflictedGestures.isEmpty() && !conflictedItems.isEmpty()) {
    5990         // get the topmost item to deliver the override event
    5991         Q_ASSERT(!conflictedItems.isEmpty());
    5992         Q_ASSERT(!conflictedItems.first().isEmpty());
    5993         QGraphicsObject *topmost = conflictedItems.first().first();
    5994         for (int i = 1; i < conflictedItems.size(); ++i) {
    5995             QGraphicsObject *item = conflictedItems.at(i).first();
    5996             if (qt_closestItemFirst(item, topmost)) {
    5997                 topmost = item;
     6161        }
     6162    }
     6163
     6164    if (!startedGestures.isEmpty()) {
     6165        QSet<QGesture *> normalGestures; // that have just one target
     6166        QSet<QGesture *> conflictedGestures; // that have multiple possible targets
     6167        gestureTargetsAtHotSpots(startedGestures, Qt::GestureFlag(0), &cachedItemGestures, 0,
     6168                                 &normalGestures, &conflictedGestures);
     6169        cachedTargetItems = cachedItemGestures.keys();
     6170        qSort(cachedTargetItems.begin(), cachedTargetItems.end(), qt_closestItemFirst);
     6171        DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:"
     6172                << "Normal gestures:" << normalGestures
     6173                << "Conflicting gestures:" << conflictedGestures;
     6174
     6175        // deliver conflicted gestures as override events AND remember
     6176        // initial gesture targets
     6177        if (!conflictedGestures.isEmpty()) {
     6178            for (int i = 0; i < cachedTargetItems.size(); ++i) {
     6179                QWeakPointer<QGraphicsObject> item = cachedTargetItems.at(i);
     6180
     6181                // get gestures to deliver to the current item
     6182                QSet<QGesture *> gestures = conflictedGestures & cachedItemGestures.value(item.data());
     6183                if (gestures.isEmpty())
     6184                    continue;
     6185
     6186                DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:"
     6187                        << "delivering override to"
     6188                        << item.data() << gestures;
     6189                // send gesture override
     6190                QGestureEvent ev(gestures.toList());
     6191                ev.t = QEvent::GestureOverride;
     6192                ev.setWidget(event->widget());
     6193                // mark event and individual gestures as ignored
     6194                ev.ignore();
     6195                foreach(QGesture *g, gestures)
     6196                    ev.setAccepted(g, false);
     6197                sendEvent(item.data(), &ev);
     6198                // mark all accepted gestures to deliver them as normal gesture events
     6199                foreach (QGesture *g, gestures) {
     6200                    if (ev.isAccepted() || ev.isAccepted(g)) {
     6201                        conflictedGestures.remove(g);
     6202                        // mark the item as a gesture target
     6203                        if (item) {
     6204                            gestureTargets.insert(g, item.data());
     6205                            QHash<QGraphicsObject *, QSet<QGesture *> >::iterator it, e;
     6206                            it = cachedItemGestures.begin();
     6207                            e = cachedItemGestures.end();
     6208                            for(; it != e; ++it)
     6209                                it.value().remove(g);
     6210                            cachedItemGestures[item.data()].insert(g);
     6211                        }
     6212                        DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:"
     6213                                << "override was accepted:"
     6214                                << g << item.data();
     6215                    }
     6216                    // remember the first item that received the override event
     6217                    // as it most likely become a target if no one else accepts
     6218                    // the override event
     6219                    if (!gestureTargets.contains(g) && item)
     6220                        gestureTargets.insert(g, item.data());
     6221
     6222                }
     6223                if (conflictedGestures.isEmpty())
     6224                    break;
    59986225            }
    59996226        }
    6000         // get a list of gestures to send to the item
    6001         QList<Qt::GestureType> grabbedGestures =
    6002                 topmost->QGraphicsItem::d_func()->gestureContext.keys();
    6003         QList<QGesture *> gestures;
    6004         for (int i = 0; i < grabbedGestures.size(); ++i) {
    6005             if (QGesture *g = conflictedGestures.value(grabbedGestures.at(i), 0)) {
    6006                 gestures.append(g);
    6007                 if (!ignoredConflictedGestures.contains(g))
    6008                     ignoredConflictedGestures.insert(g, topmost);
    6009             }
    6010         }
    6011 
    6012         // send gesture override to the topmost item
    6013         QGestureEvent ev(gestures);
    6014         ev.t = QEvent::GestureOverride;
    6015         ev.setWidget(event->widget());
    6016         // mark event and individual gestures as ignored
    6017         ev.ignore();
    6018         foreach(QGesture *g, gestures)
    6019             ev.setAccepted(g, false);
    6020         DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:"
    6021                 << "delivering override to"
    6022                 << topmost << gestures;
    6023         sendEvent(topmost, &ev);
    6024         // mark all accepted gestures to deliver them as normal gesture events
    6025         foreach (QGesture *g, gestures) {
    6026             if (ev.isAccepted() || ev.isAccepted(g)) {
    6027                 conflictedGestures.remove(g->gestureType());
    6028                 gestureTargets.remove(g);
    6029                 // add the gesture to the list of normal delivered gestures
    6030                 normalGestures.insert(g, topmost);
    6031                 DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:"
    6032                         << "override was accepted:"
    6033                         << g << topmost;
    6034                 ignoredConflictedGestures.remove(g);
    6035             }
    6036         }
    6037         // remove the item that we've already delivered from the list
    6038         for (int i = 0; i < conflictedItems.size(); ) {
    6039             QList<QGraphicsObject *> &items = conflictedItems[i];
    6040             if (items.first() == topmost) {
    6041                 items.removeFirst();
    6042                 if (items.isEmpty()) {
    6043                     conflictedItems.removeAt(i);
    6044                     continue;
     6227        // remember the initial target item for each gesture that was not in
     6228        // the conflicted state.
     6229        if (!normalGestures.isEmpty()) {
     6230            for (int i = 0; i < cachedTargetItems.size() && !normalGestures.isEmpty(); ++i) {
     6231                QGraphicsObject *item = cachedTargetItems.at(i);
     6232
     6233                // get gestures to deliver to the current item
     6234                foreach (QGesture *g, cachedItemGestures.value(item)) {
     6235                    if (!gestureTargets.contains(g)) {
     6236                        gestureTargets.insert(g, item);
     6237                        normalGestures.remove(g);
     6238                    }
    60456239                }
    60466240            }
    6047             ++i;
    6048         }
    6049     }
    6050 
    6051     // put back those started gestures that are not in the conflicted state
    6052     // and remember their targets
    6053     QHash<QGesture *, QGraphicsObject *>::const_iterator it = normalGestures.begin(),
    6054                                                           e = normalGestures.end();
    6055     for (; it != e; ++it) {
    6056         QGesture *g = it.key();
    6057         QGraphicsObject *receiver = it.value();
    6058         Q_ASSERT(!gestureTargets.contains(g));
    6059         gestureTargets.insert(g, receiver);
    6060         gesturesPerItem[receiver].append(g);
    6061     }
    6062     it = ignoredConflictedGestures.begin();
    6063     e = ignoredConflictedGestures.end();
    6064     for (; it != e; ++it) {
    6065         QGesture *g = it.key();
    6066         QGraphicsObject *receiver = it.value();
    6067         Q_ASSERT(!gestureTargets.contains(g));
    6068         gestureTargets.insert(g, receiver);
    6069         gesturesPerItem[receiver].append(g);
    6070     }
    6071 
    6072     DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:"
    6073             << "Started gestures:" << normalGestures.keys()
    6074             << "All gestures:" << gesturesPerItem.values();
    6075 
    6076     // deliver all events
    6077     QList<QGesture *> alreadyIgnoredGestures;
    6078     QHash<QGraphicsObject *, QSet<QGesture *> > itemIgnoredGestures;
    6079     QList<QGraphicsObject *> targetItems = gesturesPerItem.keys();
    6080     qSort(targetItems.begin(), targetItems.end(), qt_closestItemFirst);
    6081     for (int i = 0; i < targetItems.size(); ++i) {
    6082         QGraphicsObject *item = targetItems.at(i);
    6083         QList<QGesture *> gestures = gesturesPerItem.value(item);
    6084         // remove gestures that were already delivered once and were ignored
    6085         DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:"
    6086                 << "already ignored gestures for item"
    6087                 << item << ":" << itemIgnoredGestures.value(item);
    6088 
    6089         if (itemIgnoredGestures.contains(item)) // don't deliver twice to the same item
    6090             continue;
    6091 
    6092         QGraphicsItemPrivate *gid = item->QGraphicsItem::d_func();
    6093         foreach(QGesture *g, alreadyIgnoredGestures) {
    6094             QMap<Qt::GestureType, Qt::GestureFlags>::iterator contextit =
    6095                     gid->gestureContext.find(g->gestureType());
    6096             bool deliver = contextit != gid->gestureContext.end() &&
    6097                 (g->state() == Qt::GestureStarted ||
    6098                  (contextit.value() & Qt::ReceivePartialGestures));
    6099             if (deliver)
    6100                 gestures += g;
    6101         }
     6241        }
     6242    }
     6243
     6244
     6245    // deliver all gesture events
     6246    QSet<QGesture *> undeliveredGestures;
     6247    QSet<QGesture *> parentPropagatedGestures;
     6248    foreach (QGesture *gesture, allGestures) {
     6249        if (QGraphicsObject *target = gestureTargets.value(gesture, 0)) {
     6250            cachedItemGestures[target].insert(gesture);
     6251            cachedTargetItems.append(target);
     6252            undeliveredGestures.insert(gesture);
     6253            QGraphicsItemPrivate *d = target->QGraphicsItem::d_func();
     6254            const Qt::GestureFlags flags = d->gestureContext.value(gesture->gestureType());
     6255            if (flags & Qt::IgnoredGesturesPropagateToParent)
     6256                parentPropagatedGestures.insert(gesture);
     6257        } else {
     6258            DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:"
     6259                    << "no target for" << gesture << "at"
     6260                    << gesture->hotSpot() << gesture->d_func()->sceneHotSpot;
     6261        }
     6262    }
     6263    qSort(cachedTargetItems.begin(), cachedTargetItems.end(), qt_closestItemFirst);
     6264    for (int i = 0; i < cachedTargetItems.size(); ++i) {
     6265        QWeakPointer<QGraphicsObject> receiver = cachedTargetItems.at(i);
     6266        QSet<QGesture *> gestures =
     6267                undeliveredGestures & cachedItemGestures.value(receiver.data());
     6268        gestures -= cachedAlreadyDeliveredGestures.value(receiver.data());
     6269
    61026270        if (gestures.isEmpty())
    61036271            continue;
     6272
     6273        cachedAlreadyDeliveredGestures[receiver.data()] += gestures;
     6274        const bool isPanel = receiver.data()->isPanel();
     6275
    61046276        DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:"
    61056277                << "delivering to"
    6106                 << item << gestures;
    6107         QGestureEvent ev(gestures);
     6278                << receiver.data() << gestures;
     6279        QGestureEvent ev(gestures.toList());
    61086280        ev.setWidget(event->widget());
    6109         sendEvent(item, &ev);
     6281        sendEvent(receiver.data(), &ev);
    61106282        QSet<QGesture *> ignoredGestures;
    61116283        foreach (QGesture *g, gestures) {
    61126284            if (!ev.isAccepted() && !ev.isAccepted(g)) {
    6113                 ignoredGestures.insert(g);
     6285                // if the gesture was ignored by its target, we will update the
     6286                // targetItems list with a possible target items (items that
     6287                // want to receive partial gestures).
     6288                // ### wont' work if the target was destroyed in the event
     6289                //     we will just stop delivering it.
     6290                if (receiver && receiver.data() == gestureTargets.value(g, 0))
     6291                    ignoredGestures.insert(g);
    61146292            } else {
    6115                 if (g->state() == Qt::GestureStarted)
    6116                     gestureTargets[g] = item;
     6293                if (receiver && g->state() == Qt::GestureStarted) {
     6294                    // someone accepted the propagated initial GestureStarted
     6295                    // event, let it be the new target for all following events.
     6296                    gestureTargets[g] = receiver.data();
     6297                }
     6298                undeliveredGestures.remove(g);
    61176299            }
    61186300        }
    6119         if (!ignoredGestures.isEmpty()) {
    6120             // get a list of items under the (current) hotspot of each ignored
    6121             // gesture and start delivery again from the beginning
     6301        if (undeliveredGestures.isEmpty())
     6302            break;
     6303
     6304        // ignoredGestures list is only filled when delivering to the gesture
     6305        // target item, so it is safe to assume item == target.
     6306        if (!ignoredGestures.isEmpty() && !isPanel) {
     6307            // look for new potential targets for gestures that were ignored
     6308            // and should be propagated.
     6309
     6310            QSet<QGraphicsObject *> targetsSet = cachedTargetItems.toSet();
     6311
     6312            if (receiver) {
     6313                // first if the gesture should be propagated to parents only
     6314                for (QSet<QGesture *>::iterator it = ignoredGestures.begin();
     6315                     it != ignoredGestures.end();) {
     6316                    if (parentPropagatedGestures.contains(*it)) {
     6317                        QGesture *gesture = *it;
     6318                        const Qt::GestureType gestureType = gesture->gestureType();
     6319                        QGraphicsItem *item = receiver.data();
     6320                        while (item) {
     6321                            if (QGraphicsObject *obj = item->toGraphicsObject()) {
     6322                                if (item->d_func()->gestureContext.contains(gestureType)) {
     6323                                    targetsSet.insert(obj);
     6324                                    cachedItemGestures[obj].insert(gesture);
     6325                                }
     6326                            }
     6327                            if (item->isPanel())
     6328                                break;
     6329                            item = item->parentItem();
     6330                        }
     6331
     6332                        it = ignoredGestures.erase(it);
     6333                        continue;
     6334                    }
     6335                    ++it;
     6336                }
     6337            }
     6338
     6339            gestureTargetsAtHotSpots(ignoredGestures, Qt::ReceivePartialGestures,
     6340                                     &cachedItemGestures, &targetsSet, 0, 0);
     6341
     6342            cachedTargetItems = targetsSet.toList();
     6343            qSort(cachedTargetItems.begin(), cachedTargetItems.end(), qt_closestItemFirst);
    61226344            DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:"
    6123                     << "item has ignored the event, will propagate."
    6124                     << item << ignoredGestures;
    6125             itemIgnoredGestures[item] += ignoredGestures;
    6126             QMap<Qt::GestureType, QGesture *> conflictedGestures;
    6127             QList<QList<QGraphicsObject *> > itemsForConflictedGestures;
    6128             QHash<QGesture *, QGraphicsObject *> normalGestures;
    6129             getGestureTargets(ignoredGestures, viewport,
    6130                               &conflictedGestures, &itemsForConflictedGestures,
    6131                               &normalGestures);
    6132             QSet<QGraphicsObject *> itemsSet = targetItems.toSet();
    6133             for (int k = 0; k < itemsForConflictedGestures.size(); ++k)
    6134                 itemsSet += itemsForConflictedGestures.at(k).toSet();
    6135             targetItems = itemsSet.toList();
    6136             qSort(targetItems.begin(), targetItems.end(), qt_closestItemFirst);
    6137             alreadyIgnoredGestures = conflictedGestures.values();
    6138             DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:"
    6139                     << "new targets:" << targetItems;
     6345                    << "new targets:" << cachedTargetItems;
    61406346            i = -1; // start delivery again
    61416347            continue;
    61426348        }
    61436349    }
     6350
    61446351    foreach (QGesture *g, startedGestures) {
    61456352        if (g->gestureCancelPolicy() == QGesture::CancelAllInContext) {
    61466353            DEBUG() << "lets try to cancel some";
    61476354            // find gestures in context in Qt::GestureStarted or Qt::GestureUpdated state and cancel them
    6148             cancelGesturesForChildren(g, event->widget());
     6355            cancelGesturesForChildren(g);
    61496356        }
    61506357    }
     
    61616368        }
    61626369    }
    6163 }
    6164 
    6165 void QGraphicsScenePrivate::cancelGesturesForChildren(QGesture *original, QWidget *viewport)
     6370
     6371    cachedTargetItems.clear();
     6372    cachedItemGestures.clear();
     6373    cachedAlreadyDeliveredGestures.clear();
     6374}
     6375
     6376void QGraphicsScenePrivate::cancelGesturesForChildren(QGesture *original)
    61666377{
    61676378    Q_ASSERT(original);
    61686379    QGraphicsItem *originalItem = gestureTargets.value(original);
    6169     Q_ASSERT(originalItem);
     6380    if (originalItem == 0) // we only act on accepted gestures, which implies it has a target.
     6381        return;
    61706382
    61716383    // iterate over all active gestures and for each find the owner
     
    62196431                continue;
    62206432
    6221             QPoint screenPos = g->hotSpot().toPoint();
    6222             QList<QGraphicsItem *> items = itemsAtPosition(screenPos, QPointF(), viewport);
     6433            QList<QGraphicsItem *> items = itemsAtPosition(QPoint(), g->d_func()->sceneHotSpot, 0);
    62236434            for (int j = 0; j < items.size(); ++j) {
    62246435                QGraphicsObject *item = items.at(j)->toGraphicsObject();
     
    62466457}
    62476458
     6459void QGraphicsScenePrivate::grabGesture(QGraphicsItem *, Qt::GestureType gesture)
     6460{
     6461    (void)QGestureManager::instance(); // create a gesture manager
     6462    if (!grabbedGestures[gesture]++) {
     6463        foreach (QGraphicsView *view, views)
     6464            view->viewport()->grabGesture(gesture);
     6465    }
     6466}
     6467
     6468void QGraphicsScenePrivate::ungrabGesture(QGraphicsItem *item, Qt::GestureType gesture)
     6469{
     6470    // we know this can only be an object
     6471    Q_ASSERT(item->d_ptr->isObject);
     6472    QGraphicsObject *obj = static_cast<QGraphicsObject *>(item);
     6473    QGestureManager::instance()->cleanupCachedGestures(obj, gesture);
     6474    if (!--grabbedGestures[gesture]) {
     6475        foreach (QGraphicsView *view, views)
     6476            view->viewport()->ungrabGesture(gesture);
     6477    }
     6478}
     6479#endif // QT_NO_GESTURES
     6480
    62486481QT_END_NAMESPACE
    62496482
Note: See TracChangeset for help on using the changeset viewer.