File indexing completed on 2025-01-05 03:58:36

0001 /* ============================================================
0002  *
0003  * This file is a part of digiKam project
0004  * https://www.digikam.org
0005  *
0006  * Date        : 2009-12-01
0007  * Description : world map widget library
0008  *
0009  * SPDX-FileCopyrightText: 2010-2024 by Gilles Caulier <caulier dot gilles at gmail dot com>
0010  * SPDX-FileCopyrightText: 2009-2011 by Michael G. Hansen <mike at mghansen dot de>
0011  * SPDX-FileCopyrightText:      2014 by Justus Schwartz <justus at gmx dot li>
0012  *
0013  * SPDX-License-Identifier: GPL-2.0-or-later
0014  *
0015  * ============================================================ */
0016 
0017 #ifndef DIGIKAM_MAP_WIDGET_H
0018 #define DIGIKAM_MAP_WIDGET_H
0019 
0020 // Qt includes
0021 
0022 #include <QWidget>
0023 #include <QList>
0024 #include <QStringList>
0025 
0026 // Local includes
0027 
0028 #include "digikam_export.h"
0029 #include "digikam_config.h"
0030 #include "geoifacetypes.h"
0031 #include "geocoordinates.h"
0032 #include "geogroupstate.h"
0033 
0034 class QAction;
0035 class QDragEnterEvent;
0036 class QDropEvent;
0037 class QMenu;
0038 
0039 class KConfigGroup;
0040 
0041 namespace Digikam
0042 {
0043 
0044 class GeoIfaceSharedData;
0045 class GeoModelHelper;
0046 class GeoDragDropHandler;
0047 class AbstractMarkerTiler;
0048 class TrackManager;
0049 class MapBackend;
0050 
0051 /**
0052  * @class MapWidget
0053  * @brief The central map view class of geolocation interface
0054  *
0055  * The MapWidget class is the central widget of geolocation interface. It provides a widget which can display maps using
0056  * either the Marble or Google Maps backend. Using a model, items can be displayed on the map. For
0057  * models containing only a small number of items, the items can be shown directly, but for models with
0058  * a larger number of items, the items can also be grouped. Currently, any number of ungrouped models
0059  * can be shown, but only one grouped model. Item selection models can also be used along with the models,
0060  * to interact with the selection states of the items on the map. In order to use a model with geolocation interface, however,
0061  * a model helper has to be implemented, which extracts data from the model that is not provided by the Qt part
0062  * of a model's API.
0063  *
0064  * Now, a brief introduction on how to get geolocation interface working is provided:
0065  * @li First, an instance of @c MapWidget has to be created.
0066  * @li Next, @c GeoModelHelper has to be subclassed and at least the pure virtual functions have to be implemented.
0067  * @li To show the model's data ungrouped, the model helper has to be added to @c MapWidget instance using addUngroupedModel.
0068  * @li To show the model's data grouped, an instance of @c AbstractMarkerTiler has to be created and the model helper has to be
0069  *     set to it using setMarkerGeoModelHelper. The @c AbstractMarkerTiler has then to be given to MapWidget using setGroupedModel. If
0070  *     the items to be displayed do not reside in a model, a subclass of @c AbstractMarkerTiler can be created which returns
0071  *     just the number of items in a particular area, and picks representative items for thumbnails.
0072  * @li To handle dropping of items from the host applications UI onto the map, @c DragDropHandler has to be subclassed
0073  *     as well and added to the model using setDragDropHandler.
0074  * @li Finally, setActive() has to be called to tell the widget that it should start displaying things.
0075  */
0076 
0077 class DIGIKAM_EXPORT MapWidget : public QWidget
0078 {
0079     Q_OBJECT
0080 
0081 public:
0082 
0083     explicit MapWidget(QWidget* const parent = nullptr);
0084     ~MapWidget() override;
0085 
0086 // --------------------------------------------------
0087 
0088 /// @name Settings Management related functions
0089 //@{
0090 
0091 public:
0092 
0093     void saveSettingsToGroup(KConfigGroup* const group);
0094     void readSettingsFromGroup(const KConfigGroup* const group);
0095 
0096 protected Q_SLOTS:
0097 
0098     void slotItemDisplaySettingsChanged();
0099 
0100 private Q_SLOTS:
0101 
0102     void slotApplySettings();
0103 //@}
0104 
0105 // --------------------------------------------------
0106 
0107 /// @name Map related functions
0108 //@{
0109 
0110 public:
0111 
0112     QStringList availableBackends() const;
0113     bool setBackend(const QString& backendName);
0114 
0115     QList<MapBackend*> backends() const;
0116 
0117     GeoCoordinates getCenter() const;
0118     void setCenter(const GeoCoordinates& coordinate);
0119 
0120     void setZoom(const QString& newZoom);
0121     QString getZoom();
0122 
0123     /**
0124      * @brief Adjusts the visible map area such that all grouped markers are visible.
0125      *
0126      * Note that a call to this function currently has no effect if the widget has been
0127      * set inactive via setActive() or the backend is not yet ready.
0128      *
0129      * @param useSaneZoomLevel Stop zooming at a sane level, if markers are too close together.
0130      */
0131     void adjustBoundariesToGroupedMarkers(const bool useSaneZoomLevel = true);
0132     void refreshMap();
0133 
0134     void setRegionSelection(const GeoCoordinates::Pair& region);
0135     GeoCoordinates::Pair getRegionSelection();
0136     void clearRegionSelection();
0137 
0138     void updateMarkers();
0139     void updateClusters();
0140     void markClustersAsDirty();
0141 
0142     QPixmap getDecoratedPixmapForCluster(const int clusterId, const GeoGroupState* const selectedStateOverride,
0143                                          const int* const countOverride, QPoint* const centerPoint);
0144     QVariant getClusterRepresentativeMarker(const int clusterIndex, const int sortKey);
0145 
0146 protected:
0147 
0148     bool currentBackendReady() const;
0149     void applyCacheToBackend();
0150     void saveBackendToCache();
0151     void setShowPlaceholderWidget(const bool state);
0152 
0153     /**
0154      * @brief Set @p widgetForFrame as the widget in the frame, but does not show it.
0155      */
0156     void setMapWidgetInFrame(QWidget* const widgetForFrame);
0157 
0158     void removeMapWidgetFromFrame();
0159 
0160 public Q_SLOTS:
0161 
0162     void slotClustersNeedUpdating();
0163 
0164 protected Q_SLOTS:
0165 
0166     void slotBackendReadyChanged(const QString& backendName);
0167     void slotChangeBackend(QAction* action);
0168     void slotBackendZoomChanged(const QString& newZoom);
0169     void slotClustersMoved(const QIntList& clusterIndices, const QPair<int, QModelIndex>& snapTarget);
0170     void slotClustersClicked(const QIntList& clusterIndices);
0171 
0172     /**
0173      * @brief Helper function to buffer reclustering
0174      */
0175     void slotLazyReclusteringRequestCallBack();
0176 
0177     /**
0178      * @brief Request reclustering, repeated calls should generate only one actual update of the clusters
0179      */
0180     void slotRequestLazyReclustering();
0181 
0182     void slotRemoveCurrentRegionSelection();
0183     void slotNewSelectionFromMap(const Digikam::GeoCoordinates::Pair& sel);
0184 
0185 Q_SIGNALS:
0186 
0187     void signalRegionSelectionChanged();
0188 //@}
0189 
0190 // --------------------------------------------------
0191 
0192 /// @name Data Management
0193 //@{
0194 
0195 public:
0196 
0197     void addUngroupedModel(GeoModelHelper* const modelHelper);
0198     void removeUngroupedModel(GeoModelHelper* const modelHelper);
0199     void setGroupedModel(AbstractMarkerTiler* const markerModel);
0200     void setDragDropHandler(GeoDragDropHandler* const dragDropHandler);
0201     void setTrackManager(TrackManager* const trackManager);
0202 
0203 protected Q_SLOTS:
0204 
0205     void slotUngroupedModelChanged();
0206 
0207 Q_SIGNALS:
0208 
0209     void signalLoadTracksFromAlbums();
0210     void signalUngroupedModelChanged(const int index);
0211 //@}
0212 
0213 // --------------------------------------------------
0214 
0215 /// @name UI setup
0216 //@{
0217 
0218 public:
0219 
0220     QAction* getControlAction(const QString& actionName);
0221 
0222     /**
0223      * @brief Returns the control widget instance.
0224      */
0225     QWidget* getControlWidget();
0226 
0227     void addWidgetToControlWidget(QWidget* const newWidget);
0228     void setSortOptionsMenu(QMenu* const sortMenu);
0229     void setMouseMode(const GeoMouseModes mouseMode);
0230     void setAvailableMouseModes(const GeoMouseModes mouseModes);
0231     void setVisibleMouseModes(const GeoMouseModes mouseModes);
0232     void setAllowModifications(const bool state);
0233     void setActive(const bool state);
0234     bool getActiveState();
0235     bool getStickyModeState() const;
0236     void setStickyModeState(const bool state);
0237     void setVisibleExtraActions(const GeoExtraActions actions);
0238     void setEnabledExtraActions(const GeoExtraActions actions);
0239 
0240 public Q_SLOTS:
0241 
0242     void slotUpdateActionsEnabled();
0243     void slotStickyModeChanged();
0244 
0245 protected Q_SLOTS:
0246 
0247     void slotMouseModeChanged(QAction* triggeredAction);
0248 
0249 protected:
0250 
0251     void rebuildConfigurationMenu();
0252     void createActions();
0253     void createActionsForBackendSelection();
0254 
0255     void dropEvent(QDropEvent* event)           override;
0256     void dragMoveEvent(QDragMoveEvent* event)   override;
0257     void dragEnterEvent(QDragEnterEvent* event) override;
0258     void dragLeaveEvent(QDragLeaveEvent* event) override;
0259 
0260 Q_SIGNALS:
0261 
0262     void signalMouseModeChanged(const Digikam::GeoMouseModes& currentMouseMode);
0263 //@}
0264 
0265 // --------------------------------------------------
0266 
0267 /// @name Appearance
0268 //@{
0269 
0270 public:
0271 
0272     void setSortKey(const int sortKey);
0273     void setThumnailSize(const int newThumbnailSize);
0274     void setThumbnailGroupingRadius(const int newGroupingRadius);
0275     void setMarkerGroupingRadius(const int newGroupingRadius);
0276     int  getThumbnailSize() const;
0277     int  getUndecoratedThumbnailSize() const;
0278     void setShowThumbnails(const bool state);
0279 
0280     QString convertZoomToBackendZoom(const QString& someZoom, const QString& targetBackend) const;
0281 
0282     /**
0283      * @brief Return color and style information for rendering the cluster
0284      * @param clusterIndex Index of the cluster
0285      * @param fillColor Color used to fill the circle
0286      * @param strokeColor Color used for the stroke around the circle
0287      * @param strokeStyle Style used to draw the stroke around the circle
0288      * @param labelText Text for the label
0289      * @param labelColor Color for the label text
0290      * @param overrideSelection Get the colors for a different selection state
0291      * @param overrideCount Get the colors for a different amount of markers
0292      */
0293     void getColorInfos(const int clusterIndex, QColor* fillColor, QColor* strokeColor,
0294                        Qt::PenStyle* strokeStyle, QString* labelText, QColor* labelColor,
0295                        const GeoGroupState* const overrideSelection = nullptr,
0296                        const int* const overrideCount = nullptr) const;
0297 
0298     void getColorInfos(const GeoGroupState groupState,
0299                        const int nMarkers,
0300                        QColor* fillColor, QColor* strokeColor,
0301                        Qt::PenStyle* strokeStyle, QString* labelText, QColor* labelColor) const;
0302 
0303 public Q_SLOTS:
0304 
0305     void slotZoomIn();
0306     void slotZoomOut();
0307     void slotDecreaseThumbnailSize();
0308     void slotIncreaseThumbnailSize();
0309     void stopThumbnailTimer();
0310 
0311 protected Q_SLOTS:
0312 
0313     void slotShowThumbnailsChanged();
0314 
0315 Q_SIGNALS:
0316 
0317     void signalRemoveCurrentFilter();
0318     void signalStickyModeChanged();
0319 //@}
0320 
0321 // --------------------------------------------------
0322 
0323 private:
0324 
0325     const QExplicitlySharedDataPointer<GeoIfaceSharedData> s;
0326 
0327     class Private;
0328     Private* const                                         d;
0329 
0330     Q_DISABLE_COPY(MapWidget)
0331 };
0332 
0333 } // namespace Digikam
0334 
0335 #endif // DIGIKAM_MAP_WIDGET_H