1 /*
2  *    Copyright 2012, 2013 Thomas Schöps
3  *    Copyright 2012-2015 Kai Pastor
4  *
5  *    This file is part of OpenOrienteering.
6  *
7  *    OpenOrienteering is free software: you can redistribute it and/or modify
8  *    it under the terms of the GNU General Public License as published by
9  *    the Free Software Foundation, either version 3 of the License, or
10  *    (at your option) any later version.
11  *
12  *    OpenOrienteering is distributed in the hope that it will be useful,
13  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *    GNU General Public License for more details.
16  *
17  *    You should have received a copy of the GNU General Public License
18  *    along with OpenOrienteering.  If not, see <http://www.gnu.org/licenses/>.
19  */
20 
21 
22 #ifndef OPENORIENTEERING_GEOREFERENCING_DIALOG_H
23 #define OPENORIENTEERING_GEOREFERENCING_DIALOG_H
24 
25 #include <vector>
26 
27 #include <QDialog>
28 #include <QObject>
29 #include <QScopedPointer>
30 #include <QString>
31 
32 #include "core/map_coord.h"
33 #include "tools/tool.h"
34 
35 class QAction;
36 class QCursor;
37 class QCheckBox;
38 class QDialogButtonBox;
39 class QDoubleSpinBox;
40 class QLabel;
41 class QMouseEvent;
42 class QPushButton;
43 class QRadioButton;
44 class QNetworkReply;
45 class QWidget;
46 
47 namespace OpenOrienteering {
48 
49 class CRSSelector;
50 class Georeferencing;
51 class Map;
52 class MapEditorController;
53 class MapWidget;
54 
55 
56 /**
57  * A GeoreferencingDialog allows the user to adjust the georeferencing properties
58  * of a map.
59  */
60 class GeoreferencingDialog : public QDialog
61 {
62 Q_OBJECT
63 public:
64 	/**
65 	 * Constructs a new georeferencing dialog for the map handled by the given
66 	 * controller. The optional parameter initial allows to override the current
67 	 * properties of the map's georeferencing. The parameter
68 	 * allow_no_georeferencing determines if the okay button can
69 	 * be clicked while "- none -" is selected.
70 	 */
71 	GeoreferencingDialog(MapEditorController* controller, const Georeferencing* initial = nullptr, bool allow_no_georeferencing = true);
72 
73 	/**
74 	 * Constructs a new georeferencing dialog for the given map. The optional
75 	 * parameter initial allows to override the current properties of the map's
76 	 * georeferencing. Since the dialog will not know a MapEditorController,
77 	 * it will not allow to select a new reference point from the map.
78 	 * The parameter allow_no_georeferencing determines if the okay button can
79 	 * be clicked while "- none -" is selected.
80 	 */
81 	GeoreferencingDialog(QWidget* parent, Map* map, const Georeferencing* initial = nullptr, bool allow_no_georeferencing = true);
82 
83 protected:
84 	/**
85 	 * Constructs a new georeferencing dialog.
86 	 *
87 	 * The map parameter must not be nullptr, and it must not be a different
88 	 * map than the one handled by controller.
89 	 *
90 	 * @param parent                  A parent widget.
91 	 * @param controller              A controller which operates on the map.
92 	 * @param map                     The map.
93 	 * @param initial                 An override of the map's georeferencing
94 	 * @param allow_no_georeferencing Determines if the okay button can be
95 	 *                                be clicked while "- none -" is selected.
96 	 */
97 	GeoreferencingDialog(
98 	        QWidget* parent,
99 	        MapEditorController* controller,
100 	        Map* map,
101 	        const Georeferencing* initial,
102 	        bool allow_no_georeferencing
103 	);
104 
105 public:
106 	/**
107 	 * Releases resources.
108 	 */
109 	~GeoreferencingDialog() override;
110 
111 
112 	/**
113 	 * Updates the dialog from georeferencing state changes.
114 	 */
115 	void georefStateChanged();
116 
117 	/**
118 	  * Moves transformation properties from the georeferencing to the widgets.
119 	  */
120 	void transformationChanged();
121 
122 	/**
123 	  * Moves projection properties from the georeferencing to the widgets.
124 	  */
125 	void projectionChanged();
126 
127 	/**
128 	  * Updates the declination widget from the georeferencing.
129 	  */
130 	void declinationChanged();
131 
132 	/**
133 	  * Updates the scale factor widget from the georeferencing.
134 	  */
135 	void auxiliaryFactorChanged();
136 
137 	/**
138 	  * Sets visibility of scale compensation widgets.
139 	  */
140 	void showScaleChanged(bool checked);
141 
142 	/**
143 	 * Triggers an online request for the magnetic declination.
144 	 *
145 	 * @param no_confirm If true, the user will not be asked for confirmation.
146 	 */
147 	void requestDeclination(bool no_confirm = false);
148 
149 	/**
150 	 * Sets the map coordinates of the reference point
151 	 */
152 	void setMapRefPoint(const MapCoord& coords);
153 
154 	/**
155 	 * Activates the "keep projected reference point coordinates on CRS changes" radio button.
156 	 */
157 	void setKeepProjectedRefCoords();
158 
159 	/**
160 	 * Activates the "keep geographic reference point coordinates on CRS changes" radio button.
161 	 */
162 	void setKeepGeographicRefCoords();
163 
164 	/**
165 	 * Notifies the dialog that the active GeoreferencingTool was deleted.
166 	 */
167 	void toolDeleted();
168 
169 	/**
170 	 * Opens this dialog's help page.
171 	 */
172 	void showHelp();
173 
174 	/**
175 	 * Resets all input fields to the values in the map's Georeferencing.
176 	 *
177 	 * This will also reset initial values passed to the constructor.
178 	 */
179 	void reset();
180 
181 	/**
182 	 * Pushes the changes from the dialog to the map's Georeferencing
183 	 * and closes the dialog. The dialog's result is set to QDialog::Accepted,
184 	 * and the active exec() function will return.
185 	 */
186 	void accept() override;
187 
188 protected:
189 	/**
190 	 * Updates enabled / disabled states of all widgets.
191 	 */
192 	void updateWidgets();
193 
194 	/**
195 	 * Updates enabled / disabled state and text of the declination query button.
196 	 */
197 	void updateDeclinationButton();
198 
199 
200 	/**
201 	 * Notifies the dialog of a change in the CRS configuration.
202 	 */
203 	void crsEdited();
204 
205 	/**
206 	 * Notifies the dialog of a change in the auxiliary scale factor.
207 	 */
208 	void auxiliaryFactorEdited(double value);
209 
210 	/**
211 	 * Updates the combined scale factor field from the underlying Georeferencing.
212 	 */
213 	void updateCombinedFactor();
214 
215 	/**
216 	 * Hides the dialog and activates a GeoreferencingTool for selecting
217 	 * the reference point on the map.
218 	 */
219 	void selectMapRefPoint();
220 
221 	/**
222 	 * Notifies the dialog of a change in the map reference point fields.
223 	 */
224 	void mapRefChanged();
225 
226 	/**
227 	 * Notifies the dialog of a change in the easting / northing fields.
228 	 */
229 	void eastingNorthingEdited();
230 
231 	/**
232 	 * Notifies the dialog of change of the keep-coords buttons.
233 	 */
234 	void keepCoordsChanged();
235 
236 	/**
237 	 * Notifies the dialog of a change in the latitude / longitude fields.
238 	 */
239 	void latLonEdited();
240 
241 	/**
242 	 * Notifies the dialog of a change in the declination field.
243 	 */
244 	void declinationEdited(double value);
245 
246 	/**
247 	 * Handles replies from the online declination service.
248 	 */
249 	void declinationReplyFinished(QNetworkReply* reply);
250 
251 	/**
252 	 * Updates the grivation field from the underlying Georeferencing.
253 	 */
254 	void updateGrivation();
255 
256 private:
257 	/* Internal state */
258 	MapEditorController* const controller;
259 	Map* const map;
260 	const Georeferencing* initial_georef;
261 	QScopedPointer<Georeferencing> georef; // A working copy of the current or given initial Georeferencing
262 	bool allow_no_georeferencing;
263 	bool tool_active;
264 	bool declination_query_in_progress;
265 	bool grivation_locked;
266 	bool scale_factor_locked;
267 
268 	/* GUI elements */
269 	CRSSelector* crs_selector;
270 	QLabel* status_label;
271 	QLabel* status_field;
272 
273 	QDoubleSpinBox* map_x_edit;
274 	QDoubleSpinBox* map_y_edit;
275 	QPushButton* ref_point_button;
276 
277 	QLabel* projected_ref_label;
278 	QDoubleSpinBox* easting_edit;
279 	QDoubleSpinBox* northing_edit;
280 
281 	QDoubleSpinBox* lat_edit;
282 	QDoubleSpinBox* lon_edit;
283 	QLabel* show_refpoint_label;
284 	QLabel* link_label;
285 
286 	QRadioButton* keep_projected_radio;
287 	QRadioButton* keep_geographic_radio;
288 
289 	QDoubleSpinBox* declination_edit;
290 	QPushButton* declination_button;
291 	QLabel* grivation_label;
292 
293 	QCheckBox* show_scale_check;
294 	std::vector<QWidget*> scale_widget_list;
295 	QDoubleSpinBox* scale_factor_edit;
296 	QLabel* combined_factor_display;
297 
298 	QDialogButtonBox* buttons_box;
299 	QPushButton* reset_button;
300 };
301 
302 
303 
304 /**
305  * GeoreferencingTool is a helper to the GeoreferencingDialog which allows
306  * the user to select the position of the reference point on the map
307  * The GeoreferencingDialog hides when it activates this tool. The tool
308  * takes care of reactivating the dialog.
309  */
310 class GeoreferencingTool : public MapEditorTool
311 {
312 Q_OBJECT
313 public:
314 	/**
315 	 * Constructs a new tool for the given dialog and controller.
316 	 */
317 	GeoreferencingTool(
318 	        GeoreferencingDialog* dialog,
319 	        MapEditorController* controller,
320 	        QAction* action = nullptr
321 	);
322 
323 	/**
324 	 * Notifies the dialog that the tool is deleted.
325 	 */
326 	~GeoreferencingTool() override;
327 
328 	/**
329 	 * Activates the tool.
330 	 */
331 	void init() override;
332 
333 	/**
334 	 * Consumes left and right clicks. They are handled in mouseReleaseEvent.
335 	 */
336 	bool mousePressEvent(QMouseEvent* event, const MapCoordF& map_coord, MapWidget* widget) override;
337 
338 	/**
339 	 * Reacts to the user activity by sending the reference point coordinates
340 	 * to the dialog (on left click) and reactivating the dialog.
341 	 */
342 	bool mouseReleaseEvent(QMouseEvent* event, const MapCoordF& map_coord, MapWidget* widget) override;
343 
344 	/**
345 	 * Returns the mouse cursor that will be shown when the tool is active.
346 	 */
347 	const QCursor& getCursor() const override;
348 
349 private:
350 	GeoreferencingDialog* const dialog;
351 };
352 
353 
354 }  // namespace OpenOrienteering
355 
356 #endif
357