1 /* ============================================================
2  *
3  * This file is a part of digiKam project
4  * https://www.digikam.org
5  *
6  * Date        : 2010-01-16
7  * Description : test for the model holding markers
8  *
9  * Copyright (C) 2010-2011 by Michael G. Hansen <mike at mghansen dot de>
10  *
11  * This program is free software; you can redistribute it
12  * and/or modify it under the terms of the GNU General
13  * Public License as published by the Free Software Foundation;
14  * either version 2, or (at your option)
15  * any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * ============================================================ */
23 
24 #include "itemmarkertiler_utest.h"
25 
26 // Qt includes
27 
28 #include <QStandardItemModel>
29 
30 // Local includes
31 
32 #include "digikam_debug.h"
33 #include "geoifacecommon.h"
34 
35 using namespace Digikam;
36 
37 const int CoordinatesRole = Qt::UserRole + 0;
38 
MarkerModelHelper(QAbstractItemModel * const itemModel,QItemSelectionModel * const itemSelectionModel)39 MarkerModelHelper::MarkerModelHelper(QAbstractItemModel* const itemModel,
40                                      QItemSelectionModel* const itemSelectionModel)
41     : GeoModelHelper      (itemModel),
42       m_itemModel         (itemModel),
43       m_itemSelectionModel(itemSelectionModel)
44 {
45     connect(itemModel, SIGNAL(dataChanged(QModelIndex,QModelIndex)),
46             this, SLOT(slotDataChanged(QModelIndex,QModelIndex)));
47 }
48 
~MarkerModelHelper()49 MarkerModelHelper::~MarkerModelHelper()
50 {
51 }
52 
slotDataChanged(const QModelIndex & topLeft,const QModelIndex & bottomRight)53 void MarkerModelHelper::slotDataChanged(const QModelIndex& topLeft,
54                                         const QModelIndex& bottomRight)
55 {
56     Q_UNUSED(topLeft)
57     Q_UNUSED(bottomRight)
58     emit signalModelChangedDrastically();
59 }
60 
model() const61 QAbstractItemModel* MarkerModelHelper::model() const
62 {
63     return m_itemModel;
64 }
65 
selectionModel() const66 QItemSelectionModel* MarkerModelHelper::selectionModel() const
67 {
68     return m_itemSelectionModel;
69 }
70 
itemCoordinates(const QModelIndex & index,GeoCoordinates * const coordinates) const71 bool MarkerModelHelper::itemCoordinates(const QModelIndex& index,
72                                         GeoCoordinates* const coordinates) const
73 {
74     if (!index.data(CoordinatesRole).canConvert<GeoCoordinates>())
75     {
76         return false;
77     }
78 
79     if (coordinates)
80     {
81         *coordinates = index.data(CoordinatesRole).value<GeoCoordinates>();
82     }
83 
84     return true;
85 }
86 
87 const GeoCoordinates coord_1_2     = GeoCoordinates::fromGeoUrl(QLatin1String("geo:1,2"));
88 const GeoCoordinates coord_50_60   = GeoCoordinates::fromGeoUrl(QLatin1String("geo:50,60"));
89 const GeoCoordinates coord_m50_m60 = GeoCoordinates::fromGeoUrl(QLatin1String("geo:-50,-60"));
90 
MakeItemAt(const GeoCoordinates & coordinates)91 QStandardItem* MakeItemAt(const GeoCoordinates& coordinates)
92 {
93     QStandardItem* const newItem = new QStandardItem(coordinates.geoUrl());
94     newItem->setData(QVariant::fromValue(coordinates), CoordinatesRole);
95 
96     return newItem;
97 }
98 
99 /**
100  * @brief Helper function: count the number of markers found by an iterator
101  */
CountMarkersInIterator(ItemMarkerTiler::NonEmptyIterator * const it)102 int CountMarkersInIterator(ItemMarkerTiler::NonEmptyIterator* const it)
103 {
104     int markerCount = 0;
105 
106     while (!it->atEnd())
107     {
108         const TileIndex currentIndex = it->currentIndex();
109         markerCount                 += it->model()->getTileMarkerCount(currentIndex);
110         it->nextIndex();
111 //         qCDebug(DIGIKAM_TESTS_LOG)<<currentIndex;
112     }
113 
114     return markerCount;
115 }
116 
testNoOp()117 void TestItemMarkerTiler::testNoOp()
118 {
119 }
120 
testIndices()121 void TestItemMarkerTiler::testIndices()
122 {
123     const int maxLevel = TileIndex::MaxLevel;
124 
125     for (int l = 0 ; l <= maxLevel ; ++l)
126     {
127         const TileIndex tileIndex = TileIndex::fromCoordinates(coord_1_2, l);
128         QVERIFY(tileIndex.level() == l);
129     }
130 }
131 
testAddMarkers1()132 void TestItemMarkerTiler::testAddMarkers1()
133 {
134     QScopedPointer<QStandardItemModel> itemModel(new QStandardItemModel());
135     ItemMarkerTiler mm(new MarkerModelHelper(itemModel.data(), nullptr));
136 
137     const int maxLevel = TileIndex::MaxLevel;
138 
139     // there should be no tiles in the model yet:
140 
141     for (int l = 0 ; l <= maxLevel ; ++l)
142     {
143         QVERIFY(mm.getTile(TileIndex::fromCoordinates(coord_50_60, l), true) == nullptr);
144     }
145 
146     itemModel->appendRow(MakeItemAt(coord_50_60));
147 
148     // now there should be tiles with one marker:
149 
150     for (int l = 0 ; l <= maxLevel ; ++l)
151     {
152         const TileIndex tileIndex           = TileIndex::fromCoordinates(coord_50_60, l);
153         ItemMarkerTiler::Tile* const myTile = mm.getTile(tileIndex, true);
154 
155         if (!myTile)
156         {
157             QFAIL("Tile instance is null");
158         }
159 
160         QVERIFY(myTile->childrenEmpty());
161         QVERIFY(mm.getTileMarkerCount(tileIndex) == 1);
162     }
163 
164     itemModel->appendRow(MakeItemAt(coord_50_60));
165 
166     // now there should be tiles with two markers:
167 
168     for (int l = 0 ; l <= maxLevel ; ++l)
169     {
170         const TileIndex tileIndex           = TileIndex::fromCoordinates(coord_50_60, l);
171         ItemMarkerTiler::Tile* const myTile = mm.getTile(tileIndex, true);
172 
173         if (!myTile)
174         {
175             QFAIL("Tile instance is null");
176         }
177 
178         QCOMPARE(mm.getTileMarkerCount(tileIndex), 2);
179     }
180 }
181 
testRemoveMarkers2()182 void TestItemMarkerTiler::testRemoveMarkers2()
183 {
184     QScopedPointer<QStandardItemModel> itemModel(new QStandardItemModel());
185     ItemMarkerTiler mm(new MarkerModelHelper(itemModel.data(), nullptr));
186 
187     const int maxLevel = TileIndex::MaxLevel;
188 
189     itemModel->appendRow(MakeItemAt(coord_50_60));
190     QStandardItem* const item2 = MakeItemAt(coord_50_60);
191     itemModel->appendRow(item2);
192 
193     // now there should be tiles with two markers:
194 
195     for (int l = 0 ; l <= maxLevel ; ++l)
196     {
197         const TileIndex tileIndex           = TileIndex::fromCoordinates(coord_50_60, l);
198         ItemMarkerTiler::Tile* const myTile = mm.getTile(tileIndex, true);
199 
200         if (!myTile)
201         {
202             QFAIL("Tile instance is null");
203         }
204 
205         QCOMPARE(mm.getTileMarkerCount(tileIndex), 2);
206     }
207 
208     // remove one item:
209 
210     qDeleteAll(itemModel->takeRow(itemModel->indexFromItem(item2).row()));
211 
212     for (int l = 0 ; l <= maxLevel ; ++l)
213     {
214         const TileIndex tileIndex           = TileIndex::fromCoordinates(coord_50_60, l);
215         ItemMarkerTiler::Tile* const myTile = mm.getTile(tileIndex, true);
216 
217         if (!myTile)
218         {
219             QFAIL("Tile instance is null");
220         }
221 
222         QCOMPARE(mm.getTileMarkerCount(tileIndex), 1);
223     }
224 }
225 
testMoveMarkers1()226 void TestItemMarkerTiler::testMoveMarkers1()
227 {
228     QScopedPointer<QStandardItemModel> itemModel(new QStandardItemModel());
229     ItemMarkerTiler mm(new MarkerModelHelper(itemModel.data(), nullptr));
230     const int maxLevel  = TileIndex::MaxLevel;
231     const int fillLevel = maxLevel - 2;
232 
233     // add a marker to the model and create tiles up to a certain level:
234 
235     QStandardItem* const item1     = MakeItemAt(coord_1_2);
236     itemModel->appendRow(item1);
237     const QModelIndex markerIndex1 = itemModel->indexFromItem(item1);
238 
239     GEOIFACE_ASSERT(markerIndex1.isValid());
240 
241     for (int l = 1 ; l <= fillLevel ; ++l)
242     {
243         const TileIndex tileIndex           = TileIndex::fromCoordinates(coord_1_2, l);
244         ItemMarkerTiler::Tile* const myTile = mm.getTile(tileIndex, true);
245 
246         if (!myTile)
247         {
248             QFAIL("Tile instance is null");
249         }
250 
251         QVERIFY(myTile->childrenEmpty());
252         QCOMPARE(mm.getTileMarkerCount(tileIndex), 1);
253     }
254 
255     // now move marker 1:
256 
257     itemModel->setData(markerIndex1, QVariant::fromValue(coord_50_60), CoordinatesRole);
258 
259     for (int l = 0 ; l <= fillLevel ; ++l)
260     {
261         // make sure the marker can not be found at the old position any more
262 
263         TileIndex tileIndex = TileIndex::fromCoordinates(coord_1_2, l);
264         QVERIFY(mm.getTile(tileIndex, true) == nullptr);
265         QCOMPARE(mm.getTileMarkerCount(tileIndex), 0);
266         QVERIFY(mm.getTile(tileIndex, true) == nullptr);
267 
268         // find it at the new position:
269 
270         tileIndex                           = TileIndex::fromCoordinates(coord_50_60, l);
271         ItemMarkerTiler::Tile* const myTile = mm.getTile(tileIndex, true);
272 
273         if (!myTile)
274         {
275             QFAIL("Tile instance is null");
276         }
277 
278         QVERIFY(myTile->childrenEmpty());
279         QVERIFY(mm.getTileMarkerCount(tileIndex) == 1);
280     }
281 
282 //     mm.clear();
283 }
284 
testMoveMarkers2()285 void TestItemMarkerTiler::testMoveMarkers2()
286 {
287     QScopedPointer<QStandardItemModel> itemModel(new QStandardItemModel());
288     ItemMarkerTiler mm(new MarkerModelHelper(itemModel.data(), nullptr));
289     const int maxLevel  = TileIndex::MaxLevel;
290     const int fillLevel = maxLevel - 2;
291 
292     // add markers to the model and create tiles up to a certain level:
293 
294     QStandardItem* const item1     = MakeItemAt(coord_1_2);
295     itemModel->appendRow(item1);
296     const QModelIndex markerIndex1 = itemModel->indexFromItem(item1);
297     QStandardItem* const item2     = MakeItemAt(coord_1_2);
298     itemModel->appendRow(item2);
299 //    const QModelIndex markerIndex2 = itemModel->indexFromItem(item2);
300 
301     for (int l = 1 ; l <= fillLevel ; ++l)
302     {
303         const TileIndex tileIndex           = TileIndex::fromCoordinates(coord_1_2, l);
304         ItemMarkerTiler::Tile* const myTile = mm.getTile(tileIndex, true);
305 
306         if (!myTile)
307         {
308             QFAIL("Tile instance is null");
309         }
310 
311         QVERIFY(myTile->childrenEmpty());
312         QVERIFY(mm.getTileMarkerCount(tileIndex) == 2);
313     }
314 
315     QStandardItem* const item3     = MakeItemAt(coord_50_60);
316     itemModel->appendRow(item3);
317 //    const QModelIndex markerIndex3 = itemModel->indexFromItem(item3);
318 
319     for (int l = 1 ; l <= fillLevel ; ++l)
320     {
321         const TileIndex tileIndex           = TileIndex::fromCoordinates(coord_50_60, l);
322         ItemMarkerTiler::Tile* const myTile = mm.getTile(tileIndex, true);
323 
324         if (!myTile)
325         {
326             QFAIL("Tile instance is null");
327         }
328 
329         QVERIFY(myTile->childrenEmpty());
330         QVERIFY(mm.getTileMarkerCount(tileIndex) == 1);
331     }
332 
333     // now move marker 1:
334 
335     itemModel->setData(markerIndex1, QVariant::fromValue(coord_50_60), CoordinatesRole);
336 
337     // make sure the item model was also updated:
338 
339     QVERIFY(item1->data(CoordinatesRole).value<GeoCoordinates>() == coord_50_60);
340 
341     for (int l = 0 ; l <= fillLevel ; ++l)
342     {
343         // make sure there is only one marker left at the old position:
344 
345         TileIndex tileIndex = TileIndex::fromCoordinates(coord_1_2, l);
346         QVERIFY(mm.getTileMarkerCount(tileIndex) == 1);
347 
348         // find it at the new position:
349 
350         tileIndex                           = TileIndex::fromCoordinates(coord_50_60, l);
351         ItemMarkerTiler::Tile* const myTile = mm.getTile(tileIndex, true);
352 
353         if (!myTile)
354         {
355             QFAIL("Tile instance is null");
356         }
357 
358         if (l > fillLevel)
359         {
360             QVERIFY(myTile->childrenEmpty());
361         }
362 
363         QVERIFY(mm.getTileMarkerCount(tileIndex) == 2);
364     }
365 
366 //     mm.clear();
367 }
368 
testIteratorWholeWorldNoBackingModel()369 void TestItemMarkerTiler::testIteratorWholeWorldNoBackingModel()
370 {
371     QScopedPointer<QStandardItemModel> itemModel(new QStandardItemModel());
372     ItemMarkerTiler mm(new MarkerModelHelper(itemModel.data(), nullptr));
373     const int maxLevel = TileIndex::MaxLevel;
374 
375     for (int l = 0 ; l <= maxLevel ; ++l)
376     {
377         ItemMarkerTiler::NonEmptyIterator it(&mm, l);
378         QVERIFY( CountMarkersInIterator(&it) == 0 );
379     }
380 }
381 
testIteratorWholeWorld()382 void TestItemMarkerTiler::testIteratorWholeWorld()
383 {
384     QScopedPointer<QStandardItemModel> itemModel(new QStandardItemModel());
385     ItemMarkerTiler mm(new MarkerModelHelper(itemModel.data(), nullptr));
386     const int maxLevel = TileIndex::MaxLevel;
387 
388     for (int l = 0 ; l <= maxLevel ; ++l)
389     {
390         ItemMarkerTiler::NonEmptyIterator it(&mm, l);
391         QVERIFY( CountMarkersInIterator(&it) == 0 );
392     }
393 
394     itemModel->appendRow(MakeItemAt(coord_1_2));
395     itemModel->appendRow(MakeItemAt(coord_50_60));
396 
397     for (int l = 0 ; l <= maxLevel ; ++l)
398     {
399         // iterate over the whole world:
400 
401         ItemMarkerTiler::NonEmptyIterator it(&mm, l);
402         QVERIFY( CountMarkersInIterator(&it) == 2 );
403     }
404 }
405 
testIteratorPartial1()406 void TestItemMarkerTiler::testIteratorPartial1()
407 {
408     QScopedPointer<QStandardItemModel> itemModel(new QStandardItemModel());
409     ItemMarkerTiler mm(new MarkerModelHelper(itemModel.data(), nullptr));
410     const int maxLevel = TileIndex::MaxLevel;
411 
412     itemModel->appendRow(MakeItemAt(coord_1_2));
413     itemModel->appendRow(MakeItemAt(coord_50_60));
414 
415     for (int l = 0 ; l <= maxLevel ; ++l)
416     {
417         {
418             // iterate over a part which should be empty:
419 
420             GeoCoordinates::PairList boundsList;
421             boundsList << GeoCoordinates::makePair(-10.0, -10.0, -5.0, -5.0);
422             ItemMarkerTiler::NonEmptyIterator it(&mm, l, boundsList);
423             QVERIFY( CountMarkersInIterator(&it) == 0 );
424         }
425 
426         {
427             // iterate over a part which should contain one marker:
428 
429             GeoCoordinates::PairList boundsList;
430             boundsList << GeoCoordinates::makePair(-10.0, -10.0, 5.0, 5.0);
431             ItemMarkerTiler::NonEmptyIterator it(&mm, l, boundsList);
432             QVERIFY( CountMarkersInIterator(&it) == 1 );
433 
434             // iterate over a part which should contain one marker:
435 
436             GeoCoordinates::PairList boundsList1;
437             boundsList1 << GeoCoordinates::makePair(1.0, 2.0, 5.0, 5.0);
438             ItemMarkerTiler::NonEmptyIterator it1(&mm, l, boundsList1);
439             QVERIFY( CountMarkersInIterator(&it1) == 1 );
440 
441             GeoCoordinates::PairList boundsList2;
442             boundsList2 << GeoCoordinates::makePair(-1.0, -2.0, 1.0, 2.0);
443             ItemMarkerTiler::NonEmptyIterator it2(&mm, l, boundsList2);
444             QVERIFY( CountMarkersInIterator(&it2) == 1 );
445         }
446 
447         {
448             // iterate over a part which should contain two markers:
449 
450             GeoCoordinates::PairList boundsList;
451             boundsList << GeoCoordinates::makePair(0.0, 0.0, 60.0, 60.0);
452             ItemMarkerTiler::NonEmptyIterator it(&mm, l, boundsList);
453             QVERIFY( CountMarkersInIterator(&it) == 2 );
454         }
455 
456         {
457             // iterate over two parts which should contain two markers:
458 
459             GeoCoordinates::PairList boundsList;
460             boundsList << GeoCoordinates::makePair(0.0, 0.0, 5.0, 5.0);
461             boundsList << GeoCoordinates::makePair(49.0, 59.0, 51.0, 61.0);
462             ItemMarkerTiler::NonEmptyIterator it(&mm, l, boundsList);
463             QVERIFY( CountMarkersInIterator(&it) == 2 );
464         }
465     }
466 
467     const GeoCoordinates coord_2_2 = GeoCoordinates(2.0, 2.0);
468 
469     itemModel->appendRow(MakeItemAt(coord_2_2));
470     {
471         // at level 1, the iterator should find only one marker:
472 
473         GeoCoordinates::PairList boundsList;
474         boundsList << GeoCoordinates::makePair(0.0, 0.0, 1.0, 2.0);
475         ItemMarkerTiler::NonEmptyIterator it(&mm, 1, boundsList);
476         QVERIFY( CountMarkersInIterator(&it) == 1 );
477     }
478 }
479 
testIteratorPartial2()480 void TestItemMarkerTiler::testIteratorPartial2()
481 {
482     QScopedPointer<QStandardItemModel> itemModel(new QStandardItemModel());
483     ItemMarkerTiler mm(new MarkerModelHelper(itemModel.data(), nullptr));
484     const int maxLevel = TileIndex::MaxLevel;
485 
486     GeoCoordinates::PairList boundsList;
487     boundsList << GeoCoordinates::makePair(0.55, 1.55, 0.56, 1.56);
488 
489     const GeoCoordinates coordInBounds1    = GeoCoordinates(0.556, 1.556);
490     const GeoCoordinates coordOutOfBounds1 = GeoCoordinates(0.5, 1.5);
491     const GeoCoordinates coordOutOfBounds2 = GeoCoordinates(0.5, 1.6);
492     const GeoCoordinates coordOutOfBounds3 = GeoCoordinates(0.6, 1.5);
493     const GeoCoordinates coordOutOfBounds4 = GeoCoordinates(0.6, 1.6);
494     itemModel->appendRow(MakeItemAt(coordInBounds1));
495     itemModel->appendRow(MakeItemAt(coordOutOfBounds1));
496     itemModel->appendRow(MakeItemAt(coordOutOfBounds2));
497     itemModel->appendRow(MakeItemAt(coordOutOfBounds3));
498     itemModel->appendRow(MakeItemAt(coordOutOfBounds4));
499 
500     for (int l = 3 ; l <= maxLevel ; ++l)
501     {
502         ItemMarkerTiler::NonEmptyIterator it(&mm, l, boundsList);
503         QVERIFY( CountMarkersInIterator(&it) == 1 );
504     }
505 }
506 
testRemoveMarkers1()507 void TestItemMarkerTiler::testRemoveMarkers1()
508 {
509     QScopedPointer<QStandardItemModel> itemModel(new QStandardItemModel());
510     ItemMarkerTiler mm(new MarkerModelHelper(itemModel.data(), nullptr));
511     const int maxLevel = TileIndex::MaxLevel;
512 
513     for (int l = 0 ; l <= maxLevel ; ++l)
514     {
515         ItemMarkerTiler::NonEmptyIterator it(&mm, l);
516         QVERIFY(CountMarkersInIterator(&it) == 0 );
517     }
518 
519     QStandardItem* const item1 = MakeItemAt(coord_1_2);
520     itemModel->appendRow(item1);
521     itemModel->appendRow(MakeItemAt(coord_50_60));
522 
523     for (int l = 0 ; l <= maxLevel ; ++l)
524     {
525         // iterate over the whole world:
526 
527         ItemMarkerTiler::NonEmptyIterator it(&mm, l);
528         QCOMPARE(CountMarkersInIterator(&it), 2);
529     }
530 
531     // first make sure that comparison of indices still works
532 
533     const QPersistentModelIndex index1 = itemModel->indexFromItem(item1);
534     const QPersistentModelIndex index2 = itemModel->indexFromItem(item1);
535     QCOMPARE(index1, index2);
536 
537     // now remove items:
538 
539     QCOMPARE(itemModel->takeRow(itemModel->indexFromItem(item1).row()).count(), 1);
540     delete item1;
541     QCOMPARE(itemModel->rowCount(), 1);
542 
543     for (int l = 0 ; l <= maxLevel ; ++l)
544     {
545         // iterate over the whole world:
546 
547         ItemMarkerTiler::NonEmptyIterator it(&mm, l);
548         QCOMPARE(CountMarkersInIterator(&it), 1);
549     }
550 }
551 
552 /**
553  * @brief Make sure that items which are in the model before it is given to the tiled model are found by the tile model
554  */
testPreExistingMarkers()555 void TestItemMarkerTiler::testPreExistingMarkers()
556 {
557     QScopedPointer<QStandardItemModel> itemModel(new QStandardItemModel());
558     itemModel->appendRow(MakeItemAt(coord_50_60));
559     ItemMarkerTiler mm(new MarkerModelHelper(itemModel.data(), nullptr));
560 
561     const int maxLevel = TileIndex::MaxLevel;
562 
563     for (int l = 0; l <= maxLevel; ++l)
564     {
565         // iterate over the whole world:
566 
567         ItemMarkerTiler::NonEmptyIterator it(&mm, l);
568         QVERIFY( CountMarkersInIterator(&it) == 1 );
569     }
570 }
571 
testSelectionState1()572 void TestItemMarkerTiler::testSelectionState1()
573 {
574     QScopedPointer<QStandardItemModel> itemModel(new QStandardItemModel());
575     QItemSelectionModel* const selectionModel = new QItemSelectionModel(itemModel.data());
576     ItemMarkerTiler mm(new MarkerModelHelper(itemModel.data(), selectionModel));
577 
578     const int maxLevel         = TileIndex::MaxLevel;
579 
580     QStandardItem* const item1 = MakeItemAt(coord_50_60);
581     item1->setSelectable(true);
582     itemModel->appendRow(item1);
583     QModelIndex item1Index     = itemModel->indexFromItem(item1);
584 
585     // verify the selection state of the tiles:
586     // make sure we do not create tiles all the way down,
587     // because we want to test whether the state is okay in newly created tiles
588 
589     const int preMaxLevel = maxLevel -2;
590 
591     for (int l = 0 ; l <= preMaxLevel ; ++l)
592     {
593         const TileIndex tileIndex           = TileIndex::fromCoordinates(coord_50_60, l);
594         ItemMarkerTiler::Tile* const myTile = mm.getTile(tileIndex, true);
595 
596         if (!myTile)
597         {
598             QFAIL("Tile instance is null");
599         }
600 
601         QVERIFY(mm.getTileMarkerCount(tileIndex) == 1);
602         QVERIFY(mm.getTileGroupState(tileIndex)==SelectedNone);
603     }
604 
605     selectionModel->select(item1Index, QItemSelectionModel::Select);
606 
607     // verify the selection state of the tiles:
608 
609     for (int l = 0 ; l <= maxLevel ; ++l)
610     {
611         const TileIndex tileIndex           = TileIndex::fromCoordinates(coord_50_60, l);
612         ItemMarkerTiler::Tile* const myTile = mm.getTile(tileIndex, true);
613 
614         if (!myTile)
615         {
616             QFAIL("Tile instance is null");
617         }
618 
619         QCOMPARE(mm.getTileMarkerCount(tileIndex), 1);
620         QVERIFY(mm.getTileGroupState(tileIndex)==SelectedAll);
621         QVERIFY(mm.getTileSelectedCount(tileIndex)==1);
622     }
623 
624     // add an unselected item and make sure the tilecount is still correct
625 
626     QStandardItem* const item2             = MakeItemAt(coord_50_60);
627     item2->setSelectable(true);
628     itemModel->appendRow(item2);
629     const QPersistentModelIndex item2Index = itemModel->indexFromItem(item2);
630 
631     for (int l = 0 ; l <= maxLevel ; ++l)
632     {
633         const TileIndex tileIndex           = TileIndex::fromCoordinates(coord_50_60, l);
634         ItemMarkerTiler::Tile* const myTile = mm.getTile(tileIndex, true);
635 
636         if (!myTile)
637         {
638             QFAIL("Tile instance is null");
639         }
640 
641         QCOMPARE(mm.getTileMarkerCount(tileIndex), 2);
642         QVERIFY(mm.getTileGroupState(tileIndex)==SelectedSome);
643         QCOMPARE(mm.getTileSelectedCount(tileIndex), 1);
644     }
645 
646     selectionModel->select(item2Index, QItemSelectionModel::Select);
647 
648     for (int l = 0 ; l <= maxLevel ; ++l)
649     {
650         const TileIndex tileIndex           = TileIndex::fromCoordinates(coord_50_60, l);
651         ItemMarkerTiler::Tile* const myTile = mm.getTile(tileIndex, true);
652 
653         if (!myTile)
654         {
655             QFAIL("Tile instance is null");
656         }
657 
658         QCOMPARE(mm.getTileMarkerCount(tileIndex), 2);
659         QCOMPARE(mm.getTileSelectedCount(tileIndex), 2);
660         QVERIFY(mm.getTileGroupState(tileIndex)==SelectedAll);
661     }
662 
663     // now remove the selected item:
664 
665     QCOMPARE(itemModel->takeRow(item2Index.row()).count(), 1);
666     delete item2;
667 
668     // verify the selection state of the tiles:
669 
670     for (int l = 0 ; l <= maxLevel ; ++l)
671     {
672         const TileIndex tileIndex           = TileIndex::fromCoordinates(coord_50_60, l);
673         ItemMarkerTiler::Tile* const myTile = mm.getTile(tileIndex, true);
674 
675         if (!myTile)
676         {
677             QFAIL("Tile instance is null");
678         }
679 
680         QCOMPARE(mm.getTileMarkerCount(tileIndex), 1);
681         QCOMPARE(mm.getTileSelectedCount(tileIndex), 1);
682         QVERIFY(mm.getTileGroupState(tileIndex)==SelectedAll);
683     }
684 
685     // add a selected item and then move it:
686 
687     QStandardItem* const item3             = MakeItemAt(coord_1_2);
688     item3->setSelectable(true);
689     itemModel->appendRow(item3);
690     const QPersistentModelIndex item3Index = itemModel->indexFromItem(item3);
691     selectionModel->select(item3Index, QItemSelectionModel::Select);
692 
693     for (int l = 0 ; l <= maxLevel ; ++l)
694     {
695         const TileIndex tileIndex           = TileIndex::fromCoordinates(coord_1_2, l);
696         ItemMarkerTiler::Tile* const myTile = mm.getTile(tileIndex, true);
697 
698         if (!myTile)
699         {
700             QFAIL("Tile instance is null");
701         }
702 
703         QCOMPARE(mm.getTileMarkerCount(tileIndex), 1);
704         QCOMPARE(mm.getTileSelectedCount(tileIndex), 1);
705         QVERIFY(mm.getTileGroupState(tileIndex)==SelectedAll);
706     }
707 
708     for (int l = 0 ; l <= maxLevel ; ++l)
709     {
710         const TileIndex tileIndex           = TileIndex::fromCoordinates(coord_50_60, l);
711         ItemMarkerTiler::Tile* const myTile = mm.getTile(tileIndex, true);
712 
713         if (!myTile)
714         {
715             QFAIL("Tile instance is null");
716         }
717 
718         QCOMPARE(mm.getTileMarkerCount(tileIndex), 1);
719         QCOMPARE(mm.getTileSelectedCount(tileIndex), 1);
720         QVERIFY(mm.getTileGroupState(tileIndex)==SelectedAll);
721     }
722 
723     itemModel->setData(item3Index, QVariant::fromValue(coord_50_60), CoordinatesRole);
724 
725     for (int l = 0 ; l <= maxLevel ; ++l)
726     {
727         const TileIndex tileIndex           = TileIndex::fromCoordinates(coord_50_60, l);
728         ItemMarkerTiler::Tile* const myTile = mm.getTile(tileIndex, true);
729 
730         if (!myTile)
731         {
732             QFAIL("Tile instance is null");
733         }
734 
735         QCOMPARE(mm.getTileMarkerCount(tileIndex), 2);
736         QCOMPARE(mm.getTileSelectedCount(tileIndex), 2);
737         QVERIFY(mm.getTileGroupState(tileIndex)==SelectedAll);
738     }
739 
740     itemModel->setData(item3Index, QVariant::fromValue(coord_m50_m60), CoordinatesRole);
741 
742     for (int l = 0 ; l <= maxLevel ; ++l)
743     {
744         const TileIndex tileIndex           = TileIndex::fromCoordinates(coord_50_60, l);
745         ItemMarkerTiler::Tile* const myTile = mm.getTile(tileIndex, true);
746 
747         if (!myTile)
748         {
749             QFAIL("Tile instance is null");
750         }
751 
752         QCOMPARE(mm.getTileMarkerCount(tileIndex), 1);
753         QCOMPARE(mm.getTileSelectedCount(tileIndex), 1);
754         QVERIFY(mm.getTileGroupState(tileIndex)==SelectedAll);
755     }
756 
757     for (int l = 0 ; l <= maxLevel ; ++l)
758     {
759         const TileIndex tileIndex           = TileIndex::fromCoordinates(coord_m50_m60, l);
760         ItemMarkerTiler::Tile* const myTile = mm.getTile(tileIndex, true);
761 
762         if (!myTile)
763         {
764             QFAIL("Tile instance is null");
765         }
766 
767         QCOMPARE(mm.getTileMarkerCount(tileIndex), 1);
768         QCOMPARE(mm.getTileSelectedCount(tileIndex), 1);
769         QVERIFY(mm.getTileGroupState(tileIndex)==SelectedAll);
770     }
771 
772     // TODO: set a model with selected items, make sure the selections are read out
773     //       this is currently implemented by simply setting the tiles as dirty
774 }
775 
benchmarkIteratorWholeWorld()776 void TestItemMarkerTiler::benchmarkIteratorWholeWorld()
777 {
778 /*
779  * without non-empty child lists
780  *   RESULT : TestItemMarkerTiler::benchmarkIteratorWholeWorld():
781  *            4,470 msecs per iteration (total: 4,470, iterations: 1)
782  *            after adding lists:
783  *   RESULT : TestItemMarkerTiler::benchmarkIteratorWholeWorld():
784  *            712 msecs per iteration (total: 712, iterations: 1)
785  */
786 
787 #if 0
788 
789     return;
790 
791 #else
792 
793     QBENCHMARK
794     {
795         QScopedPointer<QStandardItemModel> itemModel(new QStandardItemModel());
796         ItemMarkerTiler mm(new MarkerModelHelper(itemModel.data(), 0));
797         const int maxLevel = TileIndex::MaxLevel;
798 
799         {
800             int l = maxLevel-1;
801             ItemMarkerTiler::NonEmptyIterator it(&mm, l);
802             QVERIFY( CountMarkersInIterator(&it) == 0 );
803         }
804 
805         itemModel->appendRow(MakeItemAt(coord_1_2));
806         itemModel->appendRow(MakeItemAt(coord_50_60));
807 
808         for (qreal x = -50; x < 50; x+=1.0)
809         {
810             for (qreal y = -50; y < 50; y+=1.0)
811             {
812                 itemModel->appendRow(MakeItemAt(GeoCoordinates(x,y)));
813             }
814         }
815 
816 //         QBENCHMARK
817         {
818             const int l = maxLevel;
819 //             for (int l = 0; l <= maxLevel; ++l)
820             {
821                 // iterate over the whole world:
822 
823                 ItemMarkerTiler::NonEmptyIterator it(&mm, l);
824                 (void)CountMarkersInIterator(&it);
825             }
826         }
827     }
828 
829 #endif
830 
831 }
832 
833 QTEST_GUILESS_MAIN(TestItemMarkerTiler)
834