1 /* ============================================================
2  *
3  * This file is a part of digiKam project
4  * https://www.digikam.org
5  *
6  * Date        : 2008-05-30
7  * Description : GPS search sidebar tab contents.
8  *
9  * Copyright (C) 2008-2021 by Gilles Caulier <caulier dot gilles at gmail dot com>
10  * Copyright (C)      2009 by Johannes Wienke <languitar at semipol dot de>
11  * Copyright (C) 2010-2011 by Michael G. Hansen <mike at mghansen dot de>
12  * Copyright (C)      2014 by Mohamed_Anwer <m_dot_anwer at gmx dot com>
13  *
14  * This program is free software; you can redistribute it
15  * and/or modify it under the terms of the GNU General
16  * Public License as published by the Free Software Foundation;
17  * either version 2, or (at your option)
18  * any later version.
19  *
20  * This program is distributed in the hope that it will be useful,
21  * but WITHOUT ANY WARRANTY; without even the implied warranty of
22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
23  * GNU General Public License for more details.
24  *
25  * ============================================================ */
26 
27 #include "gpssearchview.h"
28 
29 // Qt includes
30 
31 #include <QLabel>
32 #include <QLayout>
33 #include <QPushButton>
34 #include <QSplitter>
35 #include <QToolButton>
36 #include <QTimer>
37 #include <QMenu>
38 #include <QActionGroup>
39 #include <QAction>
40 #include <QApplication>
41 #include <QStyle>
42 #include <QLineEdit>
43 #include <QInputDialog>
44 #include <QIcon>
45 
46 // KDE includes
47 
48 #include <klocalizedstring.h>
49 #include <kconfiggroup.h>
50 
51 // Local includes
52 
53 #include "digikam_debug.h"
54 #include "searchtreeview.h"
55 #include "editablesearchtreeview.h"
56 #include "iteminfojob.h"
57 #include "coredbsearchxml.h"
58 #include "gpsmarkertiler.h"
59 #include "gpsiteminfosorter.h"
60 #include "searchtextbardb.h"
61 
62 namespace Digikam
63 {
64 
65 class Q_DECL_HIDDEN GPSSearchView::Private
66 {
67 
68 public:
69 
Private()70     explicit Private()
71       : saveBtn                 (nullptr),
72         nameEdit                (nullptr),
73         imageInfoJob            (),
74         searchGPSBar            (nullptr),
75         searchTreeView          (nullptr),
76         splitter                (nullptr),
77         mapSearchWidget         (nullptr),
78         gpsMarkerTiler          (nullptr),
79         imageAlbumModel         (nullptr),
80         imageFilterModel        (nullptr),
81         selectionModel          (nullptr),
82         searchModel             (nullptr),
83         sortOrderOptionsHelper  (nullptr)
84     {
85     }
86 
87     static const QString    configSplitterStateEntry;
88     QToolButton*            saveBtn;
89     QLineEdit*              nameEdit;
90     ItemInfoJob             imageInfoJob;
91     SearchTextBarDb*        searchGPSBar;
92     EditableSearchTreeView* searchTreeView;
93     QSplitter*              splitter;
94     MapWidget*              mapSearchWidget;
95     GPSMarkerTiler*         gpsMarkerTiler;
96     ItemAlbumModel*         imageAlbumModel;
97     ItemFilterModel*        imageFilterModel;
98     QItemSelectionModel*    selectionModel;
99     SearchModel*            searchModel;
100     GPSItemInfoSorter*      sortOrderOptionsHelper;
101     QString                 nonGeonlocatedItemsXml;
102 };
103 
104 const QString GPSSearchView::Private::configSplitterStateEntry(QLatin1String("SplitterState"));
105 
106 /**
107  * @brief Constructor
108  * @param parent the parent object.
109  * @param searchModel The model that stores the searches.
110  * @param imageFilterModel The image model used by displaying the selected images on map.
111  * @param itemSelectionModel The selection model corresponding to the imageFilterModel.
112  */
GPSSearchView(QWidget * const parent,SearchModel * const searchModel,SearchModificationHelper * const searchModificationHelper,ItemFilterModel * const imageFilterModel,QItemSelectionModel * const itemSelectionModel)113 GPSSearchView::GPSSearchView(QWidget* const parent,
114                              SearchModel* const searchModel,
115                              SearchModificationHelper* const searchModificationHelper,
116                              ItemFilterModel* const imageFilterModel,
117                              QItemSelectionModel* const itemSelectionModel)
118     : QWidget          (parent),
119       StateSavingObject(this),
120       d                (new Private)
121 {
122     setAttribute(Qt::WA_DeleteOnClose);
123 
124     /// @todo Really?
125 
126     setAcceptDrops(true);
127 
128     d->imageAlbumModel        = qobject_cast<ItemAlbumModel*>(imageFilterModel->sourceModel());
129     d->selectionModel         = itemSelectionModel;
130     d->imageFilterModel       = imageFilterModel;
131     d->searchModel            = searchModel;
132 
133     // ---------------------------------------------------------------
134 
135     QVBoxLayout* const vlay   = new QVBoxLayout(this);
136 
137     QFrame* const mapPanel    = new QFrame(this);
138     mapPanel->setMinimumWidth(256);
139     mapPanel->setMinimumHeight(256);
140     QVBoxLayout* const vlay2  = new QVBoxLayout(mapPanel);
141     d->mapSearchWidget        = new MapWidget(mapPanel);
142     d->mapSearchWidget->setBackend(QLatin1String("marble"));
143     d->mapSearchWidget->setShowThumbnails(true);
144 
145     d->gpsMarkerTiler         = new GPSMarkerTiler(this, d->imageFilterModel, d->selectionModel);
146     d->mapSearchWidget->setGroupedModel(d->gpsMarkerTiler);
147 
148     mapPanel->setFrameStyle(QFrame::StyledPanel | QFrame::Sunken);
149     mapPanel->setLineWidth(style()->pixelMetric(QStyle::PM_DefaultFrameWidth));
150 
151     d->sortOrderOptionsHelper = new GPSItemInfoSorter(this);
152     d->sortOrderOptionsHelper->addToMapWidget(d->mapSearchWidget);
153 
154     vlay2->addWidget(d->mapSearchWidget);
155     vlay2->setContentsMargins(QMargins());
156     vlay2->setSpacing(0);
157 
158     // ---------------------------------------------------------------
159 
160     DHBox* const hbox = new DHBox(this);
161     hbox->setContentsMargins(QMargins());
162     hbox->setSpacing(QApplication::style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing));
163 
164     d->nameEdit       = new QLineEdit(hbox);
165     d->nameEdit->setClearButtonEnabled(true);
166     d->nameEdit->setWhatsThis(i18n("Enter the name of the current map search to save in the "
167                                    "\"Map Searches\" view."));
168 
169     d->saveBtn        = new QToolButton(hbox);
170     d->saveBtn->setIcon(QIcon::fromTheme(QLatin1String("document-save")));
171     d->saveBtn->setEnabled(false);
172     d->saveBtn->setToolTip(i18n("Save current map search to a new virtual album."));
173     d->saveBtn->setWhatsThis(i18n("If this button is pressed, the current map search "
174                                   "will be saved to a new search "
175                                   "virtual album using the name "
176                                   "set on the left side."));
177 
178     // ---------------------------------------------------------------
179 
180     d->searchTreeView = new EditableSearchTreeView(this, d->searchModel, searchModificationHelper);
181     d->searchTreeView->filteredModel()->setFilterSearchType(DatabaseSearch::MapSearch);
182     d->searchTreeView->filteredModel()->setListTemporarySearches(true);
183     d->searchTreeView->setAlbumManagerCurrentAlbum(true);
184     d->searchGPSBar   = new SearchTextBarDb(this, QLatin1String("GPSSearchViewSearchGPSBar"));
185     d->searchGPSBar->setModel(d->searchTreeView->filteredModel(), AbstractAlbumModel::AlbumIdRole, AbstractAlbumModel::AlbumTitleRole);
186     d->searchGPSBar->setFilterModel(d->searchTreeView->albumFilterModel());
187 
188     // ---------------------------------------------------------------
189 
190     d->splitter                = new QSplitter(Qt::Vertical, this);
191 
192     QFrame* const frameTop     = new QFrame(d->splitter);
193     QVBoxLayout* const vlayTop = new QVBoxLayout(frameTop);
194     vlayTop->addWidget(mapPanel);
195     vlayTop->addWidget(d->mapSearchWidget->getControlWidget());
196 
197     d->mapSearchWidget->setAvailableMouseModes(MouseModePan                     |
198                                                MouseModeRegionSelection         |
199                                                MouseModeZoomIntoGroup           |
200                                                MouseModeRegionSelectionFromIcon |
201                                                MouseModeFilter                  |
202                                                MouseModeSelectThumbnail);
203 
204     d->mapSearchWidget->setVisibleMouseModes(MouseModePan           |
205                                              MouseModeZoomIntoGroup |
206                                              MouseModeFilter        |
207                                              MouseModeSelectThumbnail);
208 
209     /**
210      * construct a second row of control actions below the control widget
211      * @todo Should we still replace the icons of the actions with text as discussed during the sprint?
212      */
213     QWidget* const secondActionRow            = new QWidget();
214     QHBoxLayout* const secondActionRowHBox    = new QHBoxLayout();
215     secondActionRowHBox->setContentsMargins(QMargins());
216     secondActionRow->setLayout(secondActionRowHBox);
217 
218     QLabel* const secondActionRowLabel        = new QLabel(i18n("Search by area:"));
219     secondActionRowHBox->addWidget(secondActionRowLabel);
220 
221     QToolButton* const tbRegionSelection      = new QToolButton(secondActionRow);
222     tbRegionSelection->setDefaultAction(d->mapSearchWidget->getControlAction(QLatin1String("mousemode-regionselectionmode")));
223     secondActionRowHBox->addWidget(tbRegionSelection);
224 
225     QToolButton* const tbRegionFromIcon       = new QToolButton(secondActionRow);
226     tbRegionFromIcon->setDefaultAction(d->mapSearchWidget->getControlAction(QLatin1String("mousemode-regionselectionfromiconmode")));
227     secondActionRowHBox->addWidget(tbRegionFromIcon);
228 
229     QToolButton* const tbClearRegionSelection = new QToolButton(secondActionRow);
230     tbClearRegionSelection->setDefaultAction(d->mapSearchWidget->getControlAction(QLatin1String("mousemode-removecurrentregionselection")));
231     secondActionRowHBox->addWidget(tbClearRegionSelection);
232 
233     secondActionRowHBox->addStretch(10);
234     vlayTop->addWidget(secondActionRow);
235 
236     // end of the second action row
237 
238     // Show Non Geolocated Items row
239 
240     QWidget* const nonGeolocatedActionRow = new QWidget();
241     QVBoxLayout* const thirdActionRowVBox = new QVBoxLayout();
242     thirdActionRowVBox->setContentsMargins(QMargins());
243     nonGeolocatedActionRow->setLayout(thirdActionRowVBox);
244 
245     QPushButton* const nonGeolocatedBtn   = new QPushButton(nonGeolocatedActionRow);
246     nonGeolocatedBtn->setText(i18n("Show Non-Geolocated Items"));
247     nonGeolocatedBtn->setIcon(QIcon::fromTheme(QLatin1String("emblem-unmounted")));
248     thirdActionRowVBox->addWidget(nonGeolocatedBtn);
249 
250     thirdActionRowVBox->addStretch(10);
251     vlayTop->addWidget(nonGeolocatedActionRow);
252 
253     // end of the third action row
254 
255     vlayTop->addWidget(hbox);
256     vlayTop->setStretchFactor(mapPanel, 10);
257     vlayTop->setContentsMargins(QMargins());
258     vlayTop->setSpacing(QApplication::style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing));
259     QFrame* const frameBottom     = new QFrame(d->splitter);
260     QVBoxLayout* const vlayBottom = new QVBoxLayout(frameBottom);
261     vlayBottom->addWidget(d->searchTreeView);
262     vlayBottom->addWidget(d->searchGPSBar);
263     vlayBottom->setContentsMargins(QMargins());
264     vlayBottom->setSpacing(QApplication::style()->pixelMetric(QStyle::PM_DefaultLayoutSpacing));
265 
266     d->splitter->addWidget(frameTop);
267     d->splitter->addWidget(frameBottom);
268 
269     // ---------------------------------------------------------------
270 
271     vlay->addWidget(d->splitter);
272 
273     // ---------------------------------------------------------------
274 
275     connect(d->searchTreeView, SIGNAL(currentAlbumChanged(Album*)),
276             this, SLOT(slotAlbumSelected(Album*)));
277 
278     connect(d->saveBtn, SIGNAL(clicked()),
279             this, SLOT(slotSaveGPSSAlbum()));
280 
281     connect(d->nameEdit, SIGNAL(textChanged(QString)),
282             this, SLOT(slotCheckNameEditGPSConditions()));
283 
284     connect(d->nameEdit, SIGNAL(returnPressed()),
285             d->saveBtn, SLOT(animateClick()));
286 
287     connect(d->mapSearchWidget, SIGNAL(signalRegionSelectionChanged()),
288             this, SLOT(slotRegionSelectionChanged()));
289 
290     connect(d->gpsMarkerTiler, SIGNAL(signalModelFilteredImages(QList<qlonglong>)),
291             this, SLOT(slotMapSoloItems(QList<qlonglong>)));
292 
293     connect(d->mapSearchWidget, SIGNAL(signalRemoveCurrentFilter()),
294             this, SLOT(slotRemoveCurrentFilter()));
295 
296     connect(nonGeolocatedBtn, SIGNAL(clicked()),
297             d->mapSearchWidget->getControlAction(QLatin1String("mousemode-removecurrentregionselection")), SIGNAL(triggered()));
298 
299     connect(nonGeolocatedBtn, SIGNAL(clicked()),
300             this, SLOT(showNonGeolocatedItems()));
301 
302     // ---------------------------------------------------------------
303 
304     slotCheckNameEditGPSConditions();
305 }
306 
~GPSSearchView()307 GPSSearchView::~GPSSearchView()
308 {
309     delete d;
310 }
311 
setConfigGroup(const KConfigGroup & group)312 void GPSSearchView::setConfigGroup(const KConfigGroup& group)
313 {
314     StateSavingObject::setConfigGroup(group);
315     d->searchTreeView->setConfigGroup(group);
316 }
317 
doLoadState()318 void GPSSearchView::doLoadState()
319 {
320     KConfigGroup group = getConfigGroup();
321 
322     if (group.hasKey(entryName(d->configSplitterStateEntry)))
323     {
324         const QByteArray splitterState = QByteArray::fromBase64(group.readEntry(entryName(d->configSplitterStateEntry), QByteArray()));
325 
326         if (!splitterState.isEmpty())
327         {
328             d->splitter->restoreState(splitterState);
329         }
330     }
331 
332     d->sortOrderOptionsHelper->setSortOptions(GPSItemInfoSorter::SortOptions(group.readEntry(entryName(QLatin1String("Sort Order")), int(d->sortOrderOptionsHelper->getSortOptions()))));
333 
334     const KConfigGroup groupMapWidget = KConfigGroup(&group, entryName(QLatin1String("GPSSearch Map Widget")));
335 
336     d->mapSearchWidget->readSettingsFromGroup(&groupMapWidget);
337 
338     d->searchTreeView->loadState();
339 
340     AlbumManager::instance()->clearCurrentAlbums();
341 
342     d->searchTreeView->clearSelection();
343 }
344 
doSaveState()345 void GPSSearchView::doSaveState()
346 {
347     KConfigGroup group          = getConfigGroup();
348 
349     group.writeEntry(entryName(d->configSplitterStateEntry), d->splitter->saveState().toBase64());
350     group.writeEntry(entryName(QLatin1String("Sort Order")), int(d->sortOrderOptionsHelper->getSortOptions()));
351 
352     KConfigGroup groupMapWidget = KConfigGroup(&group, entryName(QLatin1String("GPSSearch Map Widget")));
353     d->mapSearchWidget->saveSettingsToGroup(&groupMapWidget);
354     d->searchTreeView->saveState();
355 
356     group.sync();
357 }
358 
359 /**
360  * @brief Sets the widget active or inactive.
361  *
362  * Called when the GPSSearch tab becomes the current/not current tab.
363  *
364  * @param state When true, the widget is enabled.
365  */
setActive(bool state)366 void GPSSearchView::setActive(bool state)
367 {
368     if (!state)
369     {
370         // make sure we reset the custom filters set by the map:
371 
372         emit signalMapSoloItems(QList<qlonglong>(), QLatin1String("gpssearch"));
373         d->mapSearchWidget->setActive(false);
374     }
375     else
376     {
377         d->mapSearchWidget->setActive(true);
378 
379         if (d->searchTreeView->currentAlbum())
380         {
381             AlbumManager::instance()->setCurrentAlbums(QList<Album*>() << d->searchTreeView->currentAlbum());
382         }
383 
384         slotClearImages();
385     }
386 }
387 
changeAlbumFromHistory(SAlbum * const album)388 void GPSSearchView::changeAlbumFromHistory(SAlbum* const album)
389 {
390     d->searchTreeView->setCurrentAlbums(QList<Album*>() << album);
391 }
392 
393 /**
394  * This slot saves the current album.
395  */
slotSaveGPSSAlbum()396 void GPSSearchView::slotSaveGPSSAlbum()
397 {
398     QString name = d->nameEdit->text();
399 
400     if (!checkName(name))
401     {
402         return;
403     }
404 
405     createNewGPSSearchAlbum(name);
406 }
407 
408 /**
409  * This slot is called when a new selection is made. It creates a new Search Album.
410  */
slotRegionSelectionChanged()411 void GPSSearchView::slotRegionSelectionChanged()
412 {
413     const GeoCoordinates::Pair newRegionSelection = d->mapSearchWidget->getRegionSelection();
414     const bool haveRegionSelection                = newRegionSelection.first.hasCoordinates();
415 
416     if (haveRegionSelection)
417     {
418         slotCheckNameEditGPSConditions();
419         createNewGPSSearchAlbum(SAlbum::getTemporaryTitle(DatabaseSearch::MapSearch));
420     }
421     else
422     {
423         // reset the search rectangle of the temporary album:
424 
425         createNewGPSSearchAlbum(SAlbum::getTemporaryTitle(DatabaseSearch::MapSearch));
426         d->gpsMarkerTiler->removeCurrentRegionSelection();
427         d->searchTreeView->clearSelection();
428         slotClearImages();
429     }
430 
431     // also remove any filters which may have been there
432 
433     slotRemoveCurrentFilter();
434 
435     slotRefreshMap();
436 }
437 
438 /**
439  * @brief This function creates a new Search Album.
440  * @param name The name of the new album.
441  */
createNewGPSSearchAlbum(const QString & name)442 void GPSSearchView::createNewGPSSearchAlbum(const QString& name)
443 {
444 /*
445     AlbumManager::instance()->clearCurrentAlbums();
446 */
447     // We query the database here
448 
449     const GeoCoordinates::Pair coordinates = d->mapSearchWidget->getRegionSelection();
450     const bool haveCoordinates                       = coordinates.first.hasCoordinates();
451 
452     if (haveCoordinates)
453     {
454         d->gpsMarkerTiler->setRegionSelection(coordinates);
455     }
456 
457     // NOTE: coordinates as lon1, lat1, lon2, lat2 (or West, North, East, South)
458     // as left/top, right/bottom rectangle.
459 
460     QList<qreal> coordinatesList = QList<qreal>() <<
461                                    coordinates.first.lon() << coordinates.first.lat() <<
462                                    coordinates.second.lon() << coordinates.second.lat();
463 
464     if (!haveCoordinates)
465     {
466         /// @todo We need to create a search album with invalid coordinates
467 
468         coordinatesList.clear();
469         coordinatesList << -200 << -200 << -200 << -200;
470     }
471 
472     qCDebug(DIGIKAM_GENERAL_LOG) << "West, North, East, South: " << coordinatesList;
473 
474     SearchXmlWriter writer;
475     writer.writeGroup();
476     writer.writeField(QLatin1String("position"), SearchXml::Inside);
477     writer.writeAttribute(QLatin1String("type"), QLatin1String("rectangle"));
478     writer.writeValue(coordinatesList);
479     writer.finishField();
480     writer.finishGroup();
481 
482     SAlbum* const salbum = AlbumManager::instance()->createSAlbum(name, DatabaseSearch::MapSearch, writer.xml());
483     AlbumManager::instance()->setCurrentAlbums(QList<Album*>() << salbum);
484     d->imageInfoJob.allItemsFromAlbum(salbum);
485     d->searchTreeView->setCurrentAlbums(QList<Album*>() << salbum);
486     d->imageAlbumModel->openAlbum(QList<Album*>() << salbum);
487 }
488 
489 /**
490  * @brief An album is selected in the saved searches list.
491  * @param a This album will be selected.
492  */
slotAlbumSelected(Album * a)493 void GPSSearchView::slotAlbumSelected(Album* a)
494 {
495     /// @todo This re-sets the region selection unwantedly...
496 
497     SAlbum* const salbum = dynamic_cast<SAlbum*>(a);
498 
499     if (!salbum)
500     {
501         return;
502     }
503 
504     SearchXmlReader reader(salbum->query());
505     reader.readToFirstField();
506     QStringRef type      = reader.attributes().value(QLatin1String("type"));
507 
508     if (type == QLatin1String("rectangle"))
509     {
510         const QList<double> list = reader.valueToDoubleList();
511 
512         const GeoCoordinates::Pair coordinates(
513             GeoCoordinates(list.at(1), list.at(0)),
514             GeoCoordinates(list.at(3), list.at(2))
515         );
516 
517         /// @todo Currently, invalid coordinates are stored as -200:
518 
519         if (list.at(1) != -200)
520         {
521             d->mapSearchWidget->setRegionSelection(coordinates);
522             d->gpsMarkerTiler->setRegionSelection(coordinates);
523         }
524         else
525         {
526             d->mapSearchWidget->clearRegionSelection();
527             d->gpsMarkerTiler->removeCurrentRegionSelection();
528         }
529 
530         slotCheckNameEditGPSConditions();
531     }
532 
533     d->imageInfoJob.allItemsFromAlbum(salbum);
534 }
535 
536 /**
537  * @brief Checks whether the newly added search name already exists.
538  * @param name The name of the current search.
539  */
checkName(QString & name)540 bool GPSSearchView::checkName(QString& name)
541 {
542     bool checked = checkAlbum(name);
543 
544     while (!checked)
545     {
546         QString label = i18n("Search name already exists.\n"
547                              "Please enter a new name:");
548         bool ok;
549         QString newTitle = QInputDialog::getText(this,
550                                                  i18n("Name exists"),
551                                                  label,
552                                                  QLineEdit::Normal,
553                                                  name,
554                                                  &ok);
555 
556         if (!ok)
557         {
558             return false;
559         }
560 
561         name    = newTitle;
562         checked = checkAlbum(name);
563     }
564 
565     return true;
566 }
567 
568 /**
569  * @brief Checks whether the newly added album name already exists.
570  * @param name The name of the album.
571  */
checkAlbum(const QString & name) const572 bool GPSSearchView::checkAlbum(const QString& name) const
573 {
574     const AlbumList list = AlbumManager::instance()->allSAlbums();
575 
576     for (AlbumList::ConstIterator it = list.constBegin() ; it != list.constEnd() ; ++it)
577     {
578         const SAlbum* const album = (SAlbum*)(*it);
579 
580         if (album->title() == name)
581         {
582             return false;
583         }
584     }
585 
586     return true;
587 }
588 
589 /**
590  * @brief Remove the current filter.
591  */
slotRemoveCurrentFilter()592 void GPSSearchView::slotRemoveCurrentFilter()
593 {
594     d->gpsMarkerTiler->setPositiveFilterIsActive(false);
595     const QList<qlonglong> emptyIdList;
596     emit signalMapSoloItems(emptyIdList, QLatin1String("gpssearch"));
597     slotRefreshMap();
598     d->mapSearchWidget->slotUpdateActionsEnabled();
599 }
600 
601 /**
602  * @brief Enable or disable the album saving controls.
603  */
slotCheckNameEditGPSConditions()604 void GPSSearchView::slotCheckNameEditGPSConditions()
605 {
606     if (d->mapSearchWidget->getRegionSelection().first.hasCoordinates())
607     {
608         d->nameEdit->setEnabled(true);
609 
610         if (!d->nameEdit->text().isEmpty())
611         {
612             d->saveBtn->setEnabled(true);
613         }
614     }
615     else
616     {
617         d->nameEdit->setEnabled(false);
618         d->saveBtn->setEnabled(false);
619     }
620 }
621 
622 /**
623  * @brief Slot which gets called when the user makes items 'solo' on the map
624  * @param gpsList List of GPSInfos which are 'solo'
625  */
slotMapSoloItems(const QList<qlonglong> & idList)626 void GPSSearchView::slotMapSoloItems(const QList<qlonglong>& idList)
627 {
628     emit signalMapSoloItems(idList, QLatin1String("gpssearch"));
629     d->mapSearchWidget->slotUpdateActionsEnabled();
630 }
631 
showNonGeolocatedItems()632 void GPSSearchView::showNonGeolocatedItems()
633 {
634     if (d->nonGeonlocatedItemsXml.isEmpty())
635     {
636         SearchXmlWriter writer;
637         writer.setFieldOperator((SearchXml::standardFieldOperator()));
638         writer.writeGroup();
639         writer.writeField(QLatin1String("nogps"), SearchXml::Equal);
640         writer.finishField();
641         writer.finishGroup();
642         writer.finish();
643         d->nonGeonlocatedItemsXml = writer.xml();
644     }
645 
646     QString title = SAlbum::getTemporaryTitle(DatabaseSearch::MapSearch);
647     SAlbum* album = AlbumManager::instance()->findSAlbum(title);
648 
649     int id;
650 
651     if (album)
652     {
653         id = album->id();
654         CoreDbAccess().db()->updateSearch(id, DatabaseSearch::AdvancedSearch,
655                                           SAlbum::getTemporaryTitle(DatabaseSearch::AdvancedSearch),
656                                           d->nonGeonlocatedItemsXml);
657     }
658     else
659     {
660         id = CoreDbAccess().db()->addSearch(DatabaseSearch::AdvancedSearch,
661                                             SAlbum::getTemporaryTitle(DatabaseSearch::AdvancedSearch),
662                                             d->nonGeonlocatedItemsXml);
663     }
664 
665     album = new SAlbum(i18n("Non Geo-located Items"), id);
666 
667     if (album)
668     {
669         AlbumManager::instance()->setCurrentAlbums(QList<Album*>() << album);
670     }
671 }
672 
673 
slotRefreshMap()674 void GPSSearchView::slotRefreshMap()
675 {
676     d->mapSearchWidget->refreshMap();
677 }
678 
slotClearImages()679 void GPSSearchView::slotClearImages()
680 {
681     if (d->mapSearchWidget->getActiveState())
682     {
683         d->imageAlbumModel->clearItemInfos();
684     }
685 }
686 
687 } // namespace Digikam
688