Changeset 561 for trunk/src/gui/graphicsview/qgraphicsscene.cpp
- Timestamp:
- Feb 11, 2010, 11:19:06 PM (15 years ago)
- Location:
- trunk
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk
-
Property svn:mergeinfo
set to (toggle deleted branches)
/branches/vendor/nokia/qt/4.6.1 merged eligible /branches/vendor/nokia/qt/current merged eligible /branches/vendor/trolltech/qt/current 3-149
-
Property svn:mergeinfo
set to (toggle deleted branches)
-
trunk/src/gui/graphicsview/qgraphicsscene.cpp
r2 r561 2 2 ** 3 3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). 4 ** Contact: Qt Software Information (qt-info@nokia.com) 4 ** All rights reserved. 5 ** Contact: Nokia Corporation (qt-info@nokia.com) 5 6 ** 6 7 ** This file is part of the QtGui module of the Qt Toolkit. … … 21 22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. 22 23 ** 23 ** In addition, as a special exception, Nokia gives you certain 24 ** additional rights. These rights are described in the Nokia Qt LGPL 25 ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this 26 ** package. 24 ** In addition, as a special exception, Nokia gives you certain additional 25 ** rights. These rights are described in the Nokia Qt LGPL Exception 26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. 27 27 ** 28 28 ** GNU General Public License Usage … … 34 34 ** met: http://www.gnu.org/copyleft/gpl.html. 35 35 ** 36 ** If you are unsure which license is appropriate for your use, please37 ** contact the sales department at qt-sales@nokia.com.36 ** If you have questions regarding the use of this file, please contact 37 ** Nokia at qt-info@nokia.com. 38 38 ** $QT_END_LICENSE$ 39 39 ** 40 40 ****************************************************************************/ 41 42 static const int QGRAPHICSSCENE_INDEXTIMER_TIMEOUT = 2000;43 41 44 42 /*! … … 47 45 number of 2D graphical items. 48 46 \since 4.2 49 \ingroup multimedia50 47 \ingroup graphicsview-api 51 \mainclass 48 52 49 53 50 The class serves as a container for QGraphicsItems. It is used together … … 220 217 #include "qgraphicswidget.h" 221 218 #include "qgraphicswidget_p.h" 219 #include "qgraphicssceneindex_p.h" 220 #include "qgraphicsscenebsptreeindex_p.h" 221 #include "qgraphicsscenelinearindex_p.h" 222 222 223 223 #include <QtCore/qdebug.h> … … 243 243 #include <QtGui/qtooltip.h> 244 244 #include <QtGui/qtransform.h> 245 #include <QtGui/qinputcontext.h> 246 #include <QtGui/qgraphicseffect.h> 245 247 #include <private/qapplication_p.h> 246 248 #include <private/qobject_p.h> … … 248 250 #include <private/qt_x11_p.h> 249 251 #endif 252 #include <private/qgraphicseffect_p.h> 253 #include <private/qgesturemanager_p.h> 254 255 // #define GESTURE_DEBUG 256 #ifndef GESTURE_DEBUG 257 # define DEBUG if (0) qDebug 258 #else 259 # define DEBUG qDebug 260 #endif 250 261 251 262 QT_BEGIN_NAMESPACE 252 263 253 static inline bool QRectF_intersects(const QRectF &s, const QRectF &r) 254 { 255 qreal xp = s.left(); 256 qreal yp = s.top(); 257 qreal w = s.width(); 258 qreal h = s.height(); 259 qreal l1 = xp; 260 qreal r1 = xp; 261 if (w < 0) 262 l1 += w; 263 else 264 r1 += w; 265 266 qreal l2 = r.left(); 267 qreal r2 = r.left(); 268 if (w < 0) 269 l2 += r.width(); 270 else 271 r2 += r.width(); 272 273 if (l1 >= r2 || l2 >= r1) 274 return false; 275 276 qreal t1 = yp; 277 qreal b1 = yp; 278 if (h < 0) 279 t1 += h; 280 else 281 b1 += h; 282 283 qreal t2 = r.top(); 284 qreal b2 = r.top(); 285 if (r.height() < 0) 286 t2 += r.height(); 287 else 288 b2 += r.height(); 289 290 return !(t1 >= b2 || t2 >= b1); 291 } 292 293 // QRectF::intersects() returns false always if either the source or target 294 // rectangle's width or height are 0. This works around that problem. 295 static inline void _q_adjustRect(QRectF *rect) 296 { 297 Q_ASSERT(rect); 298 if (!rect->width()) 299 rect->adjust(-0.00001, 0, 0.00001, 0); 300 if (!rect->height()) 301 rect->adjust(0, -0.00001, 0, 0.00001); 302 } 303 304 static inline QRectF adjustedItemBoundingRect(const QGraphicsItem *item) 305 { 306 Q_ASSERT(item); 307 QRectF boundingRect(item->boundingRect()); 308 _q_adjustRect(&boundingRect); 309 return boundingRect; 310 } 264 bool qt_sendSpontaneousEvent(QObject *receiver, QEvent *event); 311 265 312 266 static void _q_hoverFromMouseEvent(QGraphicsSceneHoverEvent *hover, const QGraphicsSceneMouseEvent *mouseEvent) … … 323 277 } 324 278 279 int QGraphicsScenePrivate::changedSignalIndex; 280 325 281 /*! 326 282 \internal 327 283 */ 328 284 QGraphicsScenePrivate::QGraphicsScenePrivate() 329 : changedSignalMask(0), 330 indexMethod(QGraphicsScene::BspTreeIndex), 331 bspTreeDepth(0), 285 : indexMethod(QGraphicsScene::BspTreeIndex), 286 index(0), 332 287 lastItemCount(0), 333 288 hasSceneRect(false), 289 dirtyGrowingItemsBoundingRect(true), 334 290 updateAll(false), 335 291 calledEmitUpdated(false), 292 processDirtyItemsEmitted(false), 336 293 selectionChanging(0), 337 dirtyItemResetPending(false),338 regenerateIndex(true),339 purgePending(false),340 indexTimerId(0),341 restartIndexTimer(false),294 needSortTopLevelItems(true), 295 unpolishedItemsModified(true), 296 holesInTopLevelSiblingIndex(false), 297 topLevelSequentialOrdering(true), 298 scenePosDescendantsUpdatePending(false), 342 299 stickyFocus(false), 343 300 hasFocus(false), … … 345 302 lastFocusItem(0), 346 303 tabFocusFirst(0), 347 activeWindow(0), 304 activePanel(0), 305 lastActivePanel(0), 348 306 activationRefCount(0), 307 childExplicitActivation(0), 349 308 lastMouseGrabberItem(0), 350 309 lastMouseGrabberItemHasImplicitMouseGrab(false), … … 352 311 enterWidget(0), 353 312 lastDropAction(Qt::IgnoreAction), 313 allItemsIgnoreHoverEvents(true), 314 allItemsUseDefaultCursor(true), 354 315 painterStateProtection(true), 355 316 sortCacheEnabled(false), 356 updatingSortCache(false),357 style(0)317 style(0), 318 allItemsIgnoreTouchEvents(true) 358 319 { 359 320 } … … 366 327 Q_Q(QGraphicsScene); 367 328 329 index = new QGraphicsSceneBspTreeIndex(q); 330 368 331 // Keep this index so we can check for connected slots later on. 369 changedSignalMask = (1 << q->metaObject()->indexOfSignal("changed(QList<QRectF>)")); 332 if (!changedSignalIndex) { 333 changedSignalIndex = signalIndex("changed(QList<QRectF>)"); 334 } 370 335 qApp->d_func()->scene_list.append(q); 371 336 q->update(); … … 375 340 \internal 376 341 */ 377 QList<QGraphicsItem *> QGraphicsScenePrivate::estimateItemsInRect(const QRectF &rect) const 378 { 379 const_cast<QGraphicsScenePrivate *>(this)->purgeRemovedItems(); 380 const_cast<QGraphicsScenePrivate *>(this)->_q_updateSortCache(); 381 382 if (indexMethod == QGraphicsScene::BspTreeIndex) { 383 // ### Only do this once in a while. 384 QGraphicsScenePrivate *that = const_cast<QGraphicsScenePrivate *>(this); 385 386 // Get items from BSP tree 387 QList<QGraphicsItem *> items = that->bspTree.items(rect); 388 389 // Fill in with any unindexed items 390 for (int i = 0; i < unindexedItems.size(); ++i) { 391 if (QGraphicsItem *item = unindexedItems.at(i)) { 392 if (!item->d_ptr->itemDiscovered && item->d_ptr->visible && !(item->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren)) { 393 QRectF boundingRect = item->sceneBoundingRect(); 394 if (QRectF_intersects(boundingRect, rect)) { 395 item->d_ptr->itemDiscovered = 1; 396 items << item; 397 } 398 } 399 } 400 } 401 402 // Reset the discovered state of all discovered items 403 for (int i = 0; i < items.size(); ++i) 404 items.at(i)->d_func()->itemDiscovered = 0; 405 return items; 406 } 407 408 QList<QGraphicsItem *> itemsInRect; 409 for (int i = 0; i < unindexedItems.size(); ++i) { 410 if (QGraphicsItem *item = unindexedItems.at(i)) { 411 if (item->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren) 412 continue; 413 if (item->d_ptr->visible && item->effectiveOpacity() > qreal(0.0)) 414 itemsInRect << item; 415 } 416 } 417 for (int i = 0; i < indexedItems.size(); ++i) { 418 if (QGraphicsItem *item = indexedItems.at(i)) { 419 if (item->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren) 420 continue; 421 if (item->d_ptr->visible && item->effectiveOpacity() > qreal(0.0)) 422 itemsInRect << item; 423 } 424 } 425 426 return itemsInRect; 427 } 428 429 /*! 430 \internal 431 */ 432 void QGraphicsScenePrivate::addToIndex(QGraphicsItem *item) 433 { 434 if (indexMethod == QGraphicsScene::BspTreeIndex) { 435 if (item->d_func()->index != -1) { 436 bspTree.insertItem(item, item->sceneBoundingRect()); 437 foreach (QGraphicsItem *child, item->children()) 438 child->addToIndex(); 439 } else { 440 // The BSP tree is regenerated if the number of items grows to a 441 // certain threshold, or if the bounding rect of the graph doubles in 442 // size. 443 startIndexTimer(); 444 } 445 } 446 } 447 448 /*! 449 \internal 450 */ 451 void QGraphicsScenePrivate::removeFromIndex(QGraphicsItem *item) 452 { 453 if (indexMethod == QGraphicsScene::BspTreeIndex) { 454 int index = item->d_func()->index; 455 if (index != -1) { 456 bspTree.removeItem(item, item->sceneBoundingRect()); 457 freeItemIndexes << index; 458 indexedItems[index] = 0; 459 item->d_func()->index = -1; 460 unindexedItems << item; 461 462 foreach (QGraphicsItem *child, item->children()) 463 child->removeFromIndex(); 464 } 465 466 startIndexTimer(); 467 } 468 } 469 470 /*! 471 \internal 472 */ 473 void QGraphicsScenePrivate::resetIndex() 474 { 475 purgeRemovedItems(); 476 if (indexMethod == QGraphicsScene::BspTreeIndex) { 477 for (int i = 0; i < indexedItems.size(); ++i) { 478 if (QGraphicsItem *item = indexedItems.at(i)) { 479 item->d_ptr->index = -1; 480 unindexedItems << item; 481 } 482 } 483 indexedItems.clear(); 484 freeItemIndexes.clear(); 485 regenerateIndex = true; 486 startIndexTimer(); 487 } 488 } 489 490 static inline int intmaxlog(int n) 491 { 492 return (n > 0 ? qMax(qCeil(qLn(qreal(n)) / qLn(qreal(2))), 5) : 0); 493 } 494 495 /*! 496 \internal 497 */ 498 void QGraphicsScenePrivate::_q_updateIndex() 499 { 500 if (!indexTimerId) 501 return; 502 503 Q_Q(QGraphicsScene); 504 q->killTimer(indexTimerId); 505 indexTimerId = 0; 506 507 purgeRemovedItems(); 508 509 // Add unindexedItems to indexedItems 510 QRectF unindexedItemsBoundingRect; 511 for (int i = 0; i < unindexedItems.size(); ++i) { 512 if (QGraphicsItem *item = unindexedItems.at(i)) { 513 unindexedItemsBoundingRect |= item->sceneBoundingRect(); 514 if (!freeItemIndexes.isEmpty()) { 515 int freeIndex = freeItemIndexes.takeFirst(); 516 item->d_func()->index = freeIndex; 517 indexedItems[freeIndex] = item; 518 } else { 519 item->d_func()->index = indexedItems.size(); 520 indexedItems << item; 521 } 522 } 523 } 524 525 // Update growing scene rect. 526 QRectF oldGrowingItemsBoundingRect = growingItemsBoundingRect; 527 growingItemsBoundingRect |= unindexedItemsBoundingRect; 528 529 // Determine whether we should regenerate the BSP tree. 530 if (indexMethod == QGraphicsScene::BspTreeIndex) { 531 int depth = bspTreeDepth; 532 if (depth == 0) { 533 int oldDepth = intmaxlog(lastItemCount); 534 depth = intmaxlog(indexedItems.size()); 535 static const int slack = 100; 536 if (bspTree.leafCount() == 0 || (oldDepth != depth && qAbs(lastItemCount - indexedItems.size()) > slack)) { 537 // ### Crude algorithm. 538 regenerateIndex = true; 539 } 540 } 541 542 // Regenerate the tree. 543 if (regenerateIndex) { 544 regenerateIndex = false; 545 bspTree.initialize(q->sceneRect(), depth); 546 unindexedItems = indexedItems; 547 lastItemCount = indexedItems.size(); 548 q->update(); 549 550 // Take this opportunity to reset our largest-item counter for 551 // untransformable items. When the items are inserted into the BSP 552 // tree, we'll get an accurate calculation. 553 largestUntransformableItem = QRectF(); 554 } 555 } 556 557 // Insert all unindexed items into the tree. 558 for (int i = 0; i < unindexedItems.size(); ++i) { 559 if (QGraphicsItem *item = unindexedItems.at(i)) { 560 QRectF rect = item->sceneBoundingRect(); 561 if (item->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren) 562 continue; 563 if (indexMethod == QGraphicsScene::BspTreeIndex) 564 bspTree.insertItem(item, rect); 565 566 // If the item ignores view transformations, update our 567 // largest-item-counter to ensure that the view can accurately 568 // discover untransformable items when drawing. 569 if (item->d_ptr->itemIsUntransformable()) { 570 QGraphicsItem *topmostUntransformable = item; 571 while (topmostUntransformable && (topmostUntransformable->d_ptr->ancestorFlags 572 & QGraphicsItemPrivate::AncestorIgnoresTransformations)) { 573 topmostUntransformable = topmostUntransformable->parentItem(); 574 } 575 // ### Verify that this is the correct largest untransformable rectangle. 576 largestUntransformableItem |= item->mapToItem(topmostUntransformable, item->boundingRect()).boundingRect(); 577 } 578 } 579 } 580 unindexedItems.clear(); 581 582 // Notify scene rect changes. 583 if (!hasSceneRect && growingItemsBoundingRect != oldGrowingItemsBoundingRect) 584 emit q->sceneRectChanged(growingItemsBoundingRect); 585 } 586 587 /*! 588 \internal 589 */ 342 QGraphicsScenePrivate *QGraphicsScenePrivate::get(QGraphicsScene *q) 343 { 344 return q->d_func(); 345 } 346 590 347 void QGraphicsScenePrivate::_q_emitUpdated() 591 348 { 592 349 Q_Q(QGraphicsScene); 593 350 calledEmitUpdated = false; 351 352 if (dirtyGrowingItemsBoundingRect) { 353 if (!hasSceneRect) { 354 const QRectF oldGrowingItemsBoundingRect = growingItemsBoundingRect; 355 growingItemsBoundingRect |= q->itemsBoundingRect(); 356 if (oldGrowingItemsBoundingRect != growingItemsBoundingRect) 357 emit q->sceneRectChanged(growingItemsBoundingRect); 358 } 359 dirtyGrowingItemsBoundingRect = false; 360 } 594 361 595 362 // Ensure all views are connected if anything is connected. This disables … … 597 364 // needs to happen in order to keep compatibility with the behavior from 598 365 // Qt 4.4 and backward. 599 if ( !views.isEmpty() && (connectedSignals & changedSignalMask)) {366 if (isSignalConnected(changedSignalIndex)) { 600 367 for (int i = 0; i < views.size(); ++i) { 601 368 QGraphicsView *view = views.at(i); … … 606 373 } 607 374 } 608 } 609 610 // Ensure all dirty items's current positions are recorded in the list of 611 // updated rects. 612 for (int i = 0; i < dirtyItems.size(); ++i) 613 updatedRects += dirtyItems.at(i)->sceneBoundingRect(); 375 } else { 376 updateAll = false; 377 for (int i = 0; i < views.size(); ++i) 378 views.at(i)->d_func()->processPendingUpdates(); 379 // It's important that we update all views before we dispatch, hence two for-loops. 380 for (int i = 0; i < views.size(); ++i) 381 views.at(i)->d_func()->dispatchPendingUpdateRequests(); 382 return; 383 } 614 384 615 385 // Notify the changes to anybody interested. … … 624 394 \internal 625 395 626 Updates all items in the pending update list. At this point, the list is627 unlikely to contain partially constructed items. 628 */ 629 void QGraphicsScenePrivate::_q_updateLater() 630 { 631 foreach (QGraphicsItem *item, pendingUpdateItems)632 item->update();633 pendingUpdateItems.clear();396 ### This function is almost identical to QGraphicsItemPrivate::addChild(). 397 */ 398 void QGraphicsScenePrivate::registerTopLevelItem(QGraphicsItem *item) 399 { 400 item->d_ptr->ensureSequentialSiblingIndex(); 401 needSortTopLevelItems = true; // ### maybe false 402 item->d_ptr->siblingIndex = topLevelItems.size(); 403 topLevelItems.append(item); 634 404 } 635 405 636 406 /*! 637 407 \internal 408 409 ### This function is almost identical to QGraphicsItemPrivate::removeChild(). 410 */ 411 void QGraphicsScenePrivate::unregisterTopLevelItem(QGraphicsItem *item) 412 { 413 if (!holesInTopLevelSiblingIndex) 414 holesInTopLevelSiblingIndex = item->d_ptr->siblingIndex != topLevelItems.size() - 1; 415 if (topLevelSequentialOrdering && !holesInTopLevelSiblingIndex) 416 topLevelItems.removeAt(item->d_ptr->siblingIndex); 417 else 418 topLevelItems.removeOne(item); 419 // NB! Do not use topLevelItems.removeAt(item->d_ptr->siblingIndex) because 420 // the item is not guaranteed to be at the index after the list is sorted 421 // (see ensureSortedTopLevelItems()). 422 item->d_ptr->siblingIndex = -1; 423 if (topLevelSequentialOrdering) 424 topLevelSequentialOrdering = !holesInTopLevelSiblingIndex; 425 } 426 427 /*! 428 \internal 638 429 */ 639 430 void QGraphicsScenePrivate::_q_polishItems() 640 431 { 432 QSet<QGraphicsItem *>::Iterator it = unpolishedItems.begin(); 641 433 const QVariant booleanTrueVariant(true); 642 foreach (QGraphicsItem *item, unpolishedItems) { 434 while (!unpolishedItems.isEmpty()) { 435 QGraphicsItem *item = *it; 436 it = unpolishedItems.erase(it); 437 unpolishedItemsModified = false; 643 438 if (!item->d_ptr->explicitlyHidden) { 644 439 item->itemChange(QGraphicsItem::ItemVisibleChange, booleanTrueVariant); … … 649 444 QApplication::sendEvent((QGraphicsWidget *)item, &event); 650 445 } 651 } 652 unpolishedItems.clear(); 446 if (unpolishedItemsModified) 447 it = unpolishedItems.begin(); 448 } 449 } 450 451 void QGraphicsScenePrivate::_q_processDirtyItems() 452 { 453 processDirtyItemsEmitted = false; 454 455 if (updateAll) { 456 Q_ASSERT(calledEmitUpdated); 457 // No need for further processing (except resetting the dirty states). 458 // The growingItemsBoundingRect is updated in _q_emitUpdated. 459 for (int i = 0; i < topLevelItems.size(); ++i) 460 resetDirtyItem(topLevelItems.at(i), /*recursive=*/true); 461 return; 462 } 463 464 const bool wasPendingSceneUpdate = calledEmitUpdated; 465 const QRectF oldGrowingItemsBoundingRect = growingItemsBoundingRect; 466 467 // Process items recursively. 468 for (int i = 0; i < topLevelItems.size(); ++i) 469 processDirtyItemsRecursive(topLevelItems.at(i)); 470 471 dirtyGrowingItemsBoundingRect = false; 472 if (!hasSceneRect && oldGrowingItemsBoundingRect != growingItemsBoundingRect) 473 emit q_func()->sceneRectChanged(growingItemsBoundingRect); 474 475 if (wasPendingSceneUpdate) 476 return; 477 478 for (int i = 0; i < views.size(); ++i) 479 views.at(i)->d_func()->processPendingUpdates(); 480 481 if (calledEmitUpdated) { 482 // We did a compatibility QGraphicsScene::update in processDirtyItemsRecursive 483 // and we cannot wait for the control to reach the eventloop before the 484 // changed signal is emitted, so we emit it now. 485 _q_emitUpdated(); 486 } 487 488 // Immediately dispatch all pending update requests on the views. 489 for (int i = 0; i < views.size(); ++i) 490 views.at(i)->d_func()->dispatchPendingUpdateRequests(); 653 491 } 654 492 … … 656 494 \internal 657 495 */ 658 void QGraphicsScenePrivate::_q_resetDirtyItems() 659 { 660 for (int i = 0; i < dirtyItems.size(); ++i) { 661 QGraphicsItem *item = dirtyItems.at(i); 662 item->d_ptr->dirty = 0; 663 item->d_ptr->dirtyChildren = 0; 664 } 665 dirtyItems.clear(); 666 dirtyItemResetPending = false; 496 void QGraphicsScenePrivate::setScenePosItemEnabled(QGraphicsItem *item, bool enabled) 497 { 498 QGraphicsItem *p = item->d_ptr->parent; 499 while (p) { 500 p->d_ptr->scenePosDescendants = enabled; 501 p = p->d_ptr->parent; 502 } 503 if (!enabled && !scenePosDescendantsUpdatePending) { 504 scenePosDescendantsUpdatePending = true; 505 QMetaObject::invokeMethod(q_func(), "_q_updateScenePosDescendants", Qt::QueuedConnection); 506 } 667 507 } 668 508 … … 670 510 \internal 671 511 */ 672 void QGraphicsScenePrivate::resetDirtyItemsLater() 673 { 674 Q_Q(QGraphicsScene); 675 if (dirtyItemResetPending) 676 return; 677 // dirtyItems.reserve(indexedItems.size() + unindexedItems.size()); 678 dirtyItemResetPending = true; 679 QMetaObject::invokeMethod(q, "_q_resetDirtyItems", Qt::QueuedConnection); 512 void QGraphicsScenePrivate::registerScenePosItem(QGraphicsItem *item) 513 { 514 scenePosItems.insert(item); 515 setScenePosItemEnabled(item, true); 680 516 } 681 517 682 518 /*! 683 519 \internal 520 */ 521 void QGraphicsScenePrivate::unregisterScenePosItem(QGraphicsItem *item) 522 { 523 scenePosItems.remove(item); 524 setScenePosItemEnabled(item, false); 525 } 526 527 /*! 528 \internal 529 */ 530 void QGraphicsScenePrivate::_q_updateScenePosDescendants() 531 { 532 foreach (QGraphicsItem *item, scenePosItems) { 533 QGraphicsItem *p = item->d_ptr->parent; 534 while (p) { 535 p->d_ptr->scenePosDescendants = 1; 536 p = p->d_ptr->parent; 537 } 538 } 539 scenePosDescendantsUpdatePending = false; 540 } 541 542 /*! 543 \internal 684 544 685 545 Schedules an item for removal. This function leaves some stale indexes 686 around in the BSP tree ; these will be cleaned up the next time someone687 triggers purgeRemovedItems().688 689 Note: This function iscalled from QGraphicsItem's destructor. \a item is546 around in the BSP tree if called from the item's destructor; these will 547 be cleaned up the next time someone triggers purgeRemovedItems(). 548 549 Note: This function might get called from QGraphicsItem's destructor. \a item is 690 550 being destroyed, so we cannot call any pure virtual functions on it (such 691 551 as boundingRect()). Also, it is unnecessary to update the item's own state 692 552 in any way. 693 694 ### Refactoring: This function shares much functionality with removeItem() 695 */ 696 void QGraphicsScenePrivate::_q_removeItemLater(QGraphicsItem *item) 553 */ 554 void QGraphicsScenePrivate::removeItemHelper(QGraphicsItem *item) 697 555 { 698 556 Q_Q(QGraphicsScene); 699 557 700 // Clear focus on the item to remove any reference in the focusWidget 701 // chain. 558 // Clear focus on the item to remove any reference in the focusWidget chain. 702 559 item->clearFocus(); 703 560 704 int index = item->d_func()->index; 705 if (index != -1) { 706 // Important: The index is useless until purgeRemovedItems() is 707 // called. 708 indexedItems[index] = (QGraphicsItem *)0; 709 if (!purgePending) { 710 purgePending = true; 711 q->update(); 712 } 713 removedItems << item; 561 markDirty(item, QRectF(), /*invalidateChildren=*/false, /*force=*/false, 562 /*ignoreOpacity=*/false, /*removingItemFromScene=*/true); 563 564 if (item->d_ptr->inDestructor) { 565 // The item is actually in its destructor, we call the special method in the index. 566 index->deleteItem(item); 714 567 } else { 715 // Recently added items are purged immediately. unindexedItems() never 716 // contains stale items. 717 unindexedItems.removeAll(item); 718 q->update(); 568 // Can potentially call item->boundingRect() (virtual function), that's why 569 // we only can call this function if the item is not in its destructor. 570 index->removeItem(item); 571 } 572 573 item->d_ptr->clearSubFocus(); 574 575 if (item->flags() & QGraphicsItem::ItemSendsScenePositionChanges) 576 unregisterScenePosItem(item); 577 578 QGraphicsScene *oldScene = item->d_func()->scene; 579 item->d_func()->scene = 0; 580 581 //We need to remove all children first because they might use their parent 582 //attributes (e.g. sceneTransform). 583 if (!item->d_ptr->inDestructor) { 584 // Remove all children recursively 585 for (int i = 0; i < item->d_ptr->children.size(); ++i) 586 q->removeItem(item->d_ptr->children.at(i)); 587 } 588 589 if (!item->d_ptr->inDestructor && item == tabFocusFirst) { 590 QGraphicsWidget *widget = static_cast<QGraphicsWidget *>(item); 591 widget->d_func()->fixFocusChainBeforeReparenting(0, oldScene, 0); 592 } 593 594 // Unregister focus proxy. 595 item->d_ptr->resetFocusProxy(); 596 597 // Remove from parent, or unregister from toplevels. 598 if (QGraphicsItem *parentItem = item->parentItem()) { 599 if (parentItem->scene()) { 600 Q_ASSERT_X(parentItem->scene() == q, "QGraphicsScene::removeItem", 601 "Parent item's scene is different from this item's scene"); 602 item->d_ptr->setParentItemHelper(0); 603 } 604 } else { 605 unregisterTopLevelItem(item); 719 606 } 720 607 … … 724 611 if (item == lastFocusItem) 725 612 lastFocusItem = 0; 726 if (item == active Window) {613 if (item == activePanel) { 727 614 // ### deactivate... 728 activeWindow = 0; 615 activePanel = 0; 616 } 617 if (item == lastActivePanel) 618 lastActivePanel = 0; 619 620 // Cancel active touches 621 { 622 QMap<int, QGraphicsItem *>::iterator it = itemForTouchPointId.begin(); 623 while (it != itemForTouchPointId.end()) { 624 if (it.value() == item) { 625 sceneCurrentTouchPoints.remove(it.key()); 626 it = itemForTouchPointId.erase(it); 627 } else { 628 ++it; 629 } 630 } 729 631 } 730 632 … … 736 638 selectedItems.remove(item); 737 639 hoverItems.removeAll(item); 738 pendingUpdateItems.removeAll(item);739 640 cachedItemsUnderMouse.removeAll(item); 740 unpolishedItems.removeAll(item); 741 dirtyItems.removeAll(item); 641 unpolishedItems.remove(item); 642 unpolishedItemsModified = true; 643 resetDirtyItem(item); 742 644 743 645 //We remove all references of item from the sceneEventFilter arrays … … 750 652 } 751 653 752 // Remove from scene transform cache 753 int transformIndex = item->d_func()->sceneTransformIndex; 754 if (transformIndex != -1) { 755 validTransforms.setBit(transformIndex, 0); 756 freeSceneTransformSlots.append(transformIndex); 757 } 758 759 // Remove all children recursively. 760 foreach (QGraphicsItem *child, item->children()) 761 _q_removeItemLater(child); 762 763 // Reset the mouse grabber 654 if (item->isPanel() && item->isVisible() && item->panelModality() != QGraphicsItem::NonModal) 655 leaveModal(item); 656 657 // Reset the mouse grabber and focus item data. 764 658 if (mouseGrabberItems.contains(item)) 765 ungrabMouse(item, /* item is dying */ true);659 ungrabMouse(item, /* item is dying */ item->d_ptr->inDestructor); 766 660 767 661 // Reset the keyboard grabber 768 662 if (keyboardGrabberItems.contains(item)) 769 ungrabKeyboard(item, /* item is dying */ true);663 ungrabKeyboard(item, /* item is dying */ item->d_ptr->inDestructor); 770 664 771 665 // Reset the last mouse grabber item … … 781 675 /*! 782 676 \internal 783 784 Removes stale pointers from all data structures. 785 */ 786 void QGraphicsScenePrivate::purgeRemovedItems() 677 */ 678 void QGraphicsScenePrivate::setActivePanelHelper(QGraphicsItem *item, bool duringActivationEvent) 787 679 { 788 680 Q_Q(QGraphicsScene); 789 790 if (!purgePending && removedItems.isEmpty()) 681 if (item && item->scene() != q) { 682 qWarning("QGraphicsScene::setActivePanel: item %p must be part of this scene", 683 item); 791 684 return; 792 793 // Remove stale items from the BSP tree. 794 if (indexMethod != QGraphicsScene::NoIndex) 795 bspTree.removeItems(removedItems); 796 797 // Purge this list. 798 removedItems.clear(); 799 freeItemIndexes.clear(); 800 for (int i = 0; i < indexedItems.size(); ++i) { 801 if (!indexedItems.at(i)) 802 freeItemIndexes << i; 803 } 804 purgePending = false; 805 806 // No locality info for the items; update the whole scene. 807 q->update(); 685 } 686 687 // Ensure the scene has focus when we change panel activation. 688 q->setFocus(Qt::ActiveWindowFocusReason); 689 690 // Find the item's panel. 691 QGraphicsItem *panel = item ? item->panel() : 0; 692 lastActivePanel = panel ? activePanel : 0; 693 if (panel == activePanel || (!q->isActive() && !duringActivationEvent)) 694 return; 695 696 // Deactivate the last active panel. 697 if (activePanel) { 698 if (QGraphicsItem *fi = activePanel->focusItem()) { 699 // Remove focus from the current focus item. 700 if (fi == q->focusItem()) 701 q->setFocusItem(0, Qt::ActiveWindowFocusReason); 702 } 703 704 QEvent event(QEvent::WindowDeactivate); 705 q->sendEvent(activePanel, &event); 706 } else if (panel && !duringActivationEvent) { 707 // Deactivate the scene if changing activation to a panel. 708 QEvent event(QEvent::WindowDeactivate); 709 foreach (QGraphicsItem *item, q->items()) { 710 if (item->isVisible() && !item->isPanel() && !item->parentItem()) 711 q->sendEvent(item, &event); 712 } 713 } 714 715 // Update activate state. 716 activePanel = panel; 717 QEvent event(QEvent::ActivationChange); 718 QApplication::sendEvent(q, &event); 719 720 // Activate 721 if (panel) { 722 QEvent event(QEvent::WindowActivate); 723 q->sendEvent(panel, &event); 724 725 // Set focus on the panel's focus item. 726 if (QGraphicsItem *focusItem = panel->focusItem()) 727 focusItem->setFocus(Qt::ActiveWindowFocusReason); 728 } else if (q->isActive()) { 729 // Activate the scene 730 QEvent event(QEvent::WindowActivate); 731 foreach (QGraphicsItem *item, q->items()) { 732 if (item->isVisible() && !item->isPanel() && !item->parentItem()) 733 q->sendEvent(item, &event); 734 } 735 } 808 736 } 809 737 810 738 /*! 811 739 \internal 812 813 Starts or restarts the timer used for reindexing unindexed items. 814 */ 815 void QGraphicsScenePrivate::startIndexTimer() 740 */ 741 void QGraphicsScenePrivate::setFocusItemHelper(QGraphicsItem *item, 742 Qt::FocusReason focusReason) 816 743 { 817 744 Q_Q(QGraphicsScene); 818 if (indexTimerId) { 819 restartIndexTimer = true; 820 } else { 821 indexTimerId = q->startTimer(QGRAPHICSSCENE_INDEXTIMER_TIMEOUT); 822 } 745 if (item == focusItem) 746 return; 747 748 // Clear focus if asked to set focus on something that can't 749 // accept input focus. 750 if (item && (!(item->flags() & QGraphicsItem::ItemIsFocusable) 751 || !item->isVisible() || !item->isEnabled())) { 752 item = 0; 753 } 754 755 // Set focus on the scene if an item requests focus. 756 if (item) { 757 q->setFocus(focusReason); 758 if (item == focusItem) 759 return; 760 } 761 762 if (focusItem) { 763 QFocusEvent event(QEvent::FocusOut, focusReason); 764 lastFocusItem = focusItem; 765 focusItem = 0; 766 sendEvent(lastFocusItem, &event); 767 768 #ifndef QT_NO_IM 769 if (lastFocusItem 770 && (lastFocusItem->flags() & QGraphicsItem::ItemAcceptsInputMethod)) { 771 // Reset any visible preedit text 772 QInputMethodEvent imEvent; 773 sendEvent(lastFocusItem, &imEvent); 774 775 // Close any external input method panel. This happens 776 // automatically by removing WA_InputMethodEnabled on 777 // the views, but if we are changing focus, we have to 778 // do it ourselves. 779 if (item) { 780 for (int i = 0; i < views.size(); ++i) 781 views.at(i)->inputContext()->reset(); 782 } 783 } 784 #endif //QT_NO_IM 785 } 786 787 if (item) { 788 focusItem = item; 789 QFocusEvent event(QEvent::FocusIn, focusReason); 790 sendEvent(item, &event); 791 } 792 793 updateInputMethodSensitivityInViews(); 823 794 } 824 795 … … 864 835 QFocusEvent event(QEvent::FocusIn, Qt::PopupFocusReason); 865 836 sendEvent(focusItem, &event); 866 } else {867 ungrabKeyboard( (QGraphicsItem *)widget, itemIsDying);837 } else if (keyboardGrabberItems.contains(static_cast<QGraphicsItem *>(widget))) { 838 ungrabKeyboard(static_cast<QGraphicsItem *>(widget), itemIsDying); 868 839 } 869 840 if (!itemIsDying && widget->isVisible()) { … … 881 852 // Append to list of mouse grabber items, and send a mouse grab event. 882 853 if (mouseGrabberItems.contains(item)) { 883 if (mouseGrabberItems.last() == item) 884 qWarning("QGraphicsItem::grabMouse: already a mouse grabber"); 885 else 854 if (mouseGrabberItems.last() == item) { 855 Q_ASSERT(!implicit); 856 if (!lastMouseGrabberItemHasImplicitMouseGrab) { 857 qWarning("QGraphicsItem::grabMouse: already a mouse grabber"); 858 } else { 859 // Upgrade to an explicit mouse grab 860 lastMouseGrabberItemHasImplicitMouseGrab = false; 861 } 862 } else { 886 863 qWarning("QGraphicsItem::grabMouse: already blocked by mouse grabber: %p", 887 864 mouseGrabberItems.last()); 865 } 888 866 return; 889 867 } … … 1037 1015 } 1038 1016 1017 void QGraphicsScenePrivate::enableMouseTrackingOnViews() 1018 { 1019 foreach (QGraphicsView *view, views) 1020 view->viewport()->setMouseTracking(true); 1021 } 1022 1039 1023 /*! 1040 1024 Returns all items for the screen position in \a event. … … 1046 1030 Q_Q(const QGraphicsScene); 1047 1031 QGraphicsView *view = widget ? qobject_cast<QGraphicsView *>(widget->parentWidget()) : 0; 1048 QList<QGraphicsItem *> items; 1049 if (view) 1050 items = view->items(view->viewport()->mapFromGlobal(screenPos)); 1051 else 1052 items = q->items(scenePos); 1053 return items; 1054 } 1055 1056 /*! 1057 \internal 1058 1059 Checks if item collides with the path and mode, but also checks that if it 1060 doesn't collide, maybe its frame rect will. 1061 */ 1062 bool QGraphicsScenePrivate::itemCollidesWithPath(QGraphicsItem *item, 1063 const QPainterPath &path, 1064 Qt::ItemSelectionMode mode) 1065 { 1066 if (item->collidesWithPath(path, mode)) 1067 return true; 1068 if (item->isWidget()) { 1069 // Check if this is a window, and if its frame rect collides. 1070 QGraphicsWidget *widget = static_cast<QGraphicsWidget *>(item); 1071 if (widget->isWindow()) { 1072 QRectF frameRect = widget->windowFrameRect(); 1073 QPainterPath framePath; 1074 framePath.addRect(frameRect); 1075 bool intersects = path.intersects(frameRect); 1076 if (mode == Qt::IntersectsItemShape || mode == Qt::IntersectsItemBoundingRect) 1077 return intersects || path.contains(frameRect.topLeft()) 1078 || framePath.contains(path.elementAt(0)); 1079 return !intersects && path.contains(frameRect.topLeft()); 1080 } 1081 } 1082 return false; 1032 if (!view) 1033 return q->items(scenePos, Qt::IntersectsItemShape, Qt::DescendingOrder, QTransform()); 1034 1035 const QRectF pointRect(QPointF(widget->mapFromGlobal(screenPos)), QSizeF(1, 1)); 1036 if (!view->isTransformed()) 1037 return q->items(pointRect, Qt::IntersectsItemShape, Qt::DescendingOrder); 1038 1039 const QTransform viewTransform = view->viewportTransform(); 1040 if (viewTransform.type() <= QTransform::TxScale) { 1041 return q->items(viewTransform.inverted().mapRect(pointRect), Qt::IntersectsItemShape, 1042 Qt::DescendingOrder, viewTransform); 1043 } 1044 return q->items(viewTransform.inverted().map(pointRect), Qt::IntersectsItemShape, 1045 Qt::DescendingOrder, viewTransform); 1083 1046 } 1084 1047 … … 1092 1055 mouseGrabberButtonDownPos.insert(Qt::MouseButton(i), 1093 1056 mouseGrabberItems.last()->d_ptr->genericMapFromScene(event->scenePos(), 1094 event->widget()));1057 event->widget())); 1095 1058 mouseGrabberButtonDownScenePos.insert(Qt::MouseButton(i), event->scenePos()); 1096 1059 mouseGrabberButtonDownScreenPos.insert(Qt::MouseButton(i), event->screenPos()); … … 1126 1089 1127 1090 /*! 1091 \internal 1092 */ 1093 bool QGraphicsScenePrivate::filterDescendantEvent(QGraphicsItem *item, QEvent *event) 1094 { 1095 if (item && (item->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorFiltersChildEvents)) { 1096 QGraphicsItem *parent = item->parentItem(); 1097 while (parent) { 1098 if (parent->d_ptr->filtersDescendantEvents && parent->sceneEventFilter(item, event)) 1099 return true; 1100 if (!(parent->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorFiltersChildEvents)) 1101 return false; 1102 parent = parent->parentItem(); 1103 } 1104 } 1105 return false; 1106 } 1107 1108 /*! 1128 1109 \internal 1129 1110 */ … … 1155 1136 bool QGraphicsScenePrivate::sendEvent(QGraphicsItem *item, QEvent *event) 1156 1137 { 1138 if (QGraphicsObject *object = item->toGraphicsObject()) { 1139 QGestureManager *gestureManager = QApplicationPrivate::instance()->gestureManager; 1140 if (gestureManager) { 1141 if (gestureManager->filterEvent(object, event)) 1142 return true; 1143 } 1144 } 1145 1157 1146 if (filterEvent(item, event)) 1158 1147 return false; 1159 return (item && item->isEnabled()) ? item->sceneEvent(event) : false; 1148 if (filterDescendantEvent(item, event)) 1149 return false; 1150 if (!item || !item->isEnabled()) 1151 return false; 1152 if (QGraphicsObject *o = item->toGraphicsObject()) { 1153 bool spont = event->spontaneous(); 1154 if (spont ? qt_sendSpontaneousEvent(o, event) : QApplication::sendEvent(o, event)) 1155 return true; 1156 event->spont = spont; 1157 } 1158 return item->sceneEvent(event); 1160 1159 } 1161 1160 … … 1220 1219 1221 1220 QGraphicsItem *item = mouseGrabberItems.last(); 1221 if (item->isBlockedByModalPanel()) 1222 return; 1223 1222 1224 for (int i = 0x1; i <= 0x10; i <<= 1) { 1223 1225 Qt::MouseButton button = Qt::MouseButton(i); … … 1243 1245 // Deliver to any existing mouse grabber. 1244 1246 if (!mouseGrabberItems.isEmpty()) { 1247 if (mouseGrabberItems.last()->isBlockedByModalPanel()) 1248 return; 1245 1249 // The event is ignored by default, but we disregard the event's 1246 1250 // accepted state after delivery; the mouse is grabbed, after all. … … 1258 1262 1259 1263 // Update window activation. 1260 QGraphicsWidget *newActiveWindow = windowForItem(cachedItemsUnderMouse.value(0)); 1261 if (newActiveWindow != activeWindow) 1264 QGraphicsItem *topItem = cachedItemsUnderMouse.value(0); 1265 QGraphicsWidget *newActiveWindow = topItem ? topItem->window() : 0; 1266 if (newActiveWindow && newActiveWindow->isBlockedByModalPanel(&topItem)) { 1267 // pass activation to the blocking modal window 1268 newActiveWindow = topItem ? topItem->window() : 0; 1269 } 1270 1271 if (newActiveWindow != q->activeWindow()) 1262 1272 q->setActiveWindow(newActiveWindow); 1263 1273 … … 1265 1275 bool setFocus = false; 1266 1276 foreach (QGraphicsItem *item, cachedItemsUnderMouse) { 1267 if (item->isEnabled() && (item->flags() & QGraphicsItem::ItemIsFocusable)) { 1277 if (item->isBlockedByModalPanel()) { 1278 // Make sure we don't clear focus. 1279 setFocus = true; 1280 break; 1281 } 1282 if (item->isEnabled() && ((item->flags() & QGraphicsItem::ItemIsFocusable) && item->d_ptr->mouseSetsFocus)) { 1268 1283 if (!item->isWidget() || ((QGraphicsWidget *)item)->focusPolicy() & Qt::ClickFocus) { 1269 1284 setFocus = true; … … 1273 1288 } 1274 1289 } 1290 if (item->isPanel()) 1291 break; 1292 } 1293 1294 // Check for scene modality. 1295 bool sceneModality = false; 1296 for (int i = 0; i < modalPanels.size(); ++i) { 1297 if (modalPanels.at(i)->panelModality() == QGraphicsItem::SceneModal) { 1298 sceneModality = true; 1299 break; 1300 } 1275 1301 } 1276 1302 1277 1303 // If nobody could take focus, clear it. 1278 if (!stickyFocus && !setFocus )1304 if (!stickyFocus && !setFocus && !sceneModality) 1279 1305 q->setFocusItem(0, Qt::MouseFocusReason); 1306 1307 // Any item will do. 1308 if (sceneModality && cachedItemsUnderMouse.isEmpty()) 1309 cachedItemsUnderMouse << modalPanels.first(); 1280 1310 1281 1311 // Find a mouse grabber by sending mouse press events to all mouse grabber … … 1289 1319 } 1290 1320 1321 // Check if this item is blocked by a modal panel and deliver the mouse event to the 1322 // blocking panel instead of this item if blocked. 1323 (void) item->isBlockedByModalPanel(&item); 1324 1291 1325 grabMouse(item, /* implicit = */ true); 1292 1326 mouseEvent->accept(); … … 1294 1328 // check if the item we are sending to are disabled (before we send the event) 1295 1329 bool disabled = !item->isEnabled(); 1296 bool isWindow = item->isWindow(); 1297 if (mouseEvent->type() == QEvent::GraphicsSceneMouseDoubleClick && item != lastMouseGrabberItem) { 1330 bool isPanel = item->isPanel(); 1331 if (mouseEvent->type() == QEvent::GraphicsSceneMouseDoubleClick 1332 && item != lastMouseGrabberItem && lastMouseGrabberItem) { 1298 1333 // If this item is different from the item that received the last 1299 1334 // mouse event, and mouseEvent is a doubleclick event, then the … … 1301 1336 // Triple-clicking will not generate a doubleclick, though. 1302 1337 QGraphicsSceneMouseEvent mousePress(QEvent::GraphicsSceneMousePress); 1338 mousePress.spont = mouseEvent->spont; 1303 1339 mousePress.accept(); 1304 1340 mousePress.setButton(mouseEvent->button()); … … 1333 1369 ungrabMouse(item, /* itemIsDying = */ dontSendUngrabEvents); 1334 1370 1335 // Don't propagate through windows.1336 if (is Window)1371 // Don't propagate through panels. 1372 if (isPanel) 1337 1373 break; 1338 1374 } … … 1356 1392 } 1357 1393 1358 QGraphicsWidget *QGraphicsScenePrivate::windowForItem(const QGraphicsItem *item) const1359 {1360 if (!item)1361 return 0;1362 do {1363 if (item->isWidget())1364 return static_cast<const QGraphicsWidget *>(item)->window();1365 item = item->parentItem();1366 } while (item);1367 return 0;1368 }1369 1370 1371 QList<QGraphicsItem *> QGraphicsScenePrivate::items_helper(const QPointF &pos) const1372 {1373 QList<QGraphicsItem *> items;1374 1375 // The index returns a rough estimate of what items are inside the rect.1376 // Refine it by iterating through all returned items.1377 QRectF adjustedRect = QRectF(pos, QSize(1,1));1378 foreach (QGraphicsItem *item, estimateItemsInRect(adjustedRect)) {1379 // Find the item's scene transform in a clever way.1380 QTransform x = item->sceneTransform();1381 bool keep = false;1382 1383 // ### _q_adjustedRect is only needed because QRectF::intersects,1384 // QRectF::contains and QTransform::map() and friends don't work with1385 // flat rectangles.1386 const QRectF br(adjustedItemBoundingRect(item));1387 // Rect intersects/contains item's shape1388 if (QRectF_intersects(adjustedRect, x.mapRect(br))) {1389 bool ok;1390 QTransform xinv = x.inverted(&ok);1391 if (ok) {1392 if (item->contains(xinv.map(pos))) {1393 items << item;1394 keep = true;1395 }1396 }1397 }1398 1399 if (keep && (item->flags() & QGraphicsItem::ItemClipsChildrenToShape)) {1400 // Recurse into children that clip children.1401 bool ok;1402 QTransform xinv = x.inverted(&ok);1403 if (ok)1404 childItems_helper(&items, item, xinv.map(pos));1405 }1406 }1407 1408 sortItems(&items, Qt::AscendingOrder, sortCacheEnabled);1409 return items;1410 }1411 1412 QList<QGraphicsItem *> QGraphicsScenePrivate::items_helper(const QRectF &rect,1413 Qt::ItemSelectionMode mode,1414 Qt::SortOrder order) const1415 {1416 QList<QGraphicsItem *> items;1417 1418 QPainterPath path;1419 1420 // The index returns a rough estimate of what items are inside the rect.1421 // Refine it by iterating through all returned items.1422 QRectF adjustedRect(rect);1423 _q_adjustRect(&adjustedRect);1424 foreach (QGraphicsItem *item, estimateItemsInRect(adjustedRect)) {1425 // Find the item's scene transform in a clever way.1426 QTransform x = item->sceneTransform();1427 bool keep = false;1428 1429 // ### _q_adjustedRect is only needed because QRectF::intersects,1430 // QRectF::contains and QTransform::map() and friends don't work with1431 // flat rectangles.1432 const QRectF br(adjustedItemBoundingRect(item));1433 if (mode >= Qt::ContainsItemBoundingRect) {1434 // Rect intersects/contains item's bounding rect1435 QRectF mbr = x.mapRect(br);1436 if ((mode == Qt::IntersectsItemBoundingRect && QRectF_intersects(rect, mbr))1437 || (mode == Qt::ContainsItemBoundingRect && rect != mbr && rect.contains(mbr))) {1438 items << item;1439 keep = true;1440 }1441 } else {1442 // Rect intersects/contains item's shape1443 if (QRectF_intersects(adjustedRect, x.mapRect(br))) {1444 bool ok;1445 QTransform xinv = x.inverted(&ok);1446 if (ok) {1447 if (path.isEmpty())1448 path.addRect(rect);1449 if (itemCollidesWithPath(item, xinv.map(path), mode)) {1450 items << item;1451 keep = true;1452 }1453 }1454 }1455 }1456 1457 if (keep && (item->flags() & QGraphicsItem::ItemClipsChildrenToShape)) {1458 // Recurse into children that clip children.1459 bool ok;1460 QTransform xinv = x.inverted(&ok);1461 if (ok) {1462 if (x.type() <= QTransform::TxScale) {1463 // Rect1464 childItems_helper(&items, item, xinv.mapRect(rect), mode);1465 } else {1466 // Polygon1467 childItems_helper(&items, item, xinv.map(rect), mode);1468 }1469 }1470 }1471 }1472 1473 if (order != Qt::SortOrder(-1))1474 sortItems(&items, order, sortCacheEnabled);1475 return items;1476 }1477 1478 QList<QGraphicsItem *> QGraphicsScenePrivate::items_helper(const QPolygonF &polygon,1479 Qt::ItemSelectionMode mode,1480 Qt::SortOrder order) const1481 {1482 QList<QGraphicsItem *> items;1483 1484 QRectF polyRect(polygon.boundingRect());1485 _q_adjustRect(&polyRect);1486 QPainterPath path;1487 1488 // The index returns a rough estimate of what items are inside the rect.1489 // Refine it by iterating through all returned items.1490 foreach (QGraphicsItem *item, estimateItemsInRect(polyRect)) {1491 // Find the item's scene transform in a clever way.1492 QTransform x = item->sceneTransform();1493 bool keep = false;1494 1495 // ### _q_adjustedRect is only needed because QRectF::intersects,1496 // QRectF::contains and QTransform::map() and friends don't work with1497 // flat rectangles.1498 const QRectF br(adjustedItemBoundingRect(item));1499 if (mode >= Qt::ContainsItemBoundingRect) {1500 // Polygon contains/intersects item's bounding rect1501 if (path == QPainterPath())1502 path.addPolygon(polygon);1503 if ((mode == Qt::IntersectsItemBoundingRect && path.intersects(x.mapRect(br)))1504 || (mode == Qt::ContainsItemBoundingRect && path.contains(x.mapRect(br)))) {1505 items << item;1506 keep = true;1507 }1508 } else {1509 // Polygon contains/intersects item's shape1510 if (QRectF_intersects(polyRect, x.mapRect(br))) {1511 bool ok;1512 QTransform xinv = x.inverted(&ok);1513 if (ok) {1514 if (path == QPainterPath())1515 path.addPolygon(polygon);1516 if (itemCollidesWithPath(item, xinv.map(path), mode)) {1517 items << item;1518 keep = true;1519 }1520 }1521 }1522 }1523 1524 if (keep && (item->flags() & QGraphicsItem::ItemClipsChildrenToShape)) {1525 // Recurse into children that clip children.1526 bool ok;1527 QTransform xinv = x.inverted(&ok);1528 if (ok)1529 childItems_helper(&items, item, xinv.map(polygon), mode);1530 }1531 }1532 1533 if (order != Qt::SortOrder(-1))1534 sortItems(&items, order, sortCacheEnabled);1535 return items;1536 }1537 1538 QList<QGraphicsItem *> QGraphicsScenePrivate::items_helper(const QPainterPath &path,1539 Qt::ItemSelectionMode mode,1540 Qt::SortOrder order) const1541 {1542 QList<QGraphicsItem *> items;1543 QRectF pathRect(path.controlPointRect());1544 _q_adjustRect(&pathRect);1545 1546 // The index returns a rough estimate of what items are inside the rect.1547 // Refine it by iterating through all returned items.1548 foreach (QGraphicsItem *item, estimateItemsInRect(pathRect)) {1549 // Find the item's scene transform in a clever way.1550 QTransform x = item->sceneTransform();1551 bool keep = false;1552 1553 // ### _q_adjustedRect is only needed because QRectF::intersects,1554 // QRectF::contains and QTransform::map() and friends don't work with1555 // flat rectangles.1556 const QRectF br(adjustedItemBoundingRect(item));1557 if (mode >= Qt::ContainsItemBoundingRect) {1558 // Path contains/intersects item's bounding rect1559 if ((mode == Qt::IntersectsItemBoundingRect && path.intersects(x.mapRect(br)))1560 || (mode == Qt::ContainsItemBoundingRect && path.contains(x.mapRect(br)))) {1561 items << item;1562 keep = true;1563 }1564 } else {1565 // Path contains/intersects item's shape1566 if (QRectF_intersects(pathRect, x.mapRect(br))) {1567 bool ok;1568 QTransform xinv = x.inverted(&ok);1569 if (ok) {1570 if (itemCollidesWithPath(item, xinv.map(path), mode)) {1571 items << item;1572 keep = true;1573 }1574 }1575 }1576 }1577 1578 if (keep && (item->flags() & QGraphicsItem::ItemClipsChildrenToShape)) {1579 bool ok;1580 QTransform xinv = x.inverted(&ok);1581 if (ok)1582 childItems_helper(&items, item, xinv.map(path), mode);1583 }1584 }1585 1586 if (order != Qt::SortOrder(-1))1587 sortItems(&items, order, sortCacheEnabled);1588 return items;1589 }1590 1591 void QGraphicsScenePrivate::childItems_helper(QList<QGraphicsItem *> *items,1592 const QGraphicsItem *parent,1593 const QPointF &pos) const1594 {1595 bool parentClip = (parent->flags() & QGraphicsItem::ItemClipsChildrenToShape);1596 if (parentClip && parent->d_ptr->isClippedAway())1597 return;1598 // ### is this needed?1599 if (parentClip && !parent->boundingRect().contains(pos))1600 return;1601 1602 QList<QGraphicsItem *> &children = parent->d_ptr->children;1603 for (int i = 0; i < children.size(); ++i) {1604 QGraphicsItem *item = children.at(i);1605 if (item->d_ptr->hasTransform && !item->transform().isInvertible())1606 continue;1607 1608 // Skip invisible items and all their children.1609 if (item->d_ptr->isInvisible())1610 continue;1611 1612 bool keep = false;1613 if (!item->d_ptr->isClippedAway()) {1614 if (item->contains(item->mapFromParent(pos))) {1615 items->append(item);1616 keep = true;1617 }1618 }1619 1620 if ((keep || !(item->flags() & QGraphicsItem::ItemClipsChildrenToShape)) && !item->d_ptr->children.isEmpty())1621 // Recurse into children.1622 childItems_helper(items, item, item->mapFromParent(pos));1623 }1624 }1625 1626 1627 void QGraphicsScenePrivate::childItems_helper(QList<QGraphicsItem *> *items,1628 const QGraphicsItem *parent,1629 const QRectF &rect,1630 Qt::ItemSelectionMode mode) const1631 {1632 bool parentClip = (parent->flags() & QGraphicsItem::ItemClipsChildrenToShape);1633 if (parentClip && parent->d_ptr->isClippedAway())1634 return;1635 QRectF adjustedRect(rect);1636 _q_adjustRect(&adjustedRect);1637 QRectF r = !parentClip ? adjustedRect : adjustedRect.intersected(adjustedItemBoundingRect(parent));1638 if (r.isEmpty())1639 return;1640 1641 QPainterPath path;1642 QList<QGraphicsItem *> &children = parent->d_ptr->children;1643 for (int i = 0; i < children.size(); ++i) {1644 QGraphicsItem *item = children.at(i);1645 if (item->d_ptr->hasTransform && !item->transform().isInvertible())1646 continue;1647 1648 // Skip invisible items and all their children.1649 if (item->d_ptr->isInvisible())1650 continue;1651 1652 bool keep = false;1653 if (!item->d_ptr->isClippedAway()) {1654 // ### _q_adjustedRect is only needed because QRectF::intersects,1655 // QRectF::contains and QTransform::map() and friends don't work with1656 // flat rectangles.1657 const QRectF br(adjustedItemBoundingRect(item));1658 QRectF mbr = item->mapRectToParent(br);1659 if (mode >= Qt::ContainsItemBoundingRect) {1660 // Rect intersects/contains item's bounding rect1661 if ((mode == Qt::IntersectsItemBoundingRect && QRectF_intersects(rect, mbr))1662 || (mode == Qt::ContainsItemBoundingRect && rect != mbr && rect.contains(br))) {1663 items->append(item);1664 keep = true;1665 }1666 } else {1667 // Rect intersects/contains item's shape1668 if (QRectF_intersects(rect, mbr)) {1669 if (path == QPainterPath())1670 path.addRect(rect);1671 if (itemCollidesWithPath(item, item->mapFromParent(path), mode)) {1672 items->append(item);1673 keep = true;1674 }1675 }1676 }1677 }1678 1679 if ((keep || !(item->flags() & QGraphicsItem::ItemClipsChildrenToShape)) && !item->d_ptr->children.isEmpty()) {1680 // Recurse into children.1681 if (!item->d_ptr->hasTransform || item->transform().type() <= QTransform::TxScale) {1682 // Rect1683 childItems_helper(items, item, item->mapRectFromParent(rect), mode);1684 } else {1685 // Polygon1686 childItems_helper(items, item, item->mapFromParent(rect), mode);1687 }1688 }1689 }1690 }1691 1692 1693 void QGraphicsScenePrivate::childItems_helper(QList<QGraphicsItem *> *items,1694 const QGraphicsItem *parent,1695 const QPolygonF &polygon,1696 Qt::ItemSelectionMode mode) const1697 {1698 bool parentClip = (parent->flags() & QGraphicsItem::ItemClipsChildrenToShape);1699 if (parentClip && parent->d_ptr->isClippedAway())1700 return;1701 QRectF polyRect(polygon.boundingRect());1702 _q_adjustRect(&polyRect);1703 QRectF r = !parentClip ? polyRect : polyRect.intersected(adjustedItemBoundingRect(parent));1704 if (r.isEmpty())1705 return;1706 1707 QPainterPath path;1708 QList<QGraphicsItem *> &children = parent->d_ptr->children;1709 for (int i = 0; i < children.size(); ++i) {1710 QGraphicsItem *item = children.at(i);1711 if (item->d_ptr->hasTransform && !item->transform().isInvertible())1712 continue;1713 1714 // Skip invisible items.1715 if (item->d_ptr->isInvisible())1716 continue;1717 1718 bool keep = false;1719 if (!item->d_ptr->isClippedAway()) {1720 // ### _q_adjustedRect is only needed because QRectF::intersects,1721 // QRectF::contains and QTransform::map() and friends don't work with1722 // flat rectangles.1723 const QRectF br(adjustedItemBoundingRect(item));1724 if (mode >= Qt::ContainsItemBoundingRect) {1725 // Polygon contains/intersects item's bounding rect1726 if (path == QPainterPath())1727 path.addPolygon(polygon);1728 if ((mode == Qt::IntersectsItemBoundingRect && path.intersects(item->mapRectToParent(br)))1729 || (mode == Qt::ContainsItemBoundingRect && path.contains(item->mapRectToParent(br)))) {1730 items->append(item);1731 keep = true;1732 }1733 } else {1734 // Polygon contains/intersects item's shape1735 if (QRectF_intersects(polyRect, item->mapRectToParent(br))) {1736 if (path == QPainterPath())1737 path.addPolygon(polygon);1738 if (itemCollidesWithPath(item, item->mapFromParent(path), mode)) {1739 items->append(item);1740 keep = true;1741 }1742 }1743 }1744 }1745 1746 if ((keep || !(item->flags() & QGraphicsItem::ItemClipsChildrenToShape)) && !item->d_ptr->children.isEmpty()) {1747 // Recurse into children that clip children.1748 childItems_helper(items, item, item->mapFromParent(polygon), mode);1749 }1750 }1751 }1752 1753 void QGraphicsScenePrivate::childItems_helper(QList<QGraphicsItem *> *items,1754 const QGraphicsItem *parent,1755 const QPainterPath &path,1756 Qt::ItemSelectionMode mode) const1757 {1758 bool parentClip = (parent->flags() & QGraphicsItem::ItemClipsChildrenToShape);1759 if (parentClip && parent->d_ptr->isClippedAway())1760 return;1761 QRectF pathRect(path.boundingRect());1762 _q_adjustRect(&pathRect);1763 QRectF r = !parentClip ? pathRect : pathRect.intersected(adjustedItemBoundingRect(parent));1764 if (r.isEmpty())1765 return;1766 1767 QList<QGraphicsItem *> &children = parent->d_ptr->children;1768 for (int i = 0; i < children.size(); ++i) {1769 QGraphicsItem *item = children.at(i);1770 if (item->d_ptr->hasTransform && !item->transform().isInvertible())1771 continue;1772 1773 // Skip invisible items.1774 if (item->d_ptr->isInvisible())1775 continue;1776 1777 bool keep = false;1778 if (!item->d_ptr->isClippedAway()) {1779 // ### _q_adjustedRect is only needed because QRectF::intersects,1780 // QRectF::contains and QTransform::map() and friends don't work with1781 // flat rectangles.1782 const QRectF br(adjustedItemBoundingRect(item));1783 if (mode >= Qt::ContainsItemBoundingRect) {1784 // Polygon contains/intersects item's bounding rect1785 if ((mode == Qt::IntersectsItemBoundingRect && path.intersects(item->mapRectToParent(br)))1786 || (mode == Qt::ContainsItemBoundingRect && path.contains(item->mapRectToParent(br)))) {1787 items->append(item);1788 keep = true;1789 }1790 } else {1791 // Path contains/intersects item's shape1792 if (QRectF_intersects(pathRect, item->mapRectToParent(br))) {1793 if (itemCollidesWithPath(item, item->mapFromParent(path), mode)) {1794 items->append(item);1795 keep = true;1796 }1797 }1798 }1799 }1800 1801 if ((keep || !(item->flags() & QGraphicsItem::ItemClipsChildrenToShape)) && !item->d_ptr->children.isEmpty()) {1802 // Recurse into children that clip children.1803 childItems_helper(items, item, item->mapFromParent(path), mode);1804 }1805 }1806 }1807 1808 void QGraphicsScenePrivate::invalidateSortCache()1809 {1810 Q_Q(QGraphicsScene);1811 if (!sortCacheEnabled || updatingSortCache)1812 return;1813 1814 updatingSortCache = true;1815 QMetaObject::invokeMethod(q, "_q_updateSortCache", Qt::QueuedConnection);1816 }1817 1818 1394 /*! 1819 1395 \internal 1820 1396 1821 Should not be exported, but we can't change that now. 1822 ### Qt 5: Remove symbol / make static 1823 */ 1824 inline bool qt_closestLeaf(const QGraphicsItem *item1, const QGraphicsItem *item2) 1825 { 1826 // Return true if sibling item1 is on top of item2. 1827 const QGraphicsItemPrivate *d1 = item1->d_ptr; 1828 const QGraphicsItemPrivate *d2 = item2->d_ptr; 1829 bool f1 = d1->flags & QGraphicsItem::ItemStacksBehindParent; 1830 bool f2 = d2->flags & QGraphicsItem::ItemStacksBehindParent; 1831 if (f1 != f2) return f2; 1832 qreal z1 = d1->z; 1833 qreal z2 = d2->z; 1834 return z1 != z2 ? z1 > z2 : item1 > item2; 1835 } 1836 1837 /*! 1838 \internal 1839 1840 Should not be exported, but we can't change that now. 1841 */ 1842 inline bool qt_closestItemFirst(const QGraphicsItem *item1, const QGraphicsItem *item2) 1843 { 1844 return QGraphicsScenePrivate::closestItemFirst_withoutCache(item1, item2); 1845 } 1846 1847 /*! 1848 Returns true if \a item1 is on top of \a item2. 1849 1850 \internal 1851 */ 1852 bool QGraphicsScenePrivate::closestItemFirst_withoutCache(const QGraphicsItem *item1, const QGraphicsItem *item2) 1853 { 1854 // Siblings? Just check their z-values. 1855 const QGraphicsItemPrivate *d1 = item1->d_ptr; 1856 const QGraphicsItemPrivate *d2 = item2->d_ptr; 1857 if (d1->parent == d2->parent) 1858 return qt_closestLeaf(item1, item2); 1859 1860 // Find common ancestor, and each item's ancestor closest to the common 1861 // ancestor. 1862 int item1Depth = d1->depth; 1863 int item2Depth = d2->depth; 1864 const QGraphicsItem *p = item1; 1865 const QGraphicsItem *t1 = item1; 1866 while (item1Depth > item2Depth && (p = p->d_ptr->parent)) { 1867 if (p == item2) { 1868 // item2 is one of item1's ancestors; item1 is on top 1869 return !(t1->d_ptr->flags & QGraphicsItem::ItemStacksBehindParent); 1870 } 1871 t1 = p; 1872 --item1Depth; 1873 } 1874 p = item2; 1875 const QGraphicsItem *t2 = item2; 1876 while (item2Depth > item1Depth && (p = p->d_ptr->parent)) { 1877 if (p == item1) { 1878 // item1 is one of item2's ancestors; item1 is not on top 1879 return (t2->d_ptr->flags & QGraphicsItem::ItemStacksBehindParent); 1880 } 1881 t2 = p; 1882 --item2Depth; 1883 } 1884 1885 // item1Ancestor is now at the same level as item2Ancestor, but not the same. 1886 const QGraphicsItem *a1 = t1; 1887 const QGraphicsItem *a2 = t2; 1888 while (a1) { 1889 const QGraphicsItem *p1 = a1; 1890 const QGraphicsItem *p2 = a2; 1891 a1 = a1->parentItem(); 1892 a2 = a2->parentItem(); 1893 if (a1 && a1 == a2) 1894 return qt_closestLeaf(p1, p2); 1895 } 1896 1897 // No common ancestor? Then just compare the items' toplevels directly. 1898 return qt_closestLeaf(t1->topLevelItem(), t2->topLevelItem()); 1899 } 1900 1901 /*! 1902 Returns true if \a item2 is on top of \a item1. 1903 1904 \internal 1905 */ 1906 bool QGraphicsScenePrivate::closestItemLast_withoutCache(const QGraphicsItem *item1, const QGraphicsItem *item2) 1907 { 1908 return closestItemFirst_withoutCache(item2, item1); 1909 } 1910 1911 void QGraphicsScenePrivate::climbTree(QGraphicsItem *item, int *stackingOrder) 1912 { 1913 if (!item->d_ptr->children.isEmpty()) { 1914 QList<QGraphicsItem *> childList = item->d_ptr->children; 1915 qSort(childList.begin(), childList.end(), qt_closestLeaf); 1916 for (int i = 0; i < childList.size(); ++i) { 1917 QGraphicsItem *item = childList.at(i); 1918 if (!(item->flags() & QGraphicsItem::ItemStacksBehindParent)) 1919 climbTree(childList.at(i), stackingOrder); 1920 } 1921 item->d_ptr->globalStackingOrder = (*stackingOrder)++; 1922 for (int i = 0; i < childList.size(); ++i) { 1923 QGraphicsItem *item = childList.at(i); 1924 if (item->flags() & QGraphicsItem::ItemStacksBehindParent) 1925 climbTree(childList.at(i), stackingOrder); 1926 } 1927 } else { 1928 item->d_ptr->globalStackingOrder = (*stackingOrder)++; 1929 } 1930 } 1931 1932 void QGraphicsScenePrivate::_q_updateSortCache() 1933 { 1934 _q_updateIndex(); 1935 1936 if (!sortCacheEnabled || !updatingSortCache) 1937 return; 1938 1939 updatingSortCache = false; 1940 int stackingOrder = 0; 1941 1942 QList<QGraphicsItem *> topLevels; 1943 1944 for (int i = 0; i < indexedItems.size(); ++i) { 1945 QGraphicsItem *item = indexedItems.at(i); 1946 if (item && item->parentItem() == 0) 1947 topLevels << item; 1948 } 1949 for (int i = 0; i < unindexedItems.size(); ++i) { 1950 QGraphicsItem *item = unindexedItems.at(i); 1951 if (item->parentItem() == 0) 1952 topLevels << item; 1953 } 1954 1955 qSort(topLevels.begin(), topLevels.end(), qt_closestLeaf); 1956 for (int i = 0; i < topLevels.size(); ++i) 1957 climbTree(topLevels.at(i), &stackingOrder); 1958 } 1959 1960 void QGraphicsScenePrivate::sortItems(QList<QGraphicsItem *> *itemList, Qt::SortOrder order, 1961 bool sortCacheEnabled) 1962 { 1963 if (sortCacheEnabled) { 1964 if (order == Qt::AscendingOrder) { 1965 qSort(itemList->begin(), itemList->end(), closestItemFirst_withCache); 1966 } else if (order == Qt::DescendingOrder) { 1967 qSort(itemList->begin(), itemList->end(), closestItemLast_withCache); 1968 } 1969 } else { 1970 if (order == Qt::AscendingOrder) { 1971 qSort(itemList->begin(), itemList->end(), closestItemFirst_withoutCache); 1972 } else if (order == Qt::DescendingOrder) { 1973 qSort(itemList->begin(), itemList->end(), closestItemLast_withoutCache); 1974 } 1397 Ensures that the list of toplevels is sorted by insertion order, and that 1398 the siblingIndexes are packed (no gaps), and start at 0. 1399 1400 ### This function is almost identical to 1401 QGraphicsItemPrivate::ensureSequentialSiblingIndex(). 1402 */ 1403 void QGraphicsScenePrivate::ensureSequentialTopLevelSiblingIndexes() 1404 { 1405 if (!topLevelSequentialOrdering) { 1406 qSort(topLevelItems.begin(), topLevelItems.end(), QGraphicsItemPrivate::insertionOrder); 1407 topLevelSequentialOrdering = true; 1408 needSortTopLevelItems = 1; 1409 } 1410 if (holesInTopLevelSiblingIndex) { 1411 holesInTopLevelSiblingIndex = 0; 1412 for (int i = 0; i < topLevelItems.size(); ++i) 1413 topLevelItems[i]->d_ptr->siblingIndex = i; 1975 1414 } 1976 1415 } … … 1997 1436 void QGraphicsScenePrivate::resolveFont() 1998 1437 { 1999 QFont naturalFont = qApp->font();1438 QFont naturalFont = QApplication::font(); 2000 1439 naturalFont.resolve(0); 2001 1440 QFont resolvedFont = font.resolve(naturalFont); … … 2053 1492 void QGraphicsScenePrivate::resolvePalette() 2054 1493 { 2055 QPalette naturalPalette = qApp->palette();1494 QPalette naturalPalette = QApplication::palette(); 2056 1495 naturalPalette.resolve(0); 2057 1496 QPalette resolvedPalette = palette.resolve(naturalPalette); … … 2108 1547 : QObject(*new QGraphicsScenePrivate, parent) 2109 1548 { 1549 d_func()->init(); 2110 1550 setSceneRect(sceneRect); 2111 d_func()->init();2112 1551 } 2113 1552 … … 2123 1562 : QObject(*new QGraphicsScenePrivate, parent) 2124 1563 { 1564 d_func()->init(); 2125 1565 setSceneRect(x, y, width, height); 2126 d_func()->init(); 2127 } 2128 2129 /*! 2130 Destroys the QGraphicsScene object. 1566 } 1567 1568 /*! 1569 Removes and deletes all items from the scene object 1570 before destroying the scene object. The scene object 1571 is removed from the application's global scene list, 1572 and it is removed from all associated views. 2131 1573 */ 2132 1574 QGraphicsScene::~QGraphicsScene() 2133 1575 { 2134 1576 Q_D(QGraphicsScene); 1577 2135 1578 // Remove this scene from qApp's global scene list. 2136 1579 qApp->d_func()->scene_list.removeAll(this); … … 2161 1604 { 2162 1605 Q_D(const QGraphicsScene); 2163 const_cast<QGraphicsScenePrivate *>(d)->_q_updateIndex(); 2164 return d->hasSceneRect ? d->sceneRect : d->growingItemsBoundingRect; 1606 if (d->hasSceneRect) 1607 return d->sceneRect; 1608 1609 if (d->dirtyGrowingItemsBoundingRect) { 1610 // Lazily update the growing items bounding rect 1611 QGraphicsScenePrivate *thatd = const_cast<QGraphicsScenePrivate *>(d); 1612 QRectF oldGrowingBoundingRect = thatd->growingItemsBoundingRect; 1613 thatd->growingItemsBoundingRect |= itemsBoundingRect(); 1614 thatd->dirtyGrowingItemsBoundingRect = false; 1615 if (oldGrowingBoundingRect != thatd->growingItemsBoundingRect) 1616 emit const_cast<QGraphicsScene *>(this)->sceneRectChanged(thatd->growingItemsBoundingRect); 1617 } 1618 return d->growingItemsBoundingRect; 2165 1619 } 2166 1620 void QGraphicsScene::setSceneRect(const QRectF &rect) … … 2170 1624 d->hasSceneRect = !rect.isNull(); 2171 1625 d->sceneRect = rect; 2172 d->resetIndex(); 2173 emit sceneRectChanged(rect); 1626 emit sceneRectChanged(d->hasSceneRect ? rect : d->growingItemsBoundingRect); 2174 1627 } 2175 1628 } … … 2212 1665 Qt::AspectRatioMode aspectRatioMode) 2213 1666 { 2214 Q_D(QGraphicsScene);1667 // ### Switch to using the recursive rendering algorithm instead. 2215 1668 2216 1669 // Default source rect = scene rect … … 2270 1723 // Generate the style options 2271 1724 QStyleOptionGraphicsItem *styleOptionArray = new QStyleOptionGraphicsItem[numItems]; 2272 for (int i = 0; i < numItems; ++i) { 2273 QGraphicsItem *item = itemArray[i]; 2274 2275 QStyleOptionGraphicsItem option; 2276 option.state = QStyle::State_None; 2277 option.rect = item->boundingRect().toRect(); 2278 if (item->isSelected()) 2279 option.state |= QStyle::State_Selected; 2280 if (item->isEnabled()) 2281 option.state |= QStyle::State_Enabled; 2282 if (item->hasFocus()) 2283 option.state |= QStyle::State_HasFocus; 2284 if (d->hoverItems.contains(item)) 2285 option.state |= QStyle::State_MouseOver; 2286 if (item == mouseGrabberItem()) 2287 option.state |= QStyle::State_Sunken; 2288 2289 // Calculate a simple level-of-detail metric. 2290 // ### almost identical code in QGraphicsView::paintEvent() 2291 // and QGraphicsView::render() - consider refactoring 2292 QTransform itemToDeviceTransform; 2293 if (item->d_ptr->itemIsUntransformable()) { 2294 itemToDeviceTransform = item->deviceTransform(painterTransform); 2295 } else { 2296 itemToDeviceTransform = item->sceneTransform() * painterTransform; 2297 } 2298 2299 option.levelOfDetail = qSqrt(itemToDeviceTransform.map(v1).length() * itemToDeviceTransform.map(v2).length()); 2300 option.matrix = itemToDeviceTransform.toAffine(); //### discards perspective 2301 2302 option.exposedRect = item->boundingRect(); 2303 option.exposedRect &= itemToDeviceTransform.inverted().mapRect(targetRect); 2304 2305 styleOptionArray[i] = option; 2306 } 1725 for (int i = 0; i < numItems; ++i) 1726 itemArray[i]->d_ptr->initStyleOption(&styleOptionArray[i], painterTransform, targetRect.toRect()); 2307 1727 2308 1728 // Render the scene. … … 2341 1761 { 2342 1762 Q_D(QGraphicsScene); 2343 d->resetIndex(); 1763 if (d->indexMethod == method) 1764 return; 1765 2344 1766 d->indexMethod = method; 1767 1768 QList<QGraphicsItem *> oldItems = d->index->items(Qt::DescendingOrder); 1769 delete d->index; 1770 if (method == BspTreeIndex) 1771 d->index = new QGraphicsSceneBspTreeIndex(this); 1772 else 1773 d->index = new QGraphicsSceneLinearIndex(this); 1774 for (int i = oldItems.size() - 1; i >= 0; --i) 1775 d->index->addItem(oldItems.at(i)); 2345 1776 } 2346 1777 … … 2380 1811 { 2381 1812 Q_D(const QGraphicsScene); 2382 return d->bspTreeDepth; 1813 QGraphicsSceneBspTreeIndex *bspTree = qobject_cast<QGraphicsSceneBspTreeIndex *>(d->index); 1814 return bspTree ? bspTree->bspTreeDepth() : 0; 2383 1815 } 2384 1816 void QGraphicsScene::setBspTreeDepth(int depth) 2385 1817 { 2386 1818 Q_D(QGraphicsScene); 2387 if (d->bspTreeDepth == depth)2388 return;2389 2390 1819 if (depth < 0) { 2391 1820 qWarning("QGraphicsScene::setBspTreeDepth: invalid depth %d ignored; must be >= 0", depth); … … 2393 1822 } 2394 1823 2395 d->bspTreeDepth = depth; 2396 d->resetIndex(); 1824 QGraphicsSceneBspTreeIndex *bspTree = qobject_cast<QGraphicsSceneBspTreeIndex *>(d->index); 1825 if (!bspTree) { 1826 qWarning("QGraphicsScene::setBspTreeDepth: can not apply if indexing method is not BSP"); 1827 return; 1828 } 1829 bspTree->setBspTreeDepth(depth); 2397 1830 } 2398 1831 … … 2401 1834 \brief whether sort caching is enabled 2402 1835 \since 4.5 2403 2404 When enabled, this property adds a cache that speeds up sorting and 2405 transformations for scenes with deep hierarchies (i.e., items with many 2406 levels of descendents), at the cost of using more memory (approx. 100 more 2407 bytes of memory per item). 2408 2409 Items that are not part of a deep hierarchy suffer no penalty from this 2410 cache. 1836 \obsolete 1837 1838 Since Qt 4.6, this property has no effect. 2411 1839 */ 2412 1840 bool QGraphicsScene::isSortCacheEnabled() const … … 2418 1846 { 2419 1847 Q_D(QGraphicsScene); 2420 if ( enabled == d->sortCacheEnabled)1848 if (d->sortCacheEnabled == enabled) 2421 1849 return; 2422 if ((d->sortCacheEnabled = enabled)) 2423 d->invalidateSortCache(); 1850 d->sortCacheEnabled = enabled; 2424 1851 } 2425 1852 … … 2433 1860 QRectF QGraphicsScene::itemsBoundingRect() const 2434 1861 { 1862 // Does not take untransformable items into account. 2435 1863 QRectF boundingRect; 2436 1864 foreach (QGraphicsItem *item, items()) … … 2440 1868 2441 1869 /*! 2442 Returns a list of all items on the scene, in no particularorder.2443 2444 \sa addItem(), removeItem() 1870 Returns a list of all items in the scene in descending stacking order. 1871 1872 \sa addItem(), removeItem(), {QGraphicsItem#Sorting}{Sorting} 2445 1873 */ 2446 1874 QList<QGraphicsItem *> QGraphicsScene::items() const 2447 1875 { 2448 1876 Q_D(const QGraphicsScene); 2449 const_cast<QGraphicsScenePrivate *>(d)->purgeRemovedItems(); 2450 2451 // If freeItemIndexes is empty, we know there are no holes in indexedItems and 2452 // unindexedItems. 2453 if (d->freeItemIndexes.isEmpty()) { 2454 if (d->unindexedItems.isEmpty()) 2455 return d->indexedItems; 2456 return d->indexedItems + d->unindexedItems; 2457 } 2458 2459 // Rebuild the list of items to avoid holes. ### We could also just 2460 // compress the item lists at this point. 2461 QList<QGraphicsItem *> itemList; 2462 foreach (QGraphicsItem *item, d->indexedItems + d->unindexedItems) { 2463 if (item) 2464 itemList << item; 2465 } 2466 return itemList; 2467 } 2468 2469 /*! 1877 return d->index->items(Qt::DescendingOrder); 1878 } 1879 1880 /*! 1881 Returns an ordered list of all items on the scene. \a order decides the 1882 stacking order. 1883 1884 \sa addItem(), removeItem(), {QGraphicsItem#Sorting}{Sorting} 1885 */ 1886 QList<QGraphicsItem *> QGraphicsScene::items(Qt::SortOrder order) const 1887 { 1888 Q_D(const QGraphicsScene); 1889 return d->index->items(order); 1890 } 1891 1892 /*! 1893 \obsolete 1894 2470 1895 Returns all visible items at position \a pos in the scene. The items are 2471 listed in descending Zorder (i.e., the first item in the list is the1896 listed in descending stacking order (i.e., the first item in the list is the 2472 1897 top-most item, and the last item is the bottom-most item). 2473 1898 2474 \sa itemAt() 1899 This function is deprecated and returns incorrect results if the scene 1900 contains items that ignore transformations. Use the overload that takes 1901 a QTransform instead. 1902 1903 \sa itemAt(), {QGraphicsItem#Sorting}{Sorting} 2475 1904 */ 2476 1905 QList<QGraphicsItem *> QGraphicsScene::items(const QPointF &pos) const 2477 1906 { 2478 1907 Q_D(const QGraphicsScene); 2479 return d->items_helper(pos); 2480 } 2481 2482 2483 /*! 2484 \fn QList<QGraphicsItem *> QGraphicsScene::items(const QRectF &rectangle, Qt::ItemSelectionMode mode) const 2485 1908 return d->index->items(pos, Qt::IntersectsItemShape, Qt::DescendingOrder); 1909 } 1910 1911 /*! 2486 1912 \overload 1913 \obsolete 2487 1914 2488 1915 Returns all visible items that, depending on \a mode, are either inside or … … 2492 1919 exact shape intersects with or is contained by \a rectangle are returned. 2493 1920 2494 \sa itemAt() 2495 */ 2496 QList<QGraphicsItem *> QGraphicsScene::items(const QRectF &rect, Qt::ItemSelectionMode mode) const 1921 This function is deprecated and returns incorrect results if the scene 1922 contains items that ignore transformations. Use the overload that takes 1923 a QTransform instead. 1924 1925 \sa itemAt(), {QGraphicsItem#Sorting}{Sorting} 1926 */ 1927 QList<QGraphicsItem *> QGraphicsScene::items(const QRectF &rectangle, Qt::ItemSelectionMode mode) const 2497 1928 { 2498 1929 Q_D(const QGraphicsScene); 2499 return d->i tems_helper(rect, mode, Qt::AscendingOrder);1930 return d->index->items(rectangle, mode, Qt::DescendingOrder); 2500 1931 } 2501 1932 2502 1933 /*! 2503 1934 \fn QList<QGraphicsItem *> QGraphicsScene::items(qreal x, qreal y, qreal w, qreal h, Qt::ItemSelectionMode mode) const 1935 \obsolete 2504 1936 \since 4.3 2505 1937 2506 1938 This convenience function is equivalent to calling items(QRectF(\a x, \a y, \a w, \a h), \a mode). 2507 */ 2508 2509 /*! 1939 1940 This function is deprecated and returns incorrect results if the scene 1941 contains items that ignore transformations. Use the overload that takes 1942 a QTransform instead. 1943 */ 1944 1945 /*! 1946 \fn QList<QGraphicsItem *> QGraphicsScene::items(qreal x, qreal y, qreal w, qreal h, Qt::ItemSelectionMode mode, Qt::SortOrder order, const QTransform &deviceTransform) const 2510 1947 \overload 1948 \since 4.6 1949 1950 \brief Returns all visible items that, depending on \a mode, are 1951 either inside or intersect with the rectangle defined by \a x, \a y, 1952 \a w and \a h, in a list sorted using \a order. 1953 1954 \a deviceTransform is the transformation that applies to the view, and needs to 1955 be provided if the scene contains items that ignore transformations. 1956 */ 1957 1958 /*! 1959 \fn QList<QGraphicsItem *> QGraphicsScene::items(const QPolygonF &polygon, Qt::ItemSelectionMode mode) const 1960 \overload 1961 \obsolete 2511 1962 2512 1963 Returns all visible items that, depending on \a mode, are either inside or … … 2516 1967 exact shape intersects with or is contained by \a polygon are returned. 2517 1968 2518 \sa itemAt() 1969 This function is deprecated and returns incorrect results if the scene 1970 contains items that ignore transformations. Use the overload that takes 1971 a QTransform instead. 1972 1973 \sa itemAt(), {QGraphicsItem#Sorting}{Sorting} 2519 1974 */ 2520 1975 QList<QGraphicsItem *> QGraphicsScene::items(const QPolygonF &polygon, Qt::ItemSelectionMode mode) const 2521 1976 { 2522 1977 Q_D(const QGraphicsScene); 2523 return d->items_helper(polygon, mode, Qt::AscendingOrder); 2524 } 2525 2526 /*! 1978 return d->index->items(polygon, mode, Qt::DescendingOrder); 1979 } 1980 1981 /*! 1982 \fn QList<QGraphicsItem *> QGraphicsScene::items(const QPainterPath &path, Qt::ItemSelectionMode mode) const 2527 1983 \overload 1984 \obsolete 2528 1985 2529 1986 Returns all visible items that, depending on \a path, are either inside or … … 2533 1990 exact shape intersects with or is contained by \a path are returned. 2534 1991 2535 \sa itemAt() 1992 This function is deprecated and returns incorrect results if the scene 1993 contains items that ignore transformations. Use the overload that takes 1994 a QTransform instead. 1995 1996 \sa itemAt(), {QGraphicsItem#Sorting}{Sorting} 2536 1997 */ 2537 1998 QList<QGraphicsItem *> QGraphicsScene::items(const QPainterPath &path, Qt::ItemSelectionMode mode) const 2538 1999 { 2539 2000 Q_D(const QGraphicsScene); 2540 return d->items_helper(path, mode, Qt::AscendingOrder); 2001 return d->index->items(path, mode, Qt::DescendingOrder); 2002 } 2003 2004 /*! 2005 \fn QList<QGraphicsItem *> QGraphicsScene::items(const QPointF &pos, Qt::ItemSelectionMode mode, Qt::SortOrder order, const QTransform &deviceTransform) const 2006 \since 4.6 2007 2008 \brief Returns all visible items that, depending on \a mode, are at 2009 the specified \a pos in a list sorted using \a order. 2010 2011 The default value for \a mode is Qt::IntersectsItemShape; all items whose 2012 exact shape intersects with \a pos are returned. 2013 2014 \a deviceTransform is the transformation that applies to the view, and needs to 2015 be provided if the scene contains items that ignore transformations. 2016 2017 \sa itemAt(), {QGraphicsItem#Sorting}{Sorting} 2018 */ 2019 QList<QGraphicsItem *> QGraphicsScene::items(const QPointF &pos, Qt::ItemSelectionMode mode, 2020 Qt::SortOrder order, const QTransform &deviceTransform) const 2021 { 2022 Q_D(const QGraphicsScene); 2023 return d->index->items(pos, mode, order, deviceTransform); 2024 } 2025 2026 /*! 2027 \fn QList<QGraphicsItem *> QGraphicsScene::items(const QRectF &rect, Qt::ItemSelectionMode mode, Qt::SortOrder order, const QTransform &deviceTransform) const 2028 \overload 2029 \since 4.6 2030 2031 \brief Returns all visible items that, depending on \a mode, are 2032 either inside or intersect with the specified \a rect and return a 2033 list sorted using \a order. 2034 2035 The default value for \a mode is Qt::IntersectsItemShape; all items whose 2036 exact shape intersects with or is contained by \a rect are returned. 2037 2038 \a deviceTransform is the transformation that applies to the view, and needs to 2039 be provided if the scene contains items that ignore transformations. 2040 2041 \sa itemAt(), {QGraphicsItem#Sorting}{Sorting} 2042 */ 2043 QList<QGraphicsItem *> QGraphicsScene::items(const QRectF &rect, Qt::ItemSelectionMode mode, 2044 Qt::SortOrder order, const QTransform &deviceTransform) const 2045 { 2046 Q_D(const QGraphicsScene); 2047 return d->index->items(rect, mode, order, deviceTransform); 2048 } 2049 2050 /*! 2051 \fn QList<QGraphicsItem *> QGraphicsScene::items(const QPolygonF &polygon, Qt::ItemSelectionMode mode, Qt::SortOrder order, const QTransform &deviceTransform) const 2052 \overload 2053 \since 4.6 2054 2055 \brief Returns all visible items that, depending on \a mode, are 2056 either inside or intersect with the specified \a polygon and return 2057 a list sorted using \a order. 2058 2059 The default value for \a mode is Qt::IntersectsItemShape; all items whose 2060 exact shape intersects with or is contained by \a polygon are returned. 2061 2062 \a deviceTransform is the transformation that applies to the view, and needs to 2063 be provided if the scene contains items that ignore transformations. 2064 2065 \sa itemAt(), {QGraphicsItem#Sorting}{Sorting} 2066 */ 2067 QList<QGraphicsItem *> QGraphicsScene::items(const QPolygonF &polygon, Qt::ItemSelectionMode mode, 2068 Qt::SortOrder order, const QTransform &deviceTransform) const 2069 { 2070 Q_D(const QGraphicsScene); 2071 return d->index->items(polygon, mode, order, deviceTransform); 2072 } 2073 2074 /*! 2075 \fn QList<QGraphicsItem *> QGraphicsScene::items(const QPainterPath &path, Qt::ItemSelectionMode mode, Qt::SortOrder order, const QTransform &deviceTransform) const 2076 \overload 2077 \since 4.6 2078 2079 \brief Returns all visible items that, depending on \a mode, are 2080 either inside or intersect with the specified \a path and return a 2081 list sorted using \a order. 2082 2083 The default value for \a mode is Qt::IntersectsItemShape; all items whose 2084 exact shape intersects with or is contained by \a path are returned. 2085 2086 \a deviceTransform is the transformation that applies to the view, and needs to 2087 be provided if the scene contains items that ignore transformations. 2088 2089 \sa itemAt(), {QGraphicsItem#Sorting}{Sorting} 2090 */ 2091 QList<QGraphicsItem *> QGraphicsScene::items(const QPainterPath &path, Qt::ItemSelectionMode mode, 2092 Qt::SortOrder order, const QTransform &deviceTransform) const 2093 { 2094 Q_D(const QGraphicsScene); 2095 return d->index->items(path, mode, order, deviceTransform); 2541 2096 } 2542 2097 … … 2547 2102 intersects \a item or is contained inside \a item's shape are returned. 2548 2103 2549 The items are returned in descending Z order (i.e., the first item in the 2550 list is the top-most item, and the last item is the bottom-most item). 2551 2552 \sa items(), itemAt(), QGraphicsItem::collidesWithItem() 2104 The items are returned in descending stacking order (i.e., the first item 2105 in the list is the uppermost item, and the last item is the lowermost 2106 item). 2107 2108 \sa items(), itemAt(), QGraphicsItem::collidesWithItem(), {QGraphicsItem#Sorting}{Sorting} 2553 2109 */ 2554 2110 QList<QGraphicsItem *> QGraphicsScene::collidingItems(const QGraphicsItem *item, … … 2561 2117 } 2562 2118 2119 // Does not support ItemIgnoresTransformations. 2563 2120 QList<QGraphicsItem *> tmp; 2564 foreach (QGraphicsItem *itemInVicinity, d-> estimateItemsInRect(item->sceneBoundingRect())) {2121 foreach (QGraphicsItem *itemInVicinity, d->index->estimateItems(item->sceneBoundingRect(), Qt::DescendingOrder)) { 2565 2122 if (item != itemInVicinity && item->collidesWithItem(itemInVicinity, mode)) 2566 2123 tmp << itemInVicinity; 2567 2124 } 2568 d->sortItems(&tmp, Qt::AscendingOrder, d->sortCacheEnabled);2569 2125 return tmp; 2570 2126 } 2571 2127 2572 2128 /*! 2573 \fn QGraphicsItem *QGraphicsScene::itemAt(const QPointF &position) const 2129 \overload 2130 \obsolete 2574 2131 2575 2132 Returns the topmost visible item at the specified \a position, or 0 if 2576 2133 there are no items at this position. 2577 2134 2578 \note The topmost item is the one with the highest Z-value. 2579 2580 \sa items(), collidingItems(), QGraphicsItem::setZValue() 2581 */ 2582 QGraphicsItem *QGraphicsScene::itemAt(const QPointF &pos) const 2583 { 2584 QList<QGraphicsItem *> itemsAtPoint = items(pos); 2135 This function is deprecated and returns incorrect results if the scene 2136 contains items that ignore transformations. Use the overload that takes 2137 a QTransform instead. 2138 2139 \sa items(), collidingItems(), {QGraphicsItem#Sorting}{Sorting} 2140 */ 2141 QGraphicsItem *QGraphicsScene::itemAt(const QPointF &position) const 2142 { 2143 QList<QGraphicsItem *> itemsAtPoint = items(position); 2585 2144 return itemsAtPoint.isEmpty() ? 0 : itemsAtPoint.first(); 2586 2145 } 2146 2147 /*! 2148 \since 4.6 2149 2150 Returns the topmost visible item at the specified \a position, or 0 2151 if there are no items at this position. 2152 2153 \a deviceTransform is the transformation that applies to the view, and needs to 2154 be provided if the scene contains items that ignore transformations. 2155 2156 \sa items(), collidingItems(), {QGraphicsItem#Sorting}{Sorting} 2157 */ 2158 QGraphicsItem *QGraphicsScene::itemAt(const QPointF &position, const QTransform &deviceTransform) const 2159 { 2160 QList<QGraphicsItem *> itemsAtPoint = items(position, Qt::IntersectsItemShape, 2161 Qt::DescendingOrder, deviceTransform); 2162 return itemsAtPoint.isEmpty() ? 0 : itemsAtPoint.first(); 2163 } 2164 2165 /*! 2166 \fn QGraphicsScene::itemAt(qreal x, qreal y, const QTransform &deviceTransform) const 2167 \overload 2168 \since 4.6 2169 2170 Returns the topmost item at the position specified by (\a x, \a 2171 y), or 0 if there are no items at this position. 2172 2173 \a deviceTransform is the transformation that applies to the view, and needs to 2174 be provided if the scene contains items that ignore transformations. 2175 2176 This convenience function is equivalent to calling \c 2177 {itemAt(QPointF(x, y), deviceTransform)}. 2178 */ 2587 2179 2588 2180 /*! 2589 2181 \fn QGraphicsScene::itemAt(qreal x, qreal y) const 2590 2182 \overload 2183 \obsolete 2591 2184 2592 2185 Returns the topmost item at the position specified by (\a x, \a … … 2596 2189 {itemAt(QPointF(x, y))}. 2597 2190 2598 \note The topmost item is the one with the highest Z-value. 2191 This function is deprecated and returns incorrect results if the scene 2192 contains items that ignore transformations. Use the overload that takes 2193 a QTransform instead. 2599 2194 */ 2600 2195 … … 2636 2231 2637 2232 /*! 2233 \since 4.6 2234 2638 2235 Sets the selection area to \a path. All items within this area are 2639 2236 immediately selected, and all items outside are unselected. You can get 2640 2237 the list of all selected items by calling selectedItems(). 2641 2238 2239 \a deviceTransform is the transformation that applies to the view, and needs to 2240 be provided if the scene contains items that ignore transformations. 2241 2642 2242 For an item to be selected, it must be marked as \e selectable 2643 2243 (QGraphicsItem::ItemIsSelectable). … … 2645 2245 \sa clearSelection(), selectionArea() 2646 2246 */ 2247 void QGraphicsScene::setSelectionArea(const QPainterPath &path, const QTransform &deviceTransform) 2248 { 2249 setSelectionArea(path, Qt::IntersectsItemShape, deviceTransform); 2250 } 2251 2252 /*! 2253 \obsolete 2254 \overload 2255 2256 Sets the selection area to \a path. 2257 2258 This function is deprecated and leads to incorrect results if the scene 2259 contains items that ignore transformations. Use the overload that takes 2260 a QTransform instead. 2261 */ 2647 2262 void QGraphicsScene::setSelectionArea(const QPainterPath &path) 2648 2263 { 2649 setSelectionArea(path, Qt::IntersectsItemShape); 2650 } 2651 2652 /*! 2264 setSelectionArea(path, Qt::IntersectsItemShape, QTransform()); 2265 } 2266 2267 /*! 2268 \obsolete 2653 2269 \overload 2654 2270 \since 4.3 … … 2660 2276 */ 2661 2277 void QGraphicsScene::setSelectionArea(const QPainterPath &path, Qt::ItemSelectionMode mode) 2278 { 2279 setSelectionArea(path, mode, QTransform()); 2280 } 2281 2282 /*! 2283 \overload 2284 \since 4.6 2285 2286 Sets the selection area to \a path using \a mode to determine if items are 2287 included in the selection area. 2288 2289 \a deviceTransform is the transformation that applies to the view, and needs to 2290 be provided if the scene contains items that ignore transformations. 2291 2292 \sa clearSelection(), selectionArea() 2293 */ 2294 void QGraphicsScene::setSelectionArea(const QPainterPath &path, Qt::ItemSelectionMode mode, 2295 const QTransform &deviceTransform) 2662 2296 { 2663 2297 Q_D(QGraphicsScene); … … 2676 2310 2677 2311 // Set all items in path to selected. 2678 foreach (QGraphicsItem *item, items(path, mode )) {2312 foreach (QGraphicsItem *item, items(path, mode, Qt::DescendingOrder, deviceTransform)) { 2679 2313 if (item->flags() & QGraphicsItem::ItemIsSelectable) { 2680 2314 if (!item->isSelected()) … … 2733 2367 { 2734 2368 Q_D(QGraphicsScene); 2735 // Recursive descent delete 2736 for (int i = 0; i < d->indexedItems.size(); ++i) { 2737 if (QGraphicsItem *item = d->indexedItems.at(i)) { 2738 if (!item->parentItem()) 2739 delete item; 2740 } 2741 } 2742 QList<QGraphicsItem *> unindexedParents; 2743 for (int i = 0; i < d->unindexedItems.size(); ++i) { 2744 QGraphicsItem *item = d->unindexedItems.at(i); 2745 if (!item->parentItem()) 2746 unindexedParents << item; 2747 } 2748 d->unindexedItems.clear(); 2749 qDeleteAll(unindexedParents); 2750 2751 d->indexedItems.clear(); 2752 d->freeItemIndexes.clear(); 2369 // NB! We have to clear the index before deleting items; otherwise the 2370 // index might try to access dangling item pointers. 2371 d->index->clear(); 2372 // NB! QGraphicsScenePrivate::unregisterTopLevelItem() removes items 2373 while (!d->topLevelItems.isEmpty()) 2374 delete d->topLevelItems.first(); 2375 Q_ASSERT(d->topLevelItems.isEmpty()); 2753 2376 d->lastItemCount = 0; 2754 d->bspTree.clear(); 2755 d->largestUntransformableItem = QRectF(); 2377 d->allItemsIgnoreHoverEvents = true; 2378 d->allItemsUseDefaultCursor = true; 2379 d->allItemsIgnoreTouchEvents = true; 2756 2380 } 2757 2381 … … 2828 2452 2829 2453 /*! 2830 Adds or moves the item \a item and all its childen to the scene. 2454 Adds or moves the \a item and all its childen to this scene. 2455 This scene takes ownership of the \a item. 2831 2456 2832 2457 If the item is visible (i.e., QGraphicsItem::isVisible() returns … … 2834 2459 to the event loop. 2835 2460 2836 If the item is already in a different scene, it will first be removed from 2837 its old scene, and then added to this scene as a top-level. 2838 2839 QGraphicsScene will send ItemSceneChange notifications to \a item while 2840 it is added to the scene. If item does not currently belong to a scene, only one 2841 notification is sent. If it does belong to scene already (i.e., it is 2842 moved to this scene), QGraphicsScene will send an addition notification as 2843 the item is removed from its previous scene. 2461 If the item is already in a different scene, it will first be 2462 removed from its old scene, and then added to this scene as a 2463 top-level. 2464 2465 QGraphicsScene will send ItemSceneChange notifications to \a item 2466 while it is added to the scene. If item does not currently belong 2467 to a scene, only one notification is sent. If it does belong to 2468 scene already (i.e., it is moved to this scene), QGraphicsScene 2469 will send an addition notification as the item is removed from its 2470 previous scene. 2471 2472 If the item is a panel, the scene is active, and there is no 2473 active panel in the scene, then the item will be activated. 2844 2474 2845 2475 \sa removeItem(), addEllipse(), addLine(), addPath(), addPixmap(), 2846 addRect(), addText(), addWidget() 2476 addRect(), addText(), addWidget(), {QGraphicsItem#Sorting}{Sorting} 2847 2477 */ 2848 2478 void QGraphicsScene::addItem(QGraphicsItem *item) … … 2857 2487 return; 2858 2488 } 2859 2860 2489 // Remove this item from its existing scene 2861 2490 if (QGraphicsScene *oldScene = item->scene()) … … 2873 2502 } 2874 2503 2875 // Prevent reusing a recently deleted pointer: purge all removed items2876 // from our lists.2877 d->purgeRemovedItems();2878 2879 // Invalidate any sort caching; arrival of a new item means we need to2880 // resort.2881 d->invalidateSortCache();2882 2883 2504 // Detach this item from its parent if the parent's scene is different 2884 2505 // from this scene. … … 2891 2512 item->d_func()->scene = targetScene; 2892 2513 2893 // Indexing requires sceneBoundingRect(), but because \a item might 2894 // not be completely constructed at this point, we need to store it in 2895 // a temporary list and schedule an indexing for later. 2896 d->unindexedItems << item; 2897 item->d_func()->index = -1; 2898 d->startIndexTimer(); 2899 2900 // Update the scene's sort cache settings. 2901 item->d_ptr->globalStackingOrder = -1; 2902 d->invalidateSortCache(); 2514 // Add the item in the index 2515 d->index->addItem(item); 2516 2517 // Add to list of toplevels if this item is a toplevel. 2518 if (!item->d_ptr->parent) 2519 d->registerTopLevelItem(item); 2903 2520 2904 2521 // Add to list of items that require an update. We cannot assume that the 2905 2522 // item is fully constructed, so calling item->update() can lead to a pure 2906 2523 // virtual function call to boundingRect(). 2907 if (!d->updateAll) { 2908 if (d->pendingUpdateItems.isEmpty()) 2909 QMetaObject::invokeMethod(this, "_q_updateLater", Qt::QueuedConnection); 2910 d->pendingUpdateItems << item; 2911 } 2524 d->markDirty(item); 2525 d->dirtyGrowingItemsBoundingRect = true; 2912 2526 2913 2527 // Disable selectionChanged() for individual items 2914 2528 ++d->selectionChanging; 2915 2529 int oldSelectedItemSize = d->selectedItems.size(); 2530 2531 // Enable mouse tracking if the item accepts hover events or has a cursor set. 2532 if (d->allItemsIgnoreHoverEvents && d->itemAcceptsHoverEvents_helper(item)) { 2533 d->allItemsIgnoreHoverEvents = false; 2534 d->enableMouseTrackingOnViews(); 2535 } 2536 #ifndef QT_NO_CURSOR 2537 if (d->allItemsUseDefaultCursor && item->hasCursor()) { 2538 d->allItemsUseDefaultCursor = false; 2539 if (d->allItemsIgnoreHoverEvents) // already enabled otherwise 2540 d->enableMouseTrackingOnViews(); 2541 } 2542 #endif //QT_NO_CURSOR 2543 2544 // Enable touch events if the item accepts touch events. 2545 if (d->allItemsIgnoreTouchEvents && item->acceptTouchEvents()) { 2546 d->allItemsIgnoreTouchEvents = false; 2547 d->enableTouchEventsOnViews(); 2548 } 2916 2549 2917 2550 // Update selection lists … … 2920 2553 if (item->isWidget() && item->isVisible() && static_cast<QGraphicsWidget *>(item)->windowType() == Qt::Popup) 2921 2554 d->addPopup(static_cast<QGraphicsWidget *>(item)); 2555 if (item->isPanel() && item->isVisible() && item->panelModality() != QGraphicsItem::NonModal) 2556 d->enterModal(item); 2922 2557 2923 2558 // Update creation order focus chain. Make sure to leave the widget's … … 2948 2583 item->d_ptr->resolvePalette(d->palette.resolve()); 2949 2584 2950 if (!item->d_ptr->explicitlyHidden) { 2951 if (d->unpolishedItems.isEmpty()) 2952 QMetaObject::invokeMethod(this, "_q_polishItems", Qt::QueuedConnection); 2953 d->unpolishedItems << item; 2954 } 2585 if (d->unpolishedItems.isEmpty()) 2586 QMetaObject::invokeMethod(this, "_q_polishItems", Qt::QueuedConnection); 2587 d->unpolishedItems.insert(item); 2588 d->unpolishedItemsModified = true; 2955 2589 2956 2590 // Reenable selectionChanged() for individual items … … 2961 2595 // Deliver post-change notification 2962 2596 item->itemChange(QGraphicsItem::ItemSceneHasChanged, newSceneVariant); 2597 2598 // Update explicit activation 2599 bool autoActivate = true; 2600 if (!d->childExplicitActivation && item->d_ptr->explicitActivate) 2601 d->childExplicitActivation = item->d_ptr->wantsActive ? 1 : 2; 2602 if (d->childExplicitActivation && item->isPanel()) { 2603 if (d->childExplicitActivation == 1) 2604 setActivePanel(item); 2605 else 2606 autoActivate = false; 2607 d->childExplicitActivation = 0; 2608 } else if (!item->d_ptr->parent) { 2609 d->childExplicitActivation = 0; 2610 } 2611 2612 // Auto-activate this item's panel if nothing else has been activated 2613 if (autoActivate) { 2614 if (!d->lastActivePanel && !d->activePanel && item->isPanel()) { 2615 if (isActive()) 2616 setActivePanel(item); 2617 else 2618 d->lastActivePanel = item; 2619 } 2620 } 2621 2622 if (item->flags() & QGraphicsItem::ItemSendsScenePositionChanges) 2623 d->registerScenePosItem(item); 2624 2625 // Ensure that newly added items that have subfocus set, gain 2626 // focus automatically if there isn't a focus item already. 2627 if (!d->focusItem && item != d->lastFocusItem && item->focusItem() == item) 2628 item->focusItem()->setFocus(); 2629 2630 d->updateInputMethodSensitivityInViews(); 2963 2631 } 2964 2632 … … 3232 2900 } 3233 2901 3234 // If the item has focus, remove it (and any focusWidget reference). 3235 item->clearFocus(); 3236 3237 // Clear its background 3238 item->update(); 3239 3240 // Note: This will access item's sceneBoundingRect(), which (as this is 3241 // C++) is why we cannot call removeItem() from QGraphicsItem's 3242 // destructor. 3243 d->removeFromIndex(item); 3244 3245 if (item == d->tabFocusFirst) { 3246 QGraphicsWidget *widget = static_cast<QGraphicsWidget *>(item); 3247 widget->d_func()->fixFocusChainBeforeReparenting(0, 0); 3248 } 3249 // Set the item's scene ptr to 0. 3250 item->d_func()->scene = 0; 3251 3252 // Detach the item from its parent. 3253 if (QGraphicsItem *parentItem = item->parentItem()) { 3254 if (parentItem->scene()) { 3255 Q_ASSERT_X(parentItem->scene() == this, "QGraphicsScene::removeItem", 3256 "Parent item's scene is different from this item's scene"); 3257 item->setParentItem(0); 3258 } 3259 } 3260 3261 // Remove from our item lists. 3262 int index = item->d_func()->index; 3263 if (index != -1) { 3264 d->freeItemIndexes << index; 3265 d->indexedItems[index] = 0; 3266 } else { 3267 d->unindexedItems.removeAll(item); 3268 } 3269 3270 // Remove from scene transform cache 3271 int transformIndex = item->d_func()->sceneTransformIndex; 3272 if (transformIndex != -1) { 3273 d->validTransforms.setBit(transformIndex, 0); 3274 d->freeSceneTransformSlots.append(transformIndex); 3275 item->d_func()->sceneTransformIndex = -1; 3276 } 3277 3278 if (item == d->focusItem) 3279 d->focusItem = 0; 3280 if (item == d->lastFocusItem) 3281 d->lastFocusItem = 0; 3282 if (item == d->activeWindow) { 3283 // ### deactivate... 3284 d->activeWindow = 0; 3285 } 3286 3287 // Disable selectionChanged() for individual items 3288 ++d->selectionChanging; 3289 int oldSelectedItemsSize = d->selectedItems.size(); 3290 3291 // Update selected & hovered item bookkeeping 3292 d->selectedItems.remove(item); 3293 d->hoverItems.removeAll(item); 3294 d->pendingUpdateItems.removeAll(item); 3295 d->cachedItemsUnderMouse.removeAll(item); 3296 d->unpolishedItems.removeAll(item); 3297 d->dirtyItems.removeAll(item); 3298 3299 //We remove all references of item from the sceneEventFilter arrays 3300 QMultiMap<QGraphicsItem*, QGraphicsItem*>::iterator iterator = d->sceneEventFilters.begin(); 3301 while (iterator != d->sceneEventFilters.end()) { 3302 if (iterator.value() == item || iterator.key() == item) 3303 iterator = d->sceneEventFilters.erase(iterator); 3304 else 3305 ++iterator; 3306 } 3307 3308 3309 //Ensure dirty flag have the correct default value so the next time it will be added it will receive updates 3310 item->d_func()->dirty = 0; 3311 item->d_func()->dirtyChildren = 0; 3312 3313 // Remove all children recursively 3314 foreach (QGraphicsItem *child, item->children()) 3315 removeItem(child); 3316 3317 // Reset the mouse grabber and focus item data. 3318 if (d->mouseGrabberItems.contains(item)) 3319 d->ungrabMouse(item); 3320 3321 // Reset the keyboard grabber 3322 if (d->keyboardGrabberItems.contains(item)) 3323 item->ungrabKeyboard(); 3324 3325 // Reset the last mouse grabber item 3326 if (item == d->lastMouseGrabberItem) 3327 d->lastMouseGrabberItem = 0; 3328 3329 // Reenable selectionChanged() for individual items 3330 --d->selectionChanging; 3331 3332 if (!d->selectionChanging && d->selectedItems.size() != oldSelectedItemsSize) 3333 emit selectionChanged(); 2902 d->removeItemHelper(item); 3334 2903 3335 2904 // Deliver post-change notification 3336 2905 item->itemChange(QGraphicsItem::ItemSceneHasChanged, newSceneVariant); 3337 } 3338 3339 /*! 3340 Returns the scene's current focus item, or 0 if no item currently has 3341 focus. 2906 2907 d->updateInputMethodSensitivityInViews(); 2908 } 2909 2910 /*! 2911 When the scene is active, this functions returns the scene's current focus 2912 item, or 0 if no item currently has focus. When the scene is inactive, this 2913 functions returns the item that will gain input focus when the scene becomes 2914 active. 3342 2915 3343 2916 The focus item receives keyboard input when the scene receives a 3344 2917 key event. 3345 2918 3346 \sa setFocusItem(), QGraphicsItem::hasFocus() 2919 \sa setFocusItem(), QGraphicsItem::hasFocus(), isActive() 3347 2920 */ 3348 2921 QGraphicsItem *QGraphicsScene::focusItem() const 3349 2922 { 3350 2923 Q_D(const QGraphicsScene); 3351 return d->focusItem;2924 return isActive() ? d->focusItem : d->lastFocusItem; 3352 2925 } 3353 2926 … … 3371 2944 { 3372 2945 Q_D(QGraphicsScene); 3373 if (item == d->focusItem) 3374 return; 3375 if (item && (!(item->flags() & QGraphicsItem::ItemIsFocusable) 3376 || !item->isVisible() || !item->isEnabled())) { 3377 item = 0; 3378 } 3379 3380 if (item) { 3381 setFocus(focusReason); 3382 if (item == d->focusItem) 3383 return; 3384 } 3385 3386 if (d->focusItem) { 3387 QFocusEvent event(QEvent::FocusOut, focusReason); 3388 d->lastFocusItem = d->focusItem; 3389 d->focusItem = 0; 3390 d->sendEvent(d->lastFocusItem, &event); 3391 } 3392 3393 if (item) { 3394 if (item->isWidget()) { 3395 // Update focus child chain. 3396 static_cast<QGraphicsWidget *>(item)->d_func()->setFocusWidget(); 3397 } 3398 3399 d->focusItem = item; 3400 QFocusEvent event(QEvent::FocusIn, focusReason); 3401 d->sendEvent(item, &event); 3402 } 2946 if (item) 2947 item->setFocus(focusReason); 2948 else 2949 d->setFocusItemHelper(item, focusReason); 3403 2950 } 3404 2951 … … 3429 2976 { 3430 2977 Q_D(QGraphicsScene); 3431 if (d->hasFocus )2978 if (d->hasFocus || !isActive()) 3432 2979 return; 3433 2980 QFocusEvent event(QEvent::FocusIn, focusReason); … … 3455 3002 /*! 3456 3003 \property QGraphicsScene::stickyFocus 3457 \brief whether or not clicking the scene will clear focus 3458 3459 If this property is false (the default), then clicking on the scene 3460 background or on an item that does not accept focus, will clear 3461 focus. Otherwise, focus will remain unchanged. 3462 3463 The focus change happens in response to a mouse press. You can reimplement 3004 \brief whether clicking into the scene background will clear focus 3005 3006 \since 4.6 3007 3008 In a QGraphicsScene with stickyFocus set to true, focus will remain 3009 unchanged when the user clicks into the scene background or on an item 3010 that does not accept focus. Otherwise, focus will be cleared. 3011 3012 By default, this property is false. 3013 3014 Focus changes in response to a mouse press. You can reimplement 3464 3015 mousePressEvent() in a subclass of QGraphicsScene to toggle this property 3465 3016 based on where the user has clicked. … … 3584 3135 { 3585 3136 Q_D(const QGraphicsScene); 3586 if (!d->focusItem )3137 if (!d->focusItem || !(d->focusItem->flags() & QGraphicsItem::ItemAcceptsInputMethod)) 3587 3138 return QVariant(); 3588 3139 const QTransform matrix = d->focusItem->sceneTransform(); … … 3613 3164 // Check if anyone's connected; if not, we can send updates directly to 3614 3165 // the views. Otherwise or if there are no views, use old behavior. 3615 bool directUpdates = !(d-> connectedSignals & d->changedSignalMask) && !d->views.isEmpty();3166 bool directUpdates = !(d->isSignalConnected(d->changedSignalIndex)) && !d->views.isEmpty(); 3616 3167 if (rect.isNull()) { 3617 3168 d->updateAll = true; … … 3620 3171 // Update all views. 3621 3172 for (int i = 0; i < d->views.size(); ++i) 3622 d->views.at(i)->d_func()-> updateAll();3173 d->views.at(i)->d_func()->fullUpdatePending = true; 3623 3174 } 3624 3175 } else { … … 3634 3185 } 3635 3186 3636 if (!d irectUpdates && !d->calledEmitUpdated) {3187 if (!d->calledEmitUpdated) { 3637 3188 d->calledEmitUpdated = true; 3638 3189 QMetaObject::invokeMethod(this, "_q_emitUpdated", Qt::QueuedConnection); … … 3745 3296 case QEvent::GraphicsSceneHoverLeave: 3746 3297 case QEvent::GraphicsSceneHoverMove: 3298 case QEvent::TouchBegin: 3299 case QEvent::TouchUpdate: 3300 case QEvent::TouchEnd: 3747 3301 // Reset the under-mouse list to ensure that this event gets fresh 3748 3302 // item-under-mouse data. Be careful about this list; if people delete … … 3750 3304 // having stale pointers in it. We need to clear it before dispatching 3751 3305 // events that use it. 3306 // ### this should only be cleared if we received a new mouse move event, 3307 // which relies on us fixing the replay mechanism in QGraphicsView. 3752 3308 d->cachedItemsUnderMouse.clear(); 3753 3309 default: … … 3805 3361 return false; 3806 3362 case QEvent::GraphicsSceneMouseMove: 3807 mouseMoveEvent(static_cast<QGraphicsSceneMouseEvent *>(event)); 3363 { 3364 QGraphicsSceneMouseEvent *mouseEvent = static_cast<QGraphicsSceneMouseEvent *>(event); 3365 d->lastSceneMousePos = mouseEvent->scenePos(); 3366 mouseMoveEvent(mouseEvent); 3808 3367 break; 3368 } 3809 3369 case QEvent::GraphicsSceneMousePress: 3810 3370 mousePressEvent(static_cast<QGraphicsSceneMouseEvent *>(event)); … … 3828 3388 case QEvent::GraphicsSceneHoverLeave: 3829 3389 case QEvent::GraphicsSceneHoverMove: 3830 d->dispatchHoverEvent(static_cast<QGraphicsSceneHoverEvent *>(event)); 3390 { 3391 QGraphicsSceneHoverEvent *hoverEvent = static_cast<QGraphicsSceneHoverEvent *>(event); 3392 d->lastSceneMousePos = hoverEvent->scenePos(); 3393 d->dispatchHoverEvent(hoverEvent); 3831 3394 break; 3395 } 3832 3396 case QEvent::Leave: 3833 3397 d->leaveScene(); … … 3839 3403 inputMethodEvent(static_cast<QInputMethodEvent *>(event)); 3840 3404 break; 3841 case QEvent::WindowActivate: {3405 case QEvent::WindowActivate: 3842 3406 if (!d->activationRefCount++) { 3843 // Notify all non-window widgets. 3844 foreach (QGraphicsItem *item, items()) { 3845 if (item->isWidget() && item->isVisible() && !item->isWindow() && !item->parentWidget()) { 3846 QEvent event(QEvent::WindowActivate); 3847 QApplication::sendEvent(static_cast<QGraphicsWidget *>(item), &event); 3407 if (d->lastActivePanel) { 3408 // Activate the last panel. 3409 d->setActivePanelHelper(d->lastActivePanel, true); 3410 } else if (d->tabFocusFirst && d->tabFocusFirst->isPanel()) { 3411 // Activate the panel of the first item in the tab focus 3412 // chain. 3413 d->setActivePanelHelper(d->tabFocusFirst, true); 3414 } else { 3415 // Activate all toplevel items. 3416 QEvent event(QEvent::WindowActivate); 3417 foreach (QGraphicsItem *item, items()) { 3418 if (item->isVisible() && !item->isPanel() && !item->parentItem()) 3419 sendEvent(item, &event); 3848 3420 } 3849 3421 } 3850 3851 // Restore window activation.3852 QGraphicsItem *nextFocusItem = d->focusItem ? d->focusItem : d->lastFocusItem;3853 if (nextFocusItem && nextFocusItem->window())3854 setActiveWindow(static_cast<QGraphicsWidget *>(nextFocusItem));3855 else if (d->tabFocusFirst && d->tabFocusFirst->isWindow())3856 setActiveWindow(d->tabFocusFirst);3857 3422 } 3858 3423 break; 3859 } 3860 case QEvent::WindowDeactivate: { 3424 case QEvent::WindowDeactivate: 3861 3425 if (!--d->activationRefCount) { 3862 // Remove window activation. 3863 setActiveWindow(0); 3864 3865 // Notify all non-window widgets. 3866 foreach (QGraphicsItem *item, items()) { 3867 if (item->isWidget() && item->isVisible() && !item->isWindow() && !item->parentWidget()) { 3868 QEvent event(QEvent::WindowDeactivate); 3869 QApplication::sendEvent(static_cast<QGraphicsWidget *>(item), &event); 3426 if (d->activePanel) { 3427 // Deactivate the active panel (but keep it so we can 3428 // reactivate it later). 3429 QGraphicsItem *lastActivePanel = d->activePanel; 3430 d->setActivePanelHelper(0, true); 3431 d->lastActivePanel = lastActivePanel; 3432 } else { 3433 // Activate all toplevel items. 3434 QEvent event(QEvent::WindowDeactivate); 3435 foreach (QGraphicsItem *item, items()) { 3436 if (item->isVisible() && !item->isPanel() && !item->parentItem()) 3437 sendEvent(item, &event); 3870 3438 } 3871 3439 } 3872 3440 } 3873 3441 break; 3874 }3875 3442 case QEvent::ApplicationFontChange: { 3876 3443 // Resolve the existing scene font. … … 3896 3463 update(); 3897 3464 break; 3898 case QEvent::Timer: 3899 if (d->indexTimerId && static_cast<QTimerEvent *>(event)->timerId() == d->indexTimerId) { 3900 if (d->restartIndexTimer) { 3901 d->restartIndexTimer = false; 3902 } else { 3903 // this call will kill the timer 3904 d->_q_updateIndex(); 3905 } 3906 } 3907 // Fallthrough intended - support timers in subclasses. 3465 case QEvent::TouchBegin: 3466 case QEvent::TouchUpdate: 3467 case QEvent::TouchEnd: 3468 d->touchEventHandler(static_cast<QTouchEvent *>(event)); 3469 break; 3470 case QEvent::Gesture: 3471 case QEvent::GestureOverride: 3472 d->gestureEventHandler(static_cast<QGestureEvent *>(event)); 3473 break; 3908 3474 default: 3909 3475 return QObject::event(event); … … 3925 3491 switch (event->type()) { 3926 3492 case QEvent::ApplicationPaletteChange: 3927 qApp->postEvent(this, new QEvent(QEvent::ApplicationPaletteChange));3493 QApplication::postEvent(this, new QEvent(QEvent::ApplicationPaletteChange)); 3928 3494 break; 3929 3495 case QEvent::ApplicationFontChange: 3930 qApp->postEvent(this, new QEvent(QEvent::ApplicationFontChange));3496 QApplication::postEvent(this, new QEvent(QEvent::ApplicationFontChange)); 3931 3497 break; 3932 3498 default: … … 4194 3760 point = helpEvent->screenPos(); 4195 3761 } 4196 QToolTip::showText(point, text );3762 QToolTip::showText(point, text, helpEvent->widget()); 4197 3763 helpEvent->setAccepted(!text.isEmpty()); 4198 3764 #endif … … 4201 3767 bool QGraphicsScenePrivate::itemAcceptsHoverEvents_helper(const QGraphicsItem *item) const 4202 3768 { 4203 return item->acceptHoverEvents() 4204 || (item->isWidget() && static_cast<const QGraphicsWidget *>(item)->d_func()->hasDecoration()); 3769 return (!item->isBlockedByModalPanel() && 3770 (item->acceptHoverEvents() 3771 || (item->isWidget() 3772 && static_cast<const QGraphicsWidget *>(item)->d_func()->hasDecoration()))); 4205 3773 } 4206 3774 … … 4215 3783 bool QGraphicsScenePrivate::dispatchHoverEvent(QGraphicsSceneHoverEvent *hoverEvent) 4216 3784 { 3785 if (allItemsIgnoreHoverEvents) 3786 return false; 3787 4217 3788 // Find the first item that accepts hover events, reusing earlier 4218 3789 // calculated data is possible. … … 4237 3808 while (commonAncestorItem && !itemAcceptsHoverEvents_helper(commonAncestorItem)) 4238 3809 commonAncestorItem = commonAncestorItem->parentItem(); 4239 if (commonAncestorItem && commonAncestorItem-> window() != item->window()) {4240 // The common ancestor isn't in the same windowas the two hovered3810 if (commonAncestorItem && commonAncestorItem->panel() != item->panel()) { 3811 // The common ancestor isn't in the same panel as the two hovered 4241 3812 // items. 4242 3813 commonAncestorItem = 0; … … 4259 3830 while (parent && parent != commonAncestorItem) { 4260 3831 parents.prepend(parent); 4261 if (parent->is Window()) {4262 // Stop at the window- we don't deliver beyond this point.3832 if (parent->isPanel()) { 3833 // Stop at the panel - we don't deliver beyond this point. 4263 3834 break; 4264 3835 } … … 4273 3844 4274 3845 // Generate a move event for the item itself 4275 if (item && !hoverItems.isEmpty() && item == hoverItems.last()) { 3846 if (item 3847 && !hoverItems.isEmpty() 3848 && item == hoverItems.last()) { 4276 3849 sendHoverEvent(QEvent::GraphicsSceneHoverMove, item, hoverEvent); 4277 3850 return true; … … 4290 3863 Q_Q(QGraphicsScene); 4291 3864 #ifndef QT_NO_TOOLTIP 4292 // Remove any tooltips 4293 QToolTip::showText(QPoint(), QString()); 3865 QToolTip::hideText(); 4294 3866 #endif 4295 3867 // Send HoverLeave events to all existing hover items, topmost first. … … 4308 3880 while (!hoverItems.isEmpty()) { 4309 3881 QGraphicsItem *lastItem = hoverItems.takeLast(); 4310 if (lastItem->acceptHoverEvents() 4311 || (lastItem->isWidget() && static_cast<QGraphicsWidget*>(lastItem)->d_func()->hasDecoration())) 3882 if (itemAcceptsHoverEvents_helper(lastItem)) 4312 3883 sendHoverEvent(QEvent::GraphicsSceneHoverLeave, lastItem, &hoverEvent); 4313 3884 } … … 4336 3907 // Send it; QGraphicsItem::keyPressEvent ignores it. If the event 4337 3908 // is filtered out, stop propagating it. 3909 if (p->isBlockedByModalPanel()) 3910 break; 4338 3911 if (!d->sendEvent(p, keyEvent)) 4339 3912 break; 4340 } while (!keyEvent->isAccepted() && !p->is Window() && (p = p->parentItem()));3913 } while (!keyEvent->isAccepted() && !p->isPanel() && (p = p->parentItem())); 4341 3914 } else { 4342 3915 keyEvent->ignore(); … … 4366 3939 // Send it; QGraphicsItem::keyPressEvent ignores it. If the event 4367 3940 // is filtered out, stop propagating it. 3941 if (p->isBlockedByModalPanel()) 3942 break; 4368 3943 if (!d->sendEvent(p, keyEvent)) 4369 3944 break; 4370 } while (!keyEvent->isAccepted() && !p->is Window() && (p = p->parentItem()));3945 } while (!keyEvent->isAccepted() && !p->isPanel() && (p = p->parentItem())); 4371 3946 } else { 4372 3947 keyEvent->ignore(); … … 4394 3969 { 4395 3970 Q_D(QGraphicsScene); 3971 if (d->mouseGrabberItems.isEmpty()) { 3972 // Dispatch hover events 3973 QGraphicsSceneHoverEvent hover; 3974 _q_hoverFromMouseEvent(&hover, mouseEvent); 3975 d->dispatchHoverEvent(&hover); 3976 } 3977 4396 3978 d->mousePressEventHandler(mouseEvent); 4397 3979 } … … 4511 4093 bool hasSetFocus = false; 4512 4094 foreach (QGraphicsItem *item, wheelCandidates) { 4513 if (!hasSetFocus && item->isEnabled() && (item->flags() & QGraphicsItem::ItemIsFocusable)) { 4095 if (!hasSetFocus && item->isEnabled() 4096 && ((item->flags() & QGraphicsItem::ItemIsFocusable) && item->d_ptr->mouseSetsFocus)) { 4514 4097 if (item->isWidget() && static_cast<QGraphicsWidget *>(item)->focusPolicy() == Qt::WheelFocus) { 4515 4098 hasSetFocus = true; … … 4522 4105 wheelEvent->widget())); 4523 4106 wheelEvent->accept(); 4524 bool is Window = item->isWindow();4107 bool isPanel = item->isPanel(); 4525 4108 d->sendEvent(item, wheelEvent); 4526 if (is Window|| wheelEvent->isAccepted())4109 if (isPanel || wheelEvent->isAccepted()) 4527 4110 break; 4528 4111 } … … 4534 4117 4535 4118 The default implementation forwards the event to the focusItem(). 4536 If no item currently has focus, this function does nothing. 4119 If no item currently has focus or the current focus item does not 4120 accept input methods, this function does nothing. 4537 4121 4538 4122 \sa QGraphicsItem::inputMethodEvent() … … 4541 4125 { 4542 4126 Q_D(QGraphicsScene); 4543 if (!d->focusItem) 4544 return; 4545 d->sendEvent(d->focusItem, event); 4127 if (d->focusItem && (d->focusItem->flags() & QGraphicsItem::ItemAcceptsInputMethod)) 4128 d->sendEvent(d->focusItem, event); 4546 4129 } 4547 4130 … … 4614 4197 const qreal oldPainterOpacity = painter->opacity(); 4615 4198 4616 if (qFuzzy Compare(windowOpacity + 1, qreal(1.0)))4199 if (qFuzzyIsNull(windowOpacity)) 4617 4200 return; 4618 4201 // Set new painter opacity. … … 4651 4234 4652 4235 // Don't use subpixmap if we get a full update. 4653 if (pixmapExposed.isEmpty() || (pixmapExposed. numRects() == 1 && br.contains(pix->rect()))) {4236 if (pixmapExposed.isEmpty() || (pixmapExposed.rectCount() == 1 && br.contains(pix->rect()))) { 4654 4237 pix->fill(Qt::transparent); 4655 4238 pixmapPainter.begin(pix); … … 4677 4260 // Blit the subpixmap into the main pixmap. 4678 4261 pixmapPainter.begin(pix); 4679 pixmapPainter.setCompositionMode(QPainter::CompositionMode_Source);4680 4262 pixmapPainter.setClipRegion(pixmapExposed); 4681 4263 pixmapPainter.drawPixmap(br.topLeft(), subPix); … … 4693 4275 bool painterStateProtection) 4694 4276 { 4695 QGraphicsItemPrivate *itemd = item->d_ptr ;4277 QGraphicsItemPrivate *itemd = item->d_ptr.data(); 4696 4278 QGraphicsItem::CacheMode cacheMode = QGraphicsItem::CacheMode(itemd->cacheMode); 4697 4279 … … 4723 4305 4724 4306 // Fetch the off-screen transparent buffer and exposed area info. 4725 Q StringpixmapKey;4307 QPixmapCache::Key pixmapKey; 4726 4308 QPixmap pix; 4309 bool pixmapFound; 4727 4310 QGraphicsItemCache *itemCache = itemd->extraItemCache(); 4728 4311 if (cacheMode == QGraphicsItem::ItemCoordinateCache) { … … 4734 4317 pixmapKey = itemCache->key; 4735 4318 } else { 4736 if ((pixmapKey = itemCache->deviceData.value(widget).key).isEmpty()) { 4737 pixmapKey.sprintf("qgv-%p-%p", item, widget); 4738 QGraphicsItemCache::DeviceData data; 4739 data.key = pixmapKey; 4740 itemCache->deviceData.insert(widget, data); 4741 } 4319 pixmapKey = itemCache->deviceData.value(widget).key; 4742 4320 } 4743 4321 4744 4322 // Find pixmap in cache. 4745 if (!itemCache->allExposed) 4746 QPixmapCache::find(pixmapKey, pix); 4323 pixmapFound = QPixmapCache::find(pixmapKey, &pix); 4747 4324 4748 4325 // Render using item coordinate cache mode. … … 4769 4346 // Redraw any newly exposed areas. 4770 4347 if (itemCache->allExposed || !itemCache->exposed.isEmpty()) { 4348 4349 //We know that we will modify the pixmap, removing it from the cache 4350 //will detach the one we have and avoid a deep copy 4351 if (pixmapFound) 4352 QPixmapCache::remove(pixmapKey); 4353 4771 4354 // Fit the item's bounding rect into the pixmap's coordinates. 4772 4355 QTransform itemToPixmap; … … 4779 4362 // Generate the item's exposedRect and map its list of expose 4780 4363 // rects to device coordinates. 4781 QStyleOptionGraphicsItem cacheOption= *option;4364 styleOptionTmp = *option; 4782 4365 QRegion pixmapExposed; 4783 4366 QRectF exposedRect; … … 4791 4374 exposedRect = brect; 4792 4375 } 4793 cacheOption.exposedRect = exposedRect;4376 styleOptionTmp.exposedRect = exposedRect; 4794 4377 4795 4378 // Render. 4796 4379 _q_paintIntoCache(&pix, item, pixmapExposed, itemToPixmap, painter->renderHints(), 4797 & cacheOption, painterStateProtection);4798 4799 // Reinsert this pixmap into the cache.4800 QPixmapCache::insert(pixmapKey,pix);4380 &styleOptionTmp, painterStateProtection); 4381 4382 // insert this pixmap into the cache. 4383 itemCache->key = QPixmapCache::insert(pix); 4801 4384 4802 4385 // Reset expose data. … … 4864 4447 #else 4865 4448 // Only if deviceRect is 20% taller or wider than the desktop. 4866 QRect desktopRect = qApp->desktop()->availableGeometry(widget); 4867 bool allowPartialCacheExposure = (desktopRect.width() * 1.2 < deviceRect.width() 4868 || desktopRect.height() * 1.2 < deviceRect.height()); 4449 bool allowPartialCacheExposure = false; 4450 if (widget) { 4451 QRect desktopRect = QApplication::desktop()->availableGeometry(widget); 4452 allowPartialCacheExposure = (desktopRect.width() * 1.2 < deviceRect.width() 4453 || desktopRect.height() * 1.2 < deviceRect.height()); 4454 } 4869 4455 #endif 4870 4456 QRegion scrollExposure; … … 4925 4511 // Check for newly invalidated areas. 4926 4512 if (itemCache->allExposed || !itemCache->exposed.isEmpty() || !scrollExposure.isEmpty()) { 4513 //We know that we will modify the pixmap, removing it from the cache 4514 //will detach the one we have and avoid a deep copy 4515 if (pixmapFound) 4516 QPixmapCache::remove(pixmapKey); 4517 4927 4518 // Construct an item-to-pixmap transform. 4928 4519 QPointF p = deviceRect.topLeft(); … … 4951 4542 br |= pixmapToItem.mapRect(r); 4952 4543 } 4953 QStyleOptionGraphicsItem cacheOption= *option;4954 cacheOption.exposedRect = br.adjusted(-1, -1, 1, 1);4544 styleOptionTmp = *option; 4545 styleOptionTmp.exposedRect = br.adjusted(-1, -1, 1, 1); 4955 4546 4956 4547 // Render the exposed areas. 4957 4548 _q_paintIntoCache(&pix, item, pixmapExposed, itemToPixmap, painter->renderHints(), 4958 & cacheOption, painterStateProtection);4549 &styleOptionTmp, painterStateProtection); 4959 4550 4960 4551 // Reset expose data. … … 4965 4556 4966 4557 if (pixModified) { 4967 // Reinsert this pixmap into the cache4968 QPixmapCache::insert(pixmapKey,pix);4558 // Insert this pixmap into the cache. 4559 deviceData->key = QPixmapCache::insert(pix); 4969 4560 } 4970 4561 … … 4985 4576 } 4986 4577 4578 void QGraphicsScenePrivate::drawItems(QPainter *painter, const QTransform *const viewTransform, 4579 QRegion *exposedRegion, QWidget *widget) 4580 { 4581 // Make sure we don't have unpolished items before we draw. 4582 if (!unpolishedItems.isEmpty()) 4583 _q_polishItems(); 4584 4585 QRectF exposedSceneRect; 4586 if (exposedRegion && indexMethod != QGraphicsScene::NoIndex) { 4587 exposedSceneRect = exposedRegion->boundingRect().adjusted(-1, -1, 1, 1); 4588 if (viewTransform) 4589 exposedSceneRect = viewTransform->inverted().mapRect(exposedSceneRect); 4590 } 4591 const QList<QGraphicsItem *> tli = index->estimateTopLevelItems(exposedSceneRect, Qt::AscendingOrder); 4592 for (int i = 0; i < tli.size(); ++i) 4593 drawSubtreeRecursive(tli.at(i), painter, viewTransform, exposedRegion, widget); 4594 } 4595 4596 void QGraphicsScenePrivate::drawSubtreeRecursive(QGraphicsItem *item, QPainter *painter, 4597 const QTransform *const viewTransform, 4598 QRegion *exposedRegion, QWidget *widget, 4599 qreal parentOpacity, const QTransform *const effectTransform) 4600 { 4601 Q_ASSERT(item); 4602 4603 if (!item->d_ptr->visible) 4604 return; 4605 4606 const bool itemHasContents = !(item->d_ptr->flags & QGraphicsItem::ItemHasNoContents); 4607 const bool itemHasChildren = !item->d_ptr->children.isEmpty(); 4608 if (!itemHasContents && !itemHasChildren) 4609 return; // Item has neither contents nor children!(?) 4610 4611 const qreal opacity = item->d_ptr->combineOpacityFromParent(parentOpacity); 4612 const bool itemIsFullyTransparent = (opacity < 0.0001); 4613 if (itemIsFullyTransparent && (!itemHasChildren || item->d_ptr->childrenCombineOpacity())) 4614 return; 4615 4616 QTransform transform(Qt::Uninitialized); 4617 QTransform *transformPtr = 0; 4618 bool translateOnlyTransform = false; 4619 #define ENSURE_TRANSFORM_PTR \ 4620 if (!transformPtr) { \ 4621 Q_ASSERT(!itemIsUntransformable); \ 4622 if (viewTransform) { \ 4623 transform = item->d_ptr->sceneTransform; \ 4624 transform *= *viewTransform; \ 4625 transformPtr = &transform; \ 4626 } else { \ 4627 transformPtr = &item->d_ptr->sceneTransform; \ 4628 translateOnlyTransform = item->d_ptr->sceneTransformTranslateOnly; \ 4629 } \ 4630 } 4631 4632 // Update the item's scene transform if the item is transformable; 4633 // otherwise calculate the full transform, 4634 bool wasDirtyParentSceneTransform = false; 4635 const bool itemIsUntransformable = item->d_ptr->itemIsUntransformable(); 4636 if (itemIsUntransformable) { 4637 transform = item->deviceTransform(viewTransform ? *viewTransform : QTransform()); 4638 transformPtr = &transform; 4639 } else if (item->d_ptr->dirtySceneTransform) { 4640 item->d_ptr->updateSceneTransformFromParent(); 4641 Q_ASSERT(!item->d_ptr->dirtySceneTransform); 4642 wasDirtyParentSceneTransform = true; 4643 } 4644 4645 const bool itemClipsChildrenToShape = (item->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape); 4646 bool drawItem = itemHasContents && !itemIsFullyTransparent; 4647 if (drawItem) { 4648 const QRectF brect = adjustedItemEffectiveBoundingRect(item); 4649 ENSURE_TRANSFORM_PTR 4650 QRect viewBoundingRect = translateOnlyTransform ? brect.translated(transformPtr->dx(), transformPtr->dy()).toRect() 4651 : transformPtr->mapRect(brect).toRect(); 4652 if (widget) 4653 item->d_ptr->paintedViewBoundingRects.insert(widget, viewBoundingRect); 4654 viewBoundingRect.adjust(-1, -1, 1, 1); 4655 drawItem = exposedRegion ? exposedRegion->intersects(viewBoundingRect) : !viewBoundingRect.isEmpty(); 4656 if (!drawItem) { 4657 if (!itemHasChildren) 4658 return; 4659 if (itemClipsChildrenToShape) { 4660 if (wasDirtyParentSceneTransform) 4661 item->d_ptr->invalidateChildrenSceneTransform(); 4662 return; 4663 } 4664 } 4665 } // else we know for sure this item has children we must process. 4666 4667 if (itemHasChildren && itemClipsChildrenToShape) 4668 ENSURE_TRANSFORM_PTR; 4669 4670 #ifndef QT_NO_GRAPHICSEFFECT 4671 if (item->d_ptr->graphicsEffect && item->d_ptr->graphicsEffect->isEnabled()) { 4672 ENSURE_TRANSFORM_PTR; 4673 QGraphicsItemPaintInfo info(viewTransform, transformPtr, effectTransform, exposedRegion, widget, &styleOptionTmp, 4674 painter, opacity, wasDirtyParentSceneTransform, drawItem); 4675 QGraphicsEffectSource *source = item->d_ptr->graphicsEffect->d_func()->source; 4676 QGraphicsItemEffectSourcePrivate *sourced = static_cast<QGraphicsItemEffectSourcePrivate *> 4677 (source->d_func()); 4678 sourced->info = &info; 4679 const QTransform restoreTransform = painter->worldTransform(); 4680 if (effectTransform) 4681 painter->setWorldTransform(*transformPtr * *effectTransform); 4682 else 4683 painter->setWorldTransform(*transformPtr); 4684 painter->setOpacity(opacity); 4685 4686 if (sourced->currentCachedSystem() != Qt::LogicalCoordinates 4687 && sourced->lastEffectTransform != painter->worldTransform()) 4688 { 4689 sourced->lastEffectTransform = painter->worldTransform(); 4690 sourced->invalidateCache(QGraphicsEffectSourcePrivate::TransformChanged); 4691 } 4692 4693 item->d_ptr->graphicsEffect->draw(painter); 4694 painter->setWorldTransform(restoreTransform); 4695 sourced->info = 0; 4696 } else 4697 #endif //QT_NO_GRAPHICSEFFECT 4698 { 4699 draw(item, painter, viewTransform, transformPtr, exposedRegion, widget, opacity, 4700 effectTransform, wasDirtyParentSceneTransform, drawItem); 4701 } 4702 } 4703 4704 void QGraphicsScenePrivate::draw(QGraphicsItem *item, QPainter *painter, const QTransform *const viewTransform, 4705 const QTransform *const transformPtr, QRegion *exposedRegion, QWidget *widget, 4706 qreal opacity, const QTransform *effectTransform, 4707 bool wasDirtyParentSceneTransform, bool drawItem) 4708 { 4709 const bool itemIsFullyTransparent = (opacity < 0.0001); 4710 const bool itemClipsChildrenToShape = (item->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape); 4711 const bool itemHasChildren = !item->d_ptr->children.isEmpty(); 4712 4713 int i = 0; 4714 if (itemHasChildren) { 4715 item->d_ptr->ensureSortedChildren(); 4716 4717 if (itemClipsChildrenToShape) { 4718 painter->save(); 4719 Q_ASSERT(transformPtr); 4720 if (effectTransform) 4721 painter->setWorldTransform(*transformPtr * *effectTransform); 4722 else 4723 painter->setWorldTransform(*transformPtr); 4724 painter->setClipPath(item->shape(), Qt::IntersectClip); 4725 } 4726 4727 // Draw children behind 4728 for (i = 0; i < item->d_ptr->children.size(); ++i) { 4729 QGraphicsItem *child = item->d_ptr->children.at(i); 4730 if (wasDirtyParentSceneTransform) 4731 child->d_ptr->dirtySceneTransform = 1; 4732 if (!(child->d_ptr->flags & QGraphicsItem::ItemStacksBehindParent)) 4733 break; 4734 if (itemIsFullyTransparent && !(child->d_ptr->flags & QGraphicsItem::ItemIgnoresParentOpacity)) 4735 continue; 4736 drawSubtreeRecursive(child, painter, viewTransform, exposedRegion, widget, opacity, effectTransform); 4737 } 4738 } 4739 4740 // Draw item 4741 if (drawItem) { 4742 Q_ASSERT(!itemIsFullyTransparent); 4743 Q_ASSERT(!(item->d_ptr->flags & QGraphicsItem::ItemHasNoContents)); 4744 Q_ASSERT(transformPtr); 4745 item->d_ptr->initStyleOption(&styleOptionTmp, *transformPtr, exposedRegion 4746 ? *exposedRegion : QRegion(), exposedRegion == 0); 4747 4748 const bool itemClipsToShape = item->d_ptr->flags & QGraphicsItem::ItemClipsToShape; 4749 const bool savePainter = itemClipsToShape || painterStateProtection; 4750 if (savePainter) 4751 painter->save(); 4752 4753 if (!itemHasChildren || !itemClipsChildrenToShape) { 4754 if (effectTransform) 4755 painter->setWorldTransform(*transformPtr * *effectTransform); 4756 else 4757 painter->setWorldTransform(*transformPtr); 4758 } 4759 4760 if (itemClipsToShape) 4761 painter->setClipPath(item->shape(), Qt::IntersectClip); 4762 painter->setOpacity(opacity); 4763 4764 if (!item->d_ptr->cacheMode && !item->d_ptr->isWidget) 4765 item->paint(painter, &styleOptionTmp, widget); 4766 else 4767 drawItemHelper(item, painter, &styleOptionTmp, widget, painterStateProtection); 4768 4769 if (savePainter) 4770 painter->restore(); 4771 } 4772 4773 // Draw children in front 4774 if (itemHasChildren) { 4775 for (; i < item->d_ptr->children.size(); ++i) { 4776 QGraphicsItem *child = item->d_ptr->children.at(i); 4777 if (wasDirtyParentSceneTransform) 4778 child->d_ptr->dirtySceneTransform = 1; 4779 if (itemIsFullyTransparent && !(child->d_ptr->flags & QGraphicsItem::ItemIgnoresParentOpacity)) 4780 continue; 4781 drawSubtreeRecursive(child, painter, viewTransform, exposedRegion, widget, opacity, effectTransform); 4782 } 4783 } 4784 4785 // Restore child clip 4786 if (itemHasChildren && itemClipsChildrenToShape) 4787 painter->restore(); 4788 } 4789 4790 void QGraphicsScenePrivate::markDirty(QGraphicsItem *item, const QRectF &rect, bool invalidateChildren, 4791 bool force, bool ignoreOpacity, bool removingItemFromScene) 4792 { 4793 Q_ASSERT(item); 4794 if (updateAll) 4795 return; 4796 4797 if (item->d_ptr->discardUpdateRequest(/*ignoreVisibleBit=*/force, 4798 /*ignoreDirtyBit=*/removingItemFromScene || invalidateChildren, 4799 /*ignoreOpacity=*/ignoreOpacity)) { 4800 if (item->d_ptr->dirty) { 4801 // The item is already marked as dirty and will be processed later. However, 4802 // we have to make sure ignoreVisible and ignoreOpacity are set properly; 4803 // otherwise things like: item->update(); item->hide() (force is now true) 4804 // won't work as expected. 4805 if (force) 4806 item->d_ptr->ignoreVisible = 1; 4807 if (ignoreOpacity) 4808 item->d_ptr->ignoreOpacity = 1; 4809 } 4810 return; 4811 } 4812 4813 const bool fullItemUpdate = rect.isNull(); 4814 if (!fullItemUpdate && rect.isEmpty()) 4815 return; 4816 4817 if (!processDirtyItemsEmitted) { 4818 QMetaObject::invokeMethod(q_ptr, "_q_processDirtyItems", Qt::QueuedConnection); 4819 processDirtyItemsEmitted = true; 4820 } 4821 4822 if (removingItemFromScene) { 4823 // Note that this function can be called from the item's destructor, so 4824 // do NOT call any virtual functions on it within this block. 4825 if (isSignalConnected(changedSignalIndex) || views.isEmpty()) { 4826 // This block of code is kept for compatibility. Since 4.5, by default 4827 // QGraphicsView does not connect the signal and we use the below 4828 // method of delivering updates. 4829 q_func()->update(); 4830 return; 4831 } 4832 4833 for (int i = 0; i < views.size(); ++i) { 4834 QGraphicsViewPrivate *viewPrivate = views.at(i)->d_func(); 4835 QRect rect = item->d_ptr->paintedViewBoundingRects.value(viewPrivate->viewport); 4836 rect.translate(viewPrivate->dirtyScrollOffset); 4837 viewPrivate->updateRect(rect); 4838 } 4839 return; 4840 } 4841 4842 bool hasNoContents = item->d_ptr->flags & QGraphicsItem::ItemHasNoContents 4843 && !item->d_ptr->graphicsEffect; 4844 if (!hasNoContents) { 4845 item->d_ptr->dirty = 1; 4846 if (fullItemUpdate) 4847 item->d_ptr->fullUpdatePending = 1; 4848 else if (!item->d_ptr->fullUpdatePending) 4849 item->d_ptr->needsRepaint |= rect; 4850 } 4851 4852 if (invalidateChildren) { 4853 item->d_ptr->allChildrenDirty = 1; 4854 item->d_ptr->dirtyChildren = 1; 4855 } 4856 4857 if (force) 4858 item->d_ptr->ignoreVisible = 1; 4859 if (ignoreOpacity) 4860 item->d_ptr->ignoreOpacity = 1; 4861 4862 QGraphicsItem *p = item->d_ptr->parent; 4863 while (p) { 4864 p->d_ptr->dirtyChildren = 1; 4865 #ifndef QT_NO_GRAPHICSEFFECT 4866 if (p->d_ptr->graphicsEffect && p->d_ptr->graphicsEffect->isEnabled()) { 4867 p->d_ptr->dirty = 1; 4868 p->d_ptr->fullUpdatePending = 1; 4869 } 4870 #endif //QT_NO_GRAPHICSEFFECT 4871 p = p->d_ptr->parent; 4872 } 4873 } 4874 4875 static inline bool updateHelper(QGraphicsViewPrivate *view, QGraphicsItemPrivate *item, 4876 const QRectF &rect, bool itemIsUntransformable) 4877 { 4878 Q_ASSERT(view); 4879 Q_ASSERT(item); 4880 4881 QGraphicsItem *itemq = static_cast<QGraphicsItem *>(item->q_ptr); 4882 QGraphicsView *viewq = static_cast<QGraphicsView *>(view->q_ptr); 4883 4884 if (itemIsUntransformable) { 4885 const QTransform xform = itemq->deviceTransform(viewq->viewportTransform()); 4886 if (!item->hasBoundingRegionGranularity) 4887 return view->updateRect(xform.mapRect(rect).toRect()); 4888 return view->updateRegion(xform.map(QRegion(rect.toRect()))); 4889 } 4890 4891 if (item->sceneTransformTranslateOnly && view->identityMatrix) { 4892 const qreal dx = item->sceneTransform.dx(); 4893 const qreal dy = item->sceneTransform.dy(); 4894 if (!item->hasBoundingRegionGranularity) { 4895 QRectF r(rect); 4896 r.translate(dx - view->horizontalScroll(), dy - view->verticalScroll()); 4897 return view->updateRect(r.toRect()); 4898 } 4899 QRegion r(rect.toRect()); 4900 r.translate(qRound(dx) - view->horizontalScroll(), qRound(dy) - view->verticalScroll()); 4901 return view->updateRegion(r); 4902 } 4903 4904 if (!viewq->isTransformed()) { 4905 if (!item->hasBoundingRegionGranularity) 4906 return view->updateRect(item->sceneTransform.mapRect(rect).toRect()); 4907 return view->updateRegion(item->sceneTransform.map(QRegion(rect.toRect()))); 4908 } 4909 4910 QTransform xform = item->sceneTransform; 4911 xform *= viewq->viewportTransform(); 4912 if (!item->hasBoundingRegionGranularity) 4913 return view->updateRect(xform.mapRect(rect).toRect()); 4914 return view->updateRegion(xform.map(QRegion(rect.toRect()))); 4915 } 4916 4917 void QGraphicsScenePrivate::processDirtyItemsRecursive(QGraphicsItem *item, bool dirtyAncestorContainsChildren, 4918 qreal parentOpacity) 4919 { 4920 Q_Q(QGraphicsScene); 4921 Q_ASSERT(item); 4922 Q_ASSERT(!updateAll); 4923 4924 if (!item->d_ptr->dirty && !item->d_ptr->dirtyChildren) { 4925 resetDirtyItem(item); 4926 return; 4927 } 4928 4929 const bool itemIsHidden = !item->d_ptr->ignoreVisible && !item->d_ptr->visible; 4930 if (itemIsHidden) { 4931 resetDirtyItem(item, /*recursive=*/true); 4932 return; 4933 } 4934 4935 bool itemHasContents = !(item->d_ptr->flags & QGraphicsItem::ItemHasNoContents); 4936 const bool itemHasChildren = !item->d_ptr->children.isEmpty(); 4937 if (!itemHasContents) { 4938 if (!itemHasChildren) { 4939 resetDirtyItem(item); 4940 return; // Item has neither contents nor children!(?) 4941 } 4942 if (item->d_ptr->graphicsEffect) 4943 itemHasContents = true; 4944 } 4945 4946 const qreal opacity = item->d_ptr->combineOpacityFromParent(parentOpacity); 4947 const bool itemIsFullyTransparent = !item->d_ptr->ignoreOpacity && opacity < 0.0001; 4948 if (itemIsFullyTransparent && (!itemHasChildren || item->d_ptr->childrenCombineOpacity())) { 4949 resetDirtyItem(item, /*recursive=*/itemHasChildren); 4950 return; 4951 } 4952 4953 bool wasDirtyParentSceneTransform = item->d_ptr->dirtySceneTransform; 4954 const bool itemIsUntransformable = item->d_ptr->itemIsUntransformable(); 4955 if (wasDirtyParentSceneTransform && !itemIsUntransformable) { 4956 item->d_ptr->updateSceneTransformFromParent(); 4957 Q_ASSERT(!item->d_ptr->dirtySceneTransform); 4958 } 4959 4960 const bool wasDirtyParentViewBoundingRects = item->d_ptr->paintedViewBoundingRectsNeedRepaint; 4961 if (itemIsFullyTransparent || !itemHasContents || dirtyAncestorContainsChildren) { 4962 // Make sure we don't process invisible items or items with no content. 4963 item->d_ptr->dirty = 0; 4964 item->d_ptr->fullUpdatePending = 0; 4965 // Might have a dirty view bounding rect otherwise. 4966 if (itemIsFullyTransparent || !itemHasContents) 4967 item->d_ptr->paintedViewBoundingRectsNeedRepaint = 0; 4968 } 4969 4970 if (!hasSceneRect && item->d_ptr->geometryChanged && item->d_ptr->visible) { 4971 // Update growingItemsBoundingRect. 4972 if (item->d_ptr->sceneTransformTranslateOnly) { 4973 growingItemsBoundingRect |= item->boundingRect().translated(item->d_ptr->sceneTransform.dx(), 4974 item->d_ptr->sceneTransform.dy()); 4975 } else { 4976 growingItemsBoundingRect |= item->d_ptr->sceneTransform.mapRect(item->boundingRect()); 4977 } 4978 } 4979 4980 // Process item. 4981 if (item->d_ptr->dirty || item->d_ptr->paintedViewBoundingRectsNeedRepaint) { 4982 const bool useCompatUpdate = views.isEmpty() || isSignalConnected(changedSignalIndex); 4983 const QRectF itemBoundingRect = adjustedItemEffectiveBoundingRect(item); 4984 4985 if (useCompatUpdate && !itemIsUntransformable && qFuzzyIsNull(item->boundingRegionGranularity())) { 4986 // This block of code is kept for compatibility. Since 4.5, by default 4987 // QGraphicsView does not connect the signal and we use the below 4988 // method of delivering updates. 4989 if (item->d_ptr->sceneTransformTranslateOnly) { 4990 q->update(itemBoundingRect.translated(item->d_ptr->sceneTransform.dx(), 4991 item->d_ptr->sceneTransform.dy())); 4992 } else { 4993 q->update(item->d_ptr->sceneTransform.mapRect(itemBoundingRect)); 4994 } 4995 } else { 4996 QRectF dirtyRect; 4997 bool uninitializedDirtyRect = true; 4998 4999 for (int j = 0; j < views.size(); ++j) { 5000 QGraphicsView *view = views.at(j); 5001 QGraphicsViewPrivate *viewPrivate = view->d_func(); 5002 QRect &paintedViewBoundingRect = item->d_ptr->paintedViewBoundingRects[viewPrivate->viewport]; 5003 if (viewPrivate->fullUpdatePending 5004 || viewPrivate->viewportUpdateMode == QGraphicsView::NoViewportUpdate) { 5005 // Okay, if we have a full update pending or no viewport update, this item's 5006 // paintedViewBoundingRect will be updated correctly in the next paintEvent if 5007 // it is inside the viewport, but for now we can pretend that it is outside. 5008 paintedViewBoundingRect = QRect(-1, -1, -1, -1); 5009 continue; 5010 } 5011 5012 if (item->d_ptr->paintedViewBoundingRectsNeedRepaint) { 5013 paintedViewBoundingRect.translate(viewPrivate->dirtyScrollOffset); 5014 if (!viewPrivate->updateRect(paintedViewBoundingRect)) 5015 paintedViewBoundingRect = QRect(-1, -1, -1, -1); // Outside viewport. 5016 } 5017 5018 if (!item->d_ptr->dirty) 5019 continue; 5020 5021 if (!item->d_ptr->paintedViewBoundingRectsNeedRepaint 5022 && paintedViewBoundingRect.x() == -1 && paintedViewBoundingRect.y() == -1 5023 && paintedViewBoundingRect.width() == -1 && paintedViewBoundingRect.height() == -1) { 5024 continue; // Outside viewport. 5025 } 5026 5027 if (uninitializedDirtyRect) { 5028 dirtyRect = itemBoundingRect; 5029 if (!item->d_ptr->fullUpdatePending) { 5030 _q_adjustRect(&item->d_ptr->needsRepaint); 5031 dirtyRect &= item->d_ptr->needsRepaint; 5032 } 5033 uninitializedDirtyRect = false; 5034 } 5035 5036 if (dirtyRect.isEmpty()) 5037 continue; // Discard updates outside the bounding rect. 5038 5039 if (!updateHelper(viewPrivate, item->d_ptr.data(), dirtyRect, itemIsUntransformable) 5040 && item->d_ptr->paintedViewBoundingRectsNeedRepaint) { 5041 paintedViewBoundingRect = QRect(-1, -1, -1, -1); // Outside viewport. 5042 } 5043 } 5044 } 5045 } 5046 5047 // Process children. 5048 if (itemHasChildren && item->d_ptr->dirtyChildren) { 5049 if (!dirtyAncestorContainsChildren) { 5050 dirtyAncestorContainsChildren = item->d_ptr->fullUpdatePending 5051 && (item->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape); 5052 } 5053 const bool allChildrenDirty = item->d_ptr->allChildrenDirty; 5054 const bool parentIgnoresVisible = item->d_ptr->ignoreVisible; 5055 const bool parentIgnoresOpacity = item->d_ptr->ignoreOpacity; 5056 for (int i = 0; i < item->d_ptr->children.size(); ++i) { 5057 QGraphicsItem *child = item->d_ptr->children.at(i); 5058 if (wasDirtyParentSceneTransform) 5059 child->d_ptr->dirtySceneTransform = 1; 5060 if (wasDirtyParentViewBoundingRects) 5061 child->d_ptr->paintedViewBoundingRectsNeedRepaint = 1; 5062 if (parentIgnoresVisible) 5063 child->d_ptr->ignoreVisible = 1; 5064 if (parentIgnoresOpacity) 5065 child->d_ptr->ignoreOpacity = 1; 5066 if (allChildrenDirty) { 5067 child->d_ptr->dirty = 1; 5068 child->d_ptr->fullUpdatePending = 1; 5069 child->d_ptr->dirtyChildren = 1; 5070 child->d_ptr->allChildrenDirty = 1; 5071 } 5072 processDirtyItemsRecursive(child, dirtyAncestorContainsChildren, opacity); 5073 } 5074 } else if (wasDirtyParentSceneTransform) { 5075 item->d_ptr->invalidateChildrenSceneTransform(); 5076 } 5077 5078 resetDirtyItem(item); 5079 } 5080 4987 5081 /*! 4988 5082 Paints the given \a items using the provided \a painter, after the … … 4990 5084 drawn. All painting is done in \e scene coordinates. Before 4991 5085 drawing each item, the painter must be transformed using 4992 QGraphicsItem::scene Matrix().5086 QGraphicsItem::sceneTransform(). 4993 5087 4994 5088 The \a options parameter is the list of style option objects for … … 5008 5102 \snippet doc/src/snippets/graphicssceneadditemsnippet.cpp 0 5009 5103 5104 \obsolete Since Qt 4.6, this function is not called anymore unless 5105 the QGraphicsView::IndirectPainting flag is given as an Optimization 5106 flag. 5107 5010 5108 \sa drawBackground(), drawForeground() 5011 5109 */ … … 5016 5114 { 5017 5115 Q_D(QGraphicsScene); 5018 5019 // Detect if painter state protection is disabled. 5116 // Make sure we don't have unpolished items before we draw. 5117 if (!d->unpolishedItems.isEmpty()) 5118 d->_q_polishItems(); 5119 5020 5120 QTransform viewTransform = painter->worldTransform(); 5021 QVarLengthArray<QGraphicsItem *, 16> childClippers; 5022 5121 Q_UNUSED(options); 5122 5123 // Determine view, expose and flags. 5124 QGraphicsView *view = widget ? qobject_cast<QGraphicsView *>(widget->parentWidget()) : 0; 5125 QRegion *expose = 0; 5126 if (view) 5127 expose = &view->d_func()->exposedRegion; 5128 5129 // Find all toplevels, they are already sorted. 5130 QList<QGraphicsItem *> topLevelItems; 5023 5131 for (int i = 0; i < numItems; ++i) { 5024 QGraphicsItem *item = items[i]; 5025 if (!(item->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren)) { 5026 if (!childClippers.isEmpty()) { 5027 // Item is not clipped to any ancestor: pop all current clippers. 5028 for (int i = 0; i < childClippers.size(); ++i) 5029 painter->restore(); 5030 childClippers.clear(); 5031 } 5032 } else { 5033 // Item is clipped to an ancestor, which may or may not be in our 5034 // child clipper list. Let's start by finding the item's closest 5035 // clipping ancestor. 5036 QGraphicsItem *clipParent = item->parentItem(); 5037 while (clipParent && !(clipParent->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape)) 5038 clipParent = clipParent->parentItem(); 5039 5040 // Pop any in-between clippers. If the clipper is unknown, pop 5041 // them all. ### QVarLengthArray::lastIndexOf(). 5042 int index = -1; 5043 for (int n = childClippers.size() - 1; n >= 0; --n) { 5044 if (childClippers[n] == clipParent) { 5045 index = n; 5046 break; 5047 } 5048 } 5049 if (index != -1) { 5050 int toPop = childClippers.size() - index - 1; 5051 if (toPop > 0) { 5052 for (int i = 0; i < toPop; ++i) 5053 painter->restore(); 5054 childClippers.resize(index + 1); 5055 } 5056 } 5057 5058 // Sanity check 5059 if (!childClippers.isEmpty()) 5060 Q_ASSERT(childClippers[childClippers.size() - 1] == clipParent); 5061 5062 // If the clipper list is empty at this point, but we're still 5063 // clipped to an ancestor, then we need to build the clip chain 5064 // ourselves. There is only one case that can produce this issue: 5065 // This item is stacked behind an ancestor: 5066 // ItemStacksBehindParent. 5067 if (childClippers.isEmpty()) { 5068 Q_ASSERT(clipParent != 0); 5069 // Build a stack of clippers. 5070 QVarLengthArray<QGraphicsItem *, 16> clippers; 5071 QGraphicsItem *p = clipParent; 5072 do { 5073 if (p->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape) 5074 clippers.append(p); 5075 } while ((p = p->parentItem()) && (p->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren)); 5076 5077 // ### This code path can also use the itemTransform 5078 // optimization, but it's hit very rarely. 5079 for (int i = clippers.size() - 1; i >= 0; --i) { 5080 QGraphicsItem *clipper = clippers[i]; 5081 if (clipper->d_ptr->itemIsUntransformable()) { 5082 painter->setWorldTransform(clipper->deviceTransform(viewTransform), false); 5083 } else { 5084 painter->setWorldTransform(clipper->sceneTransform() * viewTransform, false); 5085 } 5086 5087 childClippers.append(clipper); 5088 painter->save(); 5089 painter->setClipPath(clipper->shape(), Qt::IntersectClip); 5090 } 5091 Q_ASSERT(childClippers[childClippers.size() - 1] == clipParent); 5092 } 5093 } 5094 5095 // Set up the painter transform 5096 if (item->d_ptr->itemIsUntransformable()) { 5097 painter->setWorldTransform(item->deviceTransform(viewTransform), false); 5098 } else { 5099 painter->setWorldTransform(item->sceneTransform() * viewTransform, false); 5100 } 5101 5102 // Save painter 5103 bool saveState = (d->painterStateProtection || (item->flags() & QGraphicsItem::ItemClipsToShape)); 5104 if (saveState) 5105 painter->save(); 5106 5107 // Set local clip 5108 if (item->flags() & QGraphicsItem::ItemClipsToShape) 5109 painter->setClipPath(item->shape(), Qt::IntersectClip); 5110 5111 // Setup opacity 5112 painter->setOpacity(item->effectiveOpacity()); 5113 5114 // Draw the item 5115 d->drawItemHelper(item, painter, &options[i], widget, d->painterStateProtection); 5116 5117 if (saveState) 5118 painter->restore(); 5119 5120 if (item->flags() & QGraphicsItem::ItemClipsChildrenToShape) { 5121 // Clip descendents to this item's shape, and keep the painter 5122 // saved. 5123 childClippers.append(item); 5124 painter->save(); 5125 painter->setClipPath(item->shape(), Qt::IntersectClip); 5126 } 5127 } 5128 5129 for (int i = 0; i < childClippers.size(); ++i) 5130 painter->restore(); 5132 QGraphicsItem *item = items[i]->topLevelItem(); 5133 if (!item->d_ptr->itemDiscovered) { 5134 topLevelItems << item; 5135 item->d_ptr->itemDiscovered = 1; 5136 d->drawSubtreeRecursive(item, painter, &viewTransform, expose, widget); 5137 } 5138 } 5139 5140 // Reset discovery bits. 5141 for (int i = 0; i < topLevelItems.size(); ++i) 5142 topLevelItems.at(i)->d_ptr->itemDiscovered = 0; 5131 5143 5132 5144 painter->setWorldTransform(viewTransform); … … 5185 5197 && widget->isEnabled() && widget->isVisibleTo(0) 5186 5198 && (widget->focusPolicy() & Qt::TabFocus) 5187 && (!item || !item->is Window() || item->isAncestorOf(widget))5199 && (!item || !item->isPanel() || item->isAncestorOf(widget)) 5188 5200 ) { 5189 5201 setFocusItem(widget, next ? Qt::TabFocusReason : Qt::BacktabFocusReason); … … 5240 5252 5241 5253 /*! 5242 \internal5243 5244 This private function is called by QGraphicsItem, which is a friend of5245 QGraphicsScene. It is used by QGraphicsScene to record the rectangles that5246 need updating. It also launches a single-shot timer to ensure that5247 updated() will be emitted later.5248 5249 The \a item parameter is the item that changed, and \a rect is the5250 area of the item that changed given in item coordinates.5251 */5252 void QGraphicsScene::itemUpdated(QGraphicsItem *item, const QRectF &rect)5253 {5254 Q_D(QGraphicsScene);5255 // Deliver the actual update.5256 if (!d->updateAll) {5257 if (d->views.isEmpty() || ((d->connectedSignals & d->changedSignalMask) && !item->d_ptr->itemIsUntransformable()5258 && qFuzzyCompare(item->boundingRegionGranularity(), qreal(0.0)))) {5259 // This block of code is kept for compatibility. Since 4.5, by default5260 // QGraphicsView does not connect the signal and we use the below5261 // method of delivering updates.5262 update(item->sceneBoundingRect());5263 } else {5264 // ### Remove _q_adjustedRects().5265 QRectF boundingRect(adjustedItemBoundingRect(item));5266 if (!rect.isNull()) {5267 QRectF adjustedRect(rect);5268 _q_adjustRect(&adjustedRect);5269 boundingRect &= adjustedRect;5270 }5271 5272 // Update each view directly.5273 for (int i = 0; i < d->views.size(); ++i)5274 d->views.at(i)->d_func()->itemUpdated(item, boundingRect);5275 }5276 }5277 if (item->d_ptr->dirty) {5278 d->dirtyItems << item;5279 d->resetDirtyItemsLater();5280 }5281 5282 if (!item->isVisible())5283 return; // Hiding an item won't effect the largestUntransformableItem/sceneRect.5284 5285 // Update d->largestUntransformableItem by mapping this item's bounding5286 // rect back to the topmost untransformable item's untransformed5287 // coordinate system (which sort of equals the 1:1 coordinate system of an5288 // untransformed view).5289 if (item->d_ptr->itemIsUntransformable()) {5290 QGraphicsItem *parent = item;5291 while (parent && (parent->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorIgnoresTransformations))5292 parent = parent->parentItem();5293 d->largestUntransformableItem |= item->mapToItem(parent, item->boundingRect()).boundingRect();5294 }5295 5296 // Only track the automatically growing scene rect if the scene has no5297 // defined scene rect.5298 if (!d->hasSceneRect) {5299 QRectF oldGrowingItemsBoundingRect = d->growingItemsBoundingRect;5300 QRectF adjustedItemSceneBoundingRect(item->sceneBoundingRect());5301 _q_adjustRect(&adjustedItemSceneBoundingRect);5302 d->growingItemsBoundingRect |= adjustedItemSceneBoundingRect;5303 if (d->growingItemsBoundingRect != oldGrowingItemsBoundingRect)5304 emit sceneRectChanged(d->growingItemsBoundingRect);5305 }5306 }5307 5308 /*!5309 5254 \since 4.4 5310 5255 … … 5318 5263 Q_D(const QGraphicsScene); 5319 5264 // ### This function, and the use of styles in general, is non-reentrant. 5320 return d->style ? d->style : qApp->style();5265 return d->style ? d->style : QApplication::style(); 5321 5266 } 5322 5267 … … 5395 5340 { 5396 5341 Q_D(QGraphicsScene); 5397 QFont naturalFont = qApp->font();5342 QFont naturalFont = QApplication::font(); 5398 5343 naturalFont.resolve(0); 5399 5344 QFont resolvedFont = font.resolve(naturalFont); … … 5432 5377 { 5433 5378 Q_D(QGraphicsScene); 5434 QPalette naturalPalette = qApp->palette();5379 QPalette naturalPalette = QApplication::palette(); 5435 5380 naturalPalette.resolve(0); 5436 5381 QPalette resolvedPalette = palette.resolve(naturalPalette); … … 5439 5384 5440 5385 /*! 5386 \since 4.6 5387 5388 Returns true if the scene is active (e.g., it's viewed by 5389 at least one QGraphicsView that is active); otherwise returns false. 5390 5391 \sa QGraphicsItem::isActive(), QWidget::isActiveWindow() 5392 */ 5393 bool QGraphicsScene::isActive() const 5394 { 5395 Q_D(const QGraphicsScene); 5396 return d->activationRefCount > 0; 5397 } 5398 5399 /*! 5400 \since 4.6 5401 Returns the current active panel, or 0 if no panel is currently active. 5402 5403 \sa QGraphicsScene::setActivePanel() 5404 */ 5405 QGraphicsItem *QGraphicsScene::activePanel() const 5406 { 5407 Q_D(const QGraphicsScene); 5408 return d->activePanel; 5409 } 5410 5411 /*! 5412 \since 4.6 5413 Activates \a item, which must be an item in this scene. You 5414 can also pass 0 for \a item, in which case QGraphicsScene will 5415 deactivate any currently active panel. 5416 5417 If the scene is currently inactive, \a item remains inactive until the 5418 scene becomes active (or, ir \a item is 0, no item will be activated). 5419 5420 \sa activePanel(), isActive(), QGraphicsItem::isActive() 5421 */ 5422 void QGraphicsScene::setActivePanel(QGraphicsItem *item) 5423 { 5424 Q_D(QGraphicsScene); 5425 d->setActivePanelHelper(item, false); 5426 } 5427 5428 /*! 5441 5429 \since 4.4 5442 5430 5443 Returns the current active window, or 0 if there isno window is currently5431 Returns the current active window, or 0 if no window is currently 5444 5432 active. 5445 5433 … … 5449 5437 { 5450 5438 Q_D(const QGraphicsScene); 5451 return d->activeWindow; 5439 if (d->activePanel && d->activePanel->isWindow()) 5440 return static_cast<QGraphicsWidget *>(d->activePanel); 5441 return 0; 5452 5442 } 5453 5443 … … 5462 5452 void QGraphicsScene::setActiveWindow(QGraphicsWidget *widget) 5463 5453 { 5464 Q_D(QGraphicsScene);5465 5454 if (widget && widget->scene() != this) { 5466 5455 qWarning("QGraphicsScene::setActiveWindow: widget %p must be part of this scene", … … 5469 5458 } 5470 5459 5471 // Activate the widget's window. 5472 QGraphicsWidget *window = widget ? widget->window() : 0; 5473 if (window == d->activeWindow) 5474 return; 5475 5476 // Deactivate the last active window. 5477 if (d->activeWindow) { 5478 if (QGraphicsWidget *fw = d->activeWindow->focusWidget()) { 5479 // Remove focus from the current focus item. 5480 if (fw == focusItem()) 5481 setFocusItem(0, Qt::ActiveWindowFocusReason); 5482 } 5483 5484 QEvent event(QEvent::WindowDeactivate); 5485 QApplication::sendEvent(d->activeWindow, &event); 5486 } 5487 5488 // Update activate state. 5489 d->activeWindow = window; 5490 QEvent event(QEvent::ActivationChange); 5491 QApplication::sendEvent(this, &event); 5492 5493 // Activate 5494 if (window) { 5495 QEvent event(QEvent::WindowActivate); 5496 QApplication::sendEvent(window, &event); 5497 5460 // Activate the widget's panel (all windows are panels). 5461 QGraphicsItem *panel = widget ? widget->panel() : 0; 5462 setActivePanel(panel); 5463 5464 // Raise 5465 if (panel) { 5498 5466 QList<QGraphicsItem *> siblingWindows; 5499 QGraphicsItem *parent = window->parentItem();5467 QGraphicsItem *parent = panel->parentItem(); 5500 5468 // Raise ### inefficient for toplevels 5501 5469 foreach (QGraphicsItem *sibling, parent ? parent->children() : items()) { 5502 if (sibling != window && sibling->isWidget() 5503 && static_cast<QGraphicsWidget *>(sibling)->isWindow()) { 5470 if (sibling != panel && sibling->isWindow()) 5504 5471 siblingWindows << sibling; 5505 }5506 5472 } 5507 5473 5508 5474 // Find the highest z value. 5509 qreal z = window->zValue();5475 qreal z = panel->zValue(); 5510 5476 for (int i = 0; i < siblingWindows.size(); ++i) 5511 5477 z = qMax(z, siblingWindows.at(i)->zValue()); … … 5513 5479 // This will probably never overflow. 5514 5480 const qreal litt = qreal(0.001); 5515 window->setZValue(z + litt); 5516 5517 if (QGraphicsWidget *focusChild = window->focusWidget()) 5518 focusChild->setFocus(Qt::ActiveWindowFocusReason); 5481 panel->setZValue(z + litt); 5482 } 5483 } 5484 5485 /*! 5486 \since 4.6 5487 5488 Sends event \a event to item \a item through possible event filters. 5489 5490 The event is sent only if the item is enabled. 5491 5492 Returns \c false if the event was filtered or if the item is disabled. 5493 Otherwise returns the value that was returned from the event handler. 5494 5495 \sa QGraphicsItem::sceneEvent(), QGraphicsItem::sceneEventFilter() 5496 */ 5497 bool QGraphicsScene::sendEvent(QGraphicsItem *item, QEvent *event) 5498 { 5499 Q_D(QGraphicsScene); 5500 if (!item) { 5501 qWarning("QGraphicsScene::sendEvent: cannot send event to a null item"); 5502 return false; 5503 } 5504 if (item->scene() != this) { 5505 qWarning("QGraphicsScene::sendEvent: item %p's scene (%p)" 5506 " is different from this scene (%p)", 5507 item, item->scene(), this); 5508 return false; 5509 } 5510 return d->sendEvent(item, event); 5511 } 5512 5513 void QGraphicsScenePrivate::addView(QGraphicsView *view) 5514 { 5515 views << view; 5516 } 5517 5518 void QGraphicsScenePrivate::removeView(QGraphicsView *view) 5519 { 5520 views.removeAll(view); 5521 } 5522 5523 void QGraphicsScenePrivate::updateTouchPointsForItem(QGraphicsItem *item, QTouchEvent *touchEvent) 5524 { 5525 QList<QTouchEvent::TouchPoint> touchPoints = touchEvent->touchPoints(); 5526 for (int i = 0; i < touchPoints.count(); ++i) { 5527 QTouchEvent::TouchPoint &touchPoint = touchPoints[i]; 5528 touchPoint.setRect(item->mapFromScene(touchPoint.sceneRect()).boundingRect()); 5529 touchPoint.setStartPos(item->d_ptr->genericMapFromScene(touchPoint.startScenePos(), touchEvent->widget())); 5530 touchPoint.setLastPos(item->d_ptr->genericMapFromScene(touchPoint.lastScenePos(), touchEvent->widget())); 5531 } 5532 touchEvent->setTouchPoints(touchPoints); 5533 } 5534 5535 int QGraphicsScenePrivate::findClosestTouchPointId(const QPointF &scenePos) 5536 { 5537 int closestTouchPointId = -1; 5538 qreal closestDistance = qreal(0.); 5539 foreach (const QTouchEvent::TouchPoint &touchPoint, sceneCurrentTouchPoints) { 5540 qreal distance = QLineF(scenePos, touchPoint.scenePos()).length(); 5541 if (closestTouchPointId == -1|| distance < closestDistance) { 5542 closestTouchPointId = touchPoint.id(); 5543 closestDistance = distance; 5544 } 5545 } 5546 return closestTouchPointId; 5547 } 5548 5549 void QGraphicsScenePrivate::touchEventHandler(QTouchEvent *sceneTouchEvent) 5550 { 5551 typedef QPair<Qt::TouchPointStates, QList<QTouchEvent::TouchPoint> > StatesAndTouchPoints; 5552 QHash<QGraphicsItem *, StatesAndTouchPoints> itemsNeedingEvents; 5553 5554 for (int i = 0; i < sceneTouchEvent->touchPoints().count(); ++i) { 5555 const QTouchEvent::TouchPoint &touchPoint = sceneTouchEvent->touchPoints().at(i); 5556 5557 // update state 5558 QGraphicsItem *item = 0; 5559 if (touchPoint.state() == Qt::TouchPointPressed) { 5560 if (sceneTouchEvent->deviceType() == QTouchEvent::TouchPad) { 5561 // on touch-pad devices, send all touch points to the same item 5562 item = itemForTouchPointId.isEmpty() 5563 ? 0 5564 : itemForTouchPointId.constBegin().value(); 5565 } 5566 5567 if (!item) { 5568 // determine which item this touch point will go to 5569 cachedItemsUnderMouse = itemsAtPosition(touchPoint.screenPos().toPoint(), 5570 touchPoint.scenePos(), 5571 sceneTouchEvent->widget()); 5572 item = cachedItemsUnderMouse.isEmpty() ? 0 : cachedItemsUnderMouse.first(); 5573 } 5574 5575 if (sceneTouchEvent->deviceType() == QTouchEvent::TouchScreen) { 5576 // on touch-screens, combine this touch point with the closest one we find if it 5577 // is a a direct descendent or ancestor ( 5578 int closestTouchPointId = findClosestTouchPointId(touchPoint.scenePos()); 5579 QGraphicsItem *closestItem = itemForTouchPointId.value(closestTouchPointId); 5580 if (!item 5581 || (closestItem 5582 && (item->isAncestorOf(closestItem) 5583 || closestItem->isAncestorOf(item)))) { 5584 item = closestItem; 5585 } 5586 } 5587 if (!item) 5588 continue; 5589 5590 itemForTouchPointId.insert(touchPoint.id(), item); 5591 sceneCurrentTouchPoints.insert(touchPoint.id(), touchPoint); 5592 } else if (touchPoint.state() == Qt::TouchPointReleased) { 5593 item = itemForTouchPointId.take(touchPoint.id()); 5594 if (!item) 5595 continue; 5596 5597 sceneCurrentTouchPoints.remove(touchPoint.id()); 5598 } else { 5599 item = itemForTouchPointId.value(touchPoint.id()); 5600 if (!item) 5601 continue; 5602 Q_ASSERT(sceneCurrentTouchPoints.contains(touchPoint.id())); 5603 sceneCurrentTouchPoints[touchPoint.id()] = touchPoint; 5604 } 5605 5606 StatesAndTouchPoints &statesAndTouchPoints = itemsNeedingEvents[item]; 5607 statesAndTouchPoints.first |= touchPoint.state(); 5608 statesAndTouchPoints.second.append(touchPoint); 5609 } 5610 5611 if (itemsNeedingEvents.isEmpty()) { 5612 sceneTouchEvent->accept(); 5613 return; 5614 } 5615 5616 bool ignoreSceneTouchEvent = true; 5617 QHash<QGraphicsItem *, StatesAndTouchPoints>::ConstIterator it = itemsNeedingEvents.constBegin(); 5618 const QHash<QGraphicsItem *, StatesAndTouchPoints>::ConstIterator end = itemsNeedingEvents.constEnd(); 5619 for (; it != end; ++it) { 5620 QGraphicsItem *item = it.key(); 5621 5622 (void) item->isBlockedByModalPanel(&item); 5623 5624 // determine event type from the state mask 5625 QEvent::Type eventType; 5626 switch (it.value().first) { 5627 case Qt::TouchPointPressed: 5628 // all touch points have pressed state 5629 eventType = QEvent::TouchBegin; 5630 break; 5631 case Qt::TouchPointReleased: 5632 // all touch points have released state 5633 eventType = QEvent::TouchEnd; 5634 break; 5635 case Qt::TouchPointStationary: 5636 // don't send the event if nothing changed 5637 continue; 5638 default: 5639 // all other combinations 5640 eventType = QEvent::TouchUpdate; 5641 break; 5642 } 5643 5644 QTouchEvent touchEvent(eventType); 5645 touchEvent.setWidget(sceneTouchEvent->widget()); 5646 touchEvent.setDeviceType(sceneTouchEvent->deviceType()); 5647 touchEvent.setModifiers(sceneTouchEvent->modifiers()); 5648 touchEvent.setTouchPointStates(it.value().first); 5649 touchEvent.setTouchPoints(it.value().second); 5650 5651 switch (touchEvent.type()) { 5652 case QEvent::TouchBegin: 5653 { 5654 // if the TouchBegin handler recurses, we assume that means the event 5655 // has been implicitly accepted and continue to send touch events 5656 item->d_ptr->acceptedTouchBeginEvent = true; 5657 bool res = sendTouchBeginEvent(item, &touchEvent) 5658 && touchEvent.isAccepted(); 5659 if (!res) 5660 ignoreSceneTouchEvent = false; 5661 break; 5662 } 5663 default: 5664 if (item->d_ptr->acceptedTouchBeginEvent) { 5665 updateTouchPointsForItem(item, &touchEvent); 5666 (void) sendEvent(item, &touchEvent); 5667 ignoreSceneTouchEvent = false; 5668 } 5669 break; 5670 } 5671 } 5672 sceneTouchEvent->setAccepted(ignoreSceneTouchEvent); 5673 } 5674 5675 bool QGraphicsScenePrivate::sendTouchBeginEvent(QGraphicsItem *origin, QTouchEvent *touchEvent) 5676 { 5677 Q_Q(QGraphicsScene); 5678 5679 if (cachedItemsUnderMouse.isEmpty() || cachedItemsUnderMouse.first() != origin) { 5680 const QTouchEvent::TouchPoint &firstTouchPoint = touchEvent->touchPoints().first(); 5681 cachedItemsUnderMouse = itemsAtPosition(firstTouchPoint.screenPos().toPoint(), 5682 firstTouchPoint.scenePos(), 5683 touchEvent->widget()); 5684 } 5685 Q_ASSERT(cachedItemsUnderMouse.first() == origin); 5686 5687 // Set focus on the topmost enabled item that can take focus. 5688 bool setFocus = false; 5689 foreach (QGraphicsItem *item, cachedItemsUnderMouse) { 5690 if (item->isEnabled() && ((item->flags() & QGraphicsItem::ItemIsFocusable) && item->d_ptr->mouseSetsFocus)) { 5691 if (!item->isWidget() || ((QGraphicsWidget *)item)->focusPolicy() & Qt::ClickFocus) { 5692 setFocus = true; 5693 if (item != q->focusItem()) 5694 q->setFocusItem(item, Qt::MouseFocusReason); 5695 break; 5696 } 5697 } 5698 if (item->isPanel()) 5699 break; 5700 } 5701 5702 // If nobody could take focus, clear it. 5703 if (!stickyFocus && !setFocus) 5704 q->setFocusItem(0, Qt::MouseFocusReason); 5705 5706 bool res = false; 5707 bool eventAccepted = touchEvent->isAccepted(); 5708 foreach (QGraphicsItem *item, cachedItemsUnderMouse) { 5709 // first, try to deliver the touch event 5710 updateTouchPointsForItem(item, touchEvent); 5711 bool acceptTouchEvents = item->acceptTouchEvents(); 5712 touchEvent->setAccepted(acceptTouchEvents); 5713 res = acceptTouchEvents && sendEvent(item, touchEvent); 5714 eventAccepted = touchEvent->isAccepted(); 5715 if (itemForTouchPointId.value(touchEvent->touchPoints().first().id()) == 0) { 5716 // item was deleted 5717 item = 0; 5718 } else { 5719 item->d_ptr->acceptedTouchBeginEvent = (res && eventAccepted); 5720 } 5721 touchEvent->spont = false; 5722 if (res && eventAccepted) { 5723 // the first item to accept the TouchBegin gets an implicit grab. 5724 for (int i = 0; i < touchEvent->touchPoints().count(); ++i) { 5725 const QTouchEvent::TouchPoint &touchPoint = touchEvent->touchPoints().at(i); 5726 itemForTouchPointId[touchPoint.id()] = item; // can be zero 5727 } 5728 break; 5729 } 5730 if (item && item->isPanel()) 5731 break; 5732 } 5733 5734 touchEvent->setAccepted(eventAccepted); 5735 return res; 5736 } 5737 5738 void QGraphicsScenePrivate::enableTouchEventsOnViews() 5739 { 5740 foreach (QGraphicsView *view, views) 5741 view->viewport()->setAttribute(Qt::WA_AcceptTouchEvents, true); 5742 } 5743 5744 void QGraphicsScenePrivate::updateInputMethodSensitivityInViews() 5745 { 5746 for (int i = 0; i < views.size(); ++i) 5747 views.at(i)->d_func()->updateInputMethodSensitivity(); 5748 } 5749 5750 void QGraphicsScenePrivate::enterModal(QGraphicsItem *panel, QGraphicsItem::PanelModality previousModality) 5751 { 5752 Q_Q(QGraphicsScene); 5753 Q_ASSERT(panel && panel->isPanel()); 5754 5755 QGraphicsItem::PanelModality panelModality = panel->d_ptr->panelModality; 5756 if (previousModality != QGraphicsItem::NonModal) { 5757 // the panel is changing from one modality type to another... temporarily set it back so 5758 // that blockedPanels is populated correctly 5759 panel->d_ptr->panelModality = previousModality; 5760 } 5761 5762 QSet<QGraphicsItem *> blockedPanels; 5763 QList<QGraphicsItem *> items = q->items(); // ### store panels separately 5764 for (int i = 0; i < items.count(); ++i) { 5765 QGraphicsItem *item = items.at(i); 5766 if (item->isPanel() && item->isBlockedByModalPanel()) 5767 blockedPanels.insert(item); 5768 } 5769 // blockedPanels contains all currently blocked panels 5770 5771 if (previousModality != QGraphicsItem::NonModal) { 5772 // reset the modality to the proper value, since we changed it above 5773 panel->d_ptr->panelModality = panelModality; 5774 // remove this panel so that it will be reinserted at the front of the stack 5775 modalPanels.removeAll(panel); 5776 } 5777 5778 modalPanels.prepend(panel); 5779 5780 if (!hoverItems.isEmpty()) { 5781 // send GraphicsSceneHoverLeave events to newly blocked hoverItems 5782 QGraphicsSceneHoverEvent hoverEvent; 5783 hoverEvent.setScenePos(lastSceneMousePos); 5784 dispatchHoverEvent(&hoverEvent); 5785 } 5786 5787 if (!mouseGrabberItems.isEmpty() && lastMouseGrabberItemHasImplicitMouseGrab) { 5788 QGraphicsItem *item = mouseGrabberItems.last(); 5789 if (item->isBlockedByModalPanel()) 5790 ungrabMouse(item, /*itemIsDying =*/ false); 5791 } 5792 5793 QEvent windowBlockedEvent(QEvent::WindowBlocked); 5794 QEvent windowUnblockedEvent(QEvent::WindowUnblocked); 5795 for (int i = 0; i < items.count(); ++i) { 5796 QGraphicsItem *item = items.at(i); 5797 if (item->isPanel()) { 5798 if (!blockedPanels.contains(item) && item->isBlockedByModalPanel()) { 5799 // send QEvent::WindowBlocked to newly blocked panels 5800 sendEvent(item, &windowBlockedEvent); 5801 } else if (blockedPanels.contains(item) && !item->isBlockedByModalPanel()) { 5802 // send QEvent::WindowUnblocked to unblocked panels when downgrading 5803 // a panel from SceneModal to PanelModal 5804 sendEvent(item, &windowUnblockedEvent); 5805 } 5806 } 5807 } 5808 } 5809 5810 void QGraphicsScenePrivate::leaveModal(QGraphicsItem *panel) 5811 { 5812 Q_Q(QGraphicsScene); 5813 Q_ASSERT(panel && panel->isPanel()); 5814 5815 QSet<QGraphicsItem *> blockedPanels; 5816 QList<QGraphicsItem *> items = q->items(); // ### same as above 5817 for (int i = 0; i < items.count(); ++i) { 5818 QGraphicsItem *item = items.at(i); 5819 if (item->isPanel() && item->isBlockedByModalPanel()) 5820 blockedPanels.insert(item); 5821 } 5822 5823 modalPanels.removeAll(panel); 5824 5825 QEvent e(QEvent::WindowUnblocked); 5826 for (int i = 0; i < items.count(); ++i) { 5827 QGraphicsItem *item = items.at(i); 5828 if (item->isPanel() && blockedPanels.contains(item) && !item->isBlockedByModalPanel()) 5829 sendEvent(item, &e); 5830 } 5831 5832 // send GraphicsSceneHoverEnter events to newly unblocked items 5833 QGraphicsSceneHoverEvent hoverEvent; 5834 hoverEvent.setScenePos(lastSceneMousePos); 5835 dispatchHoverEvent(&hoverEvent); 5836 } 5837 5838 void QGraphicsScenePrivate::getGestureTargets(const QSet<QGesture *> &gestures, 5839 QWidget *viewport, 5840 QMap<Qt::GestureType, QGesture *> *conflictedGestures, 5841 QList<QList<QGraphicsObject *> > *conflictedItems, 5842 QHash<QGesture *, QGraphicsObject *> *normalGestures) 5843 { 5844 foreach (QGesture *gesture, gestures) { 5845 Qt::GestureType gestureType = gesture->gestureType(); 5846 if (gesture->hasHotSpot()) { 5847 QPoint screenPos = gesture->hotSpot().toPoint(); 5848 QList<QGraphicsItem *> items = itemsAtPosition(screenPos, QPointF(), viewport); 5849 QList<QGraphicsObject *> result; 5850 for (int j = 0; j < items.size(); ++j) { 5851 QGraphicsObject *item = items.at(j)->toGraphicsObject(); 5852 if (!item) 5853 continue; 5854 QGraphicsItemPrivate *d = item->QGraphicsItem::d_func(); 5855 if (d->gestureContext.contains(gestureType)) { 5856 result.append(item); 5857 } 5858 } 5859 DEBUG() << "QGraphicsScenePrivate::getGestureTargets:" 5860 << gesture << result; 5861 if (result.size() == 1) { 5862 normalGestures->insert(gesture, result.first()); 5863 } else if (!result.isEmpty()) { 5864 conflictedGestures->insert(gestureType, gesture); 5865 conflictedItems->append(result); 5866 } 5867 } 5868 } 5869 } 5870 5871 void QGraphicsScenePrivate::gestureEventHandler(QGestureEvent *event) 5872 { 5873 QWidget *viewport = event->widget(); 5874 if (!viewport) 5875 return; 5876 QList<QGesture *> allGestures = event->gestures(); 5877 DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:" 5878 << "Delivering gestures:" << allGestures; 5879 5880 typedef QHash<QGraphicsObject *, QList<QGesture *> > GesturesPerItem; 5881 GesturesPerItem gesturesPerItem; 5882 5883 QSet<QGesture *> startedGestures; 5884 foreach (QGesture *gesture, allGestures) { 5885 QGraphicsObject *target = gestureTargets.value(gesture, 0); 5886 if (!target) { 5887 // when we are not in started mode but don't have a target 5888 // then the only one interested in gesture is the view/scene 5889 if (gesture->state() == Qt::GestureStarted) 5890 startedGestures.insert(gesture); 5891 } else { 5892 gesturesPerItem[target].append(gesture); 5893 } 5894 } 5895 5896 QMap<Qt::GestureType, QGesture *> conflictedGestures; 5897 QList<QList<QGraphicsObject *> > conflictedItems; 5898 QHash<QGesture *, QGraphicsObject *> normalGestures; 5899 getGestureTargets(startedGestures, viewport, &conflictedGestures, &conflictedItems, 5900 &normalGestures); 5901 DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:" 5902 << "Conflicting gestures:" << conflictedGestures.values() << conflictedItems; 5903 Q_ASSERT((conflictedGestures.isEmpty() && conflictedItems.isEmpty()) || 5904 (!conflictedGestures.isEmpty() && !conflictedItems.isEmpty())); 5905 5906 // gestures that were sent as override events, but no one accepted them 5907 QHash<QGesture *, QGraphicsObject *> ignoredConflictedGestures; 5908 5909 // deliver conflicted gestures as override events first 5910 while (!conflictedGestures.isEmpty() && !conflictedItems.isEmpty()) { 5911 // get the topmost item to deliver the override event 5912 Q_ASSERT(!conflictedItems.isEmpty()); 5913 Q_ASSERT(!conflictedItems.first().isEmpty()); 5914 QGraphicsObject *topmost = conflictedItems.first().first(); 5915 for (int i = 1; i < conflictedItems.size(); ++i) { 5916 QGraphicsObject *item = conflictedItems.at(i).first(); 5917 if (qt_closestItemFirst(item, topmost)) { 5918 topmost = item; 5919 } 5920 } 5921 // get a list of gestures to send to the item 5922 QList<Qt::GestureType> grabbedGestures = 5923 topmost->QGraphicsItem::d_func()->gestureContext.keys(); 5924 QList<QGesture *> gestures; 5925 for (int i = 0; i < grabbedGestures.size(); ++i) { 5926 if (QGesture *g = conflictedGestures.value(grabbedGestures.at(i), 0)) { 5927 gestures.append(g); 5928 if (!ignoredConflictedGestures.contains(g)) 5929 ignoredConflictedGestures.insert(g, topmost); 5930 } 5931 } 5932 5933 // send gesture override to the topmost item 5934 QGestureEvent ev(gestures); 5935 ev.t = QEvent::GestureOverride; 5936 ev.setWidget(event->widget()); 5937 // mark event and individual gestures as ignored 5938 ev.ignore(); 5939 foreach(QGesture *g, gestures) 5940 ev.setAccepted(g, false); 5941 DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:" 5942 << "delivering override to" 5943 << topmost << gestures; 5944 sendEvent(topmost, &ev); 5945 // mark all accepted gestures to deliver them as normal gesture events 5946 foreach (QGesture *g, gestures) { 5947 if (ev.isAccepted() || ev.isAccepted(g)) { 5948 conflictedGestures.remove(g->gestureType()); 5949 gestureTargets.remove(g); 5950 // add the gesture to the list of normal delivered gestures 5951 normalGestures.insert(g, topmost); 5952 DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:" 5953 << "override was accepted:" 5954 << g << topmost; 5955 ignoredConflictedGestures.remove(g); 5956 } 5957 } 5958 // remove the item that we've already delivered from the list 5959 for (int i = 0; i < conflictedItems.size(); ) { 5960 QList<QGraphicsObject *> &items = conflictedItems[i]; 5961 if (items.first() == topmost) { 5962 items.removeFirst(); 5963 if (items.isEmpty()) { 5964 conflictedItems.removeAt(i); 5965 continue; 5966 } 5967 } 5968 ++i; 5969 } 5970 } 5971 5972 // put back those started gestures that are not in the conflicted state 5973 // and remember their targets 5974 QHash<QGesture *, QGraphicsObject *>::const_iterator it = normalGestures.begin(), 5975 e = normalGestures.end(); 5976 for (; it != e; ++it) { 5977 QGesture *g = it.key(); 5978 QGraphicsObject *receiver = it.value(); 5979 Q_ASSERT(!gestureTargets.contains(g)); 5980 gestureTargets.insert(g, receiver); 5981 gesturesPerItem[receiver].append(g); 5982 } 5983 it = ignoredConflictedGestures.begin(); 5984 e = ignoredConflictedGestures.end(); 5985 for (; it != e; ++it) { 5986 QGesture *g = it.key(); 5987 QGraphicsObject *receiver = it.value(); 5988 Q_ASSERT(!gestureTargets.contains(g)); 5989 gestureTargets.insert(g, receiver); 5990 gesturesPerItem[receiver].append(g); 5991 } 5992 5993 DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:" 5994 << "Started gestures:" << normalGestures.keys() 5995 << "All gestures:" << gesturesPerItem.values(); 5996 5997 // deliver all events 5998 QList<QGesture *> alreadyIgnoredGestures; 5999 QHash<QGraphicsObject *, QSet<QGesture *> > itemIgnoredGestures; 6000 QList<QGraphicsObject *> targetItems = gesturesPerItem.keys(); 6001 qSort(targetItems.begin(), targetItems.end(), qt_closestItemFirst); 6002 for (int i = 0; i < targetItems.size(); ++i) { 6003 QGraphicsObject *item = targetItems.at(i); 6004 QList<QGesture *> gestures = gesturesPerItem.value(item); 6005 // remove gestures that were already delivered once and were ignored 6006 DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:" 6007 << "already ignored gestures for item" 6008 << item << ":" << itemIgnoredGestures.value(item); 6009 6010 if (itemIgnoredGestures.contains(item)) // don't deliver twice to the same item 6011 continue; 6012 6013 QGraphicsItemPrivate *gid = item->QGraphicsItem::d_func(); 6014 foreach(QGesture *g, alreadyIgnoredGestures) { 6015 QMap<Qt::GestureType, Qt::GestureFlags>::iterator contextit = 6016 gid->gestureContext.find(g->gestureType()); 6017 bool deliver = contextit != gid->gestureContext.end() && 6018 (g->state() == Qt::GestureStarted || 6019 (contextit.value() & Qt::ReceivePartialGestures)); 6020 if (deliver) 6021 gestures += g; 6022 } 6023 if (gestures.isEmpty()) 6024 continue; 6025 DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:" 6026 << "delivering to" 6027 << item << gestures; 6028 QGestureEvent ev(gestures); 6029 ev.setWidget(event->widget()); 6030 sendEvent(item, &ev); 6031 QSet<QGesture *> ignoredGestures; 6032 foreach (QGesture *g, gestures) { 6033 if (!ev.isAccepted() && !ev.isAccepted(g)) { 6034 ignoredGestures.insert(g); 6035 } else { 6036 if (g->state() == Qt::GestureStarted) 6037 gestureTargets[g] = item; 6038 } 6039 } 6040 if (!ignoredGestures.isEmpty()) { 6041 // get a list of items under the (current) hotspot of each ignored 6042 // gesture and start delivery again from the beginning 6043 DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:" 6044 << "item has ignored the event, will propagate." 6045 << item << ignoredGestures; 6046 itemIgnoredGestures[item] += ignoredGestures; 6047 QMap<Qt::GestureType, QGesture *> conflictedGestures; 6048 QList<QList<QGraphicsObject *> > itemsForConflictedGestures; 6049 QHash<QGesture *, QGraphicsObject *> normalGestures; 6050 getGestureTargets(ignoredGestures, viewport, 6051 &conflictedGestures, &itemsForConflictedGestures, 6052 &normalGestures); 6053 QSet<QGraphicsObject *> itemsSet = targetItems.toSet(); 6054 for (int k = 0; k < itemsForConflictedGestures.size(); ++k) 6055 itemsSet += itemsForConflictedGestures.at(k).toSet(); 6056 targetItems = itemsSet.toList(); 6057 qSort(targetItems.begin(), targetItems.end(), qt_closestItemFirst); 6058 alreadyIgnoredGestures = conflictedGestures.values(); 6059 DEBUG() << "QGraphicsScenePrivate::gestureEventHandler:" 6060 << "new targets:" << targetItems; 6061 i = -1; // start delivery again 6062 continue; 6063 } 6064 } 6065 foreach (QGesture *g, startedGestures) { 6066 if (g->gestureCancelPolicy() == QGesture::CancelAllInContext) { 6067 DEBUG() << "lets try to cancel some"; 6068 // find gestures in context in Qt::GestureStarted or Qt::GestureUpdated state and cancel them 6069 cancelGesturesForChildren(g, event->widget()); 6070 } 6071 } 6072 6073 // forget about targets for gestures that have ended 6074 foreach (QGesture *g, allGestures) { 6075 switch (g->state()) { 6076 case Qt::GestureFinished: 6077 case Qt::GestureCanceled: 6078 gestureTargets.remove(g); 6079 break; 6080 default: 6081 break; 6082 } 6083 } 6084 } 6085 6086 void QGraphicsScenePrivate::cancelGesturesForChildren(QGesture *original, QWidget *viewport) 6087 { 6088 Q_ASSERT(original); 6089 QGraphicsItem *originalItem = gestureTargets.value(original); 6090 Q_ASSERT(originalItem); 6091 6092 // iterate over all active gestures and for each find the owner 6093 // if the owner is part of our sub-hierarchy, cancel it. 6094 6095 QSet<QGesture *> canceledGestures; 6096 QHash<QGesture *, QGraphicsObject *>::Iterator iter = gestureTargets.begin(); 6097 while (iter != gestureTargets.end()) { 6098 QGraphicsObject *item = iter.value(); 6099 // note that we don't touch the gestures for our originalItem 6100 if (item != originalItem && originalItem->isAncestorOf(item)) { 6101 DEBUG() << " found a gesture to cancel" << iter.key(); 6102 iter.key()->d_func()->state = Qt::GestureCanceled; 6103 canceledGestures << iter.key(); 6104 } 6105 ++iter; 6106 } 6107 6108 // sort them per target item by cherry picking from almostCanceledGestures and delivering 6109 QSet<QGesture *> almostCanceledGestures = canceledGestures; 6110 QSet<QGesture *>::Iterator setIter; 6111 while (!almostCanceledGestures.isEmpty()) { 6112 QGraphicsObject *target = 0; 6113 QSet<QGesture*> gestures; 6114 setIter = almostCanceledGestures.begin(); 6115 // sort per target item 6116 while (setIter != almostCanceledGestures.end()) { 6117 QGraphicsObject *item = gestureTargets.value(*setIter); 6118 if (target == 0) 6119 target = item; 6120 if (target == item) { 6121 gestures << *setIter; 6122 setIter = almostCanceledGestures.erase(setIter); 6123 } else { 6124 ++setIter; 6125 } 6126 } 6127 Q_ASSERT(target); 6128 6129 QList<QGesture *> list = gestures.toList(); 6130 QGestureEvent ev(list); 6131 sendEvent(target, &ev); 6132 6133 foreach (QGesture *g, list) { 6134 if (ev.isAccepted() || ev.isAccepted(g)) 6135 gestures.remove(g); 6136 } 6137 6138 foreach (QGesture *g, gestures) { 6139 if (!g->hasHotSpot()) 6140 continue; 6141 6142 QPoint screenPos = g->hotSpot().toPoint(); 6143 QList<QGraphicsItem *> items = itemsAtPosition(screenPos, QPointF(), viewport); 6144 for (int j = 0; j < items.size(); ++j) { 6145 QGraphicsObject *item = items.at(j)->toGraphicsObject(); 6146 if (!item) 6147 continue; 6148 QGraphicsItemPrivate *d = item->QGraphicsItem::d_func(); 6149 if (d->gestureContext.contains(g->gestureType())) { 6150 QList<QGesture *> list; 6151 list << g; 6152 QGestureEvent ev(list); 6153 sendEvent(item, &ev); 6154 if (ev.isAccepted() || ev.isAccepted(g)) 6155 break; // successfully delivered 6156 } 6157 } 6158 } 6159 } 6160 6161 QGestureManager *gestureManager = QApplicationPrivate::instance()->gestureManager; 6162 Q_ASSERT(gestureManager); // it would be very odd if we got called without a manager. 6163 for (setIter = canceledGestures.begin(); setIter != canceledGestures.end(); ++setIter) { 6164 gestureManager->recycle(*setIter); 6165 gestureTargets.remove(*setIter); 5519 6166 } 5520 6167 }
Note:
See TracChangeset
for help on using the changeset viewer.