Added option to surpress error messages
[GPXSee.git] / src / GUI / gui.cpp
blob9de1c3d8889dae18b5e0bc011b9d41b68a41ea3d
1 #include <QApplication>
2 #include <QSplitter>
3 #include <QVBoxLayout>
4 #include <QMenuBar>
5 #include <QStatusBar>
6 #include <QMessageBox>
7 #include <QCheckBox>
8 #include <QFileDialog>
9 #include <QPrintDialog>
10 #include <QPainter>
11 #include <QPaintEngine>
12 #include <QPaintDevice>
13 #include <QKeyEvent>
14 #include <QMenu>
15 #include <QToolBar>
16 #include <QTabWidget>
17 #include <QActionGroup>
18 #include <QAction>
19 #include <QLabel>
20 #include <QSettings>
21 #include <QLocale>
22 #include <QMimeData>
23 #include <QUrl>
24 #include <QPixmapCache>
25 #include <QWindow>
26 #include <QScreen>
27 #include <QStyle>
28 #include <QTabBar>
29 #include <QGeoPositionInfoSource>
30 #include "common/config.h"
31 #include "common/programpaths.h"
32 #include "common/downloader.h"
33 #include "data/data.h"
34 #include "data/poi.h"
35 #include "data/demloader.h"
36 #include "map/maplist.h"
37 #include "map/emptymap.h"
38 #include "map/crs.h"
39 #include "icons.h"
40 #include "keys.h"
41 #include "settings.h"
42 #include "elevationgraph.h"
43 #include "speedgraph.h"
44 #include "heartrategraph.h"
45 #include "temperaturegraph.h"
46 #include "cadencegraph.h"
47 #include "powergraph.h"
48 #include "gearratiograph.h"
49 #include "mapview.h"
50 #include "trackinfo.h"
51 #include "filebrowser.h"
52 #include "graphtab.h"
53 #include "graphitem.h"
54 #include "pathitem.h"
55 #include "mapitem.h"
56 #include "mapaction.h"
57 #include "poiaction.h"
58 #include "navigationwidget.h"
59 #include "gui.h"
62 #define TOOLBAR_ICON_SIZE 22
64 GUI::GUI()
66 QString activeMap;
67 QStringList disabledPOIs;
69 _poi = new POI(this);
70 _dem = new DEMLoader(ProgramPaths::demDir(true), this);
71 connect(_dem, &DEMLoader::finished, this, &GUI::demLoaded);
73 createMapView();
74 createGraphTabs();
75 createStatusBar();
76 createActions();
77 createMenus();
78 #ifdef Q_OS_ANDROID
79 createNavigation();
80 #else // Q_OS_ANDROID
81 createToolBars();
82 #endif // Q_OS_ANDROID
83 createBrowser();
85 _splitter = new QSplitter();
86 _splitter->setOrientation(Qt::Vertical);
87 _splitter->setChildrenCollapsible(false);
88 _splitter->addWidget(_mapView);
89 _splitter->addWidget(_graphTabWidget);
90 _splitter->setContentsMargins(0, 0, 0, 0);
91 _splitter->setStretchFactor(0, 255);
92 _splitter->setStretchFactor(1, 1);
94 setCentralWidget(_splitter);
96 setWindowIcon(QIcon(APP_ICON));
97 setWindowTitle(APP_NAME);
98 setUnifiedTitleAndToolBarOnMac(true);
99 setAcceptDrops(true);
101 _trackCount = 0;
102 _routeCount = 0;
103 _waypointCount = 0;
104 _areaCount = 0;
105 _trackDistance = 0;
106 _routeDistance = 0;
107 _time = 0;
108 _movingTime = 0;
109 _lastTab = 0;
111 readSettings(activeMap, disabledPOIs);
113 loadInitialMaps(activeMap);
114 loadInitialPOIs(disabledPOIs);
116 updateGraphTabs();
117 updateStatusBarInfo();
120 void GUI::createBrowser()
122 _browser = new FileBrowser(this);
123 _browser->setFilter(Data::filter());
124 connect(_browser, &FileBrowser::listChanged, this,
125 &GUI::updateNavigationActions);
128 TreeNode<MapAction*> GUI::createMapActionsNode(const TreeNode<Map*> &node)
130 TreeNode<MapAction*> tree(node.name());
132 for (int i = 0; i < node.childs().size(); i++)
133 tree.addChild(createMapActionsNode(node.childs().at(i)));
135 for (int i = 0; i < node.items().size(); i++) {
136 Map *map = node.items().at(i);
137 if (map->isValid()) {
138 MapAction *a = new MapAction(map, _mapsActionGroup);
139 connect(a, &MapAction::loaded, this, &GUI::mapInitialized);
140 tree.addItem(a);
141 } else
142 delete map;
145 return tree;
148 void GUI::mapInitialized()
150 MapAction *action = static_cast<MapAction*>(QObject::sender());
151 Map *map = action->data().value<Map*>();
153 if (map->isValid()) {
154 if (!_mapsActionGroup->checkedAction())
155 action->trigger();
156 _showMapAction->setEnabled(true);
157 _clearMapCacheAction->setEnabled(true);
158 } else {
159 qWarning("%s: %s", qPrintable(map->path()), qPrintable(map->errorString()));
160 action->deleteLater();
164 TreeNode<POIAction *> GUI::createPOIActionsNode(const TreeNode<QString> &node)
166 TreeNode<POIAction*> tree(node.name());
168 for (int i = 0; i < node.childs().size(); i++)
169 tree.addChild(createPOIActionsNode(node.childs().at(i)));
170 for (int i = 0; i < node.items().size(); i++)
171 tree.addItem(new POIAction(node.items().at(i), _poisActionGroup));
173 return tree;
176 void GUI::createActions()
178 QActionGroup *ag;
180 // Action Groups
181 _fileActionGroup = new QActionGroup(this);
182 _fileActionGroup->setExclusive(false);
183 _fileActionGroup->setEnabled(false);
185 _navigationActionGroup = new QActionGroup(this);
186 _navigationActionGroup->setEnabled(false);
188 // General actions
189 #if !defined(Q_OS_MAC) && !defined(Q_OS_ANDROID)
190 _exitAction = new QAction(QIcon(QUIT_ICON), tr("Quit"), this);
191 _exitAction->setShortcut(QUIT_SHORTCUT);
192 _exitAction->setMenuRole(QAction::QuitRole);
193 connect(_exitAction, &QAction::triggered, this, &GUI::close);
194 addAction(_exitAction);
195 #endif // Q_OS_MAC + Q_OS_ANDROID
197 // Help & About
198 _pathsAction = new QAction(tr("Paths"), this);
199 _pathsAction->setMenuRole(QAction::NoRole);
200 connect(_pathsAction, &QAction::triggered, this, &GUI::paths);
201 #ifndef Q_OS_ANDROID
202 _keysAction = new QAction(tr("Keyboard controls"), this);
203 _keysAction->setMenuRole(QAction::NoRole);
204 connect(_keysAction, &QAction::triggered, this, &GUI::keys);
205 #endif // Q_OS_ANDROID
206 _aboutAction = new QAction(QIcon(APP_ICON), tr("About GPXSee"), this);
207 _aboutAction->setMenuRole(QAction::AboutRole);
208 connect(_aboutAction, &QAction::triggered, this, &GUI::about);
210 // File actions
211 _openFileAction = new QAction(QIcon(OPEN_FILE_ICON), tr("Open..."), this);
212 _openFileAction->setMenuRole(QAction::NoRole);
213 _openFileAction->setShortcut(OPEN_SHORTCUT);
214 connect(_openFileAction, &QAction::triggered, this,
215 QOverload<>::of(&GUI::openFile));
216 addAction(_openFileAction);
217 #ifdef Q_OS_ANDROID
218 _openDirAction = new QAction(QIcon(OPEN_FILE_ICON), tr("Open directory..."),
219 this);
220 _openDirAction->setMenuRole(QAction::NoRole);
221 connect(_openDirAction, &QAction::triggered, this, &GUI::openDir);
222 #endif // Q_OS_ANDROID
223 _printFileAction = new QAction(QIcon(PRINT_FILE_ICON), tr("Print..."),
224 this);
225 _printFileAction->setMenuRole(QAction::NoRole);
226 _printFileAction->setActionGroup(_fileActionGroup);
227 connect(_printFileAction, &QAction::triggered, this, &GUI::printFile);
228 addAction(_printFileAction);
229 _exportPDFFileAction = new QAction(QIcon(EXPORT_FILE_ICON),
230 tr("Export to PDF..."), this);
231 _exportPDFFileAction->setMenuRole(QAction::NoRole);
232 _exportPDFFileAction->setShortcut(PDF_EXPORT_SHORTCUT);
233 _exportPDFFileAction->setActionGroup(_fileActionGroup);
234 connect(_exportPDFFileAction, &QAction::triggered, this, &GUI::exportPDFFile);
235 addAction(_exportPDFFileAction);
236 _exportPNGFileAction = new QAction(QIcon(EXPORT_FILE_ICON),
237 tr("Export to PNG..."), this);
238 _exportPNGFileAction->setMenuRole(QAction::NoRole);
239 _exportPNGFileAction->setShortcut(PNG_EXPORT_SHORTCUT);
240 _exportPNGFileAction->setActionGroup(_fileActionGroup);
241 connect(_exportPNGFileAction, &QAction::triggered, this, &GUI::exportPNGFile);
242 addAction(_exportPNGFileAction);
243 _closeFileAction = new QAction(QIcon(CLOSE_FILE_ICON), tr("Close"), this);
244 _closeFileAction->setMenuRole(QAction::NoRole);
245 _closeFileAction->setShortcut(CLOSE_SHORTCUT);
246 _closeFileAction->setActionGroup(_fileActionGroup);
247 connect(_closeFileAction, &QAction::triggered, this, &GUI::closeAll);
248 addAction(_closeFileAction);
249 _reloadFileAction = new QAction(QIcon(RELOAD_FILE_ICON), tr("Reload"),
250 this);
251 _reloadFileAction->setMenuRole(QAction::NoRole);
252 _reloadFileAction->setShortcut(RELOAD_SHORTCUT);
253 _reloadFileAction->setActionGroup(_fileActionGroup);
254 connect(_reloadFileAction, &QAction::triggered, this, &GUI::reloadFiles);
255 addAction(_reloadFileAction);
256 _statisticsAction = new QAction(tr("Statistics..."), this);
257 _statisticsAction->setMenuRole(QAction::NoRole);
258 _statisticsAction->setShortcut(STATISTICS_SHORTCUT);
259 _statisticsAction->setActionGroup(_fileActionGroup);
260 connect(_statisticsAction, &QAction::triggered, this, &GUI::statistics);
261 addAction(_statisticsAction);
263 // POI actions
264 _poisActionGroup = new QActionGroup(this);
265 _poisActionGroup->setExclusive(false);
266 connect(_poisActionGroup, &QActionGroup::triggered, this,
267 &GUI::poiFileChecked);
268 _openPOIAction = new QAction(QIcon(OPEN_FILE_ICON), tr("Load POI file..."),
269 this);
270 _openPOIAction->setMenuRole(QAction::NoRole);
271 connect(_openPOIAction, &QAction::triggered, this,
272 QOverload<>::of(&GUI::openPOIFile));
273 _selectAllPOIAction = new QAction(tr("Select all files"), this);
274 _selectAllPOIAction->setMenuRole(QAction::NoRole);
275 _selectAllPOIAction->setEnabled(false);
276 connect(_selectAllPOIAction, &QAction::triggered, this,
277 &GUI::selectAllPOIs);
278 _unselectAllPOIAction = new QAction(tr("Unselect all files"), this);
279 _unselectAllPOIAction->setMenuRole(QAction::NoRole);
280 _unselectAllPOIAction->setEnabled(false);
281 connect(_unselectAllPOIAction, &QAction::triggered, this,
282 &GUI::unselectAllPOIs);
283 _overlapPOIAction = new QAction(tr("Overlap POIs"), this);
284 _overlapPOIAction->setMenuRole(QAction::NoRole);
285 _overlapPOIAction->setCheckable(true);
286 connect(_overlapPOIAction, &QAction::triggered, _mapView,
287 &MapView::showOverlappedPOIs);
288 _showPOIIconsAction = new QAction(tr("Show POI icons"), this);
289 _showPOIIconsAction->setMenuRole(QAction::NoRole);
290 _showPOIIconsAction->setCheckable(true);
291 connect(_showPOIIconsAction, &QAction::triggered, _mapView,
292 &MapView::showPOIIcons);
293 _showPOILabelsAction = new QAction(tr("Show POI labels"), this);
294 _showPOILabelsAction->setMenuRole(QAction::NoRole);
295 _showPOILabelsAction->setCheckable(true);
296 connect(_showPOILabelsAction, &QAction::triggered, _mapView,
297 &MapView::showPOILabels);
298 _showPOIAction = new QAction(QIcon(SHOW_POI_ICON), tr("Show POIs"), this);
299 _showPOIAction->setMenuRole(QAction::NoRole);
300 _showPOIAction->setCheckable(true);
301 _showPOIAction->setShortcut(SHOW_POI_SHORTCUT);
302 connect(_showPOIAction, &QAction::triggered, _mapView, &MapView::showPOI);
303 addAction(_showPOIAction);
305 // Map actions
306 _mapsActionGroup = new QActionGroup(this);
307 _mapsActionGroup->setExclusive(true);
308 connect(_mapsActionGroup, &QActionGroup::triggered, this, &GUI::mapChanged);
309 _showMapAction = new QAction(QIcon(SHOW_MAP_ICON), tr("Show map"),
310 this);
311 _showMapAction->setEnabled(false);
312 _showMapAction->setMenuRole(QAction::NoRole);
313 _showMapAction->setCheckable(true);
314 _showMapAction->setShortcut(SHOW_MAP_SHORTCUT);
315 connect(_showMapAction, &QAction::triggered, _mapView,
316 &MapView::showMap);
317 addAction(_showMapAction);
318 _loadMapAction = new QAction(QIcon(OPEN_FILE_ICON), tr("Load map..."),
319 this);
320 _loadMapAction->setMenuRole(QAction::NoRole);
321 connect(_loadMapAction, &QAction::triggered, this,
322 QOverload<>::of(&GUI::loadMap));
323 _loadMapDirAction = new QAction(QIcon(OPEN_FILE_ICON),
324 tr("Load map directory..."), this);
325 _loadMapDirAction->setMenuRole(QAction::NoRole);
326 connect(_loadMapDirAction, &QAction::triggered, this, &GUI::loadMapDir);
327 _clearMapCacheAction = new QAction(tr("Clear tile cache"), this);
328 _clearMapCacheAction->setEnabled(false);
329 _clearMapCacheAction->setMenuRole(QAction::NoRole);
330 connect(_clearMapCacheAction, &QAction::triggered, this,
331 &GUI::clearMapCache);
332 _nextMapAction = new QAction(tr("Next map"), this);
333 _nextMapAction->setMenuRole(QAction::NoRole);
334 _nextMapAction->setShortcut(NEXT_MAP_SHORTCUT);
335 connect(_nextMapAction, &QAction::triggered, this, &GUI::nextMap);
336 addAction(_nextMapAction);
337 _prevMapAction = new QAction(tr("Next map"), this);
338 _prevMapAction->setMenuRole(QAction::NoRole);
339 _prevMapAction->setShortcut(PREV_MAP_SHORTCUT);
340 connect(_prevMapAction, &QAction::triggered, this, &GUI::prevMap);
341 addAction(_prevMapAction);
342 _showCoordinatesAction = new QAction(tr("Show cursor coordinates"), this);
343 _showCoordinatesAction->setMenuRole(QAction::NoRole);
344 _showCoordinatesAction->setCheckable(true);
345 connect(_showCoordinatesAction, &QAction::triggered, _mapView,
346 &MapView::showCursorCoordinates);
348 // Position
349 _showPositionAction = new QAction(QIcon(SHOW_POS_ICON),
350 tr("Show position"), this);
351 _showPositionAction->setMenuRole(QAction::NoRole);
352 _showPositionAction->setCheckable(true);
353 _showPositionAction->setEnabled(false);
354 connect(_showPositionAction, &QAction::triggered, _mapView,
355 &MapView::showPosition);
356 _followPositionAction = new QAction(tr("Follow position"), this);
357 _followPositionAction->setMenuRole(QAction::NoRole);
358 _followPositionAction->setCheckable(true);
359 connect(_followPositionAction, &QAction::triggered, _mapView,
360 &MapView::followPosition);
361 _showPositionCoordinatesAction = new QAction(tr("Show coordinates"),
362 this);
363 _showPositionCoordinatesAction->setMenuRole(QAction::NoRole);
364 _showPositionCoordinatesAction->setCheckable(true);
365 connect(_showPositionCoordinatesAction, &QAction::triggered, _mapView,
366 &MapView::showPositionCoordinates);
367 _showMotionInfoAction = new QAction(tr("Show motion info"), this);
368 _showMotionInfoAction->setMenuRole(QAction::NoRole);
369 _showMotionInfoAction->setCheckable(true);
370 connect(_showMotionInfoAction, &QAction::triggered, _mapView,
371 &MapView::showMotionInfo);
373 // Data actions
374 _showTracksAction = new QAction(tr("Show tracks"), this);
375 _showTracksAction->setMenuRole(QAction::NoRole);
376 _showTracksAction->setCheckable(true);
377 _showTracksAction->setShortcut(SHOW_TRACKS_SHORTCUT);
378 connect(_showTracksAction, &QAction::triggered, this, &GUI::showTracks);
379 _showRoutesAction = new QAction(tr("Show routes"), this);
380 _showRoutesAction->setMenuRole(QAction::NoRole);
381 _showRoutesAction->setCheckable(true);
382 connect(_showRoutesAction, &QAction::triggered, this, &GUI::showRoutes);
383 _showWaypointsAction = new QAction(tr("Show waypoints"), this);
384 _showWaypointsAction->setMenuRole(QAction::NoRole);
385 _showWaypointsAction->setCheckable(true);
386 connect(_showWaypointsAction, &QAction::triggered, this,
387 &GUI::showWaypoints);
388 _showAreasAction = new QAction(tr("Show areas"), this);
389 _showAreasAction->setMenuRole(QAction::NoRole);
390 _showAreasAction->setCheckable(true);
391 connect(_showAreasAction, &QAction::triggered, this, &GUI::showAreas);
392 _showWaypointIconsAction = new QAction(tr("Waypoint icons"), this);
393 _showWaypointIconsAction->setMenuRole(QAction::NoRole);
394 _showWaypointIconsAction->setCheckable(true);
395 connect(_showWaypointIconsAction, &QAction::triggered, _mapView,
396 &MapView::showWaypointIcons);
397 _showWaypointLabelsAction = new QAction(tr("Waypoint labels"), this);
398 _showWaypointLabelsAction->setMenuRole(QAction::NoRole);
399 _showWaypointLabelsAction->setCheckable(true);
400 connect(_showWaypointLabelsAction, &QAction::triggered, _mapView,
401 &MapView::showWaypointLabels);
402 _showRouteWaypointsAction = new QAction(tr("Route waypoints"), this);
403 _showRouteWaypointsAction->setMenuRole(QAction::NoRole);
404 _showRouteWaypointsAction->setCheckable(true);
405 connect(_showRouteWaypointsAction, &QAction::triggered, _mapView,
406 &MapView::showRouteWaypoints);
407 _showTicksAction = new QAction(tr("km/mi markers"), this);
408 _showTicksAction->setMenuRole(QAction::NoRole);
409 _showTicksAction->setCheckable(true);
410 connect(_showTicksAction, &QAction::triggered, _mapView,
411 &MapView::showTicks);
412 QActionGroup *markerInfoGroup = new QActionGroup(this);
413 connect(markerInfoGroup, &QActionGroup::triggered, this,
414 &GUI::showPathMarkerInfo);
415 _hideMarkersAction = new QAction(tr("Do not show"), this);
416 _hideMarkersAction->setMenuRole(QAction::NoRole);
417 _hideMarkersAction->setCheckable(true);
418 _hideMarkersAction->setActionGroup(markerInfoGroup);
419 _showMarkersAction = new QAction(tr("Marker only"), this);
420 _showMarkersAction->setMenuRole(QAction::NoRole);
421 _showMarkersAction->setCheckable(true);
422 _showMarkersAction->setActionGroup(markerInfoGroup);
423 _showMarkerDateAction = new QAction(tr("Date/time"), this);
424 _showMarkerDateAction->setMenuRole(QAction::NoRole);
425 _showMarkerDateAction->setCheckable(true);
426 _showMarkerDateAction->setActionGroup(markerInfoGroup);
427 _showMarkerCoordinatesAction = new QAction(tr("Coordinates"), this);
428 _showMarkerCoordinatesAction->setMenuRole(QAction::NoRole);
429 _showMarkerCoordinatesAction->setCheckable(true);
430 _showMarkerCoordinatesAction->setActionGroup(markerInfoGroup);
431 _useStylesAction = new QAction(tr("Use styles"), this);
432 _useStylesAction->setMenuRole(QAction::NoRole);
433 _useStylesAction->setCheckable(true);
434 connect(_useStylesAction, &QAction::triggered, _mapView,
435 &MapView::useStyles);
437 // DEM actions
438 _downloadDEMAction = new QAction(tr("Download DEM data"), this);
439 _downloadDEMAction->setMenuRole(QAction::NoRole);
440 _downloadDEMAction->setEnabled(false);
441 _downloadDEMAction->setShortcut(DOWNLOAD_DEM_SHORTCUT);
442 connect(_downloadDEMAction, &QAction::triggered, this, &GUI::downloadDEM);
443 _showDEMTilesAction = new QAction(tr("Show local DEM tiles"), this);
444 _showDEMTilesAction->setMenuRole(QAction::NoRole);
445 connect(_showDEMTilesAction, &QAction::triggered, this, &GUI::showDEMTiles);
447 // Graph actions
448 _showGraphsAction = new QAction(QIcon(SHOW_GRAPHS_ICON), tr("Show graphs"),
449 this);
450 _showGraphsAction->setMenuRole(QAction::NoRole);
451 _showGraphsAction->setCheckable(true);
452 _showGraphsAction->setShortcut(SHOW_GRAPHS_SHORTCUT);
453 connect(_showGraphsAction, &QAction::triggered, this, &GUI::showGraphs);
454 addAction(_showGraphsAction);
455 ag = new QActionGroup(this);
456 ag->setExclusive(true);
457 _distanceGraphAction = new QAction(tr("Distance"), this);
458 _distanceGraphAction->setMenuRole(QAction::NoRole);
459 _distanceGraphAction->setCheckable(true);
460 _distanceGraphAction->setActionGroup(ag);
461 connect(_distanceGraphAction, &QAction::triggered, this,
462 &GUI::setDistanceGraph);
463 addAction(_distanceGraphAction);
464 _timeGraphAction = new QAction(tr("Time"), this);
465 _timeGraphAction->setMenuRole(QAction::NoRole);
466 _timeGraphAction->setCheckable(true);
467 _timeGraphAction->setActionGroup(ag);
468 connect(_timeGraphAction, &QAction::triggered, this, &GUI::setTimeGraph);
469 addAction(_timeGraphAction);
470 _showGraphGridAction = new QAction(tr("Show grid"), this);
471 _showGraphGridAction->setMenuRole(QAction::NoRole);
472 _showGraphGridAction->setCheckable(true);
473 connect(_showGraphGridAction, &QAction::triggered, this,
474 &GUI::showGraphGrids);
475 _showGraphSliderInfoAction = new QAction(tr("Show slider info"), this);
476 _showGraphSliderInfoAction->setMenuRole(QAction::NoRole);
477 _showGraphSliderInfoAction->setCheckable(true);
478 connect(_showGraphSliderInfoAction, &QAction::triggered, this,
479 &GUI::showGraphSliderInfo);
480 #ifdef Q_OS_ANDROID
481 _showGraphTabsAction = new QAction(tr("Show tabs"), this);
482 _showGraphTabsAction->setMenuRole(QAction::NoRole);
483 _showGraphTabsAction->setCheckable(true);
484 connect(_showGraphTabsAction, &QAction::triggered, this,
485 &GUI::showGraphTabs);
486 #endif // Q_OS_ANDROID
488 // Settings actions
489 #ifndef Q_OS_ANDROID
490 _showToolbarsAction = new QAction(tr("Show toolbars"), this);
491 _showToolbarsAction->setMenuRole(QAction::NoRole);
492 _showToolbarsAction->setCheckable(true);
493 connect(_showToolbarsAction, &QAction::triggered, this, &GUI::showToolbars);
494 #endif // Q_OS_ANDROID
495 ag = new QActionGroup(this);
496 ag->setExclusive(true);
497 _totalTimeAction = new QAction(tr("Total time"), this);
498 _totalTimeAction->setMenuRole(QAction::NoRole);
499 _totalTimeAction->setCheckable(true);
500 _totalTimeAction->setActionGroup(ag);
501 connect(_totalTimeAction, &QAction::triggered, this, &GUI::setTotalTime);
502 _movingTimeAction = new QAction(tr("Moving time"), this);
503 _movingTimeAction->setMenuRole(QAction::NoRole);
504 _movingTimeAction->setCheckable(true);
505 _movingTimeAction->setActionGroup(ag);
506 connect(_movingTimeAction, &QAction::triggered, this, &GUI::setMovingTime);
507 ag = new QActionGroup(this);
508 ag->setExclusive(true);
509 _metricUnitsAction = new QAction(tr("Metric"), this);
510 _metricUnitsAction->setMenuRole(QAction::NoRole);
511 _metricUnitsAction->setCheckable(true);
512 _metricUnitsAction->setActionGroup(ag);
513 connect(_metricUnitsAction, &QAction::triggered, this, &GUI::setMetricUnits);
514 _imperialUnitsAction = new QAction(tr("Imperial"), this);
515 _imperialUnitsAction->setMenuRole(QAction::NoRole);
516 _imperialUnitsAction->setCheckable(true);
517 _imperialUnitsAction->setActionGroup(ag);
518 connect(_imperialUnitsAction, &QAction::triggered, this,
519 &GUI::setImperialUnits);
520 _nauticalUnitsAction = new QAction(tr("Nautical"), this);
521 _nauticalUnitsAction->setMenuRole(QAction::NoRole);
522 _nauticalUnitsAction->setCheckable(true);
523 _nauticalUnitsAction->setActionGroup(ag);
524 connect(_nauticalUnitsAction, &QAction::triggered, this,
525 &GUI::setNauticalUnits);
526 ag = new QActionGroup(this);
527 ag->setExclusive(true);
528 _decimalDegreesAction = new QAction(tr("Decimal degrees (DD)"), this);
529 _decimalDegreesAction->setMenuRole(QAction::NoRole);
530 _decimalDegreesAction->setCheckable(true);
531 _decimalDegreesAction->setActionGroup(ag);
532 connect(_decimalDegreesAction, &QAction::triggered, this,
533 &GUI::setDecimalDegrees);
534 _degreesMinutesAction = new QAction(tr("Degrees and decimal minutes (DMM)"),
535 this);
536 _degreesMinutesAction->setMenuRole(QAction::NoRole);
537 _degreesMinutesAction->setCheckable(true);
538 _degreesMinutesAction->setActionGroup(ag);
539 connect(_degreesMinutesAction, &QAction::triggered, this,
540 &GUI::setDegreesMinutes);
541 _dmsAction = new QAction(tr("Degrees, minutes, seconds (DMS)"), this);
542 _dmsAction->setMenuRole(QAction::NoRole);
543 _dmsAction->setCheckable(true);
544 _dmsAction->setActionGroup(ag);
545 connect(_dmsAction, &QAction::triggered, this, &GUI::setDMS);
546 #ifndef Q_OS_ANDROID
547 _fullscreenAction = new QAction(QIcon(FULLSCREEN_ICON),
548 tr("Fullscreen mode"), this);
549 _fullscreenAction->setMenuRole(QAction::NoRole);
550 _fullscreenAction->setCheckable(true);
551 _fullscreenAction->setShortcut(FULLSCREEN_SHORTCUT);
552 connect(_fullscreenAction, &QAction::triggered, this, &GUI::showFullscreen);
553 addAction(_fullscreenAction);
554 #endif // Q_OS_ANDROID
555 _openOptionsAction = new QAction(tr("Options..."), this);
556 _openOptionsAction->setMenuRole(QAction::PreferencesRole);
557 connect(_openOptionsAction, &QAction::triggered, this, &GUI::openOptions);
559 // Navigation actions
560 #ifndef Q_OS_ANDROID
561 _nextAction = new QAction(QIcon(NEXT_FILE_ICON), tr("Next"), this);
562 _nextAction->setActionGroup(_navigationActionGroup);
563 _nextAction->setMenuRole(QAction::NoRole);
564 connect(_nextAction, &QAction::triggered, this, &GUI::next);
565 _prevAction = new QAction(QIcon(PREV_FILE_ICON), tr("Previous"), this);
566 _prevAction->setMenuRole(QAction::NoRole);
567 _prevAction->setActionGroup(_navigationActionGroup);
568 connect(_prevAction, &QAction::triggered, this, &GUI::prev);
569 _lastAction = new QAction(QIcon(LAST_FILE_ICON), tr("Last"), this);
570 _lastAction->setMenuRole(QAction::NoRole);
571 _lastAction->setActionGroup(_navigationActionGroup);
572 connect(_lastAction, &QAction::triggered, this, &GUI::last);
573 _firstAction = new QAction(QIcon(FIRST_FILE_ICON), tr("First"), this);
574 _firstAction->setMenuRole(QAction::NoRole);
575 _firstAction->setActionGroup(_navigationActionGroup);
576 connect(_firstAction, &QAction::triggered, this, &GUI::first);
577 #endif // Q_OS_ANDROID
580 void GUI::createMapNodeMenu(const TreeNode<MapAction*> &node, QMenu *menu,
581 QAction *action)
583 for (int i = 0; i < node.childs().size(); i++) {
584 QMenu *cm = new QMenu(node.childs().at(i).name(), menu);
585 menu->insertMenu(action, cm);
586 createMapNodeMenu(node.childs().at(i), cm);
589 for (int i = 0; i < node.items().size(); i++)
590 menu->insertAction(action, node.items().at(i));
593 void GUI::createPOINodeMenu(const TreeNode<POIAction*> &node, QMenu *menu,
594 QAction *action)
596 for (int i = 0; i < node.childs().size(); i++) {
597 QMenu *cm = new QMenu(node.childs().at(i).name(), menu);
598 menu->insertMenu(action, cm);
599 createPOINodeMenu(node.childs().at(i), cm);
602 for (int i = 0; i < node.items().size(); i++)
603 menu->insertAction(action, node.items().at(i));
606 void GUI::createMenus()
608 QMenu *fileMenu = menuBar()->addMenu(tr("&File"));
609 fileMenu->addAction(_openFileAction);
610 #ifdef Q_OS_ANDROID
611 fileMenu->addAction(_openDirAction);
612 #endif // Q_OS_ANDROID
613 fileMenu->addSeparator();
614 #ifndef Q_OS_ANDROID
615 fileMenu->addAction(_printFileAction);
616 #endif // Q_OS_ANDROID
617 fileMenu->addAction(_exportPDFFileAction);
618 fileMenu->addAction(_exportPNGFileAction);
619 fileMenu->addSeparator();
620 fileMenu->addAction(_statisticsAction);
621 fileMenu->addSeparator();
622 fileMenu->addAction(_reloadFileAction);
623 fileMenu->addAction(_closeFileAction);
624 #if !defined(Q_OS_MAC) && !defined(Q_OS_ANDROID)
625 fileMenu->addSeparator();
626 fileMenu->addAction(_exitAction);
627 #endif // Q_OS_MAC + Q_OS_ANDROID
629 _mapMenu = menuBar()->addMenu(tr("&Map"));
630 _mapsEnd = _mapMenu->addSeparator();
631 _mapMenu->addAction(_loadMapAction);
632 _mapMenu->addAction(_loadMapDirAction);
633 _mapMenu->addAction(_clearMapCacheAction);
634 _mapMenu->addSeparator();
635 _mapMenu->addAction(_showCoordinatesAction);
636 _mapMenu->addSeparator();
637 _mapMenu->addAction(_showMapAction);
639 QMenu *graphMenu = menuBar()->addMenu(tr("&Graph"));
640 graphMenu->addAction(_distanceGraphAction);
641 graphMenu->addAction(_timeGraphAction);
642 graphMenu->addSeparator();
643 graphMenu->addAction(_showGraphGridAction);
644 graphMenu->addAction(_showGraphSliderInfoAction);
645 #ifdef Q_OS_ANDROID
646 graphMenu->addAction(_showGraphTabsAction);
647 #endif // Q_OS_ANDROID
648 graphMenu->addSeparator();
649 graphMenu->addAction(_showGraphsAction);
651 QMenu *dataMenu = menuBar()->addMenu(tr("&Data"));
652 dataMenu->addAction(_showWaypointIconsAction);
653 dataMenu->addAction(_showWaypointLabelsAction);
654 dataMenu->addAction(_showRouteWaypointsAction);
655 dataMenu->addAction(_showTicksAction);
656 QMenu *markerMenu = dataMenu->addMenu(tr("Position info"));
657 markerMenu->addAction(_hideMarkersAction);
658 markerMenu->addAction(_showMarkersAction);
659 markerMenu->addAction(_showMarkerDateAction);
660 markerMenu->addAction(_showMarkerCoordinatesAction);
661 dataMenu->addSeparator();
662 dataMenu->addAction(_useStylesAction);
663 dataMenu->addSeparator();
664 dataMenu->addAction(_showTracksAction);
665 dataMenu->addAction(_showRoutesAction);
666 dataMenu->addAction(_showAreasAction);
667 dataMenu->addAction(_showWaypointsAction);
669 _poiMenu = menuBar()->addMenu(tr("&POI"));
670 _poisEnd = _poiMenu->addSeparator();
671 _poiMenu->addAction(_openPOIAction);
672 _poiMenu->addAction(_selectAllPOIAction);
673 _poiMenu->addAction(_unselectAllPOIAction);
674 _poiMenu->addSeparator();
675 _poiMenu->addAction(_showPOIIconsAction);
676 _poiMenu->addAction(_showPOILabelsAction);
677 _poiMenu->addAction(_overlapPOIAction);
678 _poiMenu->addSeparator();
679 _poiMenu->addAction(_showPOIAction);
681 QMenu *demMenu = menuBar()->addMenu(tr("DEM"));
682 demMenu->addAction(_showDEMTilesAction);
683 demMenu->addAction(_downloadDEMAction);
685 QMenu *positionMenu = menuBar()->addMenu(tr("Position"));
686 positionMenu->addAction(_showPositionCoordinatesAction);
687 positionMenu->addAction(_showMotionInfoAction);
688 positionMenu->addAction(_followPositionAction);
689 positionMenu->addSeparator();
690 positionMenu->addAction(_showPositionAction);
692 QMenu *settingsMenu = menuBar()->addMenu(tr("&Settings"));
693 QMenu *timeMenu = settingsMenu->addMenu(tr("Time"));
694 timeMenu->addAction(_totalTimeAction);
695 timeMenu->addAction(_movingTimeAction);
696 QMenu *unitsMenu = settingsMenu->addMenu(tr("Units"));
697 unitsMenu->addAction(_metricUnitsAction);
698 unitsMenu->addAction(_imperialUnitsAction);
699 unitsMenu->addAction(_nauticalUnitsAction);
700 QMenu *coordinatesMenu = settingsMenu->addMenu(tr("Coordinates format"));
701 coordinatesMenu->addAction(_decimalDegreesAction);
702 coordinatesMenu->addAction(_degreesMinutesAction);
703 coordinatesMenu->addAction(_dmsAction);
704 settingsMenu->addSeparator();
705 #ifndef Q_OS_ANDROID
706 settingsMenu->addAction(_showToolbarsAction);
707 settingsMenu->addAction(_fullscreenAction);
708 settingsMenu->addSeparator();
709 #endif // Q_OS_ANDROID
710 settingsMenu->addAction(_openOptionsAction);
712 QMenu *helpMenu = menuBar()->addMenu(tr("&Help"));
713 helpMenu->addAction(_pathsAction);
714 #ifndef Q_OS_ANDROID
715 helpMenu->addAction(_keysAction);
716 #endif // Q_OS_ANDROID
717 helpMenu->addSeparator();
718 helpMenu->addAction(_aboutAction);
721 #ifdef Q_OS_ANDROID
722 void GUI::createNavigation()
724 _navigation = new NavigationWidget(_mapView);
726 connect(_navigation, &NavigationWidget::next, this, &GUI::next);
727 connect(_navigation, &NavigationWidget::prev, this, &GUI::prev);
729 #else // Q_OS_ANDROID
730 void GUI::createToolBars()
732 int is = style()->pixelMetric(QStyle::PM_ToolBarIconSize);
733 QSize iconSize(qMin(is, TOOLBAR_ICON_SIZE), qMin(is, TOOLBAR_ICON_SIZE));
735 #ifdef Q_OS_MAC
736 setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
737 #endif // Q_OS_MAC
739 _fileToolBar = addToolBar(tr("File"));
740 _fileToolBar->setObjectName("File");
741 _fileToolBar->setIconSize(iconSize);
742 _fileToolBar->addAction(_openFileAction);
743 _fileToolBar->addAction(_reloadFileAction);
744 _fileToolBar->addAction(_closeFileAction);
745 #ifndef Q_OS_MAC
746 _fileToolBar->addAction(_printFileAction);
747 #endif // Q_OS_MAC
749 _showToolBar = addToolBar(tr("Show"));
750 _showToolBar->setObjectName("Show");
751 _showToolBar->setIconSize(iconSize);
752 _showToolBar->addAction(_showPOIAction);
753 _showToolBar->addAction(_showMapAction);
754 _showToolBar->addAction(_showGraphsAction);
755 _showToolBar->addAction(_showPositionAction);
757 _navigationToolBar = addToolBar(tr("Navigation"));
758 _navigationToolBar->setObjectName("Navigation");
759 _navigationToolBar->setIconSize(iconSize);
760 _navigationToolBar->addAction(_firstAction);
761 _navigationToolBar->addAction(_prevAction);
762 _navigationToolBar->addAction(_nextAction);
763 _navigationToolBar->addAction(_lastAction);
765 #endif // Q_OS_ANDROID
767 void GUI::createMapView()
769 _map = new EmptyMap(this);
770 _mapView = new MapView(_map, _poi, this);
771 _mapView->setSizePolicy(QSizePolicy(QSizePolicy::Ignored,
772 QSizePolicy::Expanding));
773 #ifdef Q_OS_ANDROID
774 _mapView->setMinimumHeight(100);
775 #else // Q_OS_ANDROID
776 _mapView->setMinimumHeight(200);
777 #endif // Q_OS_ANDROID
778 #ifdef Q_OS_WIN32
779 _mapView->setFrameShape(QFrame::NoFrame);
780 #endif // Q_OS_WIN32
783 void GUI::createGraphTabs()
785 _graphTabWidget = new QTabWidget();
786 _graphTabWidget->setSizePolicy(QSizePolicy(QSizePolicy::Ignored,
787 QSizePolicy::Preferred));
788 _graphTabWidget->setMinimumHeight(200);
789 #ifndef Q_OS_MAC
790 _graphTabWidget->setDocumentMode(true);
791 #endif // Q_OS_MAC
793 connect(_graphTabWidget, &QTabWidget::currentChanged, this,
794 &GUI::graphChanged);
796 _tabs.append(new ElevationGraph(_graphTabWidget));
797 _tabs.append(new SpeedGraph(_graphTabWidget));
798 _tabs.append(new HeartRateGraph(_graphTabWidget));
799 _tabs.append(new CadenceGraph(_graphTabWidget));
800 _tabs.append(new PowerGraph(_graphTabWidget));
801 _tabs.append(new TemperatureGraph(_graphTabWidget));
802 _tabs.append(new GearRatioGraph(_graphTabWidget));
804 for (int i = 0; i < _tabs.size(); i++)
805 connect(_tabs.at(i), &GraphTab::sliderPositionChanged, _mapView,
806 &MapView::setMarkerPosition);
809 void GUI::createStatusBar()
811 _fileNameLabel = new QLabel();
812 _distanceLabel = new QLabel();
813 _timeLabel = new QLabel();
814 _distanceLabel->setAlignment(Qt::AlignHCenter);
815 _timeLabel->setAlignment(Qt::AlignHCenter);
817 statusBar()->addPermanentWidget(_fileNameLabel, 8);
818 statusBar()->addPermanentWidget(_distanceLabel, 1);
819 statusBar()->addPermanentWidget(_timeLabel, 1);
820 statusBar()->setSizeGripEnabled(false);
823 void GUI::about()
825 QMessageBox msgBox(this);
826 QUrl homepage(APP_HOMEPAGE);
828 msgBox.setWindowTitle(tr("About GPXSee"));
829 #ifdef Q_OS_ANDROID
830 msgBox.setText("<h2>" + QString(APP_NAME) + "</h2><p>" + tr("Version %1")
831 .arg(QString(APP_VERSION) + " (" + QSysInfo::buildCpuArchitecture()
832 + ", Qt " + QT_VERSION_STR + ")") + "</p><p>"
833 + tr("GPXSee is distributed under the terms of the GNU General Public "
834 "License version 3. For more info about GPXSee visit the project "
835 "homepage at %1.").arg("<a href=\"" + homepage.toString() + "\">"
836 + homepage.toString(QUrl::RemoveScheme).mid(2) + "</a>") + "</p>");
837 #else // Q_OS_ANDROID
838 msgBox.setText("<h2>" + QString(APP_NAME) + "</h2><p>" + tr("Version %1")
839 .arg(QString(APP_VERSION) + " (" + QSysInfo::buildCpuArchitecture()
840 + ", Qt " + QT_VERSION_STR + ")") + "</p>");
841 msgBox.setInformativeText("<table width=\"300\"><tr><td>"
842 + tr("GPXSee is distributed under the terms of the GNU General Public "
843 "License version 3. For more info about GPXSee visit the project "
844 "homepage at %1.").arg("<a href=\"" + homepage.toString() + "\">"
845 + homepage.toString(QUrl::RemoveScheme).mid(2) + "</a>")
846 + "</td></tr></table>");
848 QIcon icon = msgBox.windowIcon();
849 QSize size = icon.actualSize(QSize(64, 64));
850 msgBox.setIconPixmap(icon.pixmap(size));
851 #endif // Q_OS_ANDROID
853 msgBox.exec();
856 #ifndef Q_OS_ANDROID
857 void GUI::keys()
859 QMessageBox msgBox(this);
861 msgBox.setWindowTitle(tr("Keyboard controls"));
862 msgBox.setText("<h3>" + tr("Keyboard controls") + "</h3>");
863 msgBox.setInformativeText(
864 "<style>td {padding-right: 1.5em;}</style><div><table><tr><td>"
865 + tr("Next file") + "</td><td><i>" + QKeySequence(NEXT_KEY).toString()
866 + "</i></td></tr><tr><td>" + tr("Previous file")
867 + "</td><td><i>" + QKeySequence(PREV_KEY).toString()
868 + "</i></td></tr><tr><td>" + tr("First file") + "</td><td><i>"
869 + QKeySequence(FIRST_KEY).toString() + "</i></td></tr><tr><td>"
870 + tr("Last file") + "</td><td><i>" + QKeySequence(LAST_KEY).toString()
871 + "</i></td></tr><tr><td>" + tr("Append file")
872 + "</td><td><i>" + QKeySequence(MODIFIER).toString() + tr("Next/Previous")
873 + "</i></td></tr><tr><td></td><td></td></tr><tr><td>"
874 + tr("Toggle graph type") + "</td><td><i>"
875 + QKeySequence(TOGGLE_GRAPH_TYPE_KEY).toString() + "</i></td></tr><tr><td>"
876 + tr("Toggle time type") + "</td><td><i>"
877 + QKeySequence(TOGGLE_TIME_TYPE_KEY).toString() + "</i></td></tr><tr><td>"
878 + tr("Toggle position info") + "</td><td><i>"
879 + QKeySequence(TOGGLE_MARKER_INFO_KEY).toString() + "</i></td></tr>"
880 + "<tr><td></td><td></td></tr><tr><td>" + tr("Next map")
881 + "</td><td><i>" + NEXT_MAP_SHORTCUT.toString() + "</i></td></tr><tr><td>"
882 + tr("Previous map") + "</td><td><i>" + PREV_MAP_SHORTCUT.toString()
883 + "</i></td></tr><tr><td></td><td></td></tr><tr><td>" + tr("Zoom in")
884 + "</td><td><i>" + QKeySequence(ZOOM_IN).toString()
885 + "</i></td></tr><tr><td>" + tr("Zoom out") + "</td><td><i>"
886 + QKeySequence(ZOOM_OUT).toString() + "</i></td></tr><tr><td>"
887 + tr("Digital zoom") + "</td><td><i>" + QKeySequence(MODIFIER).toString()
888 + tr("Zoom") + "</i></td></tr><tr><td></td><td></td></tr><tr><td>"
889 + tr("Copy coordinates") + "</td><td><i>"
890 + QKeySequence(MODIFIER).toString() + tr("Left Click")
891 + "</i></td></tr></table></div>");
893 msgBox.exec();
895 #endif // Q_OS_ANDROID
897 void GUI::paths()
899 QMessageBox msgBox(this);
901 msgBox.setWindowTitle(tr("Paths"));
902 #ifdef Q_OS_ANDROID
903 msgBox.setText(
904 + "<small><b>" + tr("Map directory:") + "</b><br>"
905 + QDir::cleanPath(ProgramPaths::mapDir(true)) + "<br><br><b>"
906 + tr("POI directory:") + "</b><br>"
907 + QDir::cleanPath(ProgramPaths::poiDir(true)) + "<br><br><b>"
908 + tr("CRS directory:") + "</b><br>"
909 + QDir::cleanPath(ProgramPaths::crsDir(true)) + "<br><br><b>"
910 + tr("DEM directory:") + "</b><br>"
911 + QDir::cleanPath(ProgramPaths::demDir(true)) + "<br><br><b>"
912 + tr("Styles directory:") + "</b><br>"
913 + QDir::cleanPath(ProgramPaths::styleDir(true)) + "<br><br><b>"
914 + tr("Symbols directory:") + "</b><br>"
915 + QDir::cleanPath(ProgramPaths::symbolsDir(true)) + "<br><br><b>"
916 + tr("Tile cache directory:") + "</b><br>"
917 + QDir::cleanPath(ProgramPaths::tilesDir()) + "</small>");
918 #else // Q_OS_ANDROID
919 msgBox.setText("<h3>" + tr("Paths") + "</h3>");
920 msgBox.setInformativeText(
921 "<style>td {white-space: pre; padding-right: 1em;}</style><table><tr><td>"
922 + tr("Map directory:") + "</td><td><code>"
923 + QDir::cleanPath(ProgramPaths::mapDir(true)) + "</code></td></tr><tr><td>"
924 + tr("POI directory:") + "</td><td><code>"
925 + QDir::cleanPath(ProgramPaths::poiDir(true)) + "</code></td></tr><tr><td>"
926 + tr("CRS directory:") + "</td><td><code>"
927 + QDir::cleanPath(ProgramPaths::crsDir(true)) + "</code></td></tr><tr><td>"
928 + tr("DEM directory:") + "</td><td><code>"
929 + QDir::cleanPath(ProgramPaths::demDir(true)) + "</code></td></tr><tr><td>"
930 + tr("Styles directory:") + "</td><td><code>"
931 + QDir::cleanPath(ProgramPaths::styleDir(true)) + "</code></td></tr><tr><td>"
932 + tr("Symbols directory:") + "</td><td><code>"
933 + QDir::cleanPath(ProgramPaths::symbolsDir(true)) + "</code></td></tr><tr><td>"
934 + tr("Tile cache directory:") + "</td><td><code>"
935 + QDir::cleanPath(ProgramPaths::tilesDir()) + "</code></td></tr></table>"
937 #endif // Q_OS_ANDROID
939 msgBox.exec();
942 void GUI::openFile()
944 #ifdef Q_OS_ANDROID
945 QStringList files(QFileDialog::getOpenFileNames(this, tr("Open file"),
946 _dataDir));
947 #else // Q_OS_ANDROID
948 QStringList files(QFileDialog::getOpenFileNames(this, tr("Open file"),
949 _dataDir, Data::formats()));
950 #endif // Q_OS_ANDROID
951 int showError = (files.size() > 1) ? 2 : 1;
953 for (int i = 0; i < files.size(); i++)
954 openFile(files.at(i), true, showError);
955 if (!files.isEmpty())
956 _dataDir = QFileInfo(files.last()).path();
959 #ifdef Q_OS_ANDROID
960 void GUI::openDir()
962 QString dir(QFileDialog::getExistingDirectory(this, tr("Open directory"),
963 _dataDir));
964 int showError = 1;
966 if (!dir.isEmpty()) {
967 _browser->setCurrentDir(dir);
968 openFile(_browser->current(), true, showError);
971 #endif // Q_OS_ANDROID
973 bool GUI::openFile(const QString &fileName, bool tryUnknown, int &showError)
975 if (_files.contains(fileName))
976 return true;
978 if (!loadFile(fileName, tryUnknown, showError))
979 return false;
981 _files.append(fileName);
982 #ifndef Q_OS_ANDROID
983 _browser->setCurrent(fileName);
984 #endif // Q_OS_ANDROID
985 _fileActionGroup->setEnabled(true);
986 // Explicitly enable the reload action as it may be disabled by loadMapDir()
987 _reloadFileAction->setEnabled(true);
988 _navigationActionGroup->setEnabled(true);
990 updateNavigationActions();
991 updateStatusBarInfo();
992 updateWindowTitle();
994 return true;
997 bool GUI::loadFile(const QString &fileName, bool tryUnknown, int &showError)
999 Data data(fileName, tryUnknown);
1001 if (data.isValid()) {
1002 loadData(data);
1003 return true;
1004 } else {
1005 updateNavigationActions();
1006 updateStatusBarInfo();
1007 updateWindowTitle();
1008 updateGraphTabs();
1009 updateDEMDownloadAction();
1010 if (_files.isEmpty())
1011 _fileActionGroup->setEnabled(false);
1013 if (showError) {
1014 QString error = tr("Error loading data file:") + "\n"
1015 + Util::displayName(fileName) + ": " + data.errorString();
1016 if (data.errorLine())
1017 error.append("\n" + tr("Line: %1").arg(data.errorLine()));
1019 if (showError > 1) {
1020 QMessageBox message(QMessageBox::Critical, APP_NAME, error,
1021 QMessageBox::Ok, this);
1022 QCheckBox checkBox(tr("Don't show again"));
1023 message.setCheckBox(&checkBox);
1024 message.exec();
1025 if (checkBox.isChecked())
1026 showError = 0;
1027 } else
1028 QMessageBox::critical(this, APP_NAME, error);
1031 return false;
1035 void GUI::loadData(const Data &data)
1037 QList<QList<GraphItem*> > graphs;
1038 QList<PathItem*> paths;
1040 for (int i = 0; i < data.tracks().count(); i++) {
1041 const Track &track = data.tracks().at(i);
1042 _trackDistance += track.distance();
1043 _time += track.time();
1044 _movingTime += track.movingTime();
1045 const QDateTime date = track.date().toTimeZone(_options.timeZone.zone());
1046 if (_dateRange.first.isNull() || _dateRange.first > date)
1047 _dateRange.first = date;
1048 if (_dateRange.second.isNull() || _dateRange.second < date)
1049 _dateRange.second = date;
1051 _trackCount += data.tracks().count();
1053 for (int i = 0; i < data.routes().count(); i++)
1054 _routeDistance += data.routes().at(i).distance();
1055 _routeCount += data.routes().count();
1057 _waypointCount += data.waypoints().count();
1058 _areaCount += data.areas().count();
1060 if (_pathName.isNull()) {
1061 if (data.tracks().count() == 1 && !data.routes().count())
1062 _pathName = data.tracks().first().name();
1063 else if (data.routes().count() == 1 && !data.tracks().count())
1064 _pathName = data.routes().first().name();
1065 } else
1066 _pathName = QString();
1068 for (int i = 0; i < _tabs.count(); i++)
1069 graphs.append(_tabs.at(i)->loadData(data));
1070 if (updateGraphTabs())
1071 _splitter->refresh();
1072 paths = _mapView->loadData(data);
1074 GraphTab *gt = static_cast<GraphTab*>(_graphTabWidget->currentWidget());
1076 for (int i = 0; i < paths.count(); i++) {
1077 PathItem *pi = paths.at(i);
1078 if (!pi)
1079 continue;
1081 for (int j = 0; j < graphs.count(); j++)
1082 pi->addGraph(graphs.at(j).at(i));
1084 if (gt) {
1085 pi->setGraph(_tabs.indexOf(gt));
1086 pi->setMarkerPosition(gt->sliderPosition());
1090 updateDEMDownloadAction();
1093 void GUI::openPOIFile()
1095 #ifdef Q_OS_ANDROID
1096 QStringList files(QFileDialog::getOpenFileNames(this, tr("Open POI file"),
1097 _poiDir));
1098 #else // Q_OS_ANDROID
1099 QStringList files(QFileDialog::getOpenFileNames(this, tr("Open POI file"),
1100 _poiDir, Data::formats()));
1101 #endif // Q_OS_ANDROID
1103 for (int i = 0; i < files.size(); i++)
1104 openPOIFile(files.at(i));
1105 if (!files.isEmpty())
1106 _poiDir = QFileInfo(files.last()).path();
1109 bool GUI::openPOIFile(const QString &fileName)
1111 if (_poi->isLoaded(fileName))
1112 return true;
1114 if (_poi->loadFile(fileName)) {
1115 _mapView->showPOI(true);
1116 _showPOIAction->setChecked(true);
1117 QAction *action = new POIAction(fileName, _poisActionGroup);
1118 action->setChecked(true);
1119 _poiMenu->insertAction(_poisEnd, action);
1121 _selectAllPOIAction->setEnabled(true);
1122 _unselectAllPOIAction->setEnabled(true);
1124 return true;
1125 } else {
1126 QString error = tr("Error loading POI file:") + "\n"
1127 + Util::displayName(fileName) + ": " + _poi->errorString();
1128 if (_poi->errorLine())
1129 error.append("\n" + tr("Line: %1").arg(_poi->errorLine()));
1130 QMessageBox::critical(this, APP_NAME, error);
1132 return false;
1136 void GUI::openOptions()
1138 Options options(_options);
1139 OptionsDialog dialog(options, _units, this);
1141 if (dialog.exec() != QDialog::Accepted)
1142 return;
1144 updateOptions(options);
1147 void GUI::printFile()
1149 QPrinter printer(QPrinter::HighResolution);
1150 QPrintDialog dialog(&printer, this);
1152 if (dialog.exec() == QDialog::Accepted)
1153 plot(&printer);
1156 void GUI::exportPDFFile()
1158 PDFExportDialog dialog(_pdfExport, _units, this);
1159 if (dialog.exec() != QDialog::Accepted)
1160 return;
1162 QPrinter printer(QPrinter::HighResolution);
1163 printer.setOutputFormat(QPrinter::PdfFormat);
1164 printer.setCreator(QString(APP_NAME) + QString(" ")
1165 + QString(APP_VERSION));
1166 printer.setResolution(_pdfExport.resolution);
1167 printer.setPageLayout(QPageLayout(QPageSize(_pdfExport.paperSize),
1168 _pdfExport.orientation, _pdfExport.margins, QPageLayout::Millimeter));
1169 printer.setOutputFileName(_pdfExport.fileName);
1171 plot(&printer);
1174 void GUI::exportPNGFile()
1176 PNGExportDialog dialog(_pngExport, this);
1177 if (dialog.exec() != QDialog::Accepted)
1178 return;
1180 QImage img(_pngExport.size, QImage::Format_ARGB32_Premultiplied);
1181 QPainter p(&img);
1182 QRectF rect(0, 0, img.width(), img.height());
1183 QRectF contentRect(rect.adjusted(_pngExport.margins.left(),
1184 _pngExport.margins.top(), -_pngExport.margins.right(),
1185 -_pngExport.margins.bottom()));
1187 if (_pngExport.antialiasing)
1188 p.setRenderHint(QPainter::Antialiasing);
1189 p.fillRect(rect, Qt::white);
1190 plotMainPage(&p, contentRect, 1.0, true);
1191 img.save(_pngExport.fileName, "png");
1193 if (!_tabs.isEmpty() && _options.separateGraphPage) {
1194 QImage img2(_pngExport.size.width(), (int)graphPlotHeight(rect, 1)
1195 + _pngExport.margins.bottom(), QImage::Format_ARGB32_Premultiplied);
1196 QPainter p2(&img2);
1197 QRectF rect2(0, 0, img2.width(), img2.height());
1199 if (_pngExport.antialiasing)
1200 p2.setRenderHint(QPainter::Antialiasing);
1201 p2.fillRect(rect2, Qt::white);
1202 plotGraphsPage(&p2, contentRect, 1);
1204 QFileInfo fi(_pngExport.fileName);
1205 img2.save(fi.absolutePath() + "/" + fi.baseName() + "-graphs."
1206 + fi.suffix(), "png");
1210 void GUI::statistics()
1212 QLocale l(QLocale::system());
1213 QMessageBox msgBox(this);
1214 QString text;
1216 #ifdef Q_OS_ANDROID
1217 if (_showTracksAction->isChecked() && _trackCount > 1)
1218 text.append("<b>" + tr("Tracks") + ":</b> "
1219 + l.toString(_trackCount) + "<br>");
1220 if (_showRoutesAction->isChecked() && _routeCount > 1)
1221 text.append("<b>" + tr("Routes") + ":</b> "
1222 + l.toString(_routeCount) + "<br>");
1223 if (_showWaypointsAction->isChecked() && _waypointCount > 1)
1224 text.append("<b>" + tr("Waypoints") + ":</b> "
1225 + l.toString(_waypointCount) + "<br>");
1226 if (_showAreasAction->isChecked() && _areaCount > 1)
1227 text.append("<b>" + tr("Areas") + ":</b> "
1228 + l.toString(_areaCount) + "<br>");
1230 if (_dateRange.first.isValid()) {
1231 QString format = l.dateFormat(QLocale::ShortFormat);
1232 if (_dateRange.first == _dateRange.second)
1233 text.append("<b>" + tr("Date") + ":</b> "
1234 + _dateRange.first.toString(format) + "<br>");
1235 else
1236 text.append("<b>" + tr("Date") + ":</b> "
1237 + QString("%1 - %2").arg(_dateRange.first.toString(format),
1238 _dateRange.second.toString(format)) + "<br>");
1241 if (distance() > 0)
1242 text.append("<b>" + tr("Distance") + ":</b> "
1243 + Format::distance(distance(), units()) + "<br>");
1244 if (time() > 0) {
1245 text.append("<b>" + tr("Time") + ":</b> "
1246 + Format::timeSpan(time()) + "<br>");
1247 text.append("<b>" + tr("Moving time") + ":</b> "
1248 + Format::timeSpan(movingTime()) + "<br>");
1250 text.append("<br>");
1252 for (int i = 0; i < _tabs.count(); i++) {
1253 const GraphTab *tab = _tabs.at(i);
1254 if (tab->isEmpty())
1255 continue;
1257 text.append("<i>" + tab->label() + "</i><br>");
1258 for (int j = 0; j < tab->info().size(); j++) {
1259 const KV<QString, QString> &kv = tab->info().at(j);
1260 text.append("<b>" + kv.key() + ":</b>&nbsp;" + kv.value());
1261 if (j != tab->info().size() - 1)
1262 text.append(" | ");
1264 if (i != _tabs.count() - 1)
1265 text.append("<br><br>");
1268 msgBox.setWindowTitle(tr("Statistics"));
1269 msgBox.setText(text);
1271 #else // Q_OS_ANDROID
1273 #ifdef Q_OS_WIN32
1274 text = "<style>td {white-space: pre; padding-right: 4em;}"
1275 "th {text-align: left; padding-top: 0.5em;}</style><table>";
1276 #else // Q_OS_WIN32
1277 text = "<style>td {white-space: pre; padding-right: 2em;}"
1278 "th {text-align: left; padding-top: 0.5em;}</style><table>";
1279 #endif // Q_OS_WIN32
1281 if (_showTracksAction->isChecked() && _trackCount > 1)
1282 text.append("<tr><td>" + tr("Tracks") + ":</td><td>"
1283 + l.toString(_trackCount) + "</td></tr>");
1284 if (_showRoutesAction->isChecked() && _routeCount > 1)
1285 text.append("<tr><td>" + tr("Routes") + ":</td><td>"
1286 + l.toString(_routeCount) + "</td></tr>");
1287 if (_showWaypointsAction->isChecked() && _waypointCount > 1)
1288 text.append("<tr><td>" + tr("Waypoints") + ":</td><td>"
1289 + l.toString(_waypointCount) + "</td></tr>");
1290 if (_showAreasAction->isChecked() && _areaCount > 1)
1291 text.append("<tr><td>" + tr("Areas") + ":</td><td>"
1292 + l.toString(_areaCount) + "</td></tr>");
1294 if (_dateRange.first.isValid()) {
1295 if (_dateRange.first == _dateRange.second) {
1296 QString format = l.dateFormat(QLocale::LongFormat);
1297 text.append("<tr><td>" + tr("Date") + ":</td><td>"
1298 + _dateRange.first.toString(format) + "</td></tr>");
1299 } else {
1300 QString format = l.dateFormat(QLocale::ShortFormat);
1301 text.append("<tr><td>" + tr("Date") + ":</td><td>"
1302 + QString("%1 - %2").arg(_dateRange.first.toString(format),
1303 _dateRange.second.toString(format)) + "</td></tr>");
1307 if (distance() > 0)
1308 text.append("<tr><td>" + tr("Distance") + ":</td><td>"
1309 + Format::distance(distance(), units()) + "</td></tr>");
1310 if (time() > 0) {
1311 text.append("<tr><td>" + tr("Time") + ":</td><td>"
1312 + Format::timeSpan(time()) + "</td></tr>");
1313 text.append("<tr><td>" + tr("Moving time") + ":</td><td>"
1314 + Format::timeSpan(movingTime()) + "</td></tr>");
1317 for (int i = 0; i < _tabs.count(); i++) {
1318 const GraphTab *tab = _tabs.at(i);
1319 if (tab->isEmpty())
1320 continue;
1322 text.append("<tr><th colspan=\"2\">" + tab->label() + "</th></tr>");
1323 for (int j = 0; j < tab->info().size(); j++) {
1324 const KV<QString, QString> &kv = tab->info().at(j);
1325 text.append("<tr><td>" + kv.key() + ":</td><td>" + kv.value()
1326 + "</td></tr>");
1330 text.append("</table>");
1332 msgBox.setWindowTitle(tr("Statistics"));
1333 msgBox.setText("<h3>" + tr("Statistics") + "</h3>");
1334 msgBox.setInformativeText(text);
1335 #endif // Q_OS_ANDROID
1337 msgBox.exec();
1340 void GUI::plotMainPage(QPainter *painter, const QRectF &rect, qreal ratio,
1341 bool expand)
1343 QLocale l(QLocale::system());
1344 TrackInfo info;
1345 qreal ih, gh, mh;
1346 int sc;
1349 if (!_pathName.isNull() && _options.printName)
1350 info.insert(tr("Name"), _pathName);
1352 if (_options.printItemCount) {
1353 if (_showTracksAction->isChecked() && _trackCount > 1)
1354 info.insert(tr("Tracks"), l.toString(_trackCount));
1355 if (_showRoutesAction->isChecked() && _routeCount > 1)
1356 info.insert(tr("Routes"), l.toString(_routeCount));
1357 if (_showWaypointsAction->isChecked() && _waypointCount > 1)
1358 info.insert(tr("Waypoints"), l.toString(_waypointCount));
1359 if (_showAreasAction->isChecked() && _areaCount > 1)
1360 info.insert(tr("Areas"), l.toString(_areaCount));
1363 if (_dateRange.first.isValid() && _options.printDate) {
1364 if (_dateRange.first == _dateRange.second) {
1365 QString format = l.dateFormat(QLocale::LongFormat);
1366 info.insert(tr("Date"), _dateRange.first.toString(format));
1367 } else {
1368 QString format = l.dateFormat(QLocale::ShortFormat);
1369 info.insert(tr("Date"), QString("%1 - %2")
1370 .arg(_dateRange.first.toString(format),
1371 _dateRange.second.toString(format)));
1375 if (distance() > 0 && _options.printDistance)
1376 info.insert(tr("Distance"), Format::distance(distance(), units()));
1377 if (time() > 0 && _options.printTime)
1378 info.insert(tr("Time"), Format::timeSpan(time()));
1379 if (movingTime() > 0 && _options.printMovingTime)
1380 info.insert(tr("Moving time"), Format::timeSpan(movingTime()));
1382 if (info.isEmpty()) {
1383 ih = 0;
1384 mh = 0;
1385 } else {
1386 ih = info.contentSize().height() * ratio;
1387 mh = ih / 2;
1388 info.plot(painter, QRectF(rect.x(), rect.y(), rect.width(), ih), ratio);
1390 if (_graphTabWidget->isVisible() && !_options.separateGraphPage) {
1391 qreal r = rect.width() / rect.height();
1392 gh = (rect.width() > rect.height())
1393 ? 0.15 * r * (rect.height() - ih - 2*mh)
1394 : 0.15 * (rect.height() - ih - 2*mh);
1395 if (gh < 150)
1396 gh = 150;
1397 sc = 2;
1398 GraphTab *gt = static_cast<GraphTab*>(_graphTabWidget->currentWidget());
1399 gt->plot(painter, QRectF(rect.x(), rect.y() + rect.height() - gh,
1400 rect.width(), gh), ratio);
1401 } else {
1402 gh = 0;
1403 sc = 1;
1406 MapView::PlotFlags flags;
1407 if (_options.hiresPrint)
1408 flags |= MapView::HiRes;
1409 if (expand)
1410 flags |= MapView::Expand;
1412 _mapView->plot(painter, QRectF(rect.x(), rect.y() + ih + mh, rect.width(),
1413 rect.height() - (ih + sc*mh + gh)), ratio, flags);
1416 void GUI::plotGraphsPage(QPainter *painter, const QRectF &rect, qreal ratio)
1418 int cnt = 0;
1419 for (int i = 0; i < _tabs.size(); i++)
1420 if (!_tabs.at(i)->isEmpty())
1421 cnt++;
1423 qreal sp = ratio * 20;
1424 qreal gh = qMin((rect.height() - ((cnt - 1) * sp))/(qreal)cnt,
1425 0.20 * rect.height());
1427 qreal y = 0;
1428 for (int i = 0; i < _tabs.size(); i++) {
1429 if (!_tabs.at(i)->isEmpty()) {
1430 _tabs.at(i)->plot(painter, QRectF(rect.x(), rect.y() + y,
1431 rect.width(), gh), ratio);
1432 y += gh + sp;
1437 qreal GUI::graphPlotHeight(const QRectF &rect, qreal ratio)
1439 int cnt = 0;
1440 for (int i = 0; i < _tabs.size(); i++)
1441 if (!_tabs.at(i)->isEmpty())
1442 cnt++;
1444 qreal sp = ratio * 20;
1445 qreal gh = qMin((rect.height() - ((cnt - 1) * sp))/(qreal)cnt,
1446 0.20 * rect.height());
1448 return cnt * gh + (cnt - 1) * sp;
1451 void GUI::plot(QPrinter *printer)
1453 QPainter p(printer);
1454 qreal fsr = 1085.0 / (qMax(printer->width(), printer->height())
1455 / (qreal)printer->resolution());
1456 qreal ratio = p.paintEngine()->paintDevice()->logicalDpiX() / fsr;
1457 QRectF rect(0, 0, printer->width(), printer->height());
1459 plotMainPage(&p, rect, ratio);
1461 if (!_tabs.isEmpty() && _options.separateGraphPage) {
1462 printer->newPage();
1463 plotGraphsPage(&p, rect, ratio);
1467 void GUI::reloadFiles()
1469 _trackCount = 0;
1470 _routeCount = 0;
1471 _waypointCount = 0;
1472 _areaCount = 0;
1473 _trackDistance = 0;
1474 _routeDistance = 0;
1475 _time = 0;
1476 _movingTime = 0;
1477 _dateRange = DateTimeRange(QDateTime(), QDateTime());
1478 _pathName = QString();
1480 for (int i = 0; i < _tabs.count(); i++)
1481 _tabs.at(i)->clear();
1482 _mapView->clear();
1484 int showError = 2;
1485 for (int i = 0; i < _files.size(); i++) {
1486 if (!loadFile(_files.at(i), true, showError)) {
1487 _files.removeAt(i);
1488 i--;
1492 updateStatusBarInfo();
1493 updateWindowTitle();
1494 if (_files.isEmpty())
1495 _fileActionGroup->setEnabled(false);
1496 #ifndef Q_OS_ANDROID
1497 else
1498 _browser->setCurrent(_files.last());
1499 #endif // Q_OS_ANDROID
1500 updateDEMDownloadAction();
1503 void GUI::closeFiles()
1505 _trackCount = 0;
1506 _routeCount = 0;
1507 _waypointCount = 0;
1508 _areaCount = 0;
1509 _trackDistance = 0;
1510 _routeDistance = 0;
1511 _time = 0;
1512 _movingTime = 0;
1513 _dateRange = DateTimeRange(QDateTime(), QDateTime());
1514 _pathName = QString();
1516 for (int i = 0; i < _tabs.count(); i++)
1517 _tabs.at(i)->clear();
1518 _lastTab = 0;
1520 _mapView->clear();
1522 _files.clear();
1525 void GUI::closeAll()
1527 closeFiles();
1529 _fileActionGroup->setEnabled(false);
1530 updateStatusBarInfo();
1531 updateWindowTitle();
1532 updateGraphTabs();
1533 updateDEMDownloadAction();
1535 #ifdef Q_OS_ANDROID
1536 _browser->setCurrentDir(QString());
1537 #endif // Q_OS_ANDROID
1540 void GUI::showGraphs(bool show)
1542 _graphTabWidget->setHidden(!show);
1545 #ifdef Q_OS_ANDROID
1546 void GUI::showGraphTabs(bool show)
1548 _graphTabWidget->tabBar()->setVisible(show);
1550 #else // Q_OS_ANDROID
1551 void GUI::showToolbars(bool show)
1553 if (show) {
1554 Q_ASSERT(!_windowStates.isEmpty());
1555 restoreState(_windowStates.last());
1556 _windowStates.removeLast();
1557 } else {
1558 _windowStates.append(saveState());
1559 removeToolBar(_fileToolBar);
1560 removeToolBar(_showToolBar);
1561 removeToolBar(_navigationToolBar);
1565 void GUI::showFullscreen(bool show)
1567 if (show) {
1568 _windowGeometries.append(saveGeometry());
1569 _frameStyle = _mapView->frameStyle();
1570 statusBar()->hide();
1571 menuBar()->hide();
1572 showToolbars(false);
1573 _mapView->setFrameStyle(QFrame::NoFrame);
1574 _graphTabWidget->tabBar()->hide();
1575 #ifdef Q_OS_MAC
1576 _graphTabWidget->setDocumentMode(true);
1577 #endif // Q_OS_MAC
1578 showFullScreen();
1579 } else {
1580 Q_ASSERT(!_windowGeometries.isEmpty());
1581 _windowGeometries.removeLast();
1582 statusBar()->show();
1583 menuBar()->show();
1584 showToolbars(true);
1585 _mapView->setFrameStyle(_frameStyle);
1586 _graphTabWidget->tabBar()->show();
1587 #ifdef Q_OS_MAC
1588 _graphTabWidget->setDocumentMode(false);
1589 #endif // Q_OS_MAC
1590 showNormal();
1593 #endif // Q_OS_ANDROID
1595 void GUI::showTracks(bool show)
1597 _mapView->showTracks(show);
1599 for (int i = 0; i < _tabs.size(); i++)
1600 _tabs.at(i)->showTracks(show);
1602 updateStatusBarInfo();
1603 updateGraphTabs();
1604 updateDEMDownloadAction();
1607 void GUI::showRoutes(bool show)
1609 _mapView->showRoutes(show);
1611 for (int i = 0; i < _tabs.size(); i++)
1612 _tabs.at(i)->showRoutes(show);
1614 updateStatusBarInfo();
1615 updateGraphTabs();
1616 updateDEMDownloadAction();
1619 void GUI::showWaypoints(bool show)
1621 _mapView->showWaypoints(show);
1622 updateDEMDownloadAction();
1625 void GUI::showAreas(bool show)
1627 _mapView->showAreas(show);
1628 updateDEMDownloadAction();
1631 void GUI::showGraphGrids(bool show)
1633 for (int i = 0; i < _tabs.size(); i++)
1634 _tabs.at(i)->showGrid(show);
1637 void GUI::showGraphSliderInfo(bool show)
1639 for (int i = 0; i < _tabs.size(); i++)
1640 _tabs.at(i)->showSliderInfo(show);
1643 void GUI::showPathMarkerInfo(QAction *action)
1645 if (action == _showMarkersAction) {
1646 _mapView->showMarkers(true);
1647 _mapView->showMarkerInfo(MarkerInfoItem::None);
1648 } else if (action == _showMarkerDateAction) {
1649 _mapView->showMarkers(true);
1650 _mapView->showMarkerInfo(MarkerInfoItem::Date);
1651 } else if (action == _showMarkerCoordinatesAction) {
1652 _mapView->showMarkers(true);
1653 _mapView->showMarkerInfo(MarkerInfoItem::Position);
1654 } else {
1655 _mapView->showMarkers(false);
1656 _mapView->showMarkerInfo(MarkerInfoItem::None);
1660 void GUI::loadMap()
1662 #ifdef Q_OS_ANDROID
1663 QStringList files(QFileDialog::getOpenFileNames(this, tr("Open map file"),
1664 _mapDir));
1665 #else // Q_OS_ANDROID
1666 QStringList files(QFileDialog::getOpenFileNames(this, tr("Open map file"),
1667 _mapDir, MapList::formats()));
1668 #endif // Q_OS_ANDROID
1669 MapAction *a, *lastReady = 0;
1671 for (int i = 0; i < files.size(); i++) {
1672 if (loadMap(files.at(i), a) && a)
1673 lastReady = a;
1675 if (!files.isEmpty())
1676 _mapDir = QFileInfo(files.last()).path();
1677 if (lastReady)
1678 lastReady->trigger();
1681 static MapAction *findMapAction(const QList<QAction*> &mapActions,
1682 const Map *map)
1684 for (int i = 0; i < mapActions.count(); i++) {
1685 const Map *m = mapActions.at(i)->data().value<Map*>();
1686 if (map->path() == m->path())
1687 return static_cast<MapAction*>(mapActions.at(i));
1690 return 0;
1693 bool GUI::loadMapNode(const TreeNode<Map*> &node, MapAction *&action,
1694 bool silent, const QList<QAction*> &existingActions)
1696 bool valid = false;
1698 action = 0;
1700 for (int i = 0; i < node.childs().size(); i++)
1701 valid = loadMapNode(node.childs().at(i), action, silent, existingActions);
1703 for (int i = 0; i < node.items().size(); i++) {
1704 Map *map = node.items().at(i);
1705 MapAction *a;
1707 if (!(a = findMapAction(existingActions, map))) {
1708 if (!map->isValid()) {
1709 if (!silent)
1710 QMessageBox::critical(this, APP_NAME,
1711 tr("Error loading map:") + "\n"
1712 + Util::displayName(map->path()) + ": "
1713 + map->errorString());
1714 delete map;
1715 } else {
1716 valid = true;
1717 a = new MapAction(map, _mapsActionGroup);
1718 _mapMenu->insertAction(_mapsEnd, a);
1720 if (map->isReady()) {
1721 action = a;
1722 _showMapAction->setEnabled(true);
1723 _clearMapCacheAction->setEnabled(true);
1724 } else
1725 connect(a, &MapAction::loaded, this, &GUI::mapLoaded);
1727 } else {
1728 valid = true;
1729 map = a->data().value<Map*>();
1730 if (map->isReady())
1731 action = a;
1735 return valid;
1738 bool GUI::loadMap(const QString &fileName, MapAction *&action, bool silent)
1740 TreeNode<Map*> maps(MapList::loadMaps(fileName));
1741 QList<QAction*> existingActions(_mapsActionGroup->actions());
1743 return loadMapNode(maps, action, silent, existingActions);
1746 void GUI::mapLoaded()
1748 MapAction *action = static_cast<MapAction*>(QObject::sender());
1749 Map *map = action->data().value<Map*>();
1751 if (map->isValid()) {
1752 action->trigger();
1753 _showMapAction->setEnabled(true);
1754 _clearMapCacheAction->setEnabled(true);
1755 } else {
1756 QString error = tr("Error loading map:") + "\n"
1757 + Util::displayName(map->path()) + ": " + map->errorString();
1758 QMessageBox::critical(this, APP_NAME, error);
1759 action->deleteLater();
1763 void GUI::mapLoadedDir()
1765 MapAction *action = static_cast<MapAction*>(QObject::sender());
1766 Map *map = action->data().value<Map*>();
1768 if (map->isValid()) {
1769 _showMapAction->setEnabled(true);
1770 _clearMapCacheAction->setEnabled(true);
1771 QList<MapAction*> actions;
1772 actions.append(action);
1773 _mapView->loadMaps(actions);
1774 } else {
1775 QString error = tr("Error loading map:") + "\n"
1776 + Util::displayName(map->path()) + ": " + map->errorString();
1777 QMessageBox::critical(this, APP_NAME, error);
1778 action->deleteLater();
1782 void GUI::loadMapDirNode(const TreeNode<Map *> &node, QList<MapAction*> &actions,
1783 QMenu *menu, const QList<QAction*> &existingActions)
1785 for (int i = 0; i < node.childs().size(); i++) {
1786 QMenu *cm = new QMenu(node.childs().at(i).name(), menu);
1787 menu->addMenu(cm);
1788 loadMapDirNode(node.childs().at(i), actions, cm, existingActions);
1791 for (int i = 0; i < node.items().size(); i++) {
1792 Map *map = node.items().at(i);
1793 MapAction *a;
1795 if (!(a = findMapAction(existingActions, map))) {
1796 if (!map->isValid()) {
1797 QMessageBox::critical(this, APP_NAME, tr("Error loading map:")
1798 + "\n" + Util::displayName(map->path()) + ": "
1799 + map->errorString());
1800 delete map;
1801 } else {
1802 a = new MapAction(map, _mapsActionGroup);
1803 menu->addAction(a);
1805 if (map->isReady()) {
1806 _showMapAction->setEnabled(true);
1807 _clearMapCacheAction->setEnabled(true);
1808 actions.append(a);
1809 } else
1810 connect(a, &MapAction::loaded, this, &GUI::mapLoadedDir);
1812 _areaCount++;
1814 } else {
1815 map = a->data().value<Map*>();
1816 if (map->isReady())
1817 actions.append(a);
1822 void GUI::loadMapDir()
1824 QString dir(QFileDialog::getExistingDirectory(this,
1825 tr("Select map directory"), _mapDir, QFileDialog::ShowDirsOnly));
1826 if (dir.isEmpty())
1827 return;
1829 QFileInfo fi(dir);
1830 TreeNode<Map*> maps(MapList::loadMaps(dir));
1831 QList<QAction*> existingActions(_mapsActionGroup->actions());
1832 QList<MapAction*> actions;
1833 QMenu *menu = new QMenu(maps.name());
1835 loadMapDirNode(maps, actions, menu, existingActions);
1837 _mapView->loadMaps(actions);
1839 if (menu->isEmpty())
1840 delete menu;
1841 else
1842 _mapMenu->insertMenu(_mapsEnd, menu);
1844 _mapDir = fi.absolutePath();
1845 _fileActionGroup->setEnabled(true);
1846 _reloadFileAction->setEnabled(false);
1849 void GUI::clearMapCache()
1851 if (QMessageBox::question(this, APP_NAME,
1852 tr("Clear \"%1\" tile cache?").arg(_map->name())) == QMessageBox::Yes)
1853 _mapView->clearMapCache();
1856 void GUI::downloadDEM()
1858 RectC br(_mapView->boundingRect());
1859 _demRects.append(br);
1861 if (!_dem->loadTiles(br) && _demRects.size() == 1)
1862 demLoaded();
1865 void GUI::demLoaded()
1867 for (int i = 0; i < _demRects.size(); i++) {
1868 if (!_dem->checkTiles(_demRects.at(i))) {
1869 QMessageBox::warning(this, APP_NAME,
1870 tr("Could not download all required DEM files."));
1871 break;
1875 DEM::clearCache();
1876 _demRects.clear();
1877 reloadFiles();
1880 void GUI::showDEMTiles()
1882 QList<Area> tiles(DEM::tiles());
1884 if (tiles.isEmpty()) {
1885 QMessageBox::information(this, APP_NAME, tr("No local DEM tiles found."));
1886 } else {
1887 _mapView->loadDEMs(tiles);
1889 _areaCount += tiles.size();
1891 _fileActionGroup->setEnabled(true);
1892 _reloadFileAction->setEnabled(false);
1896 void GUI::updateStatusBarInfo()
1898 if (_files.count() == 0)
1899 _fileNameLabel->setText(tr("No files loaded"));
1900 else if (_files.count() == 1)
1901 _fileNameLabel->setText(Util::displayName(_files.at(0)));
1902 else
1903 _fileNameLabel->setText(tr("%n files", "", _files.count()));
1905 if (distance() > 0)
1906 _distanceLabel->setText(Format::distance(distance(), units()));
1907 else
1908 _distanceLabel->clear();
1910 if (time() > 0) {
1911 if (_movingTimeAction->isChecked()) {
1912 _timeLabel->setText(Format::timeSpan(movingTime())
1913 + "<sub>M</sub>");
1914 _timeLabel->setToolTip(Format::timeSpan(time()));
1915 } else {
1916 _timeLabel->setText(Format::timeSpan(time()));
1917 _timeLabel->setToolTip(Format::timeSpan(movingTime())
1918 + "<sub>M</sub>");
1920 } else {
1921 _timeLabel->clear();
1922 _timeLabel->setToolTip(QString());
1925 #ifdef Q_OS_ANDROID
1926 statusBar()->setVisible(!_files.isEmpty());
1927 #endif // Q_OS_ANDROID
1930 void GUI::updateWindowTitle()
1932 if (_files.count() == 1)
1933 setWindowTitle(QFileInfo(_files.at(0)).fileName() + " - " + APP_NAME);
1934 else
1935 setWindowTitle(APP_NAME);
1938 void GUI::mapChanged(QAction *action)
1940 _map = action->data().value<Map*>();
1941 _mapView->setMap(_map);
1944 void GUI::nextMap()
1946 QAction *checked = _mapsActionGroup->checkedAction();
1947 if (!checked)
1948 return;
1950 QList<QAction*> maps(_mapsActionGroup->actions());
1951 for (int i = 1; i < maps.size(); i++) {
1952 int next = (maps.indexOf(checked) + i) % maps.count();
1953 if (maps.at(next)->isEnabled()) {
1954 maps.at(next)->trigger();
1955 break;
1960 void GUI::prevMap()
1962 QAction *checked = _mapsActionGroup->checkedAction();
1963 if (!checked)
1964 return;
1966 QList<QAction*> maps(_mapsActionGroup->actions());
1967 for (int i = 1; i < maps.size(); i++) {
1968 int prev = (maps.indexOf(checked) + maps.count() - i) % maps.count();
1969 if (maps.at(prev)->isEnabled()) {
1970 maps.at(prev)->trigger();
1971 break;
1976 void GUI::poiFileChecked(QAction *action)
1978 _poi->enableFile(action->data().value<QString>(), action->isChecked());
1981 void GUI::selectAllPOIs()
1983 QList<QAction*> actions(_poisActionGroup->actions());
1984 for (int i = 0; i < actions.size(); i++) {
1985 POIAction *a = static_cast<POIAction*>(actions.at(i));
1986 if (_poi->enableFile(a->data().toString(), true))
1987 a->setChecked(true);
1991 void GUI::unselectAllPOIs()
1993 QList<QAction*> actions(_poisActionGroup->actions());
1994 for (int i = 0; i < actions.size(); i++) {
1995 POIAction *a = static_cast<POIAction*>(actions.at(i));
1996 if (_poi->enableFile(a->data().toString(), false))
1997 a->setChecked(false);
2001 void GUI::graphChanged(int index)
2003 if (index < 0)
2004 return;
2006 GraphTab *gt = static_cast<GraphTab*>(_graphTabWidget->widget(index));
2008 _mapView->setGraph(_tabs.indexOf(gt));
2010 if (_lastTab)
2011 gt->setSliderPosition(_lastTab->sliderPosition());
2012 _lastTab = gt;
2015 void GUI::updateNavigationActions()
2017 #ifdef Q_OS_ANDROID
2018 _navigation->enableNext(!_browser->isLast()
2019 && !_browser->current().isNull());
2020 _navigation->enablePrev(!_browser->isFirst()
2021 && !_browser->current().isNull());
2022 #else // Q_OS_ANDROID
2023 _lastAction->setEnabled(!_browser->isLast());
2024 _nextAction->setEnabled(!_browser->isLast());
2025 _firstAction->setEnabled(!_browser->isFirst());
2026 _prevAction->setEnabled(!_browser->isFirst());
2027 #endif // Q_OS_ANDROID
2030 bool GUI::updateGraphTabs()
2032 int index;
2033 GraphTab *tab;
2034 bool hidden = _graphTabWidget->isHidden();
2036 for (int i = 0; i < _tabs.size(); i++) {
2037 tab = _tabs.at(i);
2038 if (tab->isEmpty() && (index = _graphTabWidget->indexOf(tab)) >= 0)
2039 _graphTabWidget->removeTab(index);
2042 for (int i = 0; i < _tabs.size(); i++) {
2043 tab = _tabs.at(i);
2044 if (!tab->isEmpty() && _graphTabWidget->indexOf(tab) < 0)
2045 _graphTabWidget->insertTab(i, tab, _tabs.at(i)->label());
2048 if (_graphTabWidget->count() &&
2049 ((_showTracksAction->isChecked() && _trackCount)
2050 || (_showRoutesAction->isChecked() && _routeCount))) {
2051 if (_showGraphsAction->isChecked())
2052 _graphTabWidget->setHidden(false);
2053 _showGraphsAction->setEnabled(true);
2054 } else {
2055 _graphTabWidget->setHidden(true);
2056 _showGraphsAction->setEnabled(false);
2059 return (hidden != _graphTabWidget->isHidden());
2062 void GUI::updateDEMDownloadAction()
2064 _downloadDEMAction->setEnabled(!_dem->url().isEmpty()
2065 && !_dem->checkTiles(_mapView->boundingRect()));
2068 void GUI::setTimeType(TimeType type)
2070 for (int i = 0; i <_tabs.count(); i++)
2071 _tabs.at(i)->setTimeType(type);
2073 updateStatusBarInfo();
2076 void GUI::setUnits(Units units)
2078 _units = units;
2080 _mapView->setUnits(units);
2081 for (int i = 0; i <_tabs.count(); i++)
2082 _tabs.at(i)->setUnits(units);
2083 updateStatusBarInfo();
2086 void GUI::setCoordinatesFormat(CoordinatesFormat format)
2088 _mapView->setCoordinatesFormat(format);
2091 void GUI::setGraphType(GraphType type)
2093 for (int i = 0; i <_tabs.count(); i++)
2094 _tabs.at(i)->setGraphType(type);
2097 void GUI::next()
2099 int showError = 1;
2100 QString file = _browser->next();
2101 if (file.isNull())
2102 return;
2104 closeFiles();
2105 openFile(file, true, showError);
2108 void GUI::prev()
2110 int showError = 1;
2111 QString file = _browser->prev();
2112 if (file.isNull())
2113 return;
2115 closeFiles();
2116 openFile(file, true, showError);
2119 void GUI::last()
2121 int showError = 1;
2122 QString file = _browser->last();
2123 if (file.isNull())
2124 return;
2126 closeFiles();
2127 openFile(file, true, showError);
2130 void GUI::first()
2132 int showError = 1;
2133 QString file = _browser->first();
2134 if (file.isNull())
2135 return;
2137 closeFiles();
2138 openFile(file, true, showError);
2141 #ifndef Q_OS_ANDROID
2142 void GUI::keyPressEvent(QKeyEvent *event)
2144 QString file;
2145 int showError = 1;
2147 switch (event->key()) {
2148 case PREV_KEY:
2149 file = _browser->prev();
2150 break;
2151 case NEXT_KEY:
2152 file = _browser->next();
2153 break;
2154 case FIRST_KEY:
2155 file = _browser->first();
2156 break;
2157 case LAST_KEY:
2158 file = _browser->last();
2159 break;
2161 case TOGGLE_GRAPH_TYPE_KEY:
2162 if (_timeGraphAction->isChecked())
2163 _distanceGraphAction->trigger();
2164 else
2165 _timeGraphAction->trigger();
2166 break;
2167 case TOGGLE_TIME_TYPE_KEY:
2168 if (_movingTimeAction->isChecked())
2169 _totalTimeAction->trigger();
2170 else
2171 _movingTimeAction->trigger();
2172 break;
2173 case TOGGLE_MARKER_INFO_KEY:
2174 if (_showMarkerDateAction->isChecked())
2175 _showMarkerCoordinatesAction->trigger();
2176 else if (_showMarkerCoordinatesAction->isChecked())
2177 _showMarkerDateAction->trigger();
2178 break;
2179 case Qt::Key_Escape:
2180 if (_fullscreenAction->isChecked()) {
2181 _fullscreenAction->setChecked(false);
2182 showFullscreen(false);
2183 return;
2185 break;
2188 if (!file.isNull()) {
2189 if (!(event->modifiers() & MODIFIER))
2190 closeFiles();
2191 openFile(file, false, showError);
2192 return;
2195 QMainWindow::keyPressEvent(event);
2197 #endif // Q_OS_ANDROID
2199 void GUI::closeEvent(QCloseEvent *event)
2201 writeSettings();
2202 QMainWindow::closeEvent(event);
2205 void GUI::dragEnterEvent(QDragEnterEvent *event)
2207 if (!event->mimeData()->hasUrls())
2208 return;
2209 if (event->proposedAction() != Qt::CopyAction)
2210 return;
2212 QList<QUrl> urls = event->mimeData()->urls();
2213 for (int i = 0; i < urls.size(); i++)
2214 if (!urls.at(i).isLocalFile())
2215 return;
2217 event->acceptProposedAction();
2220 void GUI::dropEvent(QDropEvent *event)
2222 MapAction *lastReady = 0;
2223 QList<QUrl> urls(event->mimeData()->urls());
2224 int silent = 0;
2225 int showError = (urls.size() > 1) ? 2 : 1;
2227 for (int i = 0; i < urls.size(); i++) {
2228 QString file(urls.at(i).toLocalFile());
2230 if (!openFile(file, false, silent)) {
2231 MapAction *a;
2232 if (!loadMap(file, a, true))
2233 openFile(file, true, showError);
2234 else {
2235 if (a)
2236 lastReady = a;
2241 if (lastReady)
2242 lastReady->trigger();
2244 event->acceptProposedAction();
2247 QGeoPositionInfoSource *GUI::positionSource(const Options &options)
2249 QGeoPositionInfoSource *source;
2251 #if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
2252 source = QGeoPositionInfoSource::createSource(options.plugin, this);
2253 #else // QT 5.14
2254 source = QGeoPositionInfoSource::createSource(options.plugin,
2255 options.pluginParams.value(options.plugin), this);
2256 #endif // QT 5.14
2257 if (source)
2258 source->setPreferredPositioningMethods(
2259 QGeoPositionInfoSource::SatellitePositioningMethods);
2261 return source;
2264 void GUI::writeSettings()
2266 #define WRITE(name, value) \
2267 Settings::name.write(settings, value);
2269 QSettings settings(qApp->applicationName(), qApp->applicationName());
2270 settings.clear();
2272 /* Window */
2273 #ifndef Q_OS_ANDROID
2274 settings.beginGroup(SETTINGS_WINDOW);
2275 if (!_windowStates.isEmpty() && !_windowGeometries.isEmpty()) {
2276 WRITE(windowState, _windowStates.first());
2277 WRITE(windowGeometry, _windowGeometries.first());
2278 } else {
2279 WRITE(windowState, saveState());
2280 WRITE(windowGeometry, saveGeometry());
2282 settings.endGroup();
2283 #endif // Q_OS_ANDROID
2285 /* Settings */
2286 settings.beginGroup(SETTINGS_SETTINGS);
2287 WRITE(timeType, _movingTimeAction->isChecked() ? Moving : Total);
2288 WRITE(units, _imperialUnitsAction->isChecked()
2289 ? Imperial : _nauticalUnitsAction->isChecked()
2290 ? Nautical : Metric);
2291 WRITE(coordinatesFormat, _dmsAction->isChecked()
2292 ? DMS : _degreesMinutesAction->isChecked()
2293 ? DegreesMinutes : DecimalDegrees);
2294 #ifndef Q_OS_ANDROID
2295 WRITE(showToolbars, _showToolbarsAction->isChecked());
2296 #endif // Q_OS_ANDROID
2297 settings.endGroup();
2299 /* Map */
2300 settings.beginGroup(SETTINGS_MAP);
2301 WRITE(activeMap, _map->name());
2302 WRITE(showMap, _showMapAction->isChecked());
2303 WRITE(cursorCoordinates, _showCoordinatesAction->isChecked());
2304 settings.endGroup();
2306 /* Graph */
2307 settings.beginGroup(SETTINGS_GRAPH);
2308 WRITE(showGraphs, _showGraphsAction->isChecked());
2309 WRITE(graphType, _timeGraphAction->isChecked() ? Time : Distance);
2310 WRITE(showGrid, _showGraphGridAction->isChecked());
2311 WRITE(sliderInfo, _showGraphSliderInfoAction->isChecked());
2312 #ifdef Q_OS_ANDROID
2313 WRITE(showGraphTabs, _showGraphTabsAction->isChecked());
2314 #endif // Q_OS_ANDROID
2315 settings.endGroup();
2317 /* POI */
2318 QList<QAction*> actions(_poisActionGroup->actions());
2319 QStringList disabled;
2320 for (int i = 0; i < actions.size(); i++)
2321 if (!actions.at(i)->isChecked())
2322 disabled.append(actions.at(i)->data().toString());
2324 settings.beginGroup(SETTINGS_POI);
2325 WRITE(showPoi, _showPOIAction->isChecked());
2326 WRITE(poiOverlap, _overlapPOIAction->isChecked());
2327 WRITE(poiLabels, _showPOILabelsAction->isChecked());
2328 WRITE(poiIcons, _showPOIIconsAction->isChecked());
2329 WRITE(disabledPoiFiles, disabled);
2330 settings.endGroup();
2332 /* Data */
2333 MarkerInfoItem::Type mi;
2334 if (_showMarkerDateAction->isChecked())
2335 mi = MarkerInfoItem::Date;
2336 else if (_showMarkerCoordinatesAction->isChecked())
2337 mi = MarkerInfoItem::Position;
2338 else
2339 mi = MarkerInfoItem::None;
2341 settings.beginGroup(SETTINGS_DATA);
2342 WRITE(tracks, _showTracksAction->isChecked());
2343 WRITE(routes, _showRoutesAction->isChecked());
2344 WRITE(waypoints, _showWaypointsAction->isChecked());
2345 WRITE(areas, _showAreasAction->isChecked());
2346 WRITE(waypointIcons, _showWaypointIconsAction->isChecked());
2347 WRITE(waypointLabels, _showWaypointLabelsAction->isChecked());
2348 WRITE(routeWaypoints, _showRouteWaypointsAction->isChecked());
2349 WRITE(pathTicks, _showTicksAction->isChecked());
2350 WRITE(positionMarkers, _showMarkersAction->isChecked()
2351 || _showMarkerDateAction->isChecked()
2352 || _showMarkerCoordinatesAction->isChecked());
2353 WRITE(markerInfo, mi);
2354 WRITE(useStyles, _useStylesAction->isChecked());
2355 settings.endGroup();
2357 /* Position */
2358 settings.beginGroup(SETTINGS_POSITION);
2359 WRITE(showPosition, _showPositionAction->isChecked());
2360 WRITE(followPosition, _followPositionAction->isChecked());
2361 WRITE(positionCoordinates, _showPositionCoordinatesAction->isChecked());
2362 WRITE(motionInfo, _showMotionInfoAction->isChecked());
2363 settings.endGroup();
2365 /* PDF export */
2366 settings.beginGroup(SETTINGS_PDF_EXPORT);
2367 WRITE(pdfOrientation, _pdfExport.orientation);
2368 WRITE(pdfResolution, _pdfExport.resolution);
2369 WRITE(pdfSize, _pdfExport.paperSize);
2370 WRITE(pdfMarginLeft, _pdfExport.margins.left());
2371 WRITE(pdfMarginTop, _pdfExport.margins.top());
2372 WRITE(pdfMarginRight, _pdfExport.margins.right());
2373 WRITE(pdfMarginBottom, _pdfExport.margins.bottom());
2374 WRITE(pdfFileName, _pdfExport.fileName);
2375 settings.endGroup();
2377 /* PNG export */
2378 settings.beginGroup(SETTINGS_PNG_EXPORT);
2379 WRITE(pngWidth, _pngExport.size.width());
2380 WRITE(pngHeight, _pngExport.size.height());
2381 WRITE(pngMarginLeft, _pngExport.margins.left());
2382 WRITE(pngMarginTop, _pngExport.margins.top());
2383 WRITE(pngMarginRight, _pngExport.margins.right());
2384 WRITE(pngMarginBottom, _pngExport.margins.bottom());
2385 WRITE(pngAntialiasing, _pngExport.antialiasing);
2386 WRITE(pngFileName, _pngExport.fileName);
2387 settings.endGroup();
2389 /* Options */
2390 settings.beginGroup(SETTINGS_OPTIONS);
2391 WRITE(paletteColor, _options.palette.color());
2392 WRITE(paletteShift, _options.palette.shift());
2393 WRITE(mapOpacity, _options.mapOpacity);
2394 WRITE(backgroundColor, _options.backgroundColor);
2395 WRITE(crosshairColor, _options.crosshairColor);
2396 WRITE(infoColor, _options.infoColor);
2397 WRITE(infoBackground, _options.infoBackground);
2398 WRITE(trackWidth, _options.trackWidth);
2399 WRITE(routeWidth, _options.routeWidth);
2400 WRITE(areaWidth, _options.areaWidth);
2401 WRITE(trackStyle, (int)_options.trackStyle);
2402 WRITE(routeStyle, (int)_options.routeStyle);
2403 WRITE(areaStyle, (int)_options.areaStyle);
2404 WRITE(areaOpacity, _options.areaOpacity);
2405 WRITE(waypointSize, _options.waypointSize);
2406 WRITE(waypointColor, _options.waypointColor);
2407 WRITE(poiSize, _options.poiSize);
2408 WRITE(poiColor, _options.poiColor);
2409 WRITE(graphWidth, _options.graphWidth);
2410 WRITE(pathAntiAliasing, _options.pathAntiAliasing);
2411 WRITE(graphAntiAliasing, _options.graphAntiAliasing);
2412 WRITE(elevationFilter, _options.elevationFilter);
2413 WRITE(speedFilter, _options.speedFilter);
2414 WRITE(heartRateFilter, _options.heartRateFilter);
2415 WRITE(cadenceFilter, _options.cadenceFilter);
2416 WRITE(powerFilter, _options.powerFilter);
2417 WRITE(outlierEliminate, _options.outlierEliminate);
2418 WRITE(automaticPause, _options.automaticPause);
2419 WRITE(pauseSpeed, _options.pauseSpeed);
2420 WRITE(pauseInterval, _options.pauseInterval);
2421 WRITE(useReportedSpeed, _options.useReportedSpeed);
2422 WRITE(dataUseDEM, _options.dataUseDEM);
2423 WRITE(secondaryElevation, _options.showSecondaryElevation);
2424 WRITE(secondarySpeed, _options.showSecondarySpeed);
2425 WRITE(timeZone, QVariant::fromValue(_options.timeZone));
2426 WRITE(useSegments, _options.useSegments);
2427 WRITE(poiRadius, _options.poiRadius);
2428 WRITE(demURL, _options.demURL);
2429 WRITE(demAuthentication, _options.demAuthorization);
2430 WRITE(demUsername, _options.demUsername);
2431 WRITE(demPassword, _options.demPassword);
2432 WRITE(positionPlugin(), _options.plugin);
2433 WRITE(positionPluginParameters, _options.pluginParams);
2434 WRITE(useOpenGL, _options.useOpenGL);
2435 WRITE(enableHTTP2, _options.enableHTTP2);
2436 WRITE(pixmapCache, _options.pixmapCache);
2437 WRITE(demCache, _options.demCache);
2438 WRITE(connectionTimeout, _options.connectionTimeout);
2439 WRITE(hiresPrint, _options.hiresPrint);
2440 WRITE(printName, _options.printName);
2441 WRITE(printDate, _options.printDate);
2442 WRITE(printDistance, _options.printDistance);
2443 WRITE(printTime, _options.printTime);
2444 WRITE(printMovingTime, _options.printMovingTime);
2445 WRITE(printItemCount, _options.printItemCount);
2446 WRITE(separateGraphPage, _options.separateGraphPage);
2447 WRITE(sliderColor, _options.sliderColor);
2448 WRITE(outputProjection, _options.outputProjection);
2449 WRITE(inputProjection, _options.inputProjection);
2450 WRITE(hidpiMap, _options.hidpiMap);
2451 WRITE(dataPath, _options.dataPath);
2452 WRITE(mapsPath, _options.mapsPath);
2453 WRITE(poiPath, _options.poiPath);
2454 settings.endGroup();
2457 void GUI::readSettings(QString &activeMap, QStringList &disabledPOIs)
2459 #define READ(name) \
2460 (Settings::name.read(settings))
2462 QSettings settings(qApp->applicationName(), qApp->applicationName());
2464 #ifndef Q_OS_ANDROID
2465 settings.beginGroup(SETTINGS_WINDOW);
2466 restoreGeometry(READ(windowGeometry).toByteArray());
2467 restoreState(READ(windowState).toByteArray());
2468 settings.endGroup();
2469 #endif // Q_OS_ANDROID
2471 /* Settings */
2472 settings.beginGroup(SETTINGS_SETTINGS);
2473 TimeType tt = (TimeType)READ(timeType).toInt();
2474 if (tt == Moving)
2475 _movingTimeAction->setChecked(true);
2476 else
2477 _totalTimeAction->setChecked(true);
2478 setTimeType(tt);
2480 Units u = (Units)READ(units).toInt();
2481 if (u == Imperial)
2482 _imperialUnitsAction->setChecked(true);
2483 else if (u == Nautical)
2484 _nauticalUnitsAction->setChecked(true);
2485 else
2486 _metricUnitsAction->setChecked(true);
2487 setUnits(u);
2489 CoordinatesFormat cf = (CoordinatesFormat)READ(coordinatesFormat).toInt();
2490 if (cf == DMS)
2491 _dmsAction->setChecked(true);
2492 else if (cf == DegreesMinutes)
2493 _degreesMinutesAction->setChecked(true);
2494 else
2495 _decimalDegreesAction->setChecked(true);
2496 setCoordinatesFormat(cf);
2498 #ifndef Q_OS_ANDROID
2499 if (READ(showToolbars).toBool())
2500 _showToolbarsAction->setChecked(true);
2501 else
2502 showToolbars(false);
2503 #endif // Q_OS_ANDROID
2504 settings.endGroup();
2506 /* Map */
2507 settings.beginGroup(SETTINGS_MAP);
2508 if (READ(showMap).toBool()) {
2509 _showMapAction->setChecked(true);
2510 _mapView->showMap(true);
2512 if (READ(cursorCoordinates).toBool()) {
2513 _showCoordinatesAction->setChecked(true);
2514 _mapView->showCursorCoordinates(true);
2516 activeMap = READ(activeMap).toString();
2517 settings.endGroup();
2519 /* Graph */
2520 settings.beginGroup(SETTINGS_GRAPH);
2521 if (READ(showGraphs).toBool())
2522 _showGraphsAction->setChecked(true);
2523 else
2524 showGraphs(false);
2526 GraphType gt = (GraphType)READ(graphType).toInt();
2527 if (gt == Time)
2528 _timeGraphAction->setChecked(true);
2529 else
2530 _distanceGraphAction->setChecked(true);
2531 setGraphType(gt);
2533 if (READ(showGrid).toBool())
2534 _showGraphGridAction->setChecked(true);
2535 else
2536 showGraphGrids(false);
2538 if (READ(sliderInfo).toBool())
2539 _showGraphSliderInfoAction->setChecked(true);
2540 else
2541 showGraphSliderInfo(false);
2543 #ifdef Q_OS_ANDROID
2544 if (READ(showGraphTabs).toBool())
2545 _showGraphTabsAction->setChecked(true);
2546 else
2547 showGraphTabs(false);
2548 #endif // Q_OS_ANDROID
2549 settings.endGroup();
2551 /* POI */
2552 settings.beginGroup(SETTINGS_POI);
2553 if (READ(poiOverlap).toBool()) {
2554 _overlapPOIAction->setChecked(true);
2555 _mapView->showOverlappedPOIs(true);
2557 if (READ(poiIcons).toBool()) {
2558 _showPOIIconsAction->setChecked(true);
2559 _mapView->showPOIIcons(true);
2561 if (READ(poiLabels).toBool()) {
2562 _showPOILabelsAction->setChecked(true);
2563 _mapView->showPOILabels(true);
2565 if (READ(showPoi).toBool()) {
2566 _showPOIAction->setChecked(true);
2567 _mapView->showPOI(true);
2569 disabledPOIs = READ(disabledPoiFiles);
2570 settings.endGroup();
2572 /* Data */
2573 settings.beginGroup(SETTINGS_DATA);
2574 if (READ(tracks).toBool()) {
2575 _showTracksAction->setChecked(true);
2576 _mapView->showTracks(true);
2577 for (int i = 0; i < _tabs.count(); i++)
2578 _tabs.at(i)->showTracks(true);
2580 if (READ(routes).toBool()) {
2581 _showRoutesAction->setChecked(true);
2582 _mapView->showRoutes(true);
2583 for (int i = 0; i < _tabs.count(); i++)
2584 _tabs.at(i)->showRoutes(true);
2586 if (READ(waypoints).toBool()) {
2587 _showWaypointsAction->setChecked(true);
2588 _mapView->showWaypoints(true);
2590 if (READ(areas).toBool()) {
2591 _showAreasAction->setChecked(true);
2592 _mapView->showAreas(true);
2594 if (READ(waypointIcons).toBool()) {
2595 _showWaypointIconsAction->setChecked(true);
2596 _mapView->showWaypointIcons(true);
2598 if (READ(waypointLabels).toBool()) {
2599 _showWaypointLabelsAction->setChecked(true);
2600 _mapView->showWaypointLabels(true);
2602 if (READ(routeWaypoints).toBool()) {
2603 _showRouteWaypointsAction->setChecked(true);
2604 _mapView->showRouteWaypoints(true);
2606 if (READ(pathTicks).toBool()) {
2607 _showTicksAction->setChecked(true);
2608 _mapView->showTicks(true);
2610 if (READ(useStyles).toBool()) {
2611 _useStylesAction->setChecked(true);
2612 _mapView->useStyles(true);
2614 if (READ(positionMarkers).toBool()) {
2615 MarkerInfoItem::Type mt = (MarkerInfoItem::Type)READ(markerInfo).toInt();
2616 if (mt == MarkerInfoItem::Position)
2617 _showMarkerCoordinatesAction->setChecked(true);
2618 else if (mt == MarkerInfoItem::Date)
2619 _showMarkerDateAction->setChecked(true);
2620 else
2621 _showMarkersAction->setChecked(true);
2623 _mapView->showMarkers(true);
2624 _mapView->showMarkerInfo(mt);
2625 } else
2626 _hideMarkersAction->setChecked(true);
2627 settings.endGroup();
2629 /* Position */
2630 settings.beginGroup(SETTINGS_POSITION);
2631 if (READ(showPosition).toBool()) {
2632 _showPositionAction->setChecked(true);
2633 _mapView->showPosition(true);
2635 if (READ(followPosition).toBool()) {
2636 _followPositionAction->setChecked(true);
2637 _mapView->followPosition(true);
2639 if (READ(positionCoordinates).toBool()) {
2640 _showPositionCoordinatesAction->setChecked(true);
2641 _mapView->showPositionCoordinates(true);
2643 if (READ(motionInfo).toBool()) {
2644 _showMotionInfoAction->setChecked(true);
2645 _mapView->showMotionInfo(true);
2647 settings.endGroup();
2649 /* PDF export */
2650 settings.beginGroup(SETTINGS_PDF_EXPORT);
2651 _pdfExport.orientation = (QPageLayout::Orientation)READ(pdfOrientation)
2652 .toInt();
2653 _pdfExport.resolution = READ(pdfResolution).toInt();
2654 _pdfExport.paperSize = (QPageSize::PageSizeId)READ(pdfSize).toInt();
2655 _pdfExport.margins = QMarginsF(READ(pdfMarginLeft).toReal(),
2656 READ(pdfMarginTop).toReal(), READ(pdfMarginRight).toReal(),
2657 READ(pdfMarginBottom).toReal());
2658 _pdfExport.fileName = READ(pdfFileName).toString();
2659 settings.endGroup();
2661 /* PNG export */
2662 settings.beginGroup(SETTINGS_PNG_EXPORT);
2663 _pngExport.size = QSize(READ(pngWidth).toInt(), READ(pngHeight).toInt());
2664 _pngExport.margins = QMargins(READ(pngMarginLeft).toInt(),
2665 READ(pngMarginTop).toInt(), READ(pngMarginRight).toInt(),
2666 READ(pngMarginBottom).toInt());
2667 _pngExport.antialiasing = READ(pngAntialiasing).toBool();
2668 _pngExport.fileName = READ(pngFileName).toString();
2669 settings.endGroup();
2671 /* Options */
2672 settings.beginGroup(SETTINGS_OPTIONS);
2673 _options.palette = Palette(READ(paletteColor).value<QColor>(),
2674 READ(paletteShift).toDouble());
2675 _options.mapOpacity = READ(mapOpacity).toInt();
2676 _options.backgroundColor = READ(backgroundColor).value<QColor>();
2677 _options.crosshairColor = READ(crosshairColor).value<QColor>();
2678 _options.infoColor = READ(infoColor).value<QColor>();
2679 _options.infoBackground = READ(infoBackground).toBool();
2680 _options.trackWidth = READ(trackWidth).toInt();
2681 _options.routeWidth = READ(routeWidth).toInt();
2682 _options.areaWidth = READ(areaWidth).toInt();
2683 _options.trackStyle = (Qt::PenStyle)READ(trackStyle).toInt();
2684 _options.routeStyle = (Qt::PenStyle)READ(routeStyle).toInt();
2685 _options.areaStyle = (Qt::PenStyle)READ(areaStyle).toInt();
2686 _options.areaOpacity = READ(areaOpacity).toInt();
2687 _options.pathAntiAliasing = READ(pathAntiAliasing).toBool();
2688 _options.waypointSize = READ(waypointSize).toInt();
2689 _options.waypointColor = READ(waypointColor).value<QColor>();
2690 _options.poiSize = READ(poiSize).toInt();
2691 _options.poiColor = READ(poiColor).value<QColor>();
2692 _options.graphWidth = READ(graphWidth).toInt();
2693 _options.graphAntiAliasing = READ(graphAntiAliasing).toBool();
2694 _options.elevationFilter = READ(elevationFilter).toInt();
2695 _options.speedFilter = READ(speedFilter).toInt();
2696 _options.heartRateFilter = READ(heartRateFilter).toInt();
2697 _options.cadenceFilter = READ(cadenceFilter).toInt();
2698 _options.powerFilter = READ(powerFilter).toInt();
2699 _options.outlierEliminate = READ(outlierEliminate).toBool();
2700 _options.pauseSpeed = READ(pauseSpeed).toFloat();
2701 _options.automaticPause = READ(automaticPause).toBool();
2702 _options.pauseInterval = READ(pauseInterval).toInt();
2703 _options.useReportedSpeed = READ(useReportedSpeed).toBool();
2704 _options.dataUseDEM = READ(dataUseDEM).toBool();
2705 _options.showSecondaryElevation = READ(secondaryElevation).toBool();
2706 _options.showSecondarySpeed = READ(secondarySpeed).toBool();
2707 _options.timeZone = READ(timeZone).value<TimeZoneInfo>();
2708 _options.useSegments = READ(useSegments).toBool();
2709 _options.poiRadius = READ(poiRadius).toInt();
2710 _options.demURL = READ(demURL).toString();
2711 _options.demAuthorization = READ(demAuthentication).toBool();
2712 _options.demUsername = READ(demUsername).toString();
2713 _options.demPassword = READ(demPassword).toString();
2714 _options.plugin = READ(positionPlugin()).toString();
2715 _options.pluginParams = READ(positionPluginParameters);
2716 _options.useOpenGL = READ(useOpenGL).toBool();
2717 _options.enableHTTP2 = READ(enableHTTP2).toBool();
2718 _options.pixmapCache = READ(pixmapCache).toInt();
2719 _options.demCache = READ(demCache).toInt();
2720 _options.connectionTimeout = READ(connectionTimeout).toInt();
2721 _options.hiresPrint = READ(hiresPrint).toBool();
2722 _options.printName = READ(printName).toBool();
2723 _options.printDate = READ(printDate).toBool();
2724 _options.printDistance = READ(printDistance).toBool();
2725 _options.printTime = READ(printTime).toBool();
2726 _options.printMovingTime = READ(printMovingTime).toBool();
2727 _options.printItemCount = READ(printItemCount).toBool();
2728 _options.separateGraphPage = READ(separateGraphPage).toBool();
2729 _options.sliderColor = READ(sliderColor).value<QColor>();
2730 _options.outputProjection = READ(outputProjection).toInt();
2731 _options.inputProjection = READ(inputProjection).toInt();
2732 _options.hidpiMap = READ(hidpiMap).toBool();
2733 _options.dataPath = READ(dataPath).toString();
2734 _options.mapsPath = READ(mapsPath).toString();
2735 _options.poiPath = READ(poiPath).toString();
2736 settings.endGroup();
2738 loadOptions();
2741 void GUI::loadOptions()
2743 _positionSource = positionSource(_options);
2744 _showPositionAction->setEnabled(_positionSource != 0);
2746 _mapView->setPalette(_options.palette);
2747 _mapView->setMapOpacity(_options.mapOpacity);
2748 _mapView->setBackgroundColor(_options.backgroundColor);
2749 _mapView->setCrosshairColor(_options.crosshairColor);
2750 _mapView->setInfoColor(_options.infoColor);
2751 _mapView->drawInfoBackground(_options.infoBackground);
2752 _mapView->setTrackWidth(_options.trackWidth);
2753 _mapView->setRouteWidth(_options.routeWidth);
2754 _mapView->setAreaWidth(_options.areaWidth);
2755 _mapView->setTrackStyle(_options.trackStyle);
2756 _mapView->setRouteStyle(_options.routeStyle);
2757 _mapView->setAreaStyle(_options.areaStyle);
2758 _mapView->setAreaOpacity(_options.areaOpacity);
2759 _mapView->setWaypointSize(_options.waypointSize);
2760 _mapView->setWaypointColor(_options.waypointColor);
2761 _mapView->setPOISize(_options.poiSize);
2762 _mapView->setPOIColor(_options.poiColor);
2763 _mapView->setRenderHint(QPainter::Antialiasing, _options.pathAntiAliasing);
2764 _mapView->setMarkerColor(_options.sliderColor);
2765 _mapView->useOpenGL(_options.useOpenGL);
2766 _mapView->setMapConfig(CRS::projection(_options.inputProjection),
2767 CRS::projection(4326, _options.outputProjection), _options.hidpiMap);
2768 _mapView->setTimeZone(_options.timeZone.zone());
2769 _mapView->setPositionSource(_positionSource);
2771 for (int i = 0; i < _tabs.count(); i++) {
2772 _tabs.at(i)->setPalette(_options.palette);
2773 _tabs.at(i)->setGraphWidth(_options.graphWidth);
2774 _tabs.at(i)->setRenderHint(QPainter::Antialiasing,
2775 _options.graphAntiAliasing);
2776 _tabs.at(i)->setSliderColor(_options.sliderColor);
2777 if (_options.useOpenGL)
2778 _tabs.at(i)->useOpenGL(true);
2781 Track::setElevationFilter(_options.elevationFilter);
2782 Track::setSpeedFilter(_options.speedFilter);
2783 Track::setHeartRateFilter(_options.heartRateFilter);
2784 Track::setCadenceFilter(_options.cadenceFilter);
2785 Track::setPowerFilter(_options.powerFilter);
2786 Track::setOutlierElimination(_options.outlierEliminate);
2787 Track::setAutomaticPause(_options.automaticPause);
2788 Track::setPauseSpeed(_options.pauseSpeed);
2789 Track::setPauseInterval(_options.pauseInterval);
2790 Track::useReportedSpeed(_options.useReportedSpeed);
2791 Track::useDEM(_options.dataUseDEM);
2792 Track::showSecondaryElevation(_options.showSecondaryElevation);
2793 Track::showSecondarySpeed(_options.showSecondarySpeed);
2794 Track::useSegments(_options.useSegments);
2795 Route::useDEM(_options.dataUseDEM);
2796 Route::showSecondaryElevation(_options.showSecondaryElevation);
2797 Waypoint::useDEM(_options.dataUseDEM);
2798 Waypoint::showSecondaryElevation(_options.showSecondaryElevation);
2800 Downloader::enableHTTP2(_options.enableHTTP2);
2801 Downloader::setTimeout(_options.connectionTimeout);
2803 QPixmapCache::setCacheLimit(_options.pixmapCache * 1024);
2804 DEM::setCacheSize(_options.demCache * 1024);
2806 _poi->setRadius(_options.poiRadius);
2808 _dem->setUrl(_options.demURL);
2809 if (_options.demAuthorization)
2810 _dem->setAuthorization(Authorization(_options.demUsername,
2811 _options.demPassword));
2813 _dataDir = _options.dataPath;
2814 _mapDir = _options.mapsPath;
2815 _poiDir = _options.poiPath;
2818 void GUI::updateOptions(const Options &options)
2820 #define SET_VIEW_OPTION(option, action) \
2821 if (options.option != _options.option) \
2822 _mapView->action(options.option)
2823 #define SET_TAB_OPTION(option, action) \
2824 if (options.option != _options.option) \
2825 for (int i = 0; i < _tabs.count(); i++) \
2826 _tabs.at(i)->action(options.option)
2827 #define SET_TRACK_OPTION(option, action) \
2828 if (options.option != _options.option) { \
2829 Track::action(options.option); \
2830 reload = true; \
2832 #define SET_ROUTE_OPTION(option, action) \
2833 if (options.option != _options.option) { \
2834 Route::action(options.option); \
2835 reload = true; \
2837 #define SET_WAYPOINT_OPTION(option, action) \
2838 if (options.option != _options.option) { \
2839 Waypoint::action(options.option); \
2840 reload = true; \
2843 bool reload = false;
2845 SET_VIEW_OPTION(palette, setPalette);
2846 SET_VIEW_OPTION(mapOpacity, setMapOpacity);
2847 SET_VIEW_OPTION(backgroundColor, setBackgroundColor);
2848 SET_VIEW_OPTION(trackWidth, setTrackWidth);
2849 SET_VIEW_OPTION(routeWidth, setRouteWidth);
2850 SET_VIEW_OPTION(areaWidth, setAreaWidth);
2851 SET_VIEW_OPTION(trackStyle, setTrackStyle);
2852 SET_VIEW_OPTION(routeStyle, setRouteStyle);
2853 SET_VIEW_OPTION(areaStyle, setAreaStyle);
2854 SET_VIEW_OPTION(areaOpacity, setAreaOpacity);
2855 SET_VIEW_OPTION(waypointSize, setWaypointSize);
2856 SET_VIEW_OPTION(waypointColor, setWaypointColor);
2857 SET_VIEW_OPTION(poiSize, setPOISize);
2858 SET_VIEW_OPTION(poiColor, setPOIColor);
2859 SET_VIEW_OPTION(pathAntiAliasing, useAntiAliasing);
2860 SET_VIEW_OPTION(useOpenGL, useOpenGL);
2861 SET_VIEW_OPTION(sliderColor, setMarkerColor);
2862 SET_VIEW_OPTION(crosshairColor, setCrosshairColor);
2863 SET_VIEW_OPTION(infoColor, setInfoColor);
2864 SET_VIEW_OPTION(infoBackground, drawInfoBackground);
2866 if (options.plugin != _options.plugin
2867 || options.pluginParams.value(options.plugin)
2868 != _options.pluginParams.value(_options.plugin)) {
2869 QGeoPositionInfoSource *source = positionSource(options);
2870 _showPositionAction->setEnabled(source != 0);
2871 _mapView->setPositionSource(source);
2872 delete _positionSource;
2873 _positionSource = source;
2876 if (options.hidpiMap != _options.hidpiMap
2877 || options.outputProjection != _options.outputProjection
2878 || options.inputProjection != _options.inputProjection)
2879 _mapView->setMapConfig(CRS::projection(options.inputProjection),
2880 CRS::projection(4326, options.outputProjection), options.hidpiMap);
2882 if (options.timeZone != _options.timeZone) {
2883 _mapView->setTimeZone(options.timeZone.zone());
2884 _dateRange.first = _dateRange.first.toTimeZone(options.timeZone.zone());
2885 _dateRange.second = _dateRange.second.toTimeZone(options.timeZone.zone());
2888 SET_TAB_OPTION(palette, setPalette);
2889 SET_TAB_OPTION(graphWidth, setGraphWidth);
2890 SET_TAB_OPTION(graphAntiAliasing, useAntiAliasing);
2891 SET_TAB_OPTION(useOpenGL, useOpenGL);
2892 SET_TAB_OPTION(sliderColor, setSliderColor);
2894 SET_TRACK_OPTION(elevationFilter, setElevationFilter);
2895 SET_TRACK_OPTION(speedFilter, setSpeedFilter);
2896 SET_TRACK_OPTION(heartRateFilter, setHeartRateFilter);
2897 SET_TRACK_OPTION(cadenceFilter, setCadenceFilter);
2898 SET_TRACK_OPTION(powerFilter, setPowerFilter);
2899 SET_TRACK_OPTION(outlierEliminate, setOutlierElimination);
2900 SET_TRACK_OPTION(automaticPause, setAutomaticPause);
2901 SET_TRACK_OPTION(pauseSpeed, setPauseSpeed);
2902 SET_TRACK_OPTION(pauseInterval, setPauseInterval);
2903 SET_TRACK_OPTION(useReportedSpeed, useReportedSpeed);
2904 SET_TRACK_OPTION(dataUseDEM, useDEM);
2905 SET_TRACK_OPTION(showSecondaryElevation, showSecondaryElevation);
2906 SET_TRACK_OPTION(showSecondarySpeed, showSecondarySpeed);
2907 SET_TRACK_OPTION(useSegments, useSegments);
2909 SET_ROUTE_OPTION(dataUseDEM, useDEM);
2910 SET_ROUTE_OPTION(showSecondaryElevation, showSecondaryElevation);
2912 SET_WAYPOINT_OPTION(dataUseDEM, useDEM);
2913 SET_WAYPOINT_OPTION(showSecondaryElevation, showSecondaryElevation);
2915 if (options.poiRadius != _options.poiRadius)
2916 _poi->setRadius(options.poiRadius);
2918 if (options.demURL != _options.demURL)
2919 _dem->setUrl(options.demURL);
2920 if (options.demAuthorization != _options.demAuthorization
2921 || options.demUsername != _options.demUsername
2922 || options.demPassword != _options.demPassword)
2923 _dem->setAuthorization(options.demAuthorization
2924 ? Authorization(options.demUsername, options.demPassword)
2925 : Authorization());
2927 if (options.pixmapCache != _options.pixmapCache)
2928 QPixmapCache::setCacheLimit(options.pixmapCache * 1024);
2929 if (options.demCache != _options.demCache)
2930 DEM::setCacheSize(options.demCache * 1024);
2932 if (options.connectionTimeout != _options.connectionTimeout)
2933 Downloader::setTimeout(options.connectionTimeout);
2934 if (options.enableHTTP2 != _options.enableHTTP2)
2935 Downloader::enableHTTP2(options.enableHTTP2);
2937 if (options.dataPath != _options.dataPath)
2938 _dataDir = options.dataPath;
2939 if (options.mapsPath != _options.mapsPath)
2940 _mapDir = options.mapsPath;
2941 if (options.poiPath != _options.poiPath)
2942 _poiDir = options.poiPath;
2944 if (reload)
2945 reloadFiles();
2947 _options = options;
2949 updateDEMDownloadAction();
2952 void GUI::loadInitialMaps(const QString &selected)
2954 // Load the maps
2955 QString mapDir(ProgramPaths::mapDir());
2956 if (mapDir.isNull())
2957 return;
2959 TreeNode<Map*> maps(MapList::loadMaps(mapDir));
2960 createMapNodeMenu(createMapActionsNode(maps), _mapMenu, _mapsEnd);
2962 // Select the active map according to the user settings
2963 QAction *ma = mapAction(selected);
2964 if (ma) {
2965 ma->trigger();
2966 _showMapAction->setEnabled(true);
2967 _clearMapCacheAction->setEnabled(true);
2971 void GUI::loadInitialPOIs(const QStringList &disabled)
2973 // Load the POI files
2974 QString poiDir(ProgramPaths::poiDir());
2975 if (poiDir.isNull())
2976 return;
2978 TreeNode<QString> poiFiles(_poi->loadDir(poiDir));
2979 createPOINodeMenu(createPOIActionsNode(poiFiles), _poiMenu, _poisEnd);
2981 // Enable/disable the files according to the user settings
2982 QList<QAction*> poiActions(_poisActionGroup->actions());
2983 for (int i = 0; i < poiActions.count(); i++)
2984 poiActions.at(i)->setChecked(true);
2985 for (int i = 0; i < disabled.size(); i++) {
2986 const QString &file = disabled.at(i);
2987 if (_poi->enableFile(file, false)) {
2988 for (int j = 0; j < poiActions.size(); j++)
2989 if (poiActions.at(j)->data().toString() == file)
2990 poiActions.at(j)->setChecked(false);
2994 _selectAllPOIAction->setEnabled(!poiActions.isEmpty());
2995 _unselectAllPOIAction->setEnabled(!poiActions.isEmpty());
2998 QAction *GUI::mapAction(const QString &name)
3000 QList<QAction *> maps(_mapsActionGroup->actions());
3002 // Last map
3003 for (int i = 0; i < maps.count(); i++) {
3004 Map *map = maps.at(i)->data().value<Map*>();
3005 if (map->name() == name && map->isReady())
3006 return maps.at(i);
3009 // Any usable map
3010 for (int i = 0; i < maps.count(); i++) {
3011 Map *map = maps.at(i)->data().value<Map*>();
3012 if (map->isReady())
3013 return maps.at(i);
3016 return 0;
3019 Units GUI::units() const
3021 return _imperialUnitsAction->isChecked() ? Imperial
3022 : _nauticalUnitsAction->isChecked() ? Nautical : Metric;
3025 qreal GUI::distance() const
3027 qreal dist = 0;
3029 if (_showTracksAction->isChecked())
3030 dist += _trackDistance;
3031 if (_showRoutesAction->isChecked())
3032 dist += _routeDistance;
3034 return dist;
3037 qreal GUI::time() const
3039 return (_showTracksAction->isChecked()) ? _time : 0;
3042 qreal GUI::movingTime() const
3044 return (_showTracksAction->isChecked()) ? _movingTime : 0;
3047 void GUI::show()
3049 QMainWindow::show();
3051 QWindow *w = windowHandle();
3052 connect(w->screen(), &QScreen::logicalDotsPerInchChanged, this,
3053 &GUI::logicalDotsPerInchChanged);
3054 connect(w, &QWindow::screenChanged, this, &GUI::screenChanged);
3056 _mapView->fitContentToSize();
3059 void GUI::screenChanged(QScreen *screen)
3061 _mapView->setDevicePixelRatio(devicePixelRatioF());
3063 disconnect(SIGNAL(logicalDotsPerInchChanged(qreal)), this,
3064 SLOT(logicalDotsPerInchChanged(qreal)));
3065 connect(screen, &QScreen::logicalDotsPerInchChanged, this,
3066 &GUI::logicalDotsPerInchChanged);
3069 void GUI::logicalDotsPerInchChanged(qreal dpi)
3071 Q_UNUSED(dpi)
3073 _mapView->setDevicePixelRatio(devicePixelRatioF());