1 /* ============================================================
2  *
3  * This file is a part of digiKam project
4  * https://www.digikam.org
5  *
6  * Date        : 2010-07-14
7  * Description : Common internal data structures for geolocation interface
8  *
9  * Copyright (C) 2010-2021 by Gilles Caulier <caulier dot gilles at gmail dot com>
10  * Copyright (C) 2010-2014 by Michael G. Hansen <mike at mghansen dot de>
11  * Copyright (C)      2014 by Justus Schwartz <justus at gmx dot li>
12  *
13  * This program is free software; you can redistribute it
14  * and/or modify it under the terms of the GNU General
15  * Public License as published by the Free Software Foundation;
16  * either version 2, or (at your option)
17  * any later version.
18  *
19  * This program is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU General Public License for more details.
23  *
24  * ============================================================ */
25 
26 #ifndef DIGIKAM_GEO_IFACE_COMMON_H
27 #define DIGIKAM_GEO_IFACE_COMMON_H
28 
29 // Qt includes
30 
31 #include <QFlags>
32 #include <QPoint>
33 #include <QPointer>
34 #include <QSharedData>
35 #include <QSize>
36 #include <QWidget>
37 #include <QPixmap>
38 
39 // Local includes
40 
41 #include "geoifacetypes.h"
42 #include "tileindex.h"
43 #include "groupstatecomputer.h"
44 #include "digikam_export.h"
45 
46 namespace Digikam
47 {
48 class MapWidget;
49 class AbstractMarkerTiler;
50 class TileGrouper;
51 class TrackManager;
52 class MapBackend;
53 class GeoModelHelper;
54 
55 /**
56  * @brief Class to hold information about map widgets stored in the GeoIfaceGlobalObject
57  *
58  * @todo The list of these info structures has to be cleaned up periodically
59  */
60 class DIGIKAM_EXPORT GeoIfaceInternalWidgetInfo
61 {
62 public:
63 
64     typedef void (*DeleteFunction)(GeoIfaceInternalWidgetInfo* const info);
65 
66     enum InternalWidgetState
67     {
68         InternalWidgetReleased    = 1,
69         InternalWidgetUndocked    = 2,
70         InternalWidgetStillDocked = 4
71     };
72 
73     // cppcheck-suppress unknownMacro
Q_DECLARE_FLAGS(InternalWidgetStates,InternalWidgetState)74     Q_DECLARE_FLAGS(InternalWidgetStates, InternalWidgetState)
75 
76     GeoIfaceInternalWidgetInfo()
77         : state         (),
78           widget        (),
79           backendData   (),
80           backendName   (),
81           currentOwner  (nullptr),
82           deleteFunction(nullptr)
83     {
84     }
85 
86 public:
87 
88     InternalWidgetStates state;
89     QPointer<QWidget>    widget;
90     QVariant             backendData;
91     QString              backendName;
92     QPointer<QObject>    currentOwner;
93     DeleteFunction       deleteFunction;
94 };
95 
Q_DECLARE_OPERATORS_FOR_FLAGS(GeoIfaceInternalWidgetInfo::InternalWidgetStates)96 Q_DECLARE_OPERATORS_FOR_FLAGS(GeoIfaceInternalWidgetInfo::InternalWidgetStates)
97 
98 // ----------------------------------------------------------------------------------------------
99 
100 /**
101  * @brief Global object for geolocation interface to hold items common to all
102  * geolocation interface Widget instances
103  */
104 class DIGIKAM_EXPORT GeoIfaceGlobalObject : public QObject
105 {
106     Q_OBJECT
107 
108 public:
109 
110     static GeoIfaceGlobalObject* instance();
111 
112     /// @name Shared pixmaps
113     //@{
114     QPixmap getMarkerPixmap(const QString& pixmapId);
115     QPixmap getStandardMarkerPixmap();
116     QUrl    locateDataFile(const QString& filename);
117     //@}
118 
119     /// @name Shared internal map widgets
120     //@{
121     void removeMyInternalWidgetFromPool(const MapBackend* const mapBackend);
122     bool getInternalWidgetFromPool(const MapBackend* const mapBackend, GeoIfaceInternalWidgetInfo* const targetInfo);
123     void addMyInternalWidgetToPool(const GeoIfaceInternalWidgetInfo& info);
124     void updatePooledWidgetState(const QWidget* const widget, const GeoIfaceInternalWidgetInfo::InternalWidgetState newState);
125     void clearWidgetPool();
126     //@}
127 
128 private:
129 
130     // Disable
131     explicit GeoIfaceGlobalObject(QObject*) = delete;
132     GeoIfaceGlobalObject();
133     ~GeoIfaceGlobalObject() override;
134 
135     Q_DISABLE_COPY(GeoIfaceGlobalObject)
136 
137 private:
138 
139     class Private;
140     Private* const d;
141 
142     friend class GeoIfaceGlobalObjectCreator;
143 };
144 
145 // ----------------------------------------------------------------------------------------------
146 
147 class DIGIKAM_EXPORT GeoIfaceCluster
148 {
149 
150 public:
151 
152     enum PixmapType
153     {
154         PixmapMarker,
155         PixmapCircle,
156         PixmapImage
157     } pixmapType;
158 
159     typedef QList<GeoIfaceCluster> List;
160 
161 public:
162 
GeoIfaceCluster()163     GeoIfaceCluster()
164         : pixmapType            (PixmapMarker),
165           tileIndicesList       (),
166           markerCount           (0),
167           markerSelectedCount   (0),
168           coordinates           (),
169           pixelPos              (),
170           groupState            (SelectedNone),
171           representativeMarkers (),
172           pixmapSize            (),
173           pixmapOffset          ()
174     {
175     }
176 
177     QList<TileIndex>    tileIndicesList;
178     int                 markerCount;
179     int                 markerSelectedCount;
180     GeoCoordinates      coordinates;
181     QPoint              pixelPos;
182     GeoGroupState       groupState;
183     QMap<int, QVariant> representativeMarkers;
184 
185     QSize               pixmapSize;
186 
187     /// anchor point of the image, measured from bottom-left
188     QPoint              pixmapOffset;
189 };
190 
191 // ----------------------------------------------------------------------------------------------
192 
193 /// @todo Move these somewhere else
194 const int GeoIfaceMinMarkerGroupingRadius    = 1;
195 const int GeoIfaceMinThumbnailGroupingRadius = 15;
196 const int GeoIfaceMinThumbnailSize           = GeoIfaceMinThumbnailGroupingRadius * 2;
197 
198 // ----------------------------------------------------------------------------------------------
199 
200 /**
201  * @brief Helper function, returns the square of the distance between two points
202  * @todo Move this function somewhere else
203  *
204  * @param a Point a
205  * @param b Point b
206  * @return Square of the distance between a and b
207  */
208 DIGIKAM_EXPORT int QPointSquareDistance(const QPoint& a, const QPoint& b);
209 
210 // ----------------------------------------------------------------------------------------------
211 
212 class DIGIKAM_EXPORT GeoIfaceSharedData : public QSharedData
213 {
214 public:
215 
GeoIfaceSharedData()216     GeoIfaceSharedData()
217         : QSharedData               (),
218           worldMapWidget            (nullptr),
219           tileGrouper               (nullptr),
220           markerModel               (nullptr),
221           clusterList               (),
222           trackManager              (nullptr),
223           showThumbnails            (true),
224           thumbnailSize             (GeoIfaceMinThumbnailSize),
225           thumbnailGroupingRadius   (GeoIfaceMinThumbnailGroupingRadius),
226           markerGroupingRadius      (GeoIfaceMinMarkerGroupingRadius),
227           previewSingleItems        (true),
228           previewGroupedItems       (true),
229           showNumbersOnItems        (true),
230           sortKey                   (0),
231           modificationsAllowed      (true),
232           selectionRectangle        (),
233           haveMovingCluster         (false),
234           currentMouseMode          (),
235           availableMouseModes       (),
236           visibleMouseModes         (),
237           activeState               (false)
238     {
239     }
240 
241     /// @todo De-inline?
hasRegionSelection()242     bool hasRegionSelection() const
243     {
244         return selectionRectangle.first.hasCoordinates();
245     }
246 
247 public:
248 
249     /// @name Objects
250     //@{
251     MapWidget*                worldMapWidget;
252     TileGrouper*              tileGrouper;
253     AbstractMarkerTiler*      markerModel;
254     GeoIfaceCluster::List     clusterList;
255     QList<GeoModelHelper*>    ungroupedModels;
256     TrackManager*             trackManager;
257     //@}
258 
259     /// @name Display options
260     //@{
261     bool                      showThumbnails;
262     int                       thumbnailSize;
263     int                       thumbnailGroupingRadius;
264     int                       markerGroupingRadius;
265     bool                      previewSingleItems;
266     bool                      previewGroupedItems;
267     bool                      showNumbersOnItems;
268     int                       sortKey;
269     bool                      modificationsAllowed;
270     //@}
271 
272     /// @name Current map state
273     //@{
274     GeoCoordinates::Pair      selectionRectangle;
275     bool                      haveMovingCluster;
276     GeoMouseModes             currentMouseMode;
277     GeoMouseModes             availableMouseModes;
278     GeoMouseModes             visibleMouseModes;
279     bool                      activeState;
280     //@}
281 };
282 
283 // ----------------------------------------------------------------------------------------------
284 
285 /// helper functions
286 
287 DIGIKAM_EXPORT bool GeoIfaceHelperParseLatLonString(const QString& latLonString,
288                                                     GeoCoordinates* const coordinates);
289 
290 DIGIKAM_EXPORT bool GeoIfaceHelperParseXYStringToPoint(const QString& xyString,
291                                                        QPoint* const point);
292 
293 DIGIKAM_EXPORT bool GeoIfaceHelperParseBoundsString(const QString& boundsString,
294                                                     QPair<GeoCoordinates, GeoCoordinates>* const boundsCoordinates);
295 
296 DIGIKAM_EXPORT GeoCoordinates::PairList GeoIfaceHelperNormalizeBounds(const GeoCoordinates::Pair& boundsPair);
297 
298 DIGIKAM_EXPORT void GeoIface_assert(const char* const condition,
299                                     const char* const filename,
300                                     const int lineNumber);
301 
302 } // namespace Digikam
303 
304 #define GEOIFACE_ASSERT(cond) ((!(cond)) ? Digikam::GeoIface_assert(#cond,__FILE__,__LINE__) : qt_noop())
305 
306 #endif // DIGIKAM_GEO_IFACE_COMMON_H
307