1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the QtWidgets module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39 /*!
40     \class QGraphicsSceneIndex
41     \brief The QGraphicsSceneIndex class provides a base class to implement
42     a custom indexing algorithm for discovering items in QGraphicsScene.
43     \since 4.6
44     \ingroup graphicsview-api
45 
46     \internal
47 
48     The QGraphicsSceneIndex class provides a base class to implement
49     a custom indexing algorithm for discovering items in QGraphicsScene. You
50     need to subclass it and reimplement addItem, removeItem, estimateItems
51     and items in order to have an functional indexing.
52 
53     \sa QGraphicsScene, QGraphicsView
54 */
55 
56 #include "qdebug.h"
57 #include "qgraphicsscene.h"
58 #include "qgraphicsitem_p.h"
59 #include "qgraphicsscene_p.h"
60 #include "qgraphicswidget.h"
61 #include "qgraphicssceneindex_p.h"
62 #include "qgraphicsscenebsptreeindex_p.h"
63 #include <QtGui/qpainterpath.h>
64 
65 QT_BEGIN_NAMESPACE
66 
67 namespace QtPrivate { // just to keep indentation of the following functions at the same level
68 
intersect_rect(const QGraphicsItem * item,const QRectF & exposeRect,Qt::ItemSelectionMode mode,const QTransform & deviceTransform,const void * intersectData)69     static bool intersect_rect(const QGraphicsItem *item, const QRectF &exposeRect, Qt::ItemSelectionMode mode,
70                                const QTransform &deviceTransform, const void *intersectData)
71     {
72         const QRectF sceneRect = *static_cast<const QRectF *>(intersectData);
73 
74         QRectF brect = item->boundingRect();
75         _q_adjustRect(&brect);
76 
77         // ### Add test for this (without making things slower?)
78         Q_UNUSED(exposeRect);
79 
80         bool keep = true;
81         const QGraphicsItemPrivate *itemd = QGraphicsItemPrivate::get(item);
82         if (itemd->itemIsUntransformable()) {
83             // Untransformable items; map the scene rect to item coordinates.
84             const QTransform transform = item->deviceTransform(deviceTransform);
85             QRectF itemRect = (deviceTransform * transform.inverted()).mapRect(sceneRect);
86             if (mode == Qt::ContainsItemShape || mode == Qt::ContainsItemBoundingRect)
87                 keep = itemRect.contains(brect) && itemRect != brect;
88             else
89                 keep = itemRect.intersects(brect);
90             if (keep && (mode == Qt::ContainsItemShape || mode == Qt::IntersectsItemShape)) {
91                 QPainterPath itemPath;
92                 itemPath.addRect(itemRect);
93                 keep = QGraphicsSceneIndexPrivate::itemCollidesWithPath(item, itemPath, mode);
94             }
95         } else {
96             Q_ASSERT(!itemd->dirtySceneTransform);
97             const QRectF itemSceneBoundingRect = itemd->sceneTransformTranslateOnly
98                                                ? brect.translated(itemd->sceneTransform.dx(),
99                                                                   itemd->sceneTransform.dy())
100                                                : itemd->sceneTransform.mapRect(brect);
101             if (mode == Qt::ContainsItemShape || mode == Qt::ContainsItemBoundingRect)
102                 keep = sceneRect != brect && sceneRect.contains(itemSceneBoundingRect);
103             else
104                 keep = sceneRect.intersects(itemSceneBoundingRect);
105             if (keep && (mode == Qt::ContainsItemShape || mode == Qt::IntersectsItemShape)) {
106                 QPainterPath rectPath;
107                 rectPath.addRect(sceneRect);
108                 if (itemd->sceneTransformTranslateOnly)
109                     rectPath.translate(-itemd->sceneTransform.dx(), -itemd->sceneTransform.dy());
110                 else
111                     rectPath = itemd->sceneTransform.inverted().map(rectPath);
112                 keep = QGraphicsSceneIndexPrivate::itemCollidesWithPath(item, rectPath, mode);
113             }
114         }
115         return keep;
116     }
117 
intersect_point(const QGraphicsItem * item,const QRectF & exposeRect,Qt::ItemSelectionMode mode,const QTransform & deviceTransform,const void * intersectData)118     static bool intersect_point(const QGraphicsItem *item, const QRectF &exposeRect, Qt::ItemSelectionMode mode,
119                                 const QTransform &deviceTransform, const void *intersectData)
120     {
121         const QPointF scenePoint = *static_cast<const QPointF *>(intersectData);
122 
123         QRectF brect = item->boundingRect();
124         _q_adjustRect(&brect);
125 
126         // ### Add test for this (without making things slower?)
127         Q_UNUSED(exposeRect);
128 
129         bool keep = false;
130         const QGraphicsItemPrivate *itemd = QGraphicsItemPrivate::get(item);
131         if (itemd->itemIsUntransformable()) {
132             // Untransformable items; map the scene point to item coordinates.
133             const QTransform transform = item->deviceTransform(deviceTransform);
134             QPointF itemPoint = (deviceTransform * transform.inverted()).map(scenePoint);
135             keep = brect.contains(itemPoint);
136             if (keep && (mode == Qt::ContainsItemShape || mode == Qt::IntersectsItemShape)) {
137                 QPainterPath pointPath;
138                 pointPath.addRect(QRectF(itemPoint, QSizeF(1, 1)));
139                 keep = QGraphicsSceneIndexPrivate::itemCollidesWithPath(item, pointPath, mode);
140             }
141         } else {
142             Q_ASSERT(!itemd->dirtySceneTransform);
143             QRectF sceneBoundingRect = itemd->sceneTransformTranslateOnly
144                                      ? brect.translated(itemd->sceneTransform.dx(),
145                                                         itemd->sceneTransform.dy())
146                                      : itemd->sceneTransform.mapRect(brect);
147             keep = sceneBoundingRect.intersects(QRectF(scenePoint, QSizeF(1, 1)));
148             if (keep && (mode == Qt::ContainsItemShape || mode == Qt::IntersectsItemShape)) {
149                 QPointF p = itemd->sceneTransformTranslateOnly
150                           ? QPointF(scenePoint.x() - itemd->sceneTransform.dx(),
151                                     scenePoint.y() - itemd->sceneTransform.dy())
152                           : itemd->sceneTransform.inverted().map(scenePoint);
153                 keep = item->contains(p);
154             }
155         }
156 
157         return keep;
158     }
159 
intersect_path(const QGraphicsItem * item,const QRectF & exposeRect,Qt::ItemSelectionMode mode,const QTransform & deviceTransform,const void * intersectData)160     static bool intersect_path(const QGraphicsItem *item, const QRectF &exposeRect, Qt::ItemSelectionMode mode,
161                                const QTransform &deviceTransform, const void *intersectData)
162     {
163         const QPainterPath scenePath = *static_cast<const QPainterPath *>(intersectData);
164 
165         QRectF brect = item->boundingRect();
166         _q_adjustRect(&brect);
167 
168         // ### Add test for this (without making things slower?)
169         Q_UNUSED(exposeRect);
170 
171         bool keep = true;
172         const QGraphicsItemPrivate *itemd = QGraphicsItemPrivate::get(item);
173         if (itemd->itemIsUntransformable()) {
174             // Untransformable items; map the scene rect to item coordinates.
175             const QTransform transform = item->deviceTransform(deviceTransform);
176             QPainterPath itemPath = (deviceTransform * transform.inverted()).map(scenePath);
177             if (mode == Qt::ContainsItemShape || mode == Qt::ContainsItemBoundingRect)
178                 keep = itemPath.contains(brect);
179             else
180                 keep = itemPath.intersects(brect);
181             if (keep && (mode == Qt::ContainsItemShape || mode == Qt::IntersectsItemShape))
182                 keep = QGraphicsSceneIndexPrivate::itemCollidesWithPath(item, itemPath, mode);
183         } else {
184             Q_ASSERT(!itemd->dirtySceneTransform);
185             const QRectF itemSceneBoundingRect = itemd->sceneTransformTranslateOnly
186                                                ? brect.translated(itemd->sceneTransform.dx(),
187                                                                   itemd->sceneTransform.dy())
188                                                : itemd->sceneTransform.mapRect(brect);
189             if (mode == Qt::ContainsItemShape || mode == Qt::ContainsItemBoundingRect)
190                 keep = scenePath.contains(itemSceneBoundingRect);
191             else
192                 keep = scenePath.intersects(itemSceneBoundingRect);
193             if (keep && (mode == Qt::ContainsItemShape || mode == Qt::IntersectsItemShape)) {
194                 QPainterPath itemPath = itemd->sceneTransformTranslateOnly
195                                       ? scenePath.translated(-itemd->sceneTransform.dx(),
196                                                              -itemd->sceneTransform.dy())
197                                       : itemd->sceneTransform.inverted().map(scenePath);
198                 keep = QGraphicsSceneIndexPrivate::itemCollidesWithPath(item, itemPath, mode);
199             }
200         }
201         return keep;
202     }
203 
204 } // namespace QtPrivate
205 
206 /*!
207     Constructs a private scene index.
208 */
QGraphicsSceneIndexPrivate(QGraphicsScene * scene)209 QGraphicsSceneIndexPrivate::QGraphicsSceneIndexPrivate(QGraphicsScene *scene) : scene(scene)
210 {
211 }
212 
213 /*!
214     Destructor of private scene index.
215 */
~QGraphicsSceneIndexPrivate()216 QGraphicsSceneIndexPrivate::~QGraphicsSceneIndexPrivate()
217 {
218 }
219 
220 /*!
221     \internal
222 
223     Checks if item collides with the path and mode, but also checks that if it
224     doesn't collide, maybe its frame rect will.
225 */
itemCollidesWithPath(const QGraphicsItem * item,const QPainterPath & path,Qt::ItemSelectionMode mode)226 bool QGraphicsSceneIndexPrivate::itemCollidesWithPath(const QGraphicsItem *item,
227                                                       const QPainterPath &path,
228                                                       Qt::ItemSelectionMode mode)
229 {
230     if (item->collidesWithPath(path, mode))
231         return true;
232     if (item->isWidget()) {
233         // Check if this is a window, and if its frame rect collides.
234         const QGraphicsWidget *widget = static_cast<const QGraphicsWidget *>(item);
235         if (widget->isWindow()) {
236             QRectF frameRect = widget->windowFrameRect();
237             QPainterPath framePath;
238             framePath.addRect(frameRect);
239             bool intersects = path.intersects(frameRect);
240             if (mode == Qt::IntersectsItemShape || mode == Qt::IntersectsItemBoundingRect)
241                 return intersects || path.contains(frameRect.topLeft())
242                     || framePath.contains(path.elementAt(0));
243             return !intersects && path.contains(frameRect.topLeft());
244         }
245     }
246     return false;
247 }
248 
249 /*!
250     \internal
251     This function returns the items in ascending order.
252 */
recursive_items_helper(QGraphicsItem * item,QRectF exposeRect,QGraphicsSceneIndexIntersector intersect,QList<QGraphicsItem * > * items,const QTransform & viewTransform,Qt::ItemSelectionMode mode,qreal parentOpacity,const void * intersectData) const253 void QGraphicsSceneIndexPrivate::recursive_items_helper(QGraphicsItem *item, QRectF exposeRect,
254                                                         QGraphicsSceneIndexIntersector intersect,
255                                                         QList<QGraphicsItem *> *items,
256                                                         const QTransform &viewTransform,
257                                                         Qt::ItemSelectionMode mode,
258                                                         qreal parentOpacity, const void *intersectData) const
259 {
260     Q_ASSERT(item);
261     if (!item->d_ptr->visible)
262         return;
263 
264     const qreal opacity = item->d_ptr->combineOpacityFromParent(parentOpacity);
265     const bool itemIsFullyTransparent = QGraphicsItemPrivate::isOpacityNull(opacity);
266     const bool itemHasChildren = !item->d_ptr->children.isEmpty();
267     if (itemIsFullyTransparent && (!itemHasChildren || item->d_ptr->childrenCombineOpacity()))
268         return;
269 
270     // Update the item's scene transform if dirty.
271     const bool itemIsUntransformable = item->d_ptr->itemIsUntransformable();
272     const bool wasDirtyParentSceneTransform = item->d_ptr->dirtySceneTransform && !itemIsUntransformable;
273     if (wasDirtyParentSceneTransform) {
274         item->d_ptr->updateSceneTransformFromParent();
275         Q_ASSERT(!item->d_ptr->dirtySceneTransform);
276     }
277 
278     const bool itemClipsChildrenToShape = (item->d_ptr->flags & QGraphicsItem::ItemClipsChildrenToShape
279                                            || item->d_ptr->flags & QGraphicsItem::ItemContainsChildrenInShape);
280     bool processItem = !itemIsFullyTransparent;
281     if (processItem) {
282         processItem = intersect(item, exposeRect, mode, viewTransform, intersectData);
283         if (!processItem && (!itemHasChildren || itemClipsChildrenToShape)) {
284             if (wasDirtyParentSceneTransform)
285                 item->d_ptr->invalidateChildrenSceneTransform();
286             return;
287         }
288     } // else we know for sure this item has children we must process.
289 
290     int i = 0;
291     if (itemHasChildren) {
292         // Sort children.
293         item->d_ptr->ensureSortedChildren();
294 
295         // Clip to shape.
296         if (itemClipsChildrenToShape && !itemIsUntransformable) {
297             QPainterPath mappedShape = item->d_ptr->sceneTransformTranslateOnly
298                                      ? item->shape().translated(item->d_ptr->sceneTransform.dx(),
299                                                                 item->d_ptr->sceneTransform.dy())
300                                      : item->d_ptr->sceneTransform.map(item->shape());
301             exposeRect &= mappedShape.controlPointRect();
302         }
303 
304         // Process children behind
305         for (i = 0; i < item->d_ptr->children.size(); ++i) {
306             QGraphicsItem *child = item->d_ptr->children.at(i);
307             if (wasDirtyParentSceneTransform)
308                 child->d_ptr->dirtySceneTransform = 1;
309             if (!(child->d_ptr->flags & QGraphicsItem::ItemStacksBehindParent))
310                 break;
311             if (itemIsFullyTransparent && !(child->d_ptr->flags & QGraphicsItem::ItemIgnoresParentOpacity))
312                 continue;
313             recursive_items_helper(child, exposeRect, intersect, items, viewTransform,
314                                    mode, opacity, intersectData);
315         }
316     }
317 
318     // Process item
319     if (processItem)
320         items->append(item);
321 
322     // Process children in front
323     if (itemHasChildren) {
324         for (; i < item->d_ptr->children.size(); ++i) {
325             QGraphicsItem *child = item->d_ptr->children.at(i);
326             if (wasDirtyParentSceneTransform)
327                 child->d_ptr->dirtySceneTransform = 1;
328             if (itemIsFullyTransparent && !(child->d_ptr->flags & QGraphicsItem::ItemIgnoresParentOpacity))
329                 continue;
330             recursive_items_helper(child, exposeRect, intersect, items, viewTransform,
331                                    mode, opacity, intersectData);
332         }
333     }
334 }
335 
init()336 void QGraphicsSceneIndexPrivate::init()
337 {
338     if (!scene)
339         return;
340 
341     QObject::connect(scene, SIGNAL(sceneRectChanged(QRectF)),
342                      q_func(), SLOT(updateSceneRect(QRectF)));
343 }
344 
345 /*!
346     Constructs an abstract scene index for a given \a scene.
347 */
QGraphicsSceneIndex(QGraphicsScene * scene)348 QGraphicsSceneIndex::QGraphicsSceneIndex(QGraphicsScene *scene)
349 : QObject(*new QGraphicsSceneIndexPrivate(scene), scene)
350 {
351     d_func()->init();
352 }
353 
354 /*!
355     \internal
356 */
QGraphicsSceneIndex(QGraphicsSceneIndexPrivate & dd,QGraphicsScene * scene)357 QGraphicsSceneIndex::QGraphicsSceneIndex(QGraphicsSceneIndexPrivate &dd, QGraphicsScene *scene)
358     : QObject(dd, scene)
359 {
360     d_func()->init();
361 }
362 
363 /*!
364     Destroys the scene index.
365 */
~QGraphicsSceneIndex()366 QGraphicsSceneIndex::~QGraphicsSceneIndex()
367 {
368 
369 }
370 
371 /*!
372     Returns the scene of this index.
373 */
scene() const374 QGraphicsScene* QGraphicsSceneIndex::scene() const
375 {
376     Q_D(const QGraphicsSceneIndex);
377     return d->scene;
378 }
379 
380 /*!
381     \fn QList<QGraphicsItem *> QGraphicsSceneIndex::items(const QPointF &pos,
382     Qt::ItemSelectionMode mode, Qt::SortOrder order, const QTransform
383     &deviceTransform) const
384 
385     Returns all visible items that, depending on \a mode, are at the specified
386     \a pos and return a list sorted using \a order.
387 
388     The default value for \a mode is Qt::IntersectsItemShape; all items whose
389     exact shape intersects with \a pos are returned.
390 
391     \a deviceTransform is the transformation apply to the view.
392 
393     This method use the estimation of the index (estimateItems) and refine the
394     list to get an exact result. If you want to implement your own refinement
395     algorithm you can reimplement this method.
396 
397     \sa estimateItems()
398 
399 */
items(const QPointF & pos,Qt::ItemSelectionMode mode,Qt::SortOrder order,const QTransform & deviceTransform) const400 QList<QGraphicsItem *> QGraphicsSceneIndex::items(const QPointF &pos, Qt::ItemSelectionMode mode,
401                                                   Qt::SortOrder order, const QTransform &deviceTransform) const
402 {
403 
404     Q_D(const QGraphicsSceneIndex);
405     QList<QGraphicsItem *> itemList;
406     d->items_helper(QRectF(pos, QSizeF(1, 1)), &QtPrivate::intersect_point, &itemList, deviceTransform, mode, order, &pos);
407     return itemList;
408 }
409 
410 /*!
411     \fn QList<QGraphicsItem *> QGraphicsSceneIndex::items(const QRectF &rect,
412     Qt::ItemSelectionMode mode, Qt::SortOrder order, const QTransform
413     &deviceTransform) const
414 
415     \overload
416 
417     Returns all visible items that, depending on \a mode, are either inside or
418     intersect with the specified \a rect and return a list sorted using \a order.
419 
420     The default value for \a mode is Qt::IntersectsItemShape; all items whose
421     exact shape intersects with or is contained by \a rect are returned.
422 
423     \a deviceTransform is the transformation apply to the view.
424 
425     This method use the estimation of the index (estimateItems) and refine
426     the list to get an exact result. If you want to implement your own
427     refinement algorithm you can reimplement this method.
428 
429     \sa estimateItems()
430 
431 */
items(const QRectF & rect,Qt::ItemSelectionMode mode,Qt::SortOrder order,const QTransform & deviceTransform) const432 QList<QGraphicsItem *> QGraphicsSceneIndex::items(const QRectF &rect, Qt::ItemSelectionMode mode,
433                                                   Qt::SortOrder order, const QTransform &deviceTransform) const
434 {
435     Q_D(const QGraphicsSceneIndex);
436     QRectF exposeRect = rect;
437     _q_adjustRect(&exposeRect);
438     QList<QGraphicsItem *> itemList;
439     d->items_helper(exposeRect, &QtPrivate::intersect_rect, &itemList, deviceTransform, mode, order, &rect);
440     return itemList;
441 }
442 
443 /*!
444     \fn QList<QGraphicsItem *> QGraphicsSceneIndex::items(const QPolygonF
445     &polygon, Qt::ItemSelectionMode mode, Qt::SortOrder order, const
446     QTransform &deviceTransform) const
447 
448     \overload
449 
450     Returns all visible items that, depending on \a mode, are either inside or
451     intersect with the specified \a polygon and return a list sorted using \a order.
452 
453     The default value for \a mode is Qt::IntersectsItemShape; all items whose
454     exact shape intersects with or is contained by \a polygon are returned.
455 
456     \a deviceTransform is the transformation apply to the view.
457 
458     This method use the estimation of the index (estimateItems) and refine
459     the list to get an exact result. If you want to implement your own
460     refinement algorithm you can reimplement this method.
461 
462     \sa estimateItems()
463 
464 */
items(const QPolygonF & polygon,Qt::ItemSelectionMode mode,Qt::SortOrder order,const QTransform & deviceTransform) const465 QList<QGraphicsItem *> QGraphicsSceneIndex::items(const QPolygonF &polygon, Qt::ItemSelectionMode mode,
466                                                   Qt::SortOrder order, const QTransform &deviceTransform) const
467 {
468     Q_D(const QGraphicsSceneIndex);
469     QList<QGraphicsItem *> itemList;
470     QRectF exposeRect = polygon.boundingRect();
471     _q_adjustRect(&exposeRect);
472     QPainterPath path;
473     path.addPolygon(polygon);
474     d->items_helper(exposeRect, &QtPrivate::intersect_path, &itemList, deviceTransform, mode, order, &path);
475     return itemList;
476 }
477 
478 /*!
479     \fn QList<QGraphicsItem *> QGraphicsSceneIndex::items(const QPainterPath
480     &path, Qt::ItemSelectionMode mode, Qt::SortOrder order, const QTransform
481     &deviceTransform) const
482 
483     \overload
484 
485     Returns all visible items that, depending on \a mode, are either inside or
486     intersect with the specified \a path and return a list sorted using \a order.
487 
488     The default value for \a mode is Qt::IntersectsItemShape; all items whose
489     exact shape intersects with or is contained by \a path are returned.
490 
491     \a deviceTransform is the transformation apply to the view.
492 
493     This method use the estimation of the index (estimateItems) and refine
494     the list to get an exact result. If you want to implement your own
495     refinement algorithm you can reimplement this method.
496 
497     \sa estimateItems()
498 
499 */
items(const QPainterPath & path,Qt::ItemSelectionMode mode,Qt::SortOrder order,const QTransform & deviceTransform) const500 QList<QGraphicsItem *> QGraphicsSceneIndex::items(const QPainterPath &path, Qt::ItemSelectionMode mode,
501                                                   Qt::SortOrder order, const QTransform &deviceTransform) const
502 {
503     Q_D(const QGraphicsSceneIndex);
504     QList<QGraphicsItem *> itemList;
505     QRectF exposeRect = path.controlPointRect();
506     _q_adjustRect(&exposeRect);
507     d->items_helper(exposeRect, &QtPrivate::intersect_path, &itemList, deviceTransform, mode, order, &path);
508     return itemList;
509 }
510 
511 /*!
512     This virtual function return an estimation of items at position \a point.
513     This method return a list sorted using \a order.
514 */
estimateItems(const QPointF & point,Qt::SortOrder order) const515 QList<QGraphicsItem *> QGraphicsSceneIndex::estimateItems(const QPointF &point, Qt::SortOrder order) const
516 {
517     return estimateItems(QRectF(point, QSize(1, 1)), order);
518 }
519 
estimateTopLevelItems(const QRectF & rect,Qt::SortOrder order) const520 QList<QGraphicsItem *> QGraphicsSceneIndex::estimateTopLevelItems(const QRectF &rect, Qt::SortOrder order) const
521 {
522     Q_D(const QGraphicsSceneIndex);
523     Q_UNUSED(rect);
524     QGraphicsScenePrivate *scened = d->scene->d_func();
525     scened->ensureSortedTopLevelItems();
526     if (order == Qt::DescendingOrder) {
527         QList<QGraphicsItem *> sorted;
528         const int numTopLevelItems = scened->topLevelItems.size();
529         sorted.reserve(numTopLevelItems);
530         for (int i = numTopLevelItems - 1; i >= 0; --i)
531             sorted << scened->topLevelItems.at(i);
532         return sorted;
533     }
534     return scened->topLevelItems;
535 }
536 
537 /*!
538     \fn QList<QGraphicsItem *> QGraphicsSceneIndex::items(Qt::SortOrder order = Qt::DescendingOrder) const
539 
540     This pure virtual function all items in the index and sort them using
541     \a order.
542 */
543 
544 
545 /*!
546     Notifies the index that the scene's scene rect has changed. \a rect
547     is thew new scene rect.
548 
549     \sa QGraphicsScene::sceneRect()
550 */
updateSceneRect(const QRectF & rect)551 void QGraphicsSceneIndex::updateSceneRect(const QRectF &rect)
552 {
553     Q_UNUSED(rect);
554 }
555 
556 /*!
557     This virtual function removes all items in the scene index.
558 */
clear()559 void QGraphicsSceneIndex::clear()
560 {
561     const QList<QGraphicsItem *> allItems = items();
562     for (int i = 0 ; i < allItems.size(); ++i)
563         removeItem(allItems.at(i));
564 }
565 
566 /*!
567     \fn virtual void QGraphicsSceneIndex::addItem(QGraphicsItem *item) = 0
568 
569     This pure virtual function inserts an \a item to the scene index.
570 
571     \sa removeItem(), deleteItem()
572 */
573 
574 /*!
575     \fn virtual void QGraphicsSceneIndex::removeItem(QGraphicsItem *item) = 0
576 
577     This pure virtual function removes an \a item to the scene index.
578 
579     \sa addItem(), deleteItem()
580 */
581 
582 /*!
583     This method is called when an \a item has been deleted.
584     The default implementation call removeItem. Be carefull,
585     if your implementation of removeItem use pure virtual method
586     of QGraphicsItem like boundingRect(), then you should reimplement
587     this method.
588 
589     \sa addItem(), removeItem()
590 */
deleteItem(QGraphicsItem * item)591 void QGraphicsSceneIndex::deleteItem(QGraphicsItem *item)
592 {
593     removeItem(item);
594 }
595 
596 /*!
597     This virtual function is called by QGraphicsItem to notify the index
598     that some part of the \a item 's state changes. By reimplementing this
599     function, your can react to a change, and in some cases, (depending on \a
600     change,) adjustments in the index can be made.
601 
602     \a change is the parameter of the item that is changing. \a value is the
603     value that changed; the type of the value depends on \a change.
604 
605     The default implementation does nothing.
606 
607     \sa QGraphicsItem::GraphicsItemChange
608 */
itemChange(const QGraphicsItem * item,QGraphicsItem::GraphicsItemChange change,const void * const value)609 void QGraphicsSceneIndex::itemChange(const QGraphicsItem *item, QGraphicsItem::GraphicsItemChange change, const void *const value)
610 {
611     Q_UNUSED(item);
612     Q_UNUSED(change);
613     Q_UNUSED(value);
614 }
615 
616 /*!
617     Notify the index for a geometry change of an \a item.
618 
619     \sa QGraphicsItem::prepareGeometryChange()
620 */
prepareBoundingRectChange(const QGraphicsItem * item)621 void QGraphicsSceneIndex::prepareBoundingRectChange(const QGraphicsItem *item)
622 {
623     Q_UNUSED(item);
624 }
625 
626 QT_END_NAMESPACE
627 
628 #include "moc_qgraphicssceneindex_p.cpp"
629