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

0001 /* ============================================================
0002  *
0003  * This file is a part of digiKam project
0004  * https://www.digikam.org
0005  *
0006  * Date        : 2008-05-30
0007  * Description : GPS search sidebar tab contents.
0008  *
0009  * SPDX-FileCopyrightText: 2008-2024 by Gilles Caulier <caulier dot gilles at gmail dot com>
0010  * SPDX-FileCopyrightText:      2009 by Johannes Wienke <languitar at semipol dot de>
0011  * SPDX-FileCopyrightText: 2010-2011 by Michael G. Hansen <mike at mghansen dot de>
0012  * SPDX-FileCopyrightText:      2014 by Mohamed_Anwer <m_dot_anwer at gmx dot com>
0013  *
0014  * SPDX-License-Identifier: GPL-2.0-or-later
0015  *
0016  * ============================================================ */
0017 
0018 #include "gpssearchview.h"
0019 
0020 // Qt includes
0021 
0022 #include <QLabel>
0023 #include <QLayout>
0024 #include <QPushButton>
0025 #include <QSplitter>
0026 #include <QToolButton>
0027 #include <QTimer>
0028 #include <QMenu>
0029 #include <QActionGroup>
0030 #include <QAction>
0031 #include <QApplication>
0032 #include <QStyle>
0033 #include <QLineEdit>
0034 #include <QInputDialog>
0035 #include <QIcon>
0036 
0037 // KDE includes
0038 
0039 #include <klocalizedstring.h>
0040 #include <kconfiggroup.h>
0041 
0042 // Local includes
0043 
0044 #include "digikam_debug.h"
0045 #include "searchtreeview.h"
0046 #include "editablesearchtreeview.h"
0047 #include "iteminfojob.h"
0048 #include "coredbsearchxml.h"
0049 #include "gpsmarkertiler.h"
0050 #include "gpsiteminfosorter.h"
0051 #include "searchtextbardb.h"
0052 #include "dtextedit.h"
0053 
0054 namespace Digikam
0055 {
0056 
0057 class Q_DECL_HIDDEN GPSSearchView::Private
0058 {
0059 
0060 public:
0061 
0062     explicit Private()
0063       : saveBtn                 (nullptr),
0064         nameEdit                (nullptr),
0065         imageInfoJob            (),
0066         searchGPSBar            (nullptr),
0067         searchTreeView          (nullptr),
0068         splitter                (nullptr),
0069         mapSearchWidget         (nullptr),
0070         gpsMarkerTiler          (nullptr),
0071         imageAlbumModel         (nullptr),
0072         imageFilterModel        (nullptr),
0073         selectionModel          (nullptr),
0074         searchModel             (nullptr),
0075         sortOrderOptionsHelper  (nullptr)
0076     {
0077     }
0078 
0079     static const QString    configSplitterStateEntry;
0080     QToolButton*            saveBtn;
0081     DTextEdit*              nameEdit;
0082     ItemInfoJob             imageInfoJob;
0083     SearchTextBarDb*        searchGPSBar;
0084     EditableSearchTreeView* searchTreeView;
0085     QSplitter*              splitter;
0086     MapWidget*              mapSearchWidget;
0087     GPSMarkerTiler*         gpsMarkerTiler;
0088     ItemAlbumModel*         imageAlbumModel;
0089     ItemFilterModel*        imageFilterModel;
0090     QItemSelectionModel*    selectionModel;
0091     SearchModel*            searchModel;
0092     GPSItemInfoSorter*      sortOrderOptionsHelper;
0093     QString                 nonGeonlocatedItemsXml;
0094 };
0095 
0096 const QString GPSSearchView::Private::configSplitterStateEntry(QLatin1String("SplitterState"));
0097 
0098 /**
0099  * @brief Constructor
0100  * @param parent the parent object.
0101  * @param searchModel The model that stores the searches.
0102  * @param imageFilterModel The image model used by displaying the selected images on map.
0103  * @param itemSelectionModel The selection model corresponding to the imageFilterModel.
0104  */
0105 GPSSearchView::GPSSearchView(QWidget* const parent,
0106                              SearchModel* const searchModel,
0107                              SearchModificationHelper* const searchModificationHelper,
0108                              ItemFilterModel* const imageFilterModel,
0109                              QItemSelectionModel* const itemSelectionModel)
0110     : QWidget          (parent),
0111       StateSavingObject(this),
0112       d                (new Private)
0113 {
0114     setAttribute(Qt::WA_DeleteOnClose);
0115 
0116     /// @todo Really?
0117 
0118     setAcceptDrops(true);
0119 
0120     d->imageAlbumModel        = qobject_cast<ItemAlbumModel*>(imageFilterModel->sourceModel());
0121     d->selectionModel         = itemSelectionModel;
0122     d->imageFilterModel       = imageFilterModel;
0123     d->searchModel            = searchModel;
0124 
0125     // ---------------------------------------------------------------
0126 
0127     QVBoxLayout* const vlay   = new QVBoxLayout(this);
0128 
0129     QFrame* const mapPanel    = new QFrame(this);
0130     mapPanel->setMinimumWidth(256);
0131     mapPanel->setMinimumHeight(256);
0132     QVBoxLayout* const vlay2  = new QVBoxLayout(mapPanel);
0133     d->mapSearchWidget        = new MapWidget(mapPanel);
0134     d->mapSearchWidget->setBackend(QLatin1String("marble"));
0135     d->mapSearchWidget->setShowThumbnails(true);
0136 
0137     d->gpsMarkerTiler         = new GPSMarkerTiler(this, d->imageFilterModel, d->selectionModel);
0138     d->mapSearchWidget->setGroupedModel(d->gpsMarkerTiler);
0139 
0140     mapPanel->setFrameStyle(QFrame::StyledPanel | QFrame::Sunken);
0141     mapPanel->setLineWidth(style()->pixelMetric(QStyle::PM_DefaultFrameWidth));
0142 
0143     d->sortOrderOptionsHelper = new GPSItemInfoSorter(this);
0144     d->sortOrderOptionsHelper->addToMapWidget(d->mapSearchWidget);
0145 
0146     vlay2->addWidget(d->mapSearchWidget);
0147     vlay2->setContentsMargins(QMargins());
0148     vlay2->setSpacing(0);
0149 
0150     // ---------------------------------------------------------------
0151 
0152     DHBox* const hbox = new DHBox(this);
0153     hbox->setContentsMargins(QMargins());
0154     hbox->setSpacing(qMin(QApplication::style()->pixelMetric(QStyle::PM_LayoutHorizontalSpacing),
0155                              QApplication::style()->pixelMetric(QStyle::PM_LayoutVerticalSpacing)));
0156 
0157     d->nameEdit       = new DTextEdit(hbox);
0158     d->nameEdit->setLinesVisible(1);
0159     d->nameEdit->setWhatsThis(i18n("Enter the name of the current map search to save in the "
0160                                    "\"Map Searches\" view."));
0161 
0162     d->saveBtn        = new QToolButton(hbox);
0163     d->saveBtn->setIcon(QIcon::fromTheme(QLatin1String("document-save")));
0164     d->saveBtn->setEnabled(false);
0165     d->saveBtn->setToolTip(i18n("Save current map search to a new virtual album."));
0166     d->saveBtn->setWhatsThis(i18n("If this button is pressed, the current map search "
0167                                   "will be saved to a new search "
0168                                   "virtual album using the name "
0169                                   "set on the left side."));
0170 
0171     // ---------------------------------------------------------------
0172 
0173     d->searchTreeView = new EditableSearchTreeView(this, d->searchModel, searchModificationHelper);
0174     d->searchTreeView->filteredModel()->setFilterSearchType(DatabaseSearch::MapSearch);
0175     d->searchTreeView->filteredModel()->setListTemporarySearches(true);
0176     d->searchTreeView->setAlbumManagerCurrentAlbum(true);
0177     d->searchGPSBar   = new SearchTextBarDb(this, QLatin1String("GPSSearchViewSearchGPSBar"));
0178     d->searchGPSBar->setModel(d->searchTreeView->filteredModel(), AbstractAlbumModel::AlbumIdRole, AbstractAlbumModel::AlbumTitleRole);
0179     d->searchGPSBar->setFilterModel(d->searchTreeView->albumFilterModel());
0180 
0181     // ---------------------------------------------------------------
0182 
0183     d->splitter                = new QSplitter(Qt::Vertical, this);
0184 
0185     QFrame* const frameTop     = new QFrame(d->splitter);
0186     QVBoxLayout* const vlayTop = new QVBoxLayout(frameTop);
0187     vlayTop->addWidget(mapPanel);
0188     vlayTop->addWidget(d->mapSearchWidget->getControlWidget());
0189 
0190     d->mapSearchWidget->setAvailableMouseModes(MouseModePan                     |
0191                                                MouseModeRegionSelection         |
0192                                                MouseModeZoomIntoGroup           |
0193                                                MouseModeRegionSelectionFromIcon |
0194                                                MouseModeFilter                  |
0195                                                MouseModeSelectThumbnail);
0196 
0197     d->mapSearchWidget->setVisibleMouseModes(MouseModePan           |
0198                                              MouseModeZoomIntoGroup |
0199                                              MouseModeFilter        |
0200                                              MouseModeSelectThumbnail);
0201 
0202     /**
0203      * construct a second row of control actions below the control widget
0204      * @todo Should we still replace the icons of the actions with text as discussed during the sprint?
0205      */
0206     QWidget* const secondActionRow            = new QWidget();
0207     QHBoxLayout* const secondActionRowHBox    = new QHBoxLayout();
0208     secondActionRowHBox->setContentsMargins(QMargins());
0209     secondActionRow->setLayout(secondActionRowHBox);
0210 
0211     QLabel* const secondActionRowLabel        = new QLabel(i18n("Search by area:"));
0212     secondActionRowHBox->addWidget(secondActionRowLabel);
0213 
0214     QToolButton* const tbRegionSelection      = new QToolButton(secondActionRow);
0215     tbRegionSelection->setDefaultAction(d->mapSearchWidget->getControlAction(QLatin1String("mousemode-regionselectionmode")));
0216     secondActionRowHBox->addWidget(tbRegionSelection);
0217 
0218     QToolButton* const tbRegionFromIcon       = new QToolButton(secondActionRow);
0219     tbRegionFromIcon->setDefaultAction(d->mapSearchWidget->getControlAction(QLatin1String("mousemode-regionselectionfromiconmode")));
0220     secondActionRowHBox->addWidget(tbRegionFromIcon);
0221 
0222     QToolButton* const tbClearRegionSelection = new QToolButton(secondActionRow);
0223     tbClearRegionSelection->setDefaultAction(d->mapSearchWidget->getControlAction(QLatin1String("mousemode-removecurrentregionselection")));
0224     secondActionRowHBox->addWidget(tbClearRegionSelection);
0225 
0226     secondActionRowHBox->addStretch(10);
0227     vlayTop->addWidget(secondActionRow);
0228 
0229     // end of the second action row
0230 
0231     // Show Non Geolocated Items row
0232 
0233     QWidget* const nonGeolocatedActionRow = new QWidget();
0234     QVBoxLayout* const thirdActionRowVBox = new QVBoxLayout();
0235     thirdActionRowVBox->setContentsMargins(QMargins());
0236     nonGeolocatedActionRow->setLayout(thirdActionRowVBox);
0237 
0238     QPushButton* const nonGeolocatedBtn   = new QPushButton(nonGeolocatedActionRow);
0239     nonGeolocatedBtn->setText(i18n("Show Non-Geolocated Items"));
0240     nonGeolocatedBtn->setIcon(QIcon::fromTheme(QLatin1String("emblem-unmounted")));
0241     thirdActionRowVBox->addWidget(nonGeolocatedBtn);
0242 
0243     thirdActionRowVBox->addStretch(10);
0244     vlayTop->addWidget(nonGeolocatedActionRow);
0245 
0246     // end of the third action row
0247 
0248     vlayTop->addWidget(hbox);
0249     vlayTop->setStretchFactor(mapPanel, 10);
0250     vlayTop->setContentsMargins(QMargins());
0251     vlayTop->setSpacing(qMin(QApplication::style()->pixelMetric(QStyle::PM_LayoutHorizontalSpacing),
0252                              QApplication::style()->pixelMetric(QStyle::PM_LayoutVerticalSpacing)));
0253     QFrame* const frameBottom     = new QFrame(d->splitter);
0254     QVBoxLayout* const vlayBottom = new QVBoxLayout(frameBottom);
0255     vlayBottom->addWidget(d->searchTreeView);
0256     vlayBottom->addWidget(d->searchGPSBar);
0257     vlayBottom->setContentsMargins(QMargins());
0258     vlayBottom->setSpacing(qMin(QApplication::style()->pixelMetric(QStyle::PM_LayoutHorizontalSpacing),
0259                              QApplication::style()->pixelMetric(QStyle::PM_LayoutVerticalSpacing)));
0260 
0261     d->splitter->addWidget(frameTop);
0262     d->splitter->addWidget(frameBottom);
0263 
0264     // ---------------------------------------------------------------
0265 
0266     vlay->addWidget(d->splitter);
0267 
0268     // ---------------------------------------------------------------
0269 
0270     connect(d->searchTreeView, SIGNAL(currentAlbumChanged(Album*)),
0271             this, SLOT(slotAlbumSelected(Album*)));
0272 
0273     connect(d->saveBtn, SIGNAL(clicked()),
0274             this, SLOT(slotSaveGPSSAlbum()));
0275 
0276     connect(d->nameEdit, SIGNAL(textChanged()),
0277             this, SLOT(slotCheckNameEditGPSConditions()));
0278 
0279     connect(d->nameEdit, SIGNAL(returnPressed()),
0280             d->saveBtn, SLOT(animateClick()));
0281 
0282     connect(d->mapSearchWidget, SIGNAL(signalRegionSelectionChanged()),
0283             this, SLOT(slotRegionSelectionChanged()));
0284 
0285     connect(d->gpsMarkerTiler, SIGNAL(signalModelFilteredImages(QList<qlonglong>)),
0286             this, SLOT(slotMapSoloItems(QList<qlonglong>)));
0287 
0288     connect(d->mapSearchWidget, SIGNAL(signalRemoveCurrentFilter()),
0289             this, SLOT(slotRemoveCurrentFilter()));
0290 
0291     connect(nonGeolocatedBtn, SIGNAL(clicked()),
0292             d->mapSearchWidget->getControlAction(QLatin1String("mousemode-removecurrentregionselection")), SIGNAL(triggered()));
0293 
0294     connect(nonGeolocatedBtn, SIGNAL(clicked()),
0295             this, SLOT(showNonGeolocatedItems()));
0296 
0297     // ---------------------------------------------------------------
0298 
0299     slotCheckNameEditGPSConditions();
0300 }
0301 
0302 GPSSearchView::~GPSSearchView()
0303 {
0304     delete d;
0305 }
0306 
0307 void GPSSearchView::setConfigGroup(const KConfigGroup& group)
0308 {
0309     StateSavingObject::setConfigGroup(group);
0310     d->searchTreeView->setConfigGroup(group);
0311 }
0312 
0313 void GPSSearchView::doLoadState()
0314 {
0315     KConfigGroup group = getConfigGroup();
0316 
0317     if (group.hasKey(entryName(d->configSplitterStateEntry)))
0318     {
0319         const QByteArray splitterState = QByteArray::fromBase64(group.readEntry(entryName(d->configSplitterStateEntry), QByteArray()));
0320 
0321         if (!splitterState.isEmpty())
0322         {
0323             d->splitter->restoreState(splitterState);
0324         }
0325     }
0326 
0327     d->sortOrderOptionsHelper->setSortOptions(GPSItemInfoSorter::SortOptions(group.readEntry(entryName(QLatin1String("Sort Order")), int(d->sortOrderOptionsHelper->getSortOptions()))));
0328 
0329     const KConfigGroup groupMapWidget = KConfigGroup(&group, entryName(QLatin1String("GPSSearch Map Widget")));
0330 
0331     d->mapSearchWidget->readSettingsFromGroup(&groupMapWidget);
0332 
0333     d->searchTreeView->loadState();
0334 
0335     AlbumManager::instance()->clearCurrentAlbums();
0336 
0337     d->searchTreeView->clearSelection();
0338 }
0339 
0340 void GPSSearchView::doSaveState()
0341 {
0342     KConfigGroup group          = getConfigGroup();
0343 
0344     group.writeEntry(entryName(d->configSplitterStateEntry), d->splitter->saveState().toBase64());
0345     group.writeEntry(entryName(QLatin1String("Sort Order")), int(d->sortOrderOptionsHelper->getSortOptions()));
0346 
0347     KConfigGroup groupMapWidget = KConfigGroup(&group, entryName(QLatin1String("GPSSearch Map Widget")));
0348     d->mapSearchWidget->saveSettingsToGroup(&groupMapWidget);
0349     d->searchTreeView->saveState();
0350 
0351     group.sync();
0352 }
0353 
0354 /**
0355  * @brief Sets the widget active or inactive.
0356  *
0357  * Called when the GPSSearch tab becomes the current/not current tab.
0358  *
0359  * @param state When true, the widget is enabled.
0360  */
0361 void GPSSearchView::setActive(bool state)
0362 {
0363     if (!state)
0364     {
0365         // make sure we reset the custom filters set by the map:
0366 
0367         Q_EMIT signalMapSoloItems(QList<qlonglong>(), QLatin1String("gpssearch"));
0368         d->mapSearchWidget->setActive(false);
0369     }
0370     else
0371     {
0372         d->mapSearchWidget->setActive(true);
0373 
0374         if (d->searchTreeView->currentAlbum())
0375         {
0376             AlbumManager::instance()->setCurrentAlbums(QList<Album*>() << d->searchTreeView->currentAlbum());
0377         }
0378 
0379         slotClearImages();
0380     }
0381 }
0382 
0383 void GPSSearchView::changeAlbumFromHistory(SAlbum* const album)
0384 {
0385     d->searchTreeView->setCurrentAlbums(QList<Album*>() << album);
0386 }
0387 
0388 /**
0389  * This slot saves the current album.
0390  */
0391 void GPSSearchView::slotSaveGPSSAlbum()
0392 {
0393     QString name = d->nameEdit->text();
0394 
0395     if (!checkName(name))
0396     {
0397         return;
0398     }
0399 
0400     createNewGPSSearchAlbum(name);
0401 }
0402 
0403 /**
0404  * This slot is called when a new selection is made. It creates a new Search Album.
0405  */
0406 void GPSSearchView::slotRegionSelectionChanged()
0407 {
0408     const GeoCoordinates::Pair newRegionSelection = d->mapSearchWidget->getRegionSelection();
0409     const bool haveRegionSelection                = newRegionSelection.first.hasCoordinates();
0410 
0411     if (haveRegionSelection)
0412     {
0413         slotCheckNameEditGPSConditions();
0414         createNewGPSSearchAlbum(SAlbum::getTemporaryTitle(DatabaseSearch::MapSearch));
0415     }
0416     else
0417     {
0418         // reset the search rectangle of the temporary album:
0419 
0420         createNewGPSSearchAlbum(SAlbum::getTemporaryTitle(DatabaseSearch::MapSearch));
0421         d->gpsMarkerTiler->removeCurrentRegionSelection();
0422         d->searchTreeView->clearSelection();
0423         slotClearImages();
0424     }
0425 
0426     // also remove any filters which may have been there
0427 
0428     slotRemoveCurrentFilter();
0429 
0430     slotRefreshMap();
0431 }
0432 
0433 /**
0434  * @brief This function creates a new Search Album.
0435  * @param name The name of the new album.
0436  */
0437 void GPSSearchView::createNewGPSSearchAlbum(const QString& name)
0438 {
0439 /*
0440     AlbumManager::instance()->clearCurrentAlbums();
0441 */
0442     // We query the database here
0443 
0444     const GeoCoordinates::Pair coordinates = d->mapSearchWidget->getRegionSelection();
0445     const bool haveCoordinates                       = coordinates.first.hasCoordinates();
0446 
0447     if (haveCoordinates)
0448     {
0449         d->gpsMarkerTiler->setRegionSelection(coordinates);
0450     }
0451 
0452     // NOTE: coordinates as lon1, lat1, lon2, lat2 (or West, North, East, South)
0453     // as left/top, right/bottom rectangle.
0454 
0455     QList<qreal> coordinatesList = QList<qreal>() <<
0456                                    coordinates.first.lon() << coordinates.first.lat() <<
0457                                    coordinates.second.lon() << coordinates.second.lat();
0458 
0459     if (!haveCoordinates)
0460     {
0461         /// @todo We need to create a search album with invalid coordinates
0462 
0463         coordinatesList.clear();
0464         coordinatesList << -200 << -200 << -200 << -200;
0465     }
0466 
0467     qCDebug(DIGIKAM_GENERAL_LOG) << "West, North, East, South: " << coordinatesList;
0468 
0469     SearchXmlWriter writer;
0470     writer.writeGroup();
0471     writer.writeField(QLatin1String("position"), SearchXml::Inside);
0472     writer.writeAttribute(QLatin1String("type"), QLatin1String("rectangle"));
0473     writer.writeValue(coordinatesList);
0474     writer.finishField();
0475     writer.finishGroup();
0476 
0477     SAlbum* const salbum = AlbumManager::instance()->createSAlbum(name, DatabaseSearch::MapSearch, writer.xml());
0478     AlbumManager::instance()->setCurrentAlbums(QList<Album*>() << salbum);
0479     d->imageInfoJob.allItemsFromAlbum(salbum);
0480     d->searchTreeView->setCurrentAlbums(QList<Album*>() << salbum);
0481     d->imageAlbumModel->openAlbum(QList<Album*>() << salbum);
0482 }
0483 
0484 /**
0485  * @brief An album is selected in the saved searches list.
0486  * @param a This album will be selected.
0487  */
0488 void GPSSearchView::slotAlbumSelected(Album* a)
0489 {
0490     /// @todo This re-sets the region selection unwantedly...
0491 
0492     SAlbum* const salbum = dynamic_cast<SAlbum*>(a);
0493 
0494     if (!salbum)
0495     {
0496         return;
0497     }
0498 
0499     SearchXmlReader reader(salbum->query());
0500     reader.readToFirstField();
0501     QStringView type      = reader.attributes().value(QLatin1String("type"));
0502 
0503     if (type == QLatin1String("rectangle"))
0504     {
0505         const QList<double> list = reader.valueToDoubleList();
0506 
0507         const GeoCoordinates::Pair coordinates(
0508             GeoCoordinates(list.at(1), list.at(0)),
0509             GeoCoordinates(list.at(3), list.at(2))
0510         );
0511 
0512         /// @todo Currently, invalid coordinates are stored as -200:
0513 
0514         if (list.at(1) != -200)
0515         {
0516             d->mapSearchWidget->setRegionSelection(coordinates);
0517             d->gpsMarkerTiler->setRegionSelection(coordinates);
0518         }
0519         else
0520         {
0521             d->mapSearchWidget->clearRegionSelection();
0522             d->gpsMarkerTiler->removeCurrentRegionSelection();
0523         }
0524 
0525         slotCheckNameEditGPSConditions();
0526     }
0527 
0528     d->imageInfoJob.allItemsFromAlbum(salbum);
0529 }
0530 
0531 /**
0532  * @brief Checks whether the newly added search name already exists.
0533  * @param name The name of the current search.
0534  */
0535 bool GPSSearchView::checkName(QString& name)
0536 {
0537     bool checked = checkAlbum(name);
0538 
0539     while (!checked)
0540     {
0541         QString label = i18n("Search name already exists.\n"
0542                              "Please enter a new name:");
0543         bool ok;
0544         QString newTitle = QInputDialog::getText(this,
0545                                                  i18nc("@title:window", "Name Exists"),
0546                                                  label,
0547                                                  QLineEdit::Normal,
0548                                                  name,
0549                                                  &ok);
0550 
0551         if (!ok)
0552         {
0553             return false;
0554         }
0555 
0556         name    = newTitle;
0557         checked = checkAlbum(name);
0558     }
0559 
0560     return true;
0561 }
0562 
0563 /**
0564  * @brief Checks whether the newly added album name already exists.
0565  * @param name The name of the album.
0566  */
0567 bool GPSSearchView::checkAlbum(const QString& name) const
0568 {
0569     const AlbumList list = AlbumManager::instance()->allSAlbums();
0570 
0571     for (AlbumList::ConstIterator it = list.constBegin() ; it != list.constEnd() ; ++it)
0572     {
0573         const SAlbum* const album = (SAlbum*)(*it);
0574 
0575         if (album->title() == name)
0576         {
0577             return false;
0578         }
0579     }
0580 
0581     return true;
0582 }
0583 
0584 /**
0585  * @brief Remove the current filter.
0586  */
0587 void GPSSearchView::slotRemoveCurrentFilter()
0588 {
0589     d->gpsMarkerTiler->setPositiveFilterIsActive(false);
0590     const QList<qlonglong> emptyIdList;
0591     Q_EMIT signalMapSoloItems(emptyIdList, QLatin1String("gpssearch"));
0592     slotRefreshMap();
0593     d->mapSearchWidget->slotUpdateActionsEnabled();
0594 }
0595 
0596 /**
0597  * @brief Enable or disable the album saving controls.
0598  */
0599 void GPSSearchView::slotCheckNameEditGPSConditions()
0600 {
0601     if (d->mapSearchWidget->getRegionSelection().first.hasCoordinates())
0602     {
0603         d->nameEdit->setEnabled(true);
0604 
0605         if (!d->nameEdit->text().isEmpty())
0606         {
0607             d->saveBtn->setEnabled(true);
0608         }
0609     }
0610     else
0611     {
0612         d->nameEdit->setEnabled(false);
0613         d->saveBtn->setEnabled(false);
0614     }
0615 }
0616 
0617 /**
0618  * @brief Slot which gets called when the user makes items 'solo' on the map
0619  * @param gpsList List of GPSInfos which are 'solo'
0620  */
0621 void GPSSearchView::slotMapSoloItems(const QList<qlonglong>& idList)
0622 {
0623     Q_EMIT signalMapSoloItems(idList, QLatin1String("gpssearch"));
0624     d->mapSearchWidget->slotUpdateActionsEnabled();
0625 }
0626 
0627 void GPSSearchView::showNonGeolocatedItems()
0628 {
0629     if (d->nonGeonlocatedItemsXml.isEmpty())
0630     {
0631         SearchXmlWriter writer;
0632         writer.setFieldOperator((SearchXml::standardFieldOperator()));
0633         writer.writeGroup();
0634         writer.writeField(QLatin1String("nogps"), SearchXml::Equal);
0635         writer.finishField();
0636         writer.finishGroup();
0637         writer.finish();
0638         d->nonGeonlocatedItemsXml = writer.xml();
0639     }
0640 
0641     QString title = SAlbum::getTemporaryTitle(DatabaseSearch::MapSearch);
0642     SAlbum* album = AlbumManager::instance()->findSAlbum(title);
0643 
0644     int id;
0645 
0646     if (album)
0647     {
0648         id = album->id();
0649         CoreDbAccess().db()->updateSearch(id, DatabaseSearch::AdvancedSearch,
0650                                           SAlbum::getTemporaryTitle(DatabaseSearch::AdvancedSearch),
0651                                           d->nonGeonlocatedItemsXml);
0652     }
0653     else
0654     {
0655         id = CoreDbAccess().db()->addSearch(DatabaseSearch::AdvancedSearch,
0656                                             SAlbum::getTemporaryTitle(DatabaseSearch::AdvancedSearch),
0657                                             d->nonGeonlocatedItemsXml);
0658     }
0659 
0660     album = new SAlbum(i18n("Non Geo-located Items"), id);
0661 
0662     if (album)
0663     {
0664         AlbumManager::instance()->setCurrentAlbums(QList<Album*>() << album);
0665     }
0666 }
0667 
0668 
0669 void GPSSearchView::slotRefreshMap()
0670 {
0671     d->mapSearchWidget->refreshMap();
0672 }
0673 
0674 void GPSSearchView::slotClearImages()
0675 {
0676     if (d->mapSearchWidget->getActiveState())
0677     {
0678         d->imageAlbumModel->clearItemInfos();
0679     }
0680 }
0681 
0682 } // namespace Digikam
0683 
0684 #include "moc_gpssearchview.cpp"