File indexing completed on 2025-01-05 03:58:32
0001 /* ============================================================ 0002 * 0003 * This file is a part of digiKam project 0004 * https://www.digikam.org 0005 * 0006 * Date : 2009-05-07 0007 * Description : Context menu for GPS list view. 0008 * 0009 * SPDX-FileCopyrightText: 2010-2024 by Gilles Caulier <caulier dot gilles at gmail dot com> 0010 * SPDX-FileCopyrightText: 2009-2014 by Michael G. Hansen <mike at mghansen dot de> 0011 * 0012 * SPDX-License-Identifier: GPL-2.0-or-later 0013 * 0014 * ============================================================ */ 0015 0016 #include "gpsitemlistcontextmenu.h" 0017 0018 // Qt includes: 0019 0020 #include <QEvent> 0021 #include <QContextMenuEvent> 0022 #include <QClipboard> 0023 #include <QApplication> 0024 #include <QDomDocument> 0025 #include <QPointer> 0026 #include <QAction> 0027 #include <QMenu> 0028 #include <QMessageBox> 0029 #include <QMimeData> 0030 0031 // KDE includes 0032 0033 #include <klocalizedstring.h> 0034 0035 // Local includes 0036 0037 #include "gpsundocommand.h" 0038 #include "gpscommon.h" 0039 #include "gpsitemcontainer.h" 0040 #include "lookupfactory.h" 0041 #include "gpsbookmarkowner.h" 0042 #include "digikam_debug.h" 0043 0044 namespace Digikam 0045 { 0046 0047 class Q_DECL_HIDDEN GPSItemListContextMenu::Private 0048 { 0049 public: 0050 0051 explicit Private() 0052 : enabled (true), 0053 actionBookmark (nullptr), 0054 bookmarkOwner (nullptr), 0055 actionCopy (nullptr), 0056 actionPaste (nullptr), 0057 actionPasteSwap (nullptr), 0058 actionRemoveCoordinates (nullptr), 0059 actionRemoveAltitude (nullptr), 0060 actionRemoveUncertainty (nullptr), 0061 actionRemoveSpeed (nullptr), 0062 actionLookupMissingAltitudes(nullptr), 0063 imagesList (nullptr), 0064 altitudeLookup (), 0065 altitudeUndoCommand (nullptr), 0066 altitudeRequestedCount (0), 0067 altitudeReceivedCount (0) 0068 { 0069 } 0070 0071 bool enabled; 0072 0073 QAction* actionBookmark; 0074 GPSBookmarkOwner* bookmarkOwner; 0075 0076 QAction* actionCopy; 0077 QAction* actionPaste; 0078 QAction* actionPasteSwap; 0079 QAction* actionRemoveCoordinates; 0080 QAction* actionRemoveAltitude; 0081 QAction* actionRemoveUncertainty; 0082 QAction* actionRemoveSpeed; 0083 QAction* actionLookupMissingAltitudes; 0084 0085 GPSItemList* imagesList; 0086 0087 /// Altitude lookup 0088 QPointer<LookupAltitude> altitudeLookup; 0089 GPSUndoCommand* altitudeUndoCommand; 0090 int altitudeRequestedCount; 0091 int altitudeReceivedCount; 0092 }; 0093 0094 GPSItemListContextMenu::GPSItemListContextMenu(GPSItemList* const imagesList, 0095 GPSBookmarkOwner* const bookmarkOwner) 0096 : QObject(imagesList), 0097 d(new Private) 0098 { 0099 d->imagesList = imagesList; 0100 0101 d->actionCopy = new QAction(i18n("Copy coordinates"), this); 0102 d->actionCopy->setIcon(QIcon::fromTheme(QLatin1String("edit-copy"))); 0103 d->actionPaste = new QAction(i18n("Paste coordinates"), this); 0104 d->actionPaste->setIcon(QIcon::fromTheme(QLatin1String("edit-paste"))); 0105 d->actionPasteSwap = new QAction(i18n("Paste coordinates swapped"), this); 0106 d->actionPasteSwap->setIcon(QIcon::fromTheme(QLatin1String("edit-paste"))); 0107 d->actionRemoveCoordinates = new QAction(i18n("Remove coordinates"), this); 0108 d->actionRemoveAltitude = new QAction(i18n("Remove altitude"), this); 0109 d->actionRemoveUncertainty = new QAction(i18n("Remove uncertainty"), this); 0110 d->actionRemoveSpeed = new QAction(i18n("Remove speed"), this); 0111 d->actionLookupMissingAltitudes = new QAction(i18n("Look up missing altitude values"), this); 0112 0113 connect(d->actionCopy, SIGNAL(triggered()), 0114 this, SLOT(copyActionTriggered())); 0115 0116 connect(d->actionPaste, SIGNAL(triggered()), 0117 this, SLOT(pasteActionTriggered())); 0118 0119 connect(d->actionPasteSwap, SIGNAL(triggered()), 0120 this, SLOT(pasteSwapActionTriggered())); 0121 0122 connect(d->actionRemoveCoordinates, SIGNAL(triggered()), 0123 this, SLOT(slotRemoveCoordinates())); 0124 0125 connect(d->actionRemoveAltitude, SIGNAL(triggered()), 0126 this, SLOT(slotRemoveAltitude())); 0127 0128 connect(d->actionRemoveUncertainty, SIGNAL(triggered()), 0129 this, SLOT(slotRemoveUncertainty())); 0130 0131 connect(d->actionRemoveSpeed, SIGNAL(triggered()), 0132 this, SLOT(slotRemoveSpeed())); 0133 0134 connect(d->actionLookupMissingAltitudes, SIGNAL(triggered()), 0135 this, SLOT(slotLookupMissingAltitudes())); 0136 0137 if (bookmarkOwner) 0138 { 0139 d->bookmarkOwner = bookmarkOwner; 0140 d->actionBookmark = new QAction(i18n("Bookmarks"), this); 0141 d->actionBookmark->setMenu(d->bookmarkOwner->getMenu()); 0142 0143 connect(d->bookmarkOwner, SIGNAL(positionSelected(GPSDataContainer)), 0144 this, SLOT(slotBookmarkSelected(GPSDataContainer))); 0145 } 0146 0147 d->imagesList->installEventFilter(this); 0148 } 0149 0150 GPSItemListContextMenu::~GPSItemListContextMenu() 0151 { 0152 delete d->altitudeUndoCommand; 0153 delete d; 0154 } 0155 0156 bool GPSItemListContextMenu::eventFilter(QObject* watched, QEvent* event) 0157 { 0158 // We are only interested in context-menu events. 0159 0160 if ((event->type() == QEvent::ContextMenu) && d->enabled) 0161 { 0162 // enable or disable the actions 0163 0164 GPSItemModel* const imageModel = d->imagesList->getModel(); 0165 QItemSelectionModel* const selectionModel = d->imagesList->getSelectionModel(); 0166 const QList<QModelIndex> selectedIndices = selectionModel->selectedRows(); 0167 const int nSelected = selectedIndices.size(); 0168 0169 // "copy" are only available for one selected image with geo data: 0170 0171 bool copyAvailable = (nSelected == 1); 0172 bool removeAltitudeAvailable = false; 0173 bool removeCoordinatesAvailable = false; 0174 bool removeUncertaintyAvailable = false; 0175 bool removeSpeedAvailable = false; 0176 bool lookupMissingAltitudesAvailable = false; 0177 0178 for (int i = 0 ; i < nSelected ; ++i) 0179 { 0180 GPSItemContainer* const gpsItem = imageModel->itemFromIndex(selectedIndices.at(i)); 0181 0182 if (gpsItem) 0183 { 0184 const GPSDataContainer gpsData = gpsItem->gpsData(); 0185 const bool itemHasCoordinates = gpsData.getCoordinates().hasCoordinates(); 0186 copyAvailable &= itemHasCoordinates; 0187 removeCoordinatesAvailable |= itemHasCoordinates; 0188 removeAltitudeAvailable |= gpsData.getCoordinates().hasAltitude(); 0189 removeUncertaintyAvailable |= gpsData.hasNSatellites() | gpsData.hasDop() | gpsData.hasFixType(); 0190 removeSpeedAvailable |= gpsData.hasSpeed(); 0191 lookupMissingAltitudesAvailable |= itemHasCoordinates && !gpsData.getCoordinates().hasAltitude(); 0192 } 0193 } 0194 0195 d->actionCopy->setEnabled(copyAvailable); 0196 d->actionRemoveAltitude->setEnabled(removeAltitudeAvailable); 0197 d->actionRemoveCoordinates->setEnabled(removeCoordinatesAvailable); 0198 d->actionRemoveUncertainty->setEnabled(removeUncertaintyAvailable); 0199 d->actionRemoveSpeed->setEnabled(removeSpeedAvailable); 0200 d->actionLookupMissingAltitudes->setEnabled(lookupMissingAltitudesAvailable); 0201 0202 if (d->bookmarkOwner) 0203 { 0204 d->bookmarkOwner->changeAddBookmark(copyAvailable); 0205 GPSDataContainer position; 0206 QUrl itemUrl; 0207 getCurrentItemPositionAndUrl(&position, &itemUrl); 0208 const QString itemFileName = itemUrl.fileName(); 0209 d->bookmarkOwner->setPositionAndTitle(position.getCoordinates(), itemFileName); 0210 } 0211 0212 // "paste" is only available if there is geo data in the clipboard 0213 // and at least one photo is selected: 0214 0215 bool pasteAvailable = (nSelected >= 1); 0216 bool pasteSwapAvailable = true; 0217 0218 if (pasteAvailable) 0219 { 0220 QClipboard* const clipboard = QApplication::clipboard(); 0221 const QMimeData* mimedata = clipboard->mimeData(); 0222 bool hasXmlFormat = mimedata->hasFormat(QLatin1String("application/gpx+xml")); 0223 pasteAvailable = hasXmlFormat || mimedata->hasText(); 0224 pasteSwapAvailable = !hasXmlFormat && mimedata->hasText(); 0225 } 0226 0227 d->actionPaste->setEnabled(pasteAvailable); 0228 d->actionPasteSwap->setEnabled(pasteSwapAvailable); 0229 0230 // construct the context-menu: 0231 0232 QMenu* const menu = new QMenu(d->imagesList); 0233 menu->addAction(d->actionCopy); 0234 menu->addAction(d->actionPaste); 0235 menu->addAction(d->actionPasteSwap); 0236 menu->addSeparator(); 0237 menu->addAction(d->actionRemoveCoordinates); 0238 menu->addAction(d->actionRemoveAltitude); 0239 menu->addAction(d->actionRemoveUncertainty); 0240 menu->addAction(d->actionRemoveSpeed); 0241 menu->addAction(d->actionLookupMissingAltitudes); 0242 0243 if (d->actionBookmark) 0244 { 0245 menu->addSeparator(); 0246 menu->addAction(d->actionBookmark); 0247 d->actionBookmark->setEnabled(nSelected >= 1); 0248 } 0249 0250 QContextMenuEvent* const e = static_cast<QContextMenuEvent*>(event); 0251 menu->exec(e->globalPos()); 0252 0253 delete menu; 0254 0255 return true; 0256 } 0257 else 0258 { 0259 return QObject::eventFilter(watched, event); 0260 } 0261 0262 } 0263 0264 bool GPSItemListContextMenu::getCurrentItemPositionAndUrl(GPSDataContainer* const gpsInfo, 0265 QUrl* const itemUrl) 0266 { 0267 // NOTE: currentIndex does not seem to work any more since we use KLinkItemSelectionModel 0268 0269 GPSItemModel* const imageModel = d->imagesList->getModel(); 0270 QItemSelectionModel* const selectionModel = d->imagesList->getSelectionModel(); 0271 const QList<QModelIndex> selectedIndices = selectionModel->selectedRows(); 0272 0273 if (selectedIndices.count() != 1) 0274 { 0275 return false; 0276 } 0277 0278 const QModelIndex currentIndex = selectedIndices.first(); 0279 0280 if (!currentIndex.isValid()) 0281 { 0282 return false; 0283 } 0284 0285 GPSItemContainer* const gpsItem = imageModel->itemFromIndex(currentIndex); 0286 0287 if (gpsItem) 0288 { 0289 if (gpsInfo) 0290 { 0291 *gpsInfo = gpsItem->gpsData(); 0292 } 0293 0294 if (itemUrl) 0295 { 0296 *itemUrl = gpsItem->url(); 0297 } 0298 0299 return true; 0300 } 0301 0302 return false; 0303 } 0304 0305 void GPSItemListContextMenu::copyActionTriggered() 0306 { 0307 GPSDataContainer gpsInfo; 0308 QUrl itemUrl; 0309 0310 if (!getCurrentItemPositionAndUrl(&gpsInfo, &itemUrl)) 0311 { 0312 return; 0313 } 0314 0315 coordinatesToClipboard(gpsInfo.getCoordinates(), itemUrl, QString()); 0316 } 0317 0318 void GPSItemListContextMenu::pasteSwapActionTriggered() 0319 { 0320 pasteActionTriggered(true); 0321 } 0322 0323 void GPSItemListContextMenu::pasteActionTriggered(bool swap) 0324 { 0325 // extract the coordinates from the clipboard: 0326 0327 QClipboard* const clipboard = QApplication::clipboard(); 0328 const QMimeData* mimedata = clipboard->mimeData(); 0329 0330 GPSDataContainer gpsData; 0331 bool foundData = false; 0332 0333 if (mimedata->hasFormat(QLatin1String("application/gpx+xml"))) 0334 { 0335 const QByteArray data = mimedata->data(QLatin1String("application/gpx+xml")); 0336 bool xmlOkay = true; 0337 bool foundDoubleData = false; 0338 0339 // code adapted from gpsdataparser.cpp 0340 0341 QDomDocument gpxDoc(QLatin1String("gpx")); 0342 0343 if (!gpxDoc.setContent(data)) 0344 { 0345 xmlOkay = false; 0346 } 0347 0348 if (xmlOkay) 0349 { 0350 const QDomElement gpxDocElem = gpxDoc.documentElement(); 0351 0352 if (gpxDocElem.tagName() != QLatin1String("gpx")) 0353 { 0354 xmlOkay = false; 0355 } 0356 0357 if (xmlOkay) 0358 { 0359 for (QDomNode nWpt = gpxDocElem.firstChild() ; !nWpt.isNull() ; nWpt = nWpt.nextSibling()) 0360 { 0361 const QDomElement wptElem = nWpt.toElement(); 0362 0363 if (wptElem.isNull()) 0364 { 0365 continue; 0366 } 0367 0368 if (wptElem.tagName() != QLatin1String("wpt")) 0369 { 0370 continue; 0371 } 0372 0373 double ptAltitude = 0.0; 0374 double ptLatitude = 0.0; 0375 double ptLongitude = 0.0; 0376 bool haveAltitude = false; 0377 0378 // Get GPS position. If not available continue to next point. 0379 0380 const QString lat = wptElem.attribute(QLatin1String("lat")); 0381 const QString lon = wptElem.attribute(QLatin1String("lon")); 0382 0383 if (lat.isEmpty() || lon.isEmpty()) 0384 { 0385 continue; 0386 } 0387 0388 ptLatitude = lat.toDouble(); 0389 ptLongitude = lon.toDouble(); 0390 0391 if (foundData) 0392 { 0393 foundDoubleData = true; 0394 break; 0395 } 0396 0397 // Get metadata of way point (altitude and time stamp) 0398 0399 for (QDomNode nWptMeta = wptElem.firstChild() ; !nWptMeta.isNull() ; nWptMeta = nWptMeta.nextSibling()) 0400 { 0401 const QDomElement wptMetaElem = nWptMeta.toElement(); 0402 0403 if (wptMetaElem.isNull()) 0404 { 0405 continue; 0406 } 0407 0408 if (wptMetaElem.tagName() == QLatin1String("ele")) 0409 { 0410 // Get GPS point altitude. If not available continue to next point. 0411 0412 QString ele = wptMetaElem.text(); 0413 0414 if (!ele.isEmpty()) 0415 { 0416 ptAltitude = ele.toDouble(&haveAltitude); 0417 break; 0418 } 0419 } 0420 } 0421 0422 foundData = true; 0423 GeoCoordinates coordinates(ptLatitude, ptLongitude); 0424 0425 if (haveAltitude) 0426 { 0427 coordinates.setAlt(ptAltitude); 0428 } 0429 0430 gpsData.setCoordinates(coordinates); 0431 } 0432 } 0433 } 0434 0435 if (foundDoubleData) 0436 { 0437 QMessageBox::information(d->imagesList, 0438 i18nc("@title:window", "Geolocation Editor"), 0439 i18n("Found more than one point on the clipboard - can only assign one point at a time.")); 0440 } 0441 } 0442 0443 if (!foundData && mimedata->hasText()) 0444 { 0445 const QString textdata = mimedata->text(); 0446 bool foundGeoUrl = false; 0447 GeoCoordinates testCoordinates = GeoCoordinates::fromGeoUrl(textdata, &foundGeoUrl); 0448 0449 if (foundGeoUrl) 0450 { 0451 gpsData.setCoordinates(testCoordinates); 0452 foundData = true; 0453 } 0454 else 0455 { 0456 /// @todo this is legacy code from before we used geo-url 0457 0458 QLocale locale; 0459 QString cordText = textdata.trimmed(); 0460 QStringList separators({QLatin1String(","), 0461 QLatin1String("/"), 0462 QLatin1String(":"), 0463 QLatin1String(";"), 0464 QLatin1String(" ")}); 0465 int firstPoint = cordText.indexOf(QLatin1Char('.')); 0466 0467 if ((firstPoint == -1) || (firstPoint > 4)) 0468 { 0469 locale = QLocale(QLocale::French); 0470 0471 if (cordText.count(QLatin1Char(',')) > 1) 0472 { 0473 separators.removeOne(QLatin1String(",")); 0474 } 0475 } 0476 else 0477 { 0478 locale = QLocale(QLocale::C); 0479 } 0480 0481 QStringList parts; 0482 bool foundParts = false; 0483 0484 while (!separators.isEmpty()) 0485 { 0486 parts = cordText.split(separators.takeFirst(), QT_SKIP_EMPTY_PARTS); 0487 0488 if ((parts.size() == 3) || (parts.size() == 2)) 0489 { 0490 foundParts = true; 0491 break; 0492 } 0493 } 0494 0495 if (foundParts) 0496 { 0497 double ptLongitude = 0.0; 0498 double ptAltitude = 0.0; 0499 bool haveAltitude = false; 0500 bool okay = true; 0501 double ptLatitude = locale.toDouble(parts[0], &okay); 0502 0503 if (okay) 0504 { 0505 ptLongitude = locale.toDouble(parts[1], &okay); 0506 } 0507 0508 if (okay && (parts.size() == 3)) 0509 { 0510 ptAltitude = locale.toDouble(parts[2], &okay); 0511 haveAltitude = okay; 0512 } 0513 0514 foundData = okay; 0515 0516 if (okay) 0517 { 0518 if (swap) 0519 { 0520 std::swap(ptLatitude, ptLongitude); 0521 } 0522 0523 GeoCoordinates coordinates(ptLatitude, ptLongitude); 0524 0525 if (haveAltitude) 0526 { 0527 coordinates.setAlt(ptAltitude); 0528 } 0529 0530 gpsData.setCoordinates(coordinates); 0531 } 0532 } 0533 } 0534 } 0535 0536 if (!foundData) 0537 { 0538 QMessageBox::information(d->imagesList, 0539 i18nc("@title:window", "Geolocation Editor"), 0540 i18n("Could not find any coordinates on the clipboard.")); 0541 return; 0542 } 0543 0544 setGPSDataForSelectedItems(gpsData, i18n("Coordinates pasted")); 0545 } 0546 0547 void GPSItemListContextMenu::setGPSDataForSelectedItems(const GPSDataContainer& gpsData, 0548 const QString& undoDescription) 0549 { 0550 GPSItemModel* const imageModel = d->imagesList->getModel(); 0551 QItemSelectionModel* const selectionModel = d->imagesList->getSelectionModel(); 0552 const QList<QModelIndex> selectedIndices = selectionModel->selectedRows(); 0553 const int nSelected = selectedIndices.size(); 0554 GPSUndoCommand* const undoCommand = new GPSUndoCommand(); 0555 0556 for (int i = 0 ; i < nSelected ; ++i) 0557 { 0558 const QModelIndex itemIndex = selectedIndices.at(i); 0559 GPSItemContainer* const gpsItem = imageModel->itemFromIndex(itemIndex); 0560 0561 GPSUndoCommand::UndoInfo undoInfo(itemIndex); 0562 undoInfo.readOldDataFromItem(gpsItem); 0563 0564 gpsItem->setGPSData(gpsData); 0565 undoInfo.readNewDataFromItem(gpsItem); 0566 0567 undoCommand->addUndoInfo(undoInfo); 0568 } 0569 0570 undoCommand->setText(undoDescription); 0571 Q_EMIT signalUndoCommand(undoCommand); 0572 } 0573 0574 void GPSItemListContextMenu::slotBookmarkSelected(const GPSDataContainer& position) 0575 { 0576 setGPSDataForSelectedItems(position, i18n("Bookmark selected")); 0577 } 0578 0579 bool GPSItemListContextMenu::getCurrentPosition(GPSDataContainer* position, void* mydata) 0580 { 0581 if (!position || !mydata) 0582 { 0583 return false; 0584 } 0585 0586 GPSItemListContextMenu* const me = reinterpret_cast<GPSItemListContextMenu*>(mydata); 0587 0588 return me->getCurrentItemPositionAndUrl(position, nullptr); 0589 } 0590 0591 void GPSItemListContextMenu::removeInformationFromSelectedImages(const GPSDataContainer::HasFlags flagsToClear, const QString& undoDescription) 0592 { 0593 // enable or disable the actions 0594 0595 GPSItemModel* const imageModel = d->imagesList->getModel(); 0596 QItemSelectionModel* const selectionModel = d->imagesList->getSelectionModel(); 0597 const QList<QModelIndex> selectedIndices = selectionModel->selectedRows(); 0598 const int nSelected = selectedIndices.size(); 0599 GPSUndoCommand* const undoCommand = new GPSUndoCommand(); 0600 0601 for (int i = 0 ; i < nSelected ; ++i) 0602 { 0603 const QModelIndex itemIndex = selectedIndices.at(i); 0604 GPSItemContainer* const gpsItem = imageModel->itemFromIndex(itemIndex); 0605 0606 GPSUndoCommand::UndoInfo undoInfo(itemIndex); 0607 undoInfo.readOldDataFromItem(gpsItem); 0608 0609 GPSDataContainer newGPSData = gpsItem->gpsData(); 0610 bool didSomething = false; 0611 0612 if (flagsToClear.testFlag(GPSDataContainer::HasCoordinates)) 0613 { 0614 if (newGPSData.hasCoordinates()) 0615 { 0616 didSomething = true; 0617 newGPSData.clear(); 0618 } 0619 } 0620 0621 if (flagsToClear.testFlag(GPSDataContainer::HasAltitude)) 0622 { 0623 if (newGPSData.hasAltitude()) 0624 { 0625 didSomething = true; 0626 newGPSData.clearAltitude(); 0627 } 0628 } 0629 0630 if (flagsToClear.testFlag(GPSDataContainer::HasNSatellites)) 0631 { 0632 if (newGPSData.hasNSatellites()) 0633 { 0634 didSomething = true; 0635 newGPSData.clearNSatellites(); 0636 } 0637 } 0638 0639 if (flagsToClear.testFlag(GPSDataContainer::HasDop)) 0640 { 0641 if (newGPSData.hasDop()) 0642 { 0643 didSomething = true; 0644 newGPSData.clearDop(); 0645 } 0646 } 0647 0648 if (flagsToClear.testFlag(GPSDataContainer::HasFixType)) 0649 { 0650 if (newGPSData.hasFixType()) 0651 { 0652 didSomething = true; 0653 newGPSData.clearFixType(); 0654 } 0655 } 0656 0657 if (flagsToClear.testFlag(GPSDataContainer::HasSpeed)) 0658 { 0659 if (newGPSData.hasSpeed()) 0660 { 0661 didSomething = true; 0662 newGPSData.clearSpeed(); 0663 } 0664 } 0665 0666 if (didSomething) 0667 { 0668 gpsItem->setGPSData(newGPSData); 0669 undoInfo.readNewDataFromItem(gpsItem); 0670 undoCommand->addUndoInfo(undoInfo); 0671 } 0672 } 0673 0674 if (undoCommand->affectedItemCount() > 0) 0675 { 0676 undoCommand->setText(undoDescription); 0677 Q_EMIT signalUndoCommand(undoCommand); 0678 } 0679 else 0680 { 0681 delete undoCommand; 0682 } 0683 } 0684 0685 void GPSItemListContextMenu::slotRemoveCoordinates() 0686 { 0687 removeInformationFromSelectedImages(GPSDataContainer::HasCoordinates, i18n("Remove coordinates information")); 0688 } 0689 0690 void GPSItemListContextMenu::slotRemoveAltitude() 0691 { 0692 removeInformationFromSelectedImages(GPSDataContainer::HasAltitude, i18n("Remove altitude information")); 0693 } 0694 0695 void GPSItemListContextMenu::slotRemoveUncertainty() 0696 { 0697 removeInformationFromSelectedImages(GPSDataContainer::HasNSatellites|GPSDataContainer::HasDop|GPSDataContainer::HasFixType, 0698 i18n("Remove uncertainty information")); 0699 } 0700 0701 void GPSItemListContextMenu::setEnabled(const bool state) 0702 { 0703 d->enabled = state; 0704 } 0705 0706 void GPSItemListContextMenu::slotRemoveSpeed() 0707 { 0708 removeInformationFromSelectedImages(GPSDataContainer::HasSpeed, i18n("Remove speed")); 0709 } 0710 0711 void GPSItemListContextMenu::slotLookupMissingAltitudes() 0712 { 0713 GPSItemModel* const imageModel = d->imagesList->getModel(); 0714 QItemSelectionModel* const selectionModel = d->imagesList->getSelectionModel(); 0715 const QList<QModelIndex> selectedIndices = selectionModel->selectedRows(); 0716 /* 0717 const int nSelected = selectedIndices.size(); 0718 */ 0719 // find the indices which have coordinates but no altitude 0720 0721 LookupAltitude::Request::List altitudeQueries; 0722 0723 Q_FOREACH (const QModelIndex& currentIndex, selectedIndices) 0724 { 0725 GPSItemContainer* const gpsItem = imageModel->itemFromIndex(currentIndex); 0726 0727 if (!gpsItem) 0728 { 0729 continue; 0730 } 0731 0732 const GPSDataContainer gpsData = gpsItem->gpsData(); 0733 const GeoCoordinates coordinates = gpsData.getCoordinates(); 0734 0735 if ((!coordinates.hasCoordinates()) || coordinates.hasAltitude()) 0736 { 0737 continue; 0738 } 0739 0740 // the item has coordinates but no altitude, create a query 0741 0742 LookupAltitude::Request myLookup; 0743 myLookup.coordinates = coordinates; 0744 myLookup.data = QVariant::fromValue(QPersistentModelIndex(currentIndex)); 0745 0746 altitudeQueries << myLookup; 0747 } 0748 0749 if (altitudeQueries.isEmpty()) 0750 { 0751 return; 0752 } 0753 0754 d->altitudeLookup = LookupFactory::getAltitudeLookup(QLatin1String("geonames"), this); 0755 0756 connect(d->altitudeLookup, SIGNAL(signalRequestsReady(QList<int>)), 0757 this, SLOT(slotAltitudeLookupReady(QList<int>))); 0758 0759 connect(d->altitudeLookup, SIGNAL(signalDone()), 0760 this, SLOT(slotAltitudeLookupDone())); 0761 0762 Q_EMIT signalSetUIEnabled(false, this, QString::fromUtf8(SLOT(slotAltitudeLookupCancel()))); 0763 Q_EMIT signalProgressSetup(altitudeQueries.count(), i18n("Looking up altitudes")); 0764 0765 d->altitudeUndoCommand = new GPSUndoCommand(); 0766 d->altitudeRequestedCount = altitudeQueries.count(); 0767 d->altitudeReceivedCount = 0; 0768 d->altitudeLookup->addRequests(altitudeQueries); 0769 d->altitudeLookup->startLookup(); 0770 } 0771 0772 void GPSItemListContextMenu::slotAltitudeLookupReady(const QList<int>& readyRequests) 0773 { 0774 GPSItemModel* const imageModel = d->imagesList->getModel(); 0775 0776 Q_FOREACH (const int requestIndex, readyRequests) 0777 { 0778 const LookupAltitude::Request myLookup = d->altitudeLookup->getRequest(requestIndex); 0779 const QPersistentModelIndex markerIndex = myLookup.data.value<QPersistentModelIndex>(); 0780 0781 if (!markerIndex.isValid()) 0782 { 0783 continue; 0784 } 0785 0786 GPSItemContainer* const gpsItem = imageModel->itemFromIndex(markerIndex); 0787 0788 if (!gpsItem) 0789 { 0790 continue; 0791 } 0792 0793 GPSUndoCommand::UndoInfo undoInfo(markerIndex); 0794 undoInfo.readOldDataFromItem(gpsItem); 0795 0796 GPSDataContainer gpsData = gpsItem->gpsData(); 0797 gpsData.setCoordinates(myLookup.coordinates); 0798 gpsItem->setGPSData(gpsData); 0799 undoInfo.readNewDataFromItem(gpsItem); 0800 0801 d->altitudeUndoCommand->addUndoInfo(undoInfo); 0802 d->altitudeReceivedCount++; 0803 } 0804 0805 Q_EMIT signalProgressChanged(d->altitudeReceivedCount); 0806 } 0807 0808 void GPSItemListContextMenu::slotAltitudeLookupDone() 0809 { 0810 LookupAltitude::StatusAltitude requestStatus = d->altitudeLookup->getStatus(); 0811 0812 if (requestStatus == LookupAltitude::StatusError) 0813 { 0814 const QString errorMessage = i18n("Altitude lookup failed:\n%1", d->altitudeLookup->errorMessage()); 0815 QMessageBox::information(d->imagesList, i18nc("@title:window", "Geolocation Editor"), errorMessage); 0816 } 0817 0818 if (d->altitudeReceivedCount > 0) 0819 { 0820 // at least some queries returned a result, save the undo command 0821 0822 d->altitudeUndoCommand->setText(i18n("Altitude looked up")); 0823 Q_EMIT signalUndoCommand(d->altitudeUndoCommand); 0824 } 0825 else 0826 { 0827 delete d->altitudeUndoCommand; 0828 } 0829 0830 d->altitudeUndoCommand = nullptr; 0831 d->altitudeLookup->deleteLater(); 0832 0833 Q_EMIT signalSetUIEnabled(true); 0834 } 0835 0836 void GPSItemListContextMenu::slotAltitudeLookupCancel() 0837 { 0838 if (d->altitudeLookup) 0839 { 0840 d->altitudeLookup->cancel(); 0841 } 0842 } 0843 0844 } // namespace Digikam 0845 0846 #include "moc_gpsitemlistcontextmenu.cpp"