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, ¤tMarkerCoordinates)) 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"