Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qgraphicsscenebsptreeindex.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:significant reason:default
4
5/*!
6 \class QGraphicsSceneBspTreeIndex
7 \brief The QGraphicsSceneBspTreeIndex class provides an implementation of
8 a BSP indexing algorithm for discovering items in QGraphicsScene.
9 \since 4.6
10 \ingroup graphicsview-api
11
12 \internal
13
14 QGraphicsSceneBspTreeIndex index use a BSP(Binary Space Partitioning)
15 implementation to discover items quickly. This implementation is
16 very efficient for static scenes. It has a depth that you can set.
17 The depth directly affects performance and memory usage; the latter
18 growing exponentially with the depth of the tree. With an optimal tree
19 depth, the index can instantly determine the locality of items, even
20 for scenes with thousands or millions of items. This also greatly improves
21 rendering performance.
22
23 By default, the depth value is 0, in which case Qt will guess a reasonable
24 default depth based on the size, location and number of items in the
25 scene. If these parameters change frequently, however, you may experience
26 slowdowns as the index retunes the depth internally. You can avoid
27 potential slowdowns by fixating the tree depth through setting this
28 property.
29
30 The depth of the tree and the size of the scene rectangle decide the
31 granularity of the scene's partitioning. The size of each scene segment is
32 determined by the following algorithm:
33
34 The BSP tree has an optimal size when each segment contains between 0 and
35 10 items.
36
37 \sa QGraphicsScene, QGraphicsView, QGraphicsSceneIndex
38*/
39
40#include <QtCore/qglobal.h>
41
42#include <private/qgraphicsscene_p.h>
43#include <private/qgraphicsscenebsptreeindex_p.h>
44#include <private/qgraphicssceneindex_p.h>
45
46#include <QtCore/qmath.h>
47#include <QtCore/qdebug.h>
48
49#include <algorithm>
50
51using namespace std::chrono_literals;
52
54
55static inline int intmaxlog(int n)
56{
57 return (n > 0 ? qMax(qCeil(qLn(qreal(n)) / qLn(qreal(2))), 5) : 0);
58}
59
60/*!
61 \class QGraphicsSceneBspTreeIndexPrivate
62 \inmodule QtWidgets
63 \internal
64
65 Constructs a private scene bsp index.
66*/
67QGraphicsSceneBspTreeIndexPrivate::QGraphicsSceneBspTreeIndexPrivate(QGraphicsScene *scene)
68 : QGraphicsSceneIndexPrivate(scene),
69 bspTreeDepth(0),
70 restartIndexTimer(false),
71 regenerateIndex(true),
72 lastItemCount(0),
73 purgePending(false),
74 sortCacheEnabled(false),
75 updatingSortCache(false)
76{
77}
78
79
80/*!
81 This method will update the BSP index by removing the items from the temporary
82 unindexed list and add them in the indexedItems list. This will also
83 update the growingItemsBoundingRect if needed. This will update the BSP
84 implementation as well.
85
86 \internal
87*/
88void QGraphicsSceneBspTreeIndexPrivate::_q_updateIndex()
89{
90 if (!indexTimer.isActive())
91 return;
92
93 indexTimer.stop();
94
95 purgeRemovedItems();
96
97 // Add unindexedItems to indexedItems
98 for (int i = 0; i < unindexedItems.size(); ++i) {
99 if (QGraphicsItem *item = unindexedItems.at(i)) {
100 Q_ASSERT(!item->d_ptr->itemDiscovered);
101 if (!freeItemIndexes.isEmpty()) {
102 int freeIndex = freeItemIndexes.takeFirst();
103 item->d_func()->index = freeIndex;
104 indexedItems[freeIndex] = item;
105 } else {
106 item->d_func()->index = indexedItems.size();
107 indexedItems << item;
108 }
109 }
110 }
111
112 // Determine whether we should regenerate the BSP tree.
113 if (bspTreeDepth == 0) {
114 int oldDepth = intmaxlog(lastItemCount);
115 bspTreeDepth = intmaxlog(indexedItems.size());
116 static const int slack = 100;
117 if (bsp.leafCount() == 0 || (oldDepth != bspTreeDepth && qAbs(lastItemCount - indexedItems.size()) > slack)) {
118 // ### Crude algorithm.
119 regenerateIndex = true;
120 }
121 }
122
123 // Regenerate the tree.
124 if (regenerateIndex) {
125 regenerateIndex = false;
126 bsp.initialize(sceneRect, bspTreeDepth);
127 unindexedItems = indexedItems;
128 lastItemCount = indexedItems.size();
129 }
130
131 // Insert all unindexed items into the tree.
132 for (int i = 0; i < unindexedItems.size(); ++i) {
133 if (QGraphicsItem *item = unindexedItems.at(i)) {
134 if (item->d_ptr->itemIsUntransformable()) {
135 untransformableItems << item;
136 continue;
137 }
138 if (item->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren
139 || item->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorContainsChildren)
140 continue;
141
142 bsp.insertItem(item, item->d_ptr->sceneEffectiveBoundingRect());
143 }
144 }
145 unindexedItems.clear();
146}
147
148
149/*!
150 \internal
151
152 Removes stale pointers from all data structures.
153*/
154void QGraphicsSceneBspTreeIndexPrivate::purgeRemovedItems()
155{
156 if (!purgePending && removedItems.isEmpty())
157 return;
158
159 // Remove stale items from the BSP tree.
160 bsp.removeItems(removedItems);
161 // Purge this list.
162 removedItems.clear();
163 freeItemIndexes.clear();
164 for (int i = 0; i < indexedItems.size(); ++i) {
165 if (!indexedItems.at(i))
166 freeItemIndexes << i;
167 }
168 purgePending = false;
169}
170
171/*!
172 \internal
173
174 Starts or restarts the timer used for reindexing unindexed items.
175*/
176void QGraphicsSceneBspTreeIndexPrivate::startIndexTimer(int interval)
177{
178 Q_Q(QGraphicsSceneBspTreeIndex);
179 if (indexTimer.isActive()) {
180 restartIndexTimer = true;
181 } else {
182 indexTimer.start(interval * 1ms, q);
183 }
184}
185
186/*!
187 \internal
188*/
189void QGraphicsSceneBspTreeIndexPrivate::resetIndex()
190{
191 purgeRemovedItems();
192 for (int i = 0; i < indexedItems.size(); ++i) {
193 if (QGraphicsItem *item = indexedItems.at(i)) {
194 item->d_ptr->index = -1;
195 Q_ASSERT(!item->d_ptr->itemDiscovered);
196 unindexedItems << item;
197 }
198 }
199 indexedItems.clear();
200 freeItemIndexes.clear();
201 untransformableItems.clear();
202 regenerateIndex = true;
203 startIndexTimer();
204}
205
206/*!
207 \internal
208*/
209void QGraphicsSceneBspTreeIndexPrivate::climbTree(QGraphicsItem *item, int *stackingOrder)
210{
211 if (!item->d_ptr->children.isEmpty()) {
212 QList<QGraphicsItem *> childList = item->d_ptr->children;
213 std::sort(childList.begin(), childList.end(), qt_closestLeaf);
214 for (int i = 0; i < childList.size(); ++i) {
215 QGraphicsItem *item = childList.at(i);
216 if (!(item->flags() & QGraphicsItem::ItemStacksBehindParent))
217 climbTree(childList.at(i), stackingOrder);
218 }
219 item->d_ptr->globalStackingOrder = (*stackingOrder)++;
220 for (int i = 0; i < childList.size(); ++i) {
221 QGraphicsItem *item = childList.at(i);
222 if (item->flags() & QGraphicsItem::ItemStacksBehindParent)
223 climbTree(childList.at(i), stackingOrder);
224 }
225 } else {
226 item->d_ptr->globalStackingOrder = (*stackingOrder)++;
227 }
228}
229
230/*!
231 \internal
232*/
233void QGraphicsSceneBspTreeIndexPrivate::_q_updateSortCache()
234{
235 Q_Q(QGraphicsSceneBspTreeIndex);
236 _q_updateIndex();
237
238 if (!sortCacheEnabled || !updatingSortCache)
239 return;
240
241 updatingSortCache = false;
242 int stackingOrder = 0;
243
244 QList<QGraphicsItem *> topLevels;
245 const QList<QGraphicsItem *> items = q->items();
246 for (int i = 0; i < items.size(); ++i) {
247 QGraphicsItem *item = items.at(i);
248 if (item && !item->d_ptr->parent)
249 topLevels << item;
250 }
251
252 std::sort(topLevels.begin(), topLevels.end(), qt_closestLeaf);
253 for (int i = 0; i < topLevels.size(); ++i)
254 climbTree(topLevels.at(i), &stackingOrder);
255}
256
257/*!
258 \internal
259*/
260void QGraphicsSceneBspTreeIndexPrivate::invalidateSortCache()
261{
262 Q_Q(QGraphicsSceneBspTreeIndex);
263 if (!sortCacheEnabled || updatingSortCache)
264 return;
265
266 updatingSortCache = true;
267 QMetaObject::invokeMethod(q, "_q_updateSortCache", Qt::QueuedConnection);
268}
269
270void QGraphicsSceneBspTreeIndexPrivate::addItem(QGraphicsItem *item, bool recursive)
271{
272 if (!item)
273 return;
274
275 // Prevent reusing a recently deleted pointer: purge all removed item from our lists.
276 purgeRemovedItems();
277
278 // Invalidate any sort caching; arrival of a new item means we need to resort.
279 // Update the scene's sort cache settings.
280 item->d_ptr->globalStackingOrder = -1;
281 invalidateSortCache();
282
283 // Indexing requires sceneBoundingRect(), but because \a item might
284 // not be completely constructed at this point, we need to store it in
285 // a temporary list and schedule an indexing for later.
286 if (item->d_ptr->index == -1) {
287 Q_ASSERT(!unindexedItems.contains(item));
288 unindexedItems << item;
289 startIndexTimer(0);
290 } else {
291 Q_ASSERT(indexedItems.contains(item));
292 qWarning("QGraphicsSceneBspTreeIndex::addItem: item has already been added to this BSP");
293 }
294
295 if (recursive) {
296 for (int i = 0; i < item->d_ptr->children.size(); ++i)
297 addItem(item->d_ptr->children.at(i), recursive);
298 }
299}
300
301void QGraphicsSceneBspTreeIndexPrivate::removeItem(QGraphicsItem *item, bool recursive,
302 bool moveToUnindexedItems)
303{
304 if (!item)
305 return;
306
307 if (item->d_ptr->index != -1) {
308 Q_ASSERT(item->d_ptr->index < indexedItems.size());
309 Q_ASSERT(indexedItems.at(item->d_ptr->index) == item);
310 Q_ASSERT(!item->d_ptr->itemDiscovered);
311 freeItemIndexes << item->d_ptr->index;
312 indexedItems[item->d_ptr->index] = 0;
313 item->d_ptr->index = -1;
314
315 if (item->d_ptr->itemIsUntransformable()) {
316 untransformableItems.removeOne(item);
317 } else if (item->d_ptr->inDestructor) {
318 // Avoid virtual function calls from the destructor.
319 purgePending = true;
320 removedItems << item;
321 } else if (!(item->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren
322 || item->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorContainsChildren)) {
323 bsp.removeItem(item, item->d_ptr->sceneEffectiveBoundingRect());
324 }
325 } else {
326 unindexedItems.removeOne(item);
327 }
328 invalidateSortCache(); // ### Only do this when removing from BSP?
329
330 Q_ASSERT(item->d_ptr->index == -1);
331 Q_ASSERT(!indexedItems.contains(item));
332 Q_ASSERT(!unindexedItems.contains(item));
333 Q_ASSERT(!untransformableItems.contains(item));
334
335 if (moveToUnindexedItems)
336 addItem(item);
337
338 if (recursive) {
339 for (int i = 0; i < item->d_ptr->children.size(); ++i)
340 removeItem(item->d_ptr->children.at(i), recursive, moveToUnindexedItems);
341 }
342}
343
344QList<QGraphicsItem *> QGraphicsSceneBspTreeIndexPrivate::estimateItems(const QRectF &rect, Qt::SortOrder order,
345 bool onlyTopLevelItems)
346{
347 Q_Q(QGraphicsSceneBspTreeIndex);
348 if (onlyTopLevelItems && rect.isNull())
349 return q->QGraphicsSceneIndex::estimateTopLevelItems(rect, order);
350
351 purgeRemovedItems();
352 _q_updateSortCache();
353 Q_ASSERT(unindexedItems.isEmpty());
354
355 QList<QGraphicsItem *> rectItems = bsp.items(rect, onlyTopLevelItems);
356 if (onlyTopLevelItems) {
357 for (int i = 0; i < untransformableItems.size(); ++i) {
358 QGraphicsItem *item = untransformableItems.at(i);
359 if (!item->d_ptr->parent) {
360 rectItems << item;
361 } else {
362 item = item->topLevelItem();
363 if (!rectItems.contains(item))
364 rectItems << item;
365 }
366 }
367 } else {
368 rectItems += untransformableItems;
369 }
370
371 sortItems(&rectItems, order, sortCacheEnabled, onlyTopLevelItems);
372 return rectItems;
373}
374
375/*!
376 Sort a list of \a itemList in a specific \a order and use the cache if requested.
377
378 \internal
379*/
380void QGraphicsSceneBspTreeIndexPrivate::sortItems(QList<QGraphicsItem *> *itemList, Qt::SortOrder order,
381 bool sortCacheEnabled, bool onlyTopLevelItems)
382{
383 if (order == Qt::SortOrder(-1))
384 return;
385
386 if (onlyTopLevelItems) {
387 if (order == Qt::DescendingOrder)
388 std::sort(itemList->begin(), itemList->end(), qt_closestLeaf);
389 else if (order == Qt::AscendingOrder)
390 std::sort(itemList->begin(), itemList->end(), qt_notclosestLeaf);
391 return;
392 }
393
394 if (sortCacheEnabled) {
395 if (order == Qt::DescendingOrder) {
396 std::sort(itemList->begin(), itemList->end(), closestItemFirst_withCache);
397 } else if (order == Qt::AscendingOrder) {
398 std::sort(itemList->begin(), itemList->end(), closestItemLast_withCache);
399 }
400 } else {
401 if (order == Qt::DescendingOrder) {
402 std::sort(itemList->begin(), itemList->end(), qt_closestItemFirst);
403 } else if (order == Qt::AscendingOrder) {
404 std::sort(itemList->begin(), itemList->end(), qt_closestItemLast);
405 }
406 }
407}
408
409/*!
410 Constructs a BSP scene index for the given \a scene.
411*/
412QGraphicsSceneBspTreeIndex::QGraphicsSceneBspTreeIndex(QGraphicsScene *scene)
413 : QGraphicsSceneIndex(*new QGraphicsSceneBspTreeIndexPrivate(scene), scene)
414{
415
416}
417
418QGraphicsSceneBspTreeIndex::~QGraphicsSceneBspTreeIndex()
419{
420 Q_D(QGraphicsSceneBspTreeIndex);
421 for (int i = 0; i < d->indexedItems.size(); ++i) {
422 // Ensure item bits are reset properly.
423 if (QGraphicsItem *item = d->indexedItems.at(i)) {
424 Q_ASSERT(!item->d_ptr->itemDiscovered);
425 item->d_ptr->index = -1;
426 }
427 }
428}
429
430/*!
431 \internal
432 Clear the all the BSP index.
433*/
434void QGraphicsSceneBspTreeIndex::clear()
435{
436 Q_D(QGraphicsSceneBspTreeIndex);
437 d->bsp.clear();
438 d->lastItemCount = 0;
439 d->freeItemIndexes.clear();
440 for (int i = 0; i < d->indexedItems.size(); ++i) {
441 // Ensure item bits are reset properly.
442 if (QGraphicsItem *item = d->indexedItems.at(i)) {
443 Q_ASSERT(!item->d_ptr->itemDiscovered);
444 item->d_ptr->index = -1;
445 }
446 }
447 d->indexedItems.clear();
448 d->unindexedItems.clear();
449 d->untransformableItems.clear();
450 d->regenerateIndex = true;
451}
452
453/*!
454 Add the \a item into the BSP index.
455*/
456void QGraphicsSceneBspTreeIndex::addItem(QGraphicsItem *item)
457{
458 Q_D(QGraphicsSceneBspTreeIndex);
459 d->addItem(item);
460}
461
462/*!
463 Remove the \a item from the BSP index.
464*/
465void QGraphicsSceneBspTreeIndex::removeItem(QGraphicsItem *item)
466{
467 Q_D(QGraphicsSceneBspTreeIndex);
468 d->removeItem(item);
469}
470
471/*!
472 \internal
473 Update the BSP when the \a item 's bounding rect has changed.
474*/
475void QGraphicsSceneBspTreeIndex::prepareBoundingRectChange(const QGraphicsItem *item)
476{
477 if (!item)
478 return;
479
480 if (item->d_ptr->index == -1 || item->d_ptr->itemIsUntransformable()
481 || (item->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren
482 || item->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorContainsChildren)) {
483 return; // Item is not in BSP tree; nothing to do.
484 }
485
486 Q_D(QGraphicsSceneBspTreeIndex);
487 QGraphicsItem *thatItem = const_cast<QGraphicsItem *>(item);
488 d->removeItem(thatItem, /*recursive=*/false, /*moveToUnindexedItems=*/true);
489 for (int i = 0; i < item->d_ptr->children.size(); ++i) // ### Do we really need this?
490 prepareBoundingRectChange(item->d_ptr->children.at(i));
491}
492
493/*!
494 Returns an estimation visible items that are either inside or
495 intersect with the specified \a rect and return a list sorted using \a order.
496
497 \a deviceTransform is the transformation apply to the view.
498
499*/
500QList<QGraphicsItem *> QGraphicsSceneBspTreeIndex::estimateItems(const QRectF &rect, Qt::SortOrder order) const
501{
502 Q_D(const QGraphicsSceneBspTreeIndex);
503 return const_cast<QGraphicsSceneBspTreeIndexPrivate*>(d)->estimateItems(rect, order);
504}
505
506QList<QGraphicsItem *> QGraphicsSceneBspTreeIndex::estimateTopLevelItems(const QRectF &rect, Qt::SortOrder order) const
507{
508 Q_D(const QGraphicsSceneBspTreeIndex);
509 return const_cast<QGraphicsSceneBspTreeIndexPrivate*>(d)->estimateItems(rect, order, /*onlyTopLevels=*/true);
510}
511
512/*!
513 \fn QList<QGraphicsItem *> QGraphicsSceneBspTreeIndex::items(Qt::SortOrder order = Qt::DescendingOrder) const;
514
515 Return all items in the BSP index and sort them using \a order.
516*/
517QList<QGraphicsItem *> QGraphicsSceneBspTreeIndex::items(Qt::SortOrder order) const
518{
519 Q_D(const QGraphicsSceneBspTreeIndex);
520 const_cast<QGraphicsSceneBspTreeIndexPrivate*>(d)->purgeRemovedItems();
521 QList<QGraphicsItem *> itemList;
522 itemList.reserve(d->indexedItems.size() + d->unindexedItems.size());
523
524 // Rebuild the list of items to avoid holes. ### We could also just
525 // compress the item lists at this point.
526 QGraphicsItem *null = nullptr; // work-around for (at least) MSVC 2012 emitting
527 // warning C4100 for its own header <algorithm>
528 // when passing nullptr directly to remove_copy:
529 std::remove_copy(d->indexedItems.cbegin(), d->indexedItems.cend(),
530 std::back_inserter(itemList), null);
531 std::remove_copy(d->unindexedItems.cbegin(), d->unindexedItems.cend(),
532 std::back_inserter(itemList), null);
533
534 d->sortItems(&itemList, order, d->sortCacheEnabled);
535 return itemList;
536}
537
538/*!
539 \property QGraphicsSceneBspTreeIndex::bspTreeDepth
540 \brief the depth of the BSP index tree
541 \since 4.6
542
543 This value determines the depth of BSP tree. The depth
544 directly affects performance and memory usage; the latter
545 growing exponentially with the depth of the tree. With an optimal tree
546 depth, the index can instantly determine the locality of items, even
547 for scenes with thousands or millions of items. This also greatly improves
548 rendering performance.
549
550 By default, the value is 0, in which case Qt will guess a reasonable
551 default depth based on the size, location and number of items in the
552 scene. If these parameters change frequently, however, you may experience
553 slowdowns as the index retunes the depth internally. You can avoid
554 potential slowdowns by fixating the tree depth through setting this
555 property.
556
557 The depth of the tree and the size of the scene rectangle decide the
558 granularity of the scene's partitioning. The size of each scene segment is
559 determined by the following algorithm:
560
561 The BSP tree has an optimal size when each segment contains between 0 and
562 10 items.
563
564*/
565int QGraphicsSceneBspTreeIndex::bspTreeDepth() const
566{
567 Q_D(const QGraphicsSceneBspTreeIndex);
568 return d->bspTreeDepth;
569}
570
571void QGraphicsSceneBspTreeIndex::setBspTreeDepth(int depth)
572{
573 Q_D(QGraphicsSceneBspTreeIndex);
574 if (d->bspTreeDepth == depth)
575 return;
576 d->bspTreeDepth = depth;
577 d->resetIndex();
578}
579
580/*!
581 \internal
582
583 This method react to the \a rect change of the scene and
584 reset the BSP tree index.
585*/
586void QGraphicsSceneBspTreeIndex::updateSceneRect(const QRectF &rect)
587{
588 Q_D(QGraphicsSceneBspTreeIndex);
589 d->sceneRect = rect;
590 d->resetIndex();
591}
592
593/*!
594 \internal
595
596 This method react to the \a change of the \a item and use the \a value to
597 update the BSP tree if necessary.
598*/
599void QGraphicsSceneBspTreeIndex::itemChange(const QGraphicsItem *item, QGraphicsItem::GraphicsItemChange change, const void *const value)
600{
601 Q_D(QGraphicsSceneBspTreeIndex);
602 switch (change) {
603 case QGraphicsItem::ItemFlagsChange: {
604 // Handle ItemIgnoresTransformations
605 QGraphicsItem::GraphicsItemFlags newFlags = *static_cast<const QGraphicsItem::GraphicsItemFlags *>(value);
606 bool ignoredTransform = item->d_ptr->flags & QGraphicsItem::ItemIgnoresTransformations;
607 bool willIgnoreTransform = newFlags & QGraphicsItem::ItemIgnoresTransformations;
608 bool clipsChildren = item->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape
609 || item->d_ptr->flags & QGraphicsItem::ItemContainsChildrenInShape;
610 bool willClipChildren = newFlags & QGraphicsItem::ItemClipsChildrenToShape
611 || newFlags & QGraphicsItem::ItemContainsChildrenInShape;
612 if ((ignoredTransform != willIgnoreTransform) || (clipsChildren != willClipChildren)) {
613 QGraphicsItem *thatItem = const_cast<QGraphicsItem *>(item);
614 // Remove item and its descendants from the index and append
615 // them to the list of unindexed items. Then, when the index
616 // is updated, they will be put into the bsp-tree or the list
617 // of untransformable items.
618 d->removeItem(thatItem, /*recursive=*/true, /*moveToUnidexedItems=*/true);
619 }
620 break;
621 }
622 case QGraphicsItem::ItemZValueChange:
623 d->invalidateSortCache();
624 break;
625 case QGraphicsItem::ItemParentChange: {
626 d->invalidateSortCache();
627 // Handle ItemIgnoresTransformations
628 const QGraphicsItem *newParent = static_cast<const QGraphicsItem *>(value);
629 bool ignoredTransform = item->d_ptr->itemIsUntransformable();
630 bool willIgnoreTransform = (item->d_ptr->flags & QGraphicsItem::ItemIgnoresTransformations)
631 || (newParent && newParent->d_ptr->itemIsUntransformable());
632 bool ancestorClippedChildren = item->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren
633 || item->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorContainsChildren;
634 bool ancestorWillClipChildren = newParent
635 && ((newParent->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape
636 || newParent->d_ptr->flags & QGraphicsItem::ItemContainsChildrenInShape)
637 || (newParent->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorClipsChildren
638 || newParent->d_ptr->ancestorFlags & QGraphicsItemPrivate::AncestorContainsChildren));
639 if ((ignoredTransform != willIgnoreTransform) || (ancestorClippedChildren != ancestorWillClipChildren)) {
640 QGraphicsItem *thatItem = const_cast<QGraphicsItem *>(item);
641 // Remove item and its descendants from the index and append
642 // them to the list of unindexed items. Then, when the index
643 // is updated, they will be put into the bsp-tree or the list
644 // of untransformable items.
645 d->removeItem(thatItem, /*recursive=*/true, /*moveToUnidexedItems=*/true);
646 }
647 break;
648 }
649 default:
650 break;
651 }
652}
653/*!
654 \reimp
655
656 Used to catch the timer event.
657
658 \internal
659*/
660bool QGraphicsSceneBspTreeIndex::event(QEvent *event)
661{
662 Q_D(QGraphicsSceneBspTreeIndex);
663 if (event->type() == QEvent::Timer) {
664 if (d->indexTimer.isActive() && static_cast<QTimerEvent *>(event)->id() == d->indexTimer.id()) {
665 if (d->restartIndexTimer) {
666 d->restartIndexTimer = false;
667 } else {
668 // this call will kill the timer
669 d->_q_updateIndex();
670 }
671 }
672 }
673 return QObject::event(event);
674}
675
676QT_END_NAMESPACE
677
678#include "moc_qgraphicsscenebsptreeindex_p.cpp"
static QT_BEGIN_NAMESPACE int intmaxlog(int n)