File indexing completed on 2025-01-19 03:58:09

0001 /* ============================================================
0002  *
0003  * This file is a part of digiKam project
0004  * https://www.digikam.org
0005  *
0006  * Date        : 2010-07-17
0007  * Description : A marker tiler operating on item models
0008  *
0009  * SPDX-FileCopyrightText: 2010-2024 by Gilles Caulier <caulier dot gilles at gmail dot com>
0010  * SPDX-FileCopyrightText: 2010-2011 by Michael G. Hansen <mike at mghansen dot de>
0011  *
0012  * SPDX-License-Identifier: GPL-2.0-or-later
0013  *
0014  * ============================================================ */
0015 
0016 #include "itemmarkertiler.h"
0017 
0018 // local includes
0019 
0020 #include "geomodelhelper.h"
0021 #include "digikam_debug.h"
0022 #include "geoifacecommon.h"
0023 
0024 namespace Digikam
0025 {
0026 
0027 class Q_DECL_HIDDEN ItemMarkerTiler::MyTile : public Tile
0028 {
0029 public:
0030 
0031     MyTile() = default;
0032     void removeMarkerIndexOrInvalidIndex(const QModelIndex& indexToRemove);
0033 
0034 public:
0035 
0036     QList<QPersistentModelIndex> markerIndices;
0037     int                          selectedCount = 0;
0038 
0039 private:
0040 
0041     MyTile(const MyTile&) = delete;
0042     MyTile& operator=(const MyTile&) = delete;
0043 };
0044 
0045 void ItemMarkerTiler::MyTile::removeMarkerIndexOrInvalidIndex(const QModelIndex& indexToRemove)
0046 {
0047     int i = 0;
0048 
0049     while (i < markerIndices.count())
0050     {
0051         const QPersistentModelIndex& currentIndex = markerIndices.at(i);
0052 
0053         // NOTE: this function is usually called after the model has sent
0054         //       an aboutToRemove-signal. It is possible that the persistent
0055         //       marker index became invalid before the caller received the signal.
0056         //       we remove any invalid indices as we find them.
0057 
0058         if (!currentIndex.isValid())
0059         {
0060             markerIndices.takeAt(i);
0061             continue;
0062         }
0063 
0064         if (currentIndex == indexToRemove)
0065         {
0066             markerIndices.takeAt(i);
0067 
0068             return;
0069         }
0070 
0071         ++i;
0072     }
0073 }
0074 
0075 // -------------------------------------------------------------------------------------------
0076 
0077 class Q_DECL_HIDDEN ItemMarkerTiler::Private
0078 {
0079 public:
0080 
0081     explicit Private()
0082       : modelHelper   (nullptr),
0083         selectionModel(nullptr),
0084         markerModel   (nullptr),
0085         activeState   (false)
0086     {
0087     }
0088 
0089     GeoModelHelper*         modelHelper;
0090     QItemSelectionModel* selectionModel;
0091     QAbstractItemModel*  markerModel;
0092     bool                 activeState;
0093 };
0094 
0095 ItemMarkerTiler::ItemMarkerTiler(GeoModelHelper* const modelHelper, QObject* const parent)
0096     : AbstractMarkerTiler(parent),
0097       d                  (new Private())
0098 {
0099     resetRootTile();
0100     setMarkerGeoModelHelper(modelHelper);
0101 }
0102 
0103 ItemMarkerTiler::~ItemMarkerTiler()
0104 {
0105     delete d;
0106 }
0107 
0108 void ItemMarkerTiler::setMarkerGeoModelHelper(GeoModelHelper* const modelHelper)
0109 {
0110     d->modelHelper    = modelHelper;
0111     d->markerModel    = modelHelper->model();
0112     d->selectionModel = modelHelper->selectionModel();
0113 
0114     if (d->markerModel != nullptr)
0115     {
0116         // TODO: disconnect the old model if there was one
0117 
0118         connect(d->markerModel, &QAbstractItemModel::rowsInserted,
0119                 this, &ItemMarkerTiler::slotSourceModelRowsInserted);
0120 
0121         connect(d->markerModel, &QAbstractItemModel::rowsAboutToBeRemoved,
0122                 this, &ItemMarkerTiler::slotSourceModelRowsAboutToBeRemoved);
0123 
0124         // TODO: this signal now has to be monitored in the model helper
0125 /*
0126         connect(d->markerModel, SIGNAL(dataChanged(QModelIndex,QModelIndex)),
0127                 this, SLOT(slotSourceModelDataChanged(QModelIndex,QModelIndex)));
0128 */
0129         connect(d->modelHelper, &GeoModelHelper::signalModelChangedDrastically,
0130                 this, &ItemMarkerTiler::slotSourceModelReset);
0131 
0132         connect(d->markerModel, &QAbstractItemModel::modelReset,
0133                 this, &ItemMarkerTiler::slotSourceModelReset);
0134 
0135         connect(d->markerModel, &QAbstractItemModel::layoutChanged,
0136                 this, &ItemMarkerTiler::slotSourceModelLayoutChanged);
0137 
0138         connect(d->modelHelper, &GeoModelHelper::signalThumbnailAvailableForIndex,
0139                 this, &ItemMarkerTiler::slotThumbnailAvailableForIndex);
0140 
0141         if (d->selectionModel)
0142         {
0143             connect(d->selectionModel, &QItemSelectionModel::selectionChanged,
0144                     this, &ItemMarkerTiler::slotSelectionChanged);
0145         }
0146     }
0147 
0148     setDirty();
0149 }
0150 
0151 QVariant ItemMarkerTiler::getTileRepresentativeMarker(const TileIndex& tileIndex, const int sortKey)
0152 {
0153     const QList<QPersistentModelIndex> modelIndices = getTileMarkerIndices(tileIndex);
0154 
0155     if (modelIndices.isEmpty())
0156     {
0157         return QVariant();
0158     }
0159 
0160     return QVariant::fromValue(d->modelHelper->bestRepresentativeIndexFromList(modelIndices, sortKey));
0161 }
0162 
0163 QPixmap ItemMarkerTiler::pixmapFromRepresentativeIndex(const QVariant& index, const QSize& size)
0164 {
0165     return d->modelHelper->pixmapFromRepresentativeIndex(index.value<QPersistentModelIndex>(), size);
0166 }
0167 
0168 QVariant ItemMarkerTiler::bestRepresentativeIndexFromList(const QList<QVariant>& indices, const int sortKey)
0169 {
0170     QList<QPersistentModelIndex> indexList;
0171 
0172     for (int i = 0 ; i < indices.count() ; ++i)
0173     {
0174         indexList << indices.at(i).value<QPersistentModelIndex>();
0175     }
0176 
0177     return QVariant::fromValue(d->modelHelper->bestRepresentativeIndexFromList(indexList, sortKey));
0178 }
0179 
0180 void ItemMarkerTiler::slotSelectionChanged(const QItemSelection& selected, const QItemSelection& deselected)
0181 {
0182 /*
0183     qCDebug(DIGIKAM_GEOIFACE_LOG)<<selected<<deselected;
0184 */
0185     if (isDirty())
0186     {
0187         return;
0188     }
0189 /*
0190     d->isDirty=true;
0191     Q_EMIT signalTilesOrSelectionChanged();
0192     return;
0193 */
0194 
0195     for (int i = 0 ; i < selected.count() ; ++i)
0196     {
0197         const QItemSelectionRange selectionRange = selected.at(i);
0198 
0199         for (int row = selectionRange.top() ; row <= selectionRange.bottom() ; ++row)
0200         {
0201             // get the coordinates of the item
0202 
0203             GeoCoordinates coordinates;
0204 
0205             if (!d->modelHelper->itemCoordinates(d->markerModel->index(row, 0, selectionRange.parent()), &coordinates))
0206             {
0207                 continue;
0208             }
0209 
0210             for (int l = 0 ; l <= TileIndex::MaxLevel ; ++l)
0211             {
0212                 const TileIndex tileIndex = TileIndex::fromCoordinates(coordinates, l);
0213                 MyTile* const myTile      = static_cast<MyTile*>(getTile(tileIndex, true));
0214 
0215                 if (!myTile)
0216                 {
0217                     break;
0218                 }
0219 
0220                 myTile->selectedCount++;
0221 /*
0222                 qCDebug(DIGIKAM_GEOIFACE_LOG) << l << tileIndex << myTile->selectedCount;
0223 */
0224                 GEOIFACE_ASSERT(myTile->selectedCount <= myTile->markerIndices.count());
0225 
0226                 if (myTile->childrenEmpty())
0227                 {
0228                     break;
0229                 }
0230             }
0231         }
0232     }
0233 
0234     for (int i = 0 ; i < deselected.count() ; ++i)
0235     {
0236         const QItemSelectionRange selectionRange = deselected.at(i);
0237 
0238         for (int row = selectionRange.top() ; row <= selectionRange.bottom() ; ++row)
0239         {
0240             // get the coordinates of the item
0241 
0242             GeoCoordinates coordinates;
0243 
0244             if (!d->modelHelper->itemCoordinates(d->markerModel->index(row, 0, selectionRange.parent()), &coordinates))
0245             {
0246                 continue;
0247             }
0248 
0249             for (int l = 0 ; l <= TileIndex::MaxLevel ; ++l)
0250             {
0251                 const TileIndex tileIndex = TileIndex::fromCoordinates(coordinates, l);
0252                 MyTile* const myTile      = static_cast<MyTile*>(getTile(tileIndex, true));
0253 
0254                 if (!myTile)
0255                 {
0256                     break;
0257                 }
0258 
0259                 myTile->selectedCount--;
0260                 GEOIFACE_ASSERT(myTile->selectedCount >= 0);
0261 
0262                 if (myTile->childrenEmpty())
0263                 {
0264                     break;
0265                 }
0266             }
0267         }
0268     }
0269 
0270     Q_EMIT signalTilesOrSelectionChanged();
0271 }
0272 
0273 void ItemMarkerTiler::slotSourceModelDataChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight)
0274 {
0275     qCDebug(DIGIKAM_GEOIFACE_LOG) << topLeft << bottomRight;
0276     setDirty();
0277 
0278     if (d->activeState)
0279     {
0280         Q_EMIT signalTilesOrSelectionChanged();
0281     }
0282 
0283     // TODO: if only a few items were changed, try to see whether they are still in the right tiles
0284 }
0285 
0286 void ItemMarkerTiler::slotSourceModelRowsInserted(const QModelIndex& parentIndex, int start, int end)
0287 {
0288     if (isDirty())
0289     {
0290         // rows will be added once the tiles are regenerated
0291 
0292         return;
0293     }
0294 
0295     // sort the new items into our tiles:
0296 
0297     for (int i = start ; i <= end ; ++i)
0298     {
0299         addMarkerIndexToGrid(QPersistentModelIndex(d->markerModel->index(i, 0, parentIndex)));
0300     }
0301 
0302     Q_EMIT signalTilesOrSelectionChanged();
0303 }
0304 
0305 void ItemMarkerTiler::slotSourceModelRowsAboutToBeRemoved(const QModelIndex& parentIndex, int start, int end)
0306 {
0307     // TODO: Q_EMIT signalTilesOrSelectionChanged(); in rowsWereRemoved
0308 
0309     if (isDirty())
0310     {
0311         return;
0312     }
0313 
0314     // remove the items from their tiles:
0315 
0316     for (int i = start ; i <= end ; ++i)
0317     {
0318         const QModelIndex itemIndex = d->markerModel->index(start, 0, parentIndex);
0319 
0320         // remove the marker from the grid, but leave the selection count alone because the
0321         // selection model will send a signal about the deselection of the marker
0322 
0323         removeMarkerIndexFromGrid(itemIndex, true);
0324     }
0325 }
0326 
0327 void ItemMarkerTiler::slotThumbnailAvailableForIndex(const QPersistentModelIndex& index, const QPixmap& pixmap)
0328 {
0329     Q_EMIT signalThumbnailAvailableForIndex(QVariant::fromValue(index), pixmap);
0330 }
0331 
0332 void ItemMarkerTiler::slotSourceModelReset()
0333 {
0334     qCDebug(DIGIKAM_GEOIFACE_LOG) << "----";
0335     setDirty();
0336 }
0337 
0338 /**
0339  * @brief Remove a marker from the grid
0340  * @param ignoreSelection Do not remove the marker from the count of selected items.
0341  *                        This is only used by slotSourceModelRowsAboutToBeRemoved internally,
0342  *                        because the selection model sends us an extra signal about the deselection.
0343  */
0344 void ItemMarkerTiler::removeMarkerIndexFromGrid(const QModelIndex& markerIndex, const bool ignoreSelection)
0345 {
0346     if (isDirty())
0347     {
0348         // if the model is dirty, there is no need to remove the marker
0349         // because the tiles will be regenerated on the next call
0350         // that requests data
0351 
0352         return;
0353     }
0354 
0355     GEOIFACE_ASSERT(markerIndex.isValid());
0356 
0357     bool markerIsSelected = false;
0358 
0359     if (d->selectionModel)
0360     {
0361         markerIsSelected = d->selectionModel->isSelected(markerIndex);
0362     }
0363 
0364     // remove the marker from the grid:
0365 
0366     GeoCoordinates markerCoordinates;
0367 
0368     if (!d->modelHelper->itemCoordinates(markerIndex, &markerCoordinates))
0369     {
0370         return;
0371     }
0372 
0373     const TileIndex tileIndex = TileIndex::fromCoordinates(markerCoordinates, TileIndex::MaxLevel);
0374     QList<MyTile*> tiles;
0375 
0376     // here l functions as the number of indices that we actually use, therefore we have to go one more up
0377     // in this case, l==0 returns the root tile
0378 
0379     for (int l = 0 ; l <= TileIndex::MaxLevel+1 ; ++l)
0380     {
0381         MyTile* const currentTile = static_cast<MyTile*>(getTile(tileIndex.mid(0, l), true));
0382 
0383         if (!currentTile)
0384         {
0385             break;
0386         }
0387 
0388         tiles << currentTile;
0389         currentTile->removeMarkerIndexOrInvalidIndex(markerIndex);
0390 
0391         if (markerIsSelected&&!ignoreSelection)
0392         {
0393             currentTile->selectedCount--;
0394             GEOIFACE_ASSERT(currentTile->selectedCount >= 0);
0395         }
0396     }
0397 
0398     // delete the tiles which are now empty!
0399 
0400     for (int l = tiles.count()-1 ; l > 0 ; --l)
0401     {
0402         MyTile* const currentTile = tiles.at(l);
0403 
0404         if (!currentTile->markerIndices.isEmpty())
0405         {
0406             break;
0407         }
0408 
0409         MyTile* const parentTile = tiles.at(l-1);
0410         parentTile->deleteChild(currentTile);
0411     }
0412 }
0413 
0414 int ItemMarkerTiler::getTileMarkerCount(const TileIndex& tileIndex)
0415 {
0416     if (isDirty())
0417     {
0418         regenerateTiles();
0419     }
0420 
0421     GEOIFACE_ASSERT(tileIndex.level() <= TileIndex::MaxLevel);
0422 
0423     MyTile* const myTile = static_cast<MyTile*>(getTile(tileIndex, true));
0424 
0425     if (!myTile)
0426     {
0427         return 0;
0428     }
0429 
0430     return myTile->markerIndices.count();
0431 }
0432 
0433 int ItemMarkerTiler::getTileSelectedCount(const TileIndex& tileIndex)
0434 {
0435     if (isDirty())
0436     {
0437         regenerateTiles();
0438     }
0439 
0440     GEOIFACE_ASSERT(tileIndex.level() <= TileIndex::MaxLevel);
0441 
0442     MyTile* const myTile = static_cast<MyTile*>(getTile(tileIndex, true));
0443 
0444     if (!myTile)
0445     {
0446         return 0;
0447     }
0448 
0449     return myTile->selectedCount;
0450 }
0451 
0452 GeoGroupState ItemMarkerTiler::getTileGroupState(const TileIndex& tileIndex)
0453 {
0454     if (isDirty())
0455     {
0456         regenerateTiles();
0457     }
0458 
0459     GEOIFACE_ASSERT(tileIndex.level() <= TileIndex::MaxLevel);
0460 
0461     MyTile* const myTile = static_cast<MyTile*>(getTile(tileIndex, true));
0462 
0463     if (!myTile)
0464     {
0465         return SelectedNone;
0466     }
0467 
0468     const int selectedCount = myTile->selectedCount;
0469 
0470     if      (selectedCount == 0)
0471     {
0472         return SelectedNone;
0473     }
0474     else if (selectedCount == myTile->markerIndices.count())
0475     {
0476         return SelectedAll;
0477     }
0478 
0479     return SelectedSome;
0480 }
0481 
0482 AbstractMarkerTiler::Tile* ItemMarkerTiler::getTile(const TileIndex& tileIndex, const bool stopIfEmpty)
0483 {
0484     if (isDirty())
0485     {
0486         regenerateTiles();
0487     }
0488 
0489     GEOIFACE_ASSERT(tileIndex.level() <= TileIndex::MaxLevel);
0490 
0491     MyTile* tile = static_cast<MyTile*>(rootTile());
0492 
0493     for (int level = 0 ; level < tileIndex.indexCount() ; ++level)
0494     {
0495         const int currentIndex = tileIndex.linearIndex(level);
0496         MyTile* childTile      = nullptr;
0497 
0498         if (tile->childrenEmpty())
0499         {
0500             // if there are any markers in the tile,
0501             // we have to sort them into the child tiles:
0502 
0503             if (!tile->markerIndices.isEmpty())
0504             {
0505                 for (int i = 0 ; i < tile->markerIndices.count() ; ++i)
0506                 {
0507                     const QPersistentModelIndex currentMarkerIndex = tile->markerIndices.at(i);
0508                     GEOIFACE_ASSERT(currentMarkerIndex.isValid());
0509 
0510                     // get the tile index for this marker:
0511 
0512                     GeoCoordinates currentMarkerCoordinates;
0513 
0514                     if (!d->modelHelper->itemCoordinates(currentMarkerIndex, &currentMarkerCoordinates))
0515                     {
0516                         continue;
0517                     }
0518 
0519                     const TileIndex markerTileIndex = TileIndex::fromCoordinates(currentMarkerCoordinates, level);
0520                     const int newTileIndex          = markerTileIndex.toIntList().constLast();
0521 
0522                     MyTile* newTile = static_cast<MyTile*>(tile->getChild(newTileIndex));
0523 
0524                     if (newTile == nullptr)
0525                     {
0526                         newTile = static_cast<MyTile*>(tileNew());
0527                         tile->addChild(newTileIndex, newTile);
0528                     }
0529 
0530                     newTile->markerIndices<<currentMarkerIndex;
0531 
0532                     if (d->selectionModel)
0533                     {
0534                         if (d->selectionModel->isSelected(currentMarkerIndex))
0535                         {
0536                             newTile->selectedCount++;
0537                         }
0538                     }
0539                 }
0540             }
0541         }
0542 
0543         childTile = static_cast<MyTile*>(tile->getChild(currentIndex));
0544 
0545         if (childTile == nullptr)
0546         {
0547             if (stopIfEmpty)
0548             {
0549                 // there will be no markers in this tile, therefore stop
0550 
0551                 return nullptr;
0552             }
0553 
0554             childTile = static_cast<MyTile*>(tileNew());
0555             tile->addChild(currentIndex, childTile);
0556         }
0557 
0558         tile = childTile;
0559     }
0560 
0561     return tile;
0562 }
0563 
0564 QList<QPersistentModelIndex> ItemMarkerTiler::getTileMarkerIndices(const TileIndex& tileIndex)
0565 {
0566     if (isDirty())
0567     {
0568         regenerateTiles();
0569     }
0570 
0571     GEOIFACE_ASSERT(tileIndex.level() <= TileIndex::MaxLevel);
0572 
0573     MyTile* const myTile = static_cast<MyTile*>(getTile(tileIndex, true));
0574 
0575     if (!myTile)
0576     {
0577         return QList<QPersistentModelIndex>();
0578     }
0579 
0580     return myTile->markerIndices;
0581 }
0582 
0583 void ItemMarkerTiler::addMarkerIndexToGrid(const QPersistentModelIndex& markerIndex)
0584 {
0585     if (isDirty())
0586     {
0587         // the model is dirty, so let regenerateTiles do the rest
0588 
0589         regenerateTiles();
0590 
0591         return;
0592     }
0593 
0594     GeoCoordinates markerCoordinates;
0595 
0596     if (!d->modelHelper->itemCoordinates(markerIndex, &markerCoordinates))
0597     {
0598         return;
0599     }
0600 
0601     TileIndex tileIndex = TileIndex::fromCoordinates(markerCoordinates, TileIndex::MaxLevel);
0602     GEOIFACE_ASSERT(tileIndex.level() == TileIndex::MaxLevel);
0603 
0604     bool markerIsSelected = false;
0605 
0606     if (d->selectionModel)
0607     {
0608         markerIsSelected = d->selectionModel->isSelected(markerIndex);
0609     }
0610 
0611     // add the marker to all existing tiles:
0612 
0613     MyTile* currentTile = static_cast<MyTile*>(rootTile());
0614 
0615     for (int l = 0 ; l <= TileIndex::MaxLevel ; ++l)
0616     {
0617         currentTile->markerIndices<<markerIndex;
0618 
0619         if (markerIsSelected)
0620         {
0621             currentTile->selectedCount++;
0622         }
0623 
0624         // does the tile have any children?
0625 
0626         if (currentTile->childrenEmpty())
0627         {
0628             break;
0629         }
0630 
0631         // the tile has children. make sure the tile for our marker exists:
0632 
0633         const int nextIndex = tileIndex.linearIndex(l);
0634         MyTile* nextTile    = static_cast<MyTile*>(currentTile->getChild(nextIndex));
0635 
0636         if (nextTile == nullptr)
0637         {
0638             // we have to create the tile:
0639 
0640             nextTile = static_cast<MyTile*>(tileNew());
0641             currentTile->addChild(nextIndex, nextTile);
0642         }
0643 
0644         // if this is the last loop iteration, populate the next tile now:
0645 
0646         if (l == TileIndex::MaxLevel)
0647         {
0648             nextTile->markerIndices<<markerIndex;
0649 
0650             if (markerIsSelected)
0651             {
0652                 nextTile->selectedCount++;
0653             }
0654         }
0655 
0656         currentTile = nextTile;
0657     }
0658 }
0659 
0660 void ItemMarkerTiler::prepareTiles(const GeoCoordinates& /*upperLeft*/, const GeoCoordinates&, int /*level*/)
0661 {
0662 }
0663 
0664 void ItemMarkerTiler::regenerateTiles()
0665 {
0666     resetRootTile();
0667     setDirty(false);
0668 
0669     if (!d->markerModel)
0670     {
0671         return;
0672     }
0673 
0674     // read out all existing markers into tiles:
0675 
0676     for (int row = 0 ; row < d->markerModel->rowCount() ; ++row)
0677     {
0678         const QModelIndex modelIndex = d->markerModel->index(row, 0);
0679         addMarkerIndexToGrid(QPersistentModelIndex(modelIndex));
0680     }
0681 }
0682 
0683 bool ItemMarkerTiler::indicesEqual(const QVariant& a, const QVariant& b) const
0684 {
0685     return a.value<QPersistentModelIndex>()==b.value<QPersistentModelIndex>();
0686 }
0687 
0688 void ItemMarkerTiler::onIndicesClicked(const ClickInfo& clickInfo)
0689 {
0690     QList<QPersistentModelIndex> clickedMarkers;
0691 
0692     for (int i = 0 ; i < clickInfo.tileIndicesList.count() ; ++i)
0693     {
0694         const TileIndex tileIndex = clickInfo.tileIndicesList.at(i);
0695 
0696         clickedMarkers << getTileMarkerIndices(tileIndex);
0697     }
0698 
0699     const QPersistentModelIndex representativeModelIndex = clickInfo.representativeIndex.value<QPersistentModelIndex>();
0700 
0701     if ((clickInfo.currentMouseMode == MouseModeSelectThumbnail) && d->selectionModel)
0702     {
0703         const bool doSelect = (clickInfo.groupSelectionState & SelectedMask) != SelectedAll;
0704 
0705         const QItemSelectionModel::SelectionFlags selectionFlags = (doSelect ? QItemSelectionModel::Select
0706                                                                              : QItemSelectionModel::Deselect) |
0707                                                                    QItemSelectionModel::Rows;
0708 
0709         for (int i = 0 ; i < clickedMarkers.count() ; ++i)
0710         {
0711             if (d->selectionModel->isSelected(clickedMarkers.at(i)) != doSelect)
0712             {
0713                 d->selectionModel->select(clickedMarkers.at(i), selectionFlags);
0714             }
0715         }
0716 
0717         if (representativeModelIndex.isValid())
0718         {
0719             d->selectionModel->setCurrentIndex(representativeModelIndex, selectionFlags);
0720         }
0721 
0722         /**
0723          * @todo When do we report the clicks to the modelHelper?
0724          *       Or do we only report selection changes to the selection model?
0725          */
0726 /*
0727         d->modelHelper->onIndicesClicked(clickedMarkers);
0728 */
0729     }
0730     else if (clickInfo.currentMouseMode == MouseModeFilter)
0731     {
0732         /// @todo Also forward the representative index and the mouse mode in this call
0733 
0734         d->modelHelper->onIndicesClicked(clickedMarkers);
0735     }
0736 }
0737 
0738 void ItemMarkerTiler::onIndicesMoved(const TileIndex::List& tileIndicesList, const GeoCoordinates& targetCoordinates,
0739                                      const QPersistentModelIndex& targetSnapIndex)
0740 {
0741     QList<QPersistentModelIndex> movedMarkers;
0742 
0743     if (tileIndicesList.isEmpty())
0744     {
0745         // complicated case: all selected markers were moved
0746 
0747         QModelIndexList selectedIndices = d->selectionModel->selectedIndexes();
0748 
0749         for (int i = 0 ; i < selectedIndices.count() ; ++i)
0750         {
0751             // TODO: correctly handle items with multiple columns
0752 
0753             QModelIndex movedMarker = selectedIndices.at(i);
0754 
0755             if (movedMarker.column() == 0)
0756             {
0757                 movedMarkers << movedMarker;
0758             }
0759         }
0760     }
0761     else
0762     {
0763         // only the tiles in tileIndicesList were moved
0764 
0765         for (int i = 0 ; i < tileIndicesList.count() ; ++i)
0766         {
0767             const TileIndex tileIndex = tileIndicesList.at(i);
0768 
0769             movedMarkers << getTileMarkerIndices(tileIndex);
0770         }
0771     }
0772 
0773     d->modelHelper->onIndicesMoved(movedMarkers, targetCoordinates, targetSnapIndex);
0774 }
0775 
0776 void ItemMarkerTiler::slotSourceModelLayoutChanged()
0777 {
0778     setDirty();
0779 }
0780 
0781 void ItemMarkerTiler::setActive(const bool state)
0782 {
0783     d->activeState = state;
0784 }
0785 
0786 AbstractMarkerTiler::Tile* ItemMarkerTiler::tileNew()
0787 {
0788     return new MyTile();
0789 }
0790 
0791 AbstractMarkerTiler::TilerFlags ItemMarkerTiler::tilerFlags() const
0792 {
0793     TilerFlags resultFlags = FlagNull;
0794 
0795     if (d->modelHelper->modelFlags().testFlag(GeoModelHelper::FlagMovable))
0796     {
0797         resultFlags |= FlagMovable;
0798     }
0799 
0800     return resultFlags;
0801 }
0802 
0803 GeoGroupState ItemMarkerTiler::getGlobalGroupState()
0804 {
0805     if (d->selectionModel)
0806     {
0807         if (d->selectionModel->hasSelection())
0808         {
0809             return SelectedMask;
0810         }
0811     }
0812 
0813     return SelectedNone;
0814 }
0815 
0816 } // namespace Digikam
0817 
0818 #include "moc_itemmarkertiler.cpp"