diff -r 41300fa6a67c -r 2f34d5167611 src/gui/graphicsview/qgraphicsscene.cpp --- a/src/gui/graphicsview/qgraphicsscene.cpp Tue Feb 02 00:43:10 2010 +0200 +++ b/src/gui/graphicsview/qgraphicsscene.cpp Fri Apr 16 15:50:13 2010 +0300 @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** @@ -251,6 +251,7 @@ #endif #include #include +#include // #define GESTURE_DEBUG #ifndef GESTURE_DEBUG @@ -372,7 +373,10 @@ } } } else { - updateAll = false; + if (views.isEmpty()) { + updateAll = false; + return; + } for (int i = 0; i < views.size(); ++i) views.at(i)->d_func()->processPendingUpdates(); // It's important that we update all views before we dispatch, hence two for-loops. @@ -428,21 +432,39 @@ */ void QGraphicsScenePrivate::_q_polishItems() { - QSet::Iterator it; + if (unpolishedItems.isEmpty()) + return; + const QVariant booleanTrueVariant(true); - while (!unpolishedItems.isEmpty()) { - it = unpolishedItems.begin(); - QGraphicsItem *item = *it; - unpolishedItems.erase(it); - if (!item->d_ptr->explicitlyHidden) { + QGraphicsItem *item = 0; + QGraphicsItemPrivate *itemd = 0; + const int oldUnpolishedCount = unpolishedItems.count(); + + for (int i = 0; i < oldUnpolishedCount; ++i) { + item = unpolishedItems.at(i); + if (!item) + continue; + itemd = item->d_ptr.data(); + itemd->pendingPolish = false; + if (!itemd->explicitlyHidden) { item->itemChange(QGraphicsItem::ItemVisibleChange, booleanTrueVariant); item->itemChange(QGraphicsItem::ItemVisibleHasChanged, booleanTrueVariant); } - if (item->isWidget()) { + if (itemd->isWidget) { QEvent event(QEvent::Polish); QApplication::sendEvent((QGraphicsWidget *)item, &event); } } + + if (unpolishedItems.count() == oldUnpolishedCount) { + // No new items were added to the vector. + unpolishedItems.clear(); + } else { + // New items were appended; keep them and remove the old ones. + unpolishedItems.remove(0, oldUnpolishedCount); + unpolishedItems.squeeze(); + QMetaObject::invokeMethod(q_ptr, "_q_polishItems", Qt::QueuedConnection); + } } void QGraphicsScenePrivate::_q_processDirtyItems() @@ -596,7 +618,7 @@ if (parentItem->scene()) { Q_ASSERT_X(parentItem->scene() == q, "QGraphicsScene::removeItem", "Parent item's scene is different from this item's scene"); - item->d_ptr->setParentItemHelper(0); + item->setParentItem(0); } } else { unregisterTopLevelItem(item); @@ -635,7 +657,12 @@ selectedItems.remove(item); hoverItems.removeAll(item); cachedItemsUnderMouse.removeAll(item); - unpolishedItems.remove(item); + if (item->d_ptr->pendingPolish) { + const int unpolishedIndex = unpolishedItems.indexOf(item); + if (unpolishedIndex != -1) + unpolishedItems[unpolishedIndex] = 0; + item->d_ptr->pendingPolish = false; + } resetDirtyItem(item); //We remove all references of item from the sceneEventFilter arrays @@ -774,7 +801,8 @@ // do it ourselves. if (item) { for (int i = 0; i < views.size(); ++i) - views.at(i)->inputContext()->reset(); + if (views.at(i)->inputContext()) + views.at(i)->inputContext()->reset(); } } #endif //QT_NO_IM @@ -1132,8 +1160,9 @@ bool QGraphicsScenePrivate::sendEvent(QGraphicsItem *item, QEvent *event) { if (QGraphicsObject *object = item->toGraphicsObject()) { - if (qt_gestureManager) { - if (qt_gestureManager->filterEvent(object, event)) + QGestureManager *gestureManager = QApplicationPrivate::instance()->gestureManager; + if (gestureManager) { + if (gestureManager->filterEvent(object, event)) return true; } } @@ -1561,7 +1590,10 @@ } /*! - Destroys the QGraphicsScene object. + Removes and deletes all items from the scene object + before destroying the scene object. The scene object + is removed from the application's global scene list, + and it is removed from all associated views. */ QGraphicsScene::~QGraphicsScene() { @@ -1928,7 +1960,7 @@ \since 4.3 This convenience function is equivalent to calling items(QRectF(\a x, \a y, \a w, \a h), \a mode). - + This function is deprecated and returns incorrect results if the scene contains items that ignore transformations. Use the overload that takes a QTransform instead. @@ -2443,23 +2475,26 @@ } /*! - Adds or moves the item \a item and all its childen to the scene. + Adds or moves the \a item and all its childen to this scene. + This scene takes ownership of the \a item. If the item is visible (i.e., QGraphicsItem::isVisible() returns true), QGraphicsScene will emit changed() once control goes back to the event loop. - If the item is already in a different scene, it will first be removed from - its old scene, and then added to this scene as a top-level. - - QGraphicsScene will send ItemSceneChange notifications to \a item while - it is added to the scene. If item does not currently belong to a scene, only one - notification is sent. If it does belong to scene already (i.e., it is - moved to this scene), QGraphicsScene will send an addition notification as - the item is removed from its previous scene. - - If the item is a panel, the scene is active, and there is no active panel - in the scene, then the item will be activated. + If the item is already in a different scene, it will first be + removed from its old scene, and then added to this scene as a + top-level. + + QGraphicsScene will send ItemSceneChange notifications to \a item + while it is added to the scene. If item does not currently belong + to a scene, only one notification is sent. If it does belong to + scene already (i.e., it is moved to this scene), QGraphicsScene + will send an addition notification as the item is removed from its + previous scene. + + If the item is a panel, the scene is active, and there is no + active panel in the scene, then the item will be activated. \sa removeItem(), addEllipse(), addLine(), addPath(), addPixmap(), addRect(), addText(), addWidget(), {QGraphicsItem#Sorting}{Sorting} @@ -2471,12 +2506,12 @@ qWarning("QGraphicsScene::addItem: cannot add null item"); return; } - if (item->scene() == this) { + if (item->d_ptr->scene == this) { qWarning("QGraphicsScene::addItem: item has already been added to this scene"); return; } // Remove this item from its existing scene - if (QGraphicsScene *oldScene = item->scene()) + if (QGraphicsScene *oldScene = item->d_ptr->scene) oldScene->removeItem(item); // Notify the item that its scene is changing, and allow the item to @@ -2485,15 +2520,20 @@ qVariantFromValue(this))); QGraphicsScene *targetScene = qVariantValue(newSceneVariant); if (targetScene != this) { - if (targetScene && item->scene() != targetScene) + if (targetScene && item->d_ptr->scene != targetScene) targetScene->addItem(item); return; } + if (d->unpolishedItems.isEmpty()) + QMetaObject::invokeMethod(this, "_q_polishItems", Qt::QueuedConnection); + d->unpolishedItems.append(item); + item->d_ptr->pendingPolish = true; + // Detach this item from its parent if the parent's scene is different // from this scene. - if (QGraphicsItem *itemParent = item->parentItem()) { - if (itemParent->scene() != this) + if (QGraphicsItem *itemParent = item->d_ptr->parent) { + if (itemParent->d_ptr->scene != this) item->setParentItem(0); } @@ -2523,7 +2563,7 @@ d->enableMouseTrackingOnViews(); } #ifndef QT_NO_CURSOR - if (d->allItemsUseDefaultCursor && item->hasCursor()) { + if (d->allItemsUseDefaultCursor && item->d_ptr->hasCursor) { d->allItemsUseDefaultCursor = false; if (d->allItemsIgnoreHoverEvents) // already enabled otherwise d->enableMouseTrackingOnViews(); @@ -2531,7 +2571,7 @@ #endif //QT_NO_CURSOR // Enable touch events if the item accepts touch events. - if (d->allItemsIgnoreTouchEvents && item->acceptTouchEvents()) { + if (d->allItemsIgnoreTouchEvents && item->d_ptr->acceptTouchEvents) { d->allItemsIgnoreTouchEvents = false; d->enableTouchEventsOnViews(); } @@ -2564,16 +2604,14 @@ } // Add all children recursively - foreach (QGraphicsItem *child, item->children()) - addItem(child); + item->d_ptr->ensureSortedChildren(); + for (int i = 0; i < item->d_ptr->children.size(); ++i) + addItem(item->d_ptr->children.at(i)); // Resolve font and palette. item->d_ptr->resolveFont(d->font.resolve()); item->d_ptr->resolvePalette(d->palette.resolve()); - if (d->unpolishedItems.isEmpty()) - QMetaObject::invokeMethod(this, "_q_polishItems", Qt::QueuedConnection); - d->unpolishedItems.insert(item); // Reenable selectionChanged() for individual items --d->selectionChanging; @@ -2607,7 +2645,7 @@ } } - if (item->flags() & QGraphicsItem::ItemSendsScenePositionChanges) + if (item->d_ptr->flags & QGraphicsItem::ItemSendsScenePositionChanges) d->registerScenePosItem(item); // Ensure that newly added items that have subfocus set, gain @@ -3754,10 +3792,10 @@ bool QGraphicsScenePrivate::itemAcceptsHoverEvents_helper(const QGraphicsItem *item) const { - return (!item->isBlockedByModalPanel() && - (item->acceptHoverEvents() - || (item->isWidget() - && static_cast(item)->d_func()->hasDecoration()))); + return (item->d_ptr->acceptsHover + || (item->d_ptr->isWidget + && static_cast(item)->d_func()->hasDecoration())) + && !item->isBlockedByModalPanel(); } /*! @@ -4570,6 +4608,7 @@ if (!unpolishedItems.isEmpty()) _q_polishItems(); + updateAll = false; QRectF exposedSceneRect; if (exposedRegion && indexMethod != QGraphicsScene::NoIndex) { exposedSceneRect = exposedRegion->boundingRect().adjusted(-1, -1, 1, 1); @@ -4597,7 +4636,7 @@ return; // Item has neither contents nor children!(?) const qreal opacity = item->d_ptr->combineOpacityFromParent(parentOpacity); - const bool itemIsFullyTransparent = (opacity < 0.0001); + const bool itemIsFullyTransparent = QGraphicsItemPrivate::isOpacityNull(opacity); if (itemIsFullyTransparent && (!itemHasChildren || item->d_ptr->childrenCombineOpacity())) return; @@ -4640,7 +4679,8 @@ if (widget) item->d_ptr->paintedViewBoundingRects.insert(widget, viewBoundingRect); viewBoundingRect.adjust(-1, -1, 1, 1); - drawItem = exposedRegion ? exposedRegion->intersects(viewBoundingRect) : !viewBoundingRect.isEmpty(); + drawItem = exposedRegion ? exposedRegion->intersects(viewBoundingRect) + : !viewBoundingRect.normalized().isEmpty(); if (!drawItem) { if (!itemHasChildren) return; @@ -4674,8 +4714,31 @@ if (sourced->currentCachedSystem() != Qt::LogicalCoordinates && sourced->lastEffectTransform != painter->worldTransform()) { + bool unclipped = false; + if (sourced->lastEffectTransform.type() <= QTransform::TxTranslate + && painter->worldTransform().type() <= QTransform::TxTranslate) + { + QRectF itemRect = item->boundingRect(); + if (!item->d_ptr->children.isEmpty()) + itemRect |= item->childrenBoundingRect(); + + QRectF oldSourceRect = sourced->lastEffectTransform.mapRect(itemRect); + QRectF newSourceRect = painter->worldTransform().mapRect(itemRect); + + QRect oldEffectRect = sourced->paddedEffectRect(sourced->currentCachedSystem(), sourced->currentCachedMode(), oldSourceRect); + QRect newEffectRect = sourced->paddedEffectRect(sourced->currentCachedSystem(), sourced->currentCachedMode(), newSourceRect); + + QRect deviceRect(0, 0, painter->device()->width(), painter->device()->height()); + if (deviceRect.contains(oldEffectRect) && deviceRect.contains(newEffectRect)) { + sourced->setCachedOffset(newEffectRect.topLeft()); + unclipped = true; + } + } + sourced->lastEffectTransform = painter->worldTransform(); - sourced->invalidateCache(QGraphicsEffectSourcePrivate::TransformChanged); + + if (!unclipped) + sourced->invalidateCache(QGraphicsEffectSourcePrivate::TransformChanged); } item->d_ptr->graphicsEffect->draw(painter); @@ -4694,7 +4757,7 @@ qreal opacity, const QTransform *effectTransform, bool wasDirtyParentSceneTransform, bool drawItem) { - const bool itemIsFullyTransparent = (opacity < 0.0001); + const bool itemIsFullyTransparent = QGraphicsItemPrivate::isOpacityNull(opacity); const bool itemClipsChildrenToShape = (item->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape); const bool itemHasChildren = !item->d_ptr->children.isEmpty(); @@ -4709,7 +4772,12 @@ painter->setWorldTransform(*transformPtr * *effectTransform); else painter->setWorldTransform(*transformPtr); - painter->setClipPath(item->shape(), Qt::IntersectClip); + QRectF clipRect; + const QPainterPath clipPath(item->shape()); + if (QPathClipper::pathToRect(clipPath, &clipRect)) + painter->setClipRect(clipRect, Qt::IntersectClip); + else + painter->setClipPath(clipPath, Qt::IntersectClip); } // Draw children behind @@ -4745,8 +4813,14 @@ painter->setWorldTransform(*transformPtr); } - if (itemClipsToShape) - painter->setClipPath(item->shape(), Qt::IntersectClip); + if (itemClipsToShape) { + QRectF clipRect; + const QPainterPath clipPath(item->shape()); + if (QPathClipper::pathToRect(clipPath, &clipRect)) + painter->setClipRect(clipRect, Qt::IntersectClip); + else + painter->setClipPath(clipPath, Qt::IntersectClip); + } painter->setOpacity(opacity); if (!item->d_ptr->cacheMode && !item->d_ptr->isWidget) @@ -4776,7 +4850,8 @@ } void QGraphicsScenePrivate::markDirty(QGraphicsItem *item, const QRectF &rect, bool invalidateChildren, - bool force, bool ignoreOpacity, bool removingItemFromScene) + bool force, bool ignoreOpacity, bool removingItemFromScene, + bool updateBoundingRect) { Q_ASSERT(item); if (updateAll) @@ -4847,17 +4922,8 @@ if (ignoreOpacity) item->d_ptr->ignoreOpacity = 1; - QGraphicsItem *p = item->d_ptr->parent; - while (p) { - p->d_ptr->dirtyChildren = 1; -#ifndef QT_NO_GRAPHICSEFFECT - if (p->d_ptr->graphicsEffect && p->d_ptr->graphicsEffect->isEnabled()) { - p->d_ptr->dirty = 1; - p->d_ptr->fullUpdatePending = 1; - } -#endif //QT_NO_GRAPHICSEFFECT - p = p->d_ptr->parent; - } + if (!updateBoundingRect) + item->d_ptr->markParentDirty(); } static inline bool updateHelper(QGraphicsViewPrivate *view, QGraphicsItemPrivate *item, @@ -4932,7 +4998,8 @@ } const qreal opacity = item->d_ptr->combineOpacityFromParent(parentOpacity); - const bool itemIsFullyTransparent = !item->d_ptr->ignoreOpacity && opacity < 0.0001; + const bool itemIsFullyTransparent = !item->d_ptr->ignoreOpacity + && QGraphicsItemPrivate::isOpacityNull(opacity); if (itemIsFullyTransparent && (!itemHasChildren || item->d_ptr->childrenCombineOpacity())) { resetDirtyItem(item, /*recursive=*/itemHasChildren); return; @@ -5067,6 +5134,8 @@ } /*! + \obsolete + Paints the given \a items using the provided \a painter, after the background has been drawn, and before the foreground has been drawn. All painting is done in \e scene coordinates. Before @@ -5089,6 +5158,10 @@ \snippet doc/src/snippets/graphicssceneadditemsnippet.cpp 0 + Since Qt 4.6, this function is not called anymore unless + the QGraphicsView::IndirectPainting flag is given as an Optimization + flag. + \sa drawBackground(), drawForeground() */ void QGraphicsScene::drawItems(QPainter *painter, @@ -5101,6 +5174,7 @@ if (!d->unpolishedItems.isEmpty()) d->_q_polishItems(); + d->updateAll = false; QTransform viewTransform = painter->worldTransform(); Q_UNUSED(options); @@ -5640,8 +5714,15 @@ item->d_ptr->acceptedTouchBeginEvent = true; bool res = sendTouchBeginEvent(item, &touchEvent) && touchEvent.isAccepted(); - if (!res) + if (!res) { + // forget about these touch points, we didn't handle them + for (int i = 0; i < touchEvent.touchPoints().count(); ++i) { + const QTouchEvent::TouchPoint &touchPoint = touchEvent.touchPoints().at(i); + itemForTouchPointId.remove(touchPoint.id()); + sceneCurrentTouchPoints.remove(touchPoint.id()); + } ignoreSceneTouchEvent = false; + } break; } default: @@ -5832,13 +5913,21 @@ QList items = itemsAtPosition(screenPos, QPointF(), viewport); QList result; for (int j = 0; j < items.size(); ++j) { - QGraphicsObject *item = items.at(j)->toGraphicsObject(); - if (!item) - continue; - QGraphicsItemPrivate *d = item->QGraphicsItem::d_func(); - if (d->gestureContext.contains(gestureType)) { - result.append(item); + QGraphicsItem *item = items.at(j); + + // Check if the item is blocked by a modal panel and use it as + // a target instead of this item. + (void) item->isBlockedByModalPanel(&item); + + if (QGraphicsObject *itemobj = item->toGraphicsObject()) { + QGraphicsItemPrivate *d = item->d_func(); + if (d->gestureContext.contains(gestureType)) { + result.append(itemobj); + } } + // Don't propagate through panels. + if (item->isPanel()) + break; } DEBUG() << "QGraphicsScenePrivate::getGestureTargets:" << gesture << result; @@ -6142,9 +6231,10 @@ } } - Q_ASSERT(qt_gestureManager); // it would be very odd if we got called without a manager. + QGestureManager *gestureManager = QApplicationPrivate::instance()->gestureManager; + Q_ASSERT(gestureManager); // it would be very odd if we got called without a manager. for (setIter = canceledGestures.begin(); setIter != canceledGestures.end(); ++setIter) { - qt_gestureManager->recycle(*setIter); + gestureManager->recycle(*setIter); gestureTargets.remove(*setIter); } }