mirror of
https://github.com/tumic0/GPXSee.git
synced 2025-07-10 01:04:27 +02:00
Compare commits
435 Commits
Author | SHA1 | Date | |
---|---|---|---|
14f4dead76 | |||
96bb3bbdbb | |||
22d18b6d4e | |||
c1b79217a9 | |||
e67a14b072 | |||
473d03cf1f | |||
a339706293 | |||
39c414ca73 | |||
c59d60faed | |||
32d3eab10e | |||
e7729e8745 | |||
bf145c9eb5 | |||
de0a6b0397 | |||
8cf89a580f | |||
152e2a8a09 | |||
6b860fe18c | |||
95f138f5f0 | |||
1fc4dbbb73 | |||
0999cdcba2 | |||
cc16c9e79b | |||
1990c85fd7 | |||
58f70fa833 | |||
0f6c50d588 | |||
89dce5152e | |||
8bce6a44ed | |||
59ecd3fdf0 | |||
a10c729e52 | |||
369601f102 | |||
47d0feeb46 | |||
58a0acc718 | |||
c466527625 | |||
9cd00075c7 | |||
6f72d46d6c | |||
54467e6d45 | |||
3d2e33361d | |||
f91df0d026 | |||
9bd004359d | |||
e170f92e79 | |||
0fb5d8dae6 | |||
5ff931bb5e | |||
5bd744a8ed | |||
035883aab2 | |||
571ed087e3 | |||
c461b2e549 | |||
26b5411465 | |||
8965f450ce | |||
a958544667 | |||
ddf865834a | |||
a4abed8f1f | |||
56061c93cb | |||
7385b08262 | |||
9d79bd9a9d | |||
159e5aeae9 | |||
d8beaed876 | |||
c1584f30d2 | |||
efcefe8fec | |||
cbe312d9c8 | |||
5322ee96c8 | |||
08334d7fde | |||
51d4e04343 | |||
33bbd6a592 | |||
0f96bc602c | |||
7811527239 | |||
31da4e1906 | |||
cb6a82a10a | |||
652cbd7c11 | |||
ff0711c620 | |||
eb0ff84379 | |||
74775b2c62 | |||
6ee3a8ea8d | |||
ee3d43e249 | |||
a6fbae38b8 | |||
242babb741 | |||
e26d1abd5a | |||
e80d16bec5 | |||
412ae74bfa | |||
1c472e47b9 | |||
4a725375e2 | |||
383a196414 | |||
f05b51efa6 | |||
a56c02953f | |||
00d3849e4f | |||
c9244c0684 | |||
d94938261a | |||
d5fc06d9d1 | |||
9e7ebe930e | |||
19bc509043 | |||
335794ee21 | |||
2404107d87 | |||
9447addd19 | |||
b1647d944c | |||
77ac919b83 | |||
4d652aeaff | |||
3ef2361523 | |||
e2b1c2c778 | |||
1f5ecdfc38 | |||
c55b4f1217 | |||
fd71a4c7ce | |||
0b6b09f226 | |||
517ca89814 | |||
455ec3a54b | |||
8cb8d97ee2 | |||
40e520d3bf | |||
6b75442312 | |||
cbc5b2466e | |||
19a847c7d4 | |||
f9e5cb206f | |||
441c738d0f | |||
0bf6d41de6 | |||
b7869e985d | |||
5152d5eb0b | |||
c0653ab0a8 | |||
41d27cabe2 | |||
e2f2e9700f | |||
654bfcd058 | |||
82c0c1f8a7 | |||
9ce6e16b60 | |||
98cd3c3922 | |||
a776f1d30e | |||
aea17c9fed | |||
23c18d4acd | |||
eb8fc7b540 | |||
bf0dd1b24a | |||
9b687bb830 | |||
9859608115 | |||
3d66b2fbb6 | |||
9f62b7114e | |||
c8f7e6f691 | |||
c85f404d28 | |||
273a0f0f27 | |||
bb6d6a4044 | |||
bd3a3b90bc | |||
521369a6ec | |||
440a5736f6 | |||
45a6cdeda0 | |||
f73c27c39c | |||
12827edcb2 | |||
3ec5c37fd5 | |||
ee24bd54f1 | |||
cc22df3bf2 | |||
ef017edbf6 | |||
d7f0cda4b2 | |||
dc03ab91d6 | |||
a898ff2807 | |||
497017091f | |||
9dd4e117f6 | |||
86535021aa | |||
92deaaaf2b | |||
86a943d143 | |||
015a9187a0 | |||
1de9c6ef5d | |||
54b6225c6c | |||
48c7299ba6 | |||
c284b9fa7c | |||
2c503a2406 | |||
27edc4d6b5 | |||
f333a76ef7 | |||
2c114f43c5 | |||
29e29591f8 | |||
e4ac9fda0e | |||
26229e5871 | |||
64bee2f2f4 | |||
e4288ee95c | |||
c9b3c2eedd | |||
42e4b0769f | |||
ce043ef8fa | |||
8c7050e273 | |||
d670107a11 | |||
7b03c4d852 | |||
2002b828dd | |||
71f0e1d0ac | |||
eb9767f2dd | |||
8d06ab6208 | |||
187cb77858 | |||
8167a995f6 | |||
b5aed7314e | |||
464d4c5327 | |||
11f4dc4b41 | |||
2d3ad41d69 | |||
a7dcc57dd1 | |||
2d5e11f001 | |||
e86f89308b | |||
378fa8dc0e | |||
dde8903013 | |||
37c4fe1eba | |||
f9db0acb03 | |||
1aa07a6a34 | |||
c302a67299 | |||
8b6d7acec5 | |||
ba70fd159d | |||
1773a1ae0d | |||
136f08aa76 | |||
f70d92805b | |||
69e66f1856 | |||
911c63df0c | |||
d16899530a | |||
e2339c67cd | |||
c809d2f17e | |||
fac0bae006 | |||
9bd03c1225 | |||
d63c666997 | |||
0cd20a1e57 | |||
2f70d46be8 | |||
325e83569c | |||
56b374ed30 | |||
df1be4aeb9 | |||
d79bdaef78 | |||
fa0c09b30c | |||
95c82c501a | |||
3b16f37e66 | |||
661e26fbdb | |||
25939cfa62 | |||
c59ea4e5cd | |||
5de1bc7e7d | |||
7c3399575b | |||
7bedd17071 | |||
06a84dcea2 | |||
ca204626a1 | |||
d16ef7b081 | |||
ef013dc036 | |||
633d52daca | |||
adbb5e5684 | |||
bd9b09df3d | |||
ede2b6004f | |||
a516055dc2 | |||
1ba3ada96e | |||
1667e0ca70 | |||
cb03c8a903 | |||
b50d5227a5 | |||
eef6360643 | |||
f38db3227f | |||
ac73c04445 | |||
c3aeb95660 | |||
3299b41ec7 | |||
6bdd97611d | |||
58fd5022ca | |||
15e09539c7 | |||
ebe1851abb | |||
a225c6d308 | |||
b3ddbd7b63 | |||
a94056ac7e | |||
e5042b11d7 | |||
aea7bbdf09 | |||
2e0eadd0e7 | |||
1c9b31d7c9 | |||
42e917efab | |||
7a9b26756a | |||
07761ea335 | |||
eaae965719 | |||
f17e5c2ea1 | |||
ca6e8638d8 | |||
21bcaf9562 | |||
66a22fbfee | |||
a160cb4eb3 | |||
2d3ca7c5f8 | |||
f5ec18a13a | |||
8c71d11fa6 | |||
f6b15e1acc | |||
857c5050f4 | |||
652471ac90 | |||
44d1d27c93 | |||
2da1f8bc70 | |||
68e20cff5b | |||
2d4d2721bf | |||
1c67f1cac9 | |||
d74816883a | |||
a09d13594d | |||
81b5631de4 | |||
6916d0e6b4 | |||
757ec98108 | |||
2ddb5dc28b | |||
2e84901e43 | |||
f61fb5657c | |||
24e216cdfc | |||
09d6de00a6 | |||
f7990ee2e6 | |||
cb01c0b590 | |||
21cf5ddaec | |||
48d4686dd4 | |||
d035a307d8 | |||
89e04f3678 | |||
e664fc188c | |||
3597a07ed7 | |||
0472cc03f3 | |||
d169a9f710 | |||
2ff2195116 | |||
cdbf2db5fe | |||
2bb635a120 | |||
465b146001 | |||
ce6d6298bb | |||
ae2ff99be8 | |||
5b6cd24839 | |||
cd22e6207a | |||
b826e497f3 | |||
7cc39f25e1 | |||
f61d9fcd55 | |||
67a1f7e108 | |||
040de56a54 | |||
a486abb159 | |||
37215959b8 | |||
1ccce095a9 | |||
057180e431 | |||
60e62da6a2 | |||
a3eafea60a | |||
962f8de160 | |||
6525d34e08 | |||
3c661ddf65 | |||
42b4216d9c | |||
4e7418111d | |||
a89ef11d73 | |||
d8b54ac342 | |||
293046590e | |||
ea2f67fc09 | |||
60b33064a7 | |||
2efc6fb6d3 | |||
eb744df9cc | |||
8c9180190a | |||
6c6d297a3c | |||
6839119794 | |||
669715aa32 | |||
fdc172ab38 | |||
05f23de1ed | |||
9a0344adac | |||
b9d5fa8772 | |||
d4de0edca6 | |||
fdeb24a196 | |||
7f650f9d6a | |||
a986293f20 | |||
ec0b0adba0 | |||
52c6bb569e | |||
0f670f9ddd | |||
dba46b09a8 | |||
ce59f13de7 | |||
b8cf3872ce | |||
b59112f74e | |||
17b3602fda | |||
c0928097cc | |||
e709fad764 | |||
fb566ae163 | |||
3d8a4cc6b7 | |||
4eb44a53f7 | |||
b61c39ea46 | |||
4767be1972 | |||
ee9e17e31c | |||
3721084d21 | |||
6076c9d82e | |||
2ef499001d | |||
e4d8ab1feb | |||
2fc82aceab | |||
475eb6185a | |||
cdf3a48516 | |||
dcc3c0086a | |||
0d6aeecebb | |||
704c68443a | |||
183b02a5e7 | |||
e91815150d | |||
73c33450ee | |||
e06d07c176 | |||
c73f30e21f | |||
bbf2044729 | |||
4a86ab9d1e | |||
16c3fea8a8 | |||
f4ec9b6ac4 | |||
44155f9ef0 | |||
a5e809a0f3 | |||
3e70f9262b | |||
3573a2edbe | |||
82d9623c6d | |||
258a9b0201 | |||
36d84f6c98 | |||
15c79a7a13 | |||
34e0294815 | |||
ad6a04b975 | |||
e0f682fcd8 | |||
a801359eed | |||
bb238f4c7e | |||
c1ebc8e74b | |||
110c8c6bed | |||
e8fffe65bf | |||
1731aa1890 | |||
c389889662 | |||
e38e12f89b | |||
26f71f5d00 | |||
65e04ce08b | |||
d84d8e03e0 | |||
475ad358ae | |||
db7e60bdfb | |||
444791fb4c | |||
be3a882baa | |||
6d6dc9f316 | |||
d86e825c60 | |||
6bb2af3da8 | |||
d195526afb | |||
9ec3956672 | |||
3098d2ab95 | |||
dccf9f7e1a | |||
e55c29c33c | |||
bd5728ffa0 | |||
af525d4e3d | |||
96e0b584a0 | |||
0d6e3bac17 | |||
d292b5f533 | |||
ec2cb21a8a | |||
3632ed8816 | |||
58acea1a2d | |||
9e63e3f47e | |||
7581c8a32a | |||
8715e0e37b | |||
36b9813e1b | |||
1a59e1cb24 | |||
7f7d25a6fa | |||
87755952b6 | |||
3821eb4d84 | |||
15af82ee49 | |||
1f8a66108b | |||
9309dd945b | |||
858741c9a5 | |||
26c922d9a2 | |||
2ba78545ef | |||
d2a47d1a51 | |||
b2ca97b836 | |||
979981ffb8 | |||
9a57ca69a0 | |||
7b9bdf1f08 | |||
034647b461 | |||
f1d8497851 | |||
2f2f155707 | |||
6d87587544 | |||
dad2d79361 | |||
9f2d7eb4bb | |||
b57809b3b3 | |||
6cb6c1b4fd | |||
14a01b7126 | |||
315c095af9 | |||
10d2fe4431 |
@ -1,22 +1,33 @@
|
||||
version: 7.16.{build}
|
||||
configuration: Release
|
||||
platform: Any CPU
|
||||
version: 7.31.{build}
|
||||
|
||||
configuration:
|
||||
- Release
|
||||
|
||||
image:
|
||||
- Visual Studio 2017
|
||||
|
||||
environment:
|
||||
NSISDIR: C:\Program Files (x86)\NSIS
|
||||
matrix:
|
||||
- QTDIR: C:\Qt\5.11\msvc2015
|
||||
PLATFORM: x86
|
||||
- QTDIR: C:\Qt\5.13\msvc2017
|
||||
NSI: gpxsee.nsi
|
||||
OPENSSLDIR: C:\OpenSSL-Win32\bin
|
||||
- QTDIR: C:\Qt\5.11\msvc2015_64
|
||||
PLATFORM: x86_amd64
|
||||
VCVARS: vcvars32.bat
|
||||
OPENSSLDIR: C:\OpenSSL-v111-Win32\bin
|
||||
LIBCRYPTO: libssl-1_1.dll
|
||||
LIBSSL: libcrypto-1_1.dll
|
||||
- QTDIR: C:\Qt\5.13\msvc2017_64
|
||||
NSI: gpxsee64.nsi
|
||||
OPENSSLDIR: C:\OpenSSL-Win64\bin
|
||||
VCVARS: vcvars64.bat
|
||||
OPENSSLDIR: C:\OpenSSL-v111-Win64\bin
|
||||
LIBCRYPTO: libssl-1_1-x64.dll
|
||||
LIBSSL: libcrypto-1_1-x64.dll
|
||||
|
||||
install:
|
||||
- cmd: >-
|
||||
set PATH=%QTDIR%\bin;%NSISDIR%;%PATH%
|
||||
|
||||
call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" %PLATFORM%
|
||||
call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\"%VCVARS%
|
||||
|
||||
build_script:
|
||||
- cmd: >-
|
||||
lrelease gpxsee.pro
|
||||
@ -44,9 +55,9 @@ build_script:
|
||||
|
||||
copy licence.txt installer
|
||||
|
||||
copy %OPENSSLDIR%\libeay32.dll installer
|
||||
copy %OPENSSLDIR%\%LIBCRYPTO% installer
|
||||
|
||||
copy %OPENSSLDIR%\ssleay32.dll installer
|
||||
copy %OPENSSLDIR%\%LIBSSL% installer
|
||||
|
||||
|
||||
makensis.exe installer\%NSI%
|
||||
|
1
.github/FUNDING.yml
vendored
Normal file
1
.github/FUNDING.yml
vendored
Normal file
@ -0,0 +1 @@
|
||||
github: tumic0
|
@ -6,6 +6,7 @@ os:
|
||||
|
||||
before_install:
|
||||
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo apt-get -qq update; fi
|
||||
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update; fi
|
||||
|
||||
install:
|
||||
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install qt; fi
|
||||
|
@ -2,9 +2,9 @@
|
||||
GPXSee is a Qt-based GPS log file viewer and analyzer that supports all common GPS log file formats.
|
||||
|
||||
## Features
|
||||
* Opens GPX, TCX, FIT, KML, NMEA, IGC, CUP, SLF, LOC, GeoJSON, OziExplorer (PLT, RTE, WPT), Garmin CSV and geotagged JPEG files.
|
||||
* Opens GPX, TCX, FIT, KML, NMEA, IGC, CUP, SIGMA SLF, Suunto SML, LOC, GeoJSON, OziExplorer (PLT, RTE, WPT), Garmin GPI&CSV and geotagged JPEG files.
|
||||
* User-definable online maps (OpenStreetMap/Google tiles, WMTS, WMS, TMS, QuadTiles).
|
||||
* Offline maps (MBTiles, OziExplorer maps, TrekBuddy maps/atlases, Garmin IMG & JNX maps, TwoNav RMaps, GeoTIFF images).
|
||||
* Offline maps (MBTiles, OziExplorer maps, TrekBuddy maps/atlases, Garmin IMG/GMAP & JNX maps, TwoNav RMaps, GeoTIFF images).
|
||||
* Elevation, speed, heart rate, cadence, power, temperature and gear ratio/shifts graphs.
|
||||
* Support for DEM files (SRTM HGT).
|
||||
* Support for multiple tracks in one view.
|
||||
|
48
gpxsee.pro
48
gpxsee.pro
@ -3,7 +3,7 @@ unix:!macx {
|
||||
} else {
|
||||
TARGET = GPXSee
|
||||
}
|
||||
VERSION = 7.16
|
||||
VERSION = 7.31
|
||||
|
||||
QT += core \
|
||||
gui \
|
||||
@ -20,7 +20,9 @@ equals(QT_MAJOR_VERSION, 5) : lessThan(QT_MINOR_VERSION, 4) {QT += opengl}
|
||||
INCLUDEPATH += ./src
|
||||
HEADERS += src/common/config.h \
|
||||
src/GUI/graphicsscene.h \
|
||||
src/GUI/mapaction.h \
|
||||
src/GUI/popup.h \
|
||||
src/common/garmin.h \
|
||||
src/common/staticassert.h \
|
||||
src/common/coordinates.h \
|
||||
src/common/range.h \
|
||||
@ -88,6 +90,14 @@ HEADERS += src/common/config.h \
|
||||
src/GUI/areaitem.h \
|
||||
src/data/link.h \
|
||||
src/map/IMG/bitmapline.h \
|
||||
src/map/IMG/bitstream.h \
|
||||
src/map/IMG/deltastream.h \
|
||||
src/map/IMG/gmap.h \
|
||||
src/map/IMG/huffmanstream.h \
|
||||
src/map/IMG/huffmantable.h \
|
||||
src/map/IMG/nodfile.h \
|
||||
src/map/IMG/mapdata.h \
|
||||
src/map/IMG/rastertile.h \
|
||||
src/map/IMG/textpathitem.h \
|
||||
src/map/IMG/textpointitem.h \
|
||||
src/map/projection.h \
|
||||
@ -178,7 +188,6 @@ HEADERS += src/common/config.h \
|
||||
src/map/IMG/lblfile.h \
|
||||
src/map/IMG/vectortile.h \
|
||||
src/map/IMG/subdiv.h \
|
||||
src/map/IMG/units.h \
|
||||
src/map/IMG/style.h \
|
||||
src/map/IMG/netfile.h \
|
||||
src/GUI/limitedcombobox.h \
|
||||
@ -187,7 +196,9 @@ HEADERS += src/common/config.h \
|
||||
src/map/IMG/label.h \
|
||||
src/data/csv.h \
|
||||
src/data/cupparser.h \
|
||||
src/data/gpiparser.h
|
||||
src/data/gpiparser.h \
|
||||
src/data/address.h \
|
||||
src/data/smlparser.h
|
||||
SOURCES += src/main.cpp \
|
||||
src/GUI/popup.cpp \
|
||||
src/common/coordinates.cpp \
|
||||
@ -240,7 +251,16 @@ SOURCES += src/main.cpp \
|
||||
src/GUI/gearratiographitem.cpp \
|
||||
src/GUI/mapview.cpp \
|
||||
src/GUI/areaitem.cpp \
|
||||
src/data/waypoint.cpp \
|
||||
src/map/IMG/bitmapline.cpp \
|
||||
src/map/IMG/bitstream.cpp \
|
||||
src/map/IMG/deltastream.cpp \
|
||||
src/map/IMG/gmap.cpp \
|
||||
src/map/IMG/huffmanstream.cpp \
|
||||
src/map/IMG/huffmantable.cpp \
|
||||
src/map/IMG/nodfile.cpp \
|
||||
src/map/IMG/mapdata.cpp \
|
||||
src/map/IMG/rastertile.cpp \
|
||||
src/map/IMG/textpathitem.cpp \
|
||||
src/map/IMG/textpointitem.cpp \
|
||||
src/map/maplist.cpp \
|
||||
@ -323,12 +343,16 @@ SOURCES += src/main.cpp \
|
||||
src/data/csv.cpp \
|
||||
src/data/cupparser.cpp \
|
||||
src/GUI/graphicsscene.cpp \
|
||||
src/data/gpiparser.cpp
|
||||
src/data/gpiparser.cpp \
|
||||
src/data/smlparser.cpp
|
||||
|
||||
greaterThan(QT_MAJOR_VERSION, 4) {
|
||||
HEADERS += src/data/geojsonparser.h
|
||||
SOURCES += src/data/geojsonparser.cpp
|
||||
}
|
||||
equals(QT_MAJOR_VERSION, 5):greaterThan(QT_MINOR_VERSION, 4) {
|
||||
HEADERS += src/GUI/timezoneinfo.h
|
||||
}
|
||||
|
||||
DEFINES += APP_VERSION=\\\"$$VERSION\\\" \
|
||||
QT_NO_DEPRECATED_WARNINGS
|
||||
@ -347,7 +371,10 @@ TRANSLATIONS = lang/gpxsee_en.ts \
|
||||
lang/gpxsee_da.ts \
|
||||
lang/gpxsee_tr.ts \
|
||||
lang/gpxsee_es.ts \
|
||||
lang/gpxsee_pt_BR.ts
|
||||
lang/gpxsee_pt_BR.ts \
|
||||
lang/gpxsee_uk.ts \
|
||||
lang/gpxsee_hu.ts \
|
||||
lang/gpxsee_it.ts
|
||||
|
||||
macx {
|
||||
ICON = icons/gpxsee.icns
|
||||
@ -365,7 +392,10 @@ macx {
|
||||
lang/gpxsee_da.qm \
|
||||
lang/gpxsee_tr.qm \
|
||||
lang/gpxsee_es.qm \
|
||||
lang/gpxsee_pt_BR.qm
|
||||
lang/gpxsee_pt_BR.qm \
|
||||
lang/gpxsee_uk.qm \
|
||||
lang/gpxsee_hu.qm \
|
||||
lang/gpxsee_it.qm
|
||||
csv.path = Contents/Resources
|
||||
csv.files = pkg/csv
|
||||
maps.path = Contents/Resources
|
||||
@ -384,7 +414,8 @@ macx {
|
||||
icons/formats/slf.icns \
|
||||
icons/formats/json.icns \
|
||||
icons/formats/cup.icns \
|
||||
icons/formats/gpi.icns
|
||||
icons/formats/gpi.icns \
|
||||
icons/formats/sml.icns
|
||||
QMAKE_BUNDLE_DATA += locale maps icons csv
|
||||
}
|
||||
|
||||
@ -403,7 +434,8 @@ win32 {
|
||||
icons/formats/slf.ico \
|
||||
icons/formats/json.ico \
|
||||
icons/formats/cup.ico \
|
||||
icons/formats/gpi.ico
|
||||
icons/formats/gpi.ico \
|
||||
icons/formats/sml.ico
|
||||
DEFINES += _USE_MATH_DEFINES \
|
||||
NOGDI
|
||||
}
|
||||
|
BIN
icons/formats/sml.icns
Normal file
BIN
icons/formats/sml.icns
Normal file
Binary file not shown.
BIN
icons/formats/sml.ico
Normal file
BIN
icons/formats/sml.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 304 KiB |
@ -12,3 +12,4 @@ loc:#556677
|
||||
slf:#881199
|
||||
cup:#20a810
|
||||
gpi:#fca314
|
||||
sml:#6434eb
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,4 +1,15 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE TS>
|
||||
<TS version="2.1" language="en_US">
|
||||
<context>
|
||||
<name>GUI</name>
|
||||
<message numerus="yes">
|
||||
<location filename="../src/GUI/gui.cpp" line="1392"/>
|
||||
<source>%n files</source>
|
||||
<translation>
|
||||
<numerusform>%n file</numerusform>
|
||||
<numerusform>%n files</numerusform>
|
||||
</translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
1940
lang/gpxsee_hu.ts
Normal file
1940
lang/gpxsee_hu.ts
Normal file
File diff suppressed because it is too large
Load Diff
1940
lang/gpxsee_it.ts
Normal file
1940
lang/gpxsee_it.ts
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
1941
lang/gpxsee_uk.ts
Normal file
1941
lang/gpxsee_uk.ts
Normal file
File diff suppressed because it is too large
Load Diff
@ -243,6 +243,22 @@
|
||||
<key>CFBundleTypeRole</key>
|
||||
<string>Viewer</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>CFBundleTypeExtensions</key>
|
||||
<array>
|
||||
<string>sml</string>
|
||||
</array>
|
||||
<key>CFBundleTypeMIMETypes</key>
|
||||
<array>
|
||||
<string>application/sml+xml</string>
|
||||
</array>
|
||||
<key>CFBundleTypeIconFile</key>
|
||||
<string>icons/sml.icns</string>
|
||||
<key>CFBundleTypeName</key>
|
||||
<string>Suunto Markup Language</string>
|
||||
<key>CFBundleTypeRole</key>
|
||||
<string>Viewer</string>
|
||||
</dict>
|
||||
</array>
|
||||
|
||||
<key>UTImportedTypeDeclarations</key>
|
||||
@ -538,7 +554,28 @@
|
||||
<string>gpi</string>
|
||||
</array>
|
||||
<key>public.mime-type</key>
|
||||
<string>application/vnd.garmin.cup</string>
|
||||
<string>application/vnd.garmin.gpi</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>UTTypeIdentifier</key>
|
||||
<string>com.suunto.sml</string>
|
||||
<key>UTTypeReferenceURL</key>
|
||||
<string>https://www.suunto.com</string>
|
||||
<key>UTTypeDescription</key>
|
||||
<string>Suunto Markup Language</string>
|
||||
<key>UTTypeConformsTo</key>
|
||||
<array>
|
||||
<string>public.xml</string>
|
||||
</array>
|
||||
<key>UTTypeTagSpecification</key>
|
||||
<dict>
|
||||
<key>public.filename-extension</key>
|
||||
<array>
|
||||
<string>sml</string>
|
||||
</array>
|
||||
<key>public.mime-type</key>
|
||||
<string>application/sml+xml</string>
|
||||
</dict>
|
||||
</dict>
|
||||
</array>
|
||||
|
@ -12,17 +12,18 @@
|
||||
|
||||
<p>Features:</p>
|
||||
<ul>
|
||||
<li>Opens GPX, TCX, FIT, KML, IGC, NMEA, SLF, LOC, OziExplorer (PLT,
|
||||
WPT, RTE), GeoJSON, SeeYou CUP, Garmin CSV and geotagged
|
||||
JPEG files.</li>
|
||||
<li>Opens GPX, TCX, FIT, KML, IGC, NMEA, SIGMA SLF, Suunto SML, LOC,
|
||||
OziExplorer (PLT, WPT, RTE), GeoJSON, SeeYou CUP,
|
||||
Garmin GPI & CSV and geotagged JPEG files.</li>
|
||||
<li>User-definable online maps (OpenStreetMap/Google tiles, WMTS,
|
||||
WMS, TMS).</li>
|
||||
WMS, TMS, QuadTiles).</li>
|
||||
<li>Offline maps (MBTiles, OziExplorer maps, TrekBuddy maps/atlases,
|
||||
TwoNav RMaps, Garmin IMG & JNX, GeoTIFF images).</li>
|
||||
<li>Elevation, speed, heart rate, cadence, power and temperature
|
||||
graphs.</li>
|
||||
<li>Elevation, speed, heart rate, cadence, power, temperature and
|
||||
gear ratio graphs.</li>
|
||||
<li>Support for multiple tracks in one view.</li>
|
||||
<li>Support for POI files.</li>
|
||||
<li>Support for DEM files (SRTM HGT).</li>
|
||||
<li>Print/export to PDF.</li>
|
||||
<li>Full-screen mode.</li>
|
||||
<li>HiDPI/Retina displays & maps support.</li>
|
||||
@ -69,5 +70,7 @@
|
||||
<mimetype>application/slf+xml</mimetype>
|
||||
<mimetype>application/geo+json</mimetype>
|
||||
<mimetype>application/vnd.naviter.seeyou.cup</mimetype>
|
||||
<mimetype>application/vnd.garmin.gpi</mimetype>
|
||||
<mimetype>application/sml+xml</mimetype>
|
||||
</mimetypes>
|
||||
</component>
|
||||
|
@ -3,12 +3,16 @@ Name=GPXSee
|
||||
Comment=GPS log file viewer and analyzer
|
||||
Comment[cz]=Prohlížeč a analyzátor GPS logů
|
||||
Comment[fi]=Ohjelma GPS-lokien katseluun ja analysointiin
|
||||
Comment[fr]=Visualisation et analyse de fichier GPS
|
||||
Comment[nb]=GPS-loggfilleser og analysator
|
||||
Comment[pl]=Przeglądarka i analizator plików dziennika GPS
|
||||
Comment[ru]=Программа для просмотра и анализа GPS логов
|
||||
Comment[sv]=GPS-loggfilsläsare och analysator
|
||||
Comment[tr]=GPS günlük dosyası görüntüleyici ve analizcisi
|
||||
Comment[uk]=Переглядач та аналізатор GPS логів
|
||||
Exec=gpxsee %F
|
||||
Icon=gpxsee
|
||||
Terminal=false
|
||||
Type=Application
|
||||
Categories=Graphics;Viewer;Education;Geography;Maps;Sports;Qt;
|
||||
MimeType=application/gpx+xml;application/tcx+xml;application/vnd.ant.fit;application/vnd.google-earth.kml+xml;application/vnd.fai.igc;application/vnd.nmea.nmea;application/vnd.oziexplorer.plt;application/vnd.oziexplorer.rte;application/vnd.oziexplorer.wpt;application/loc+xml;application/slf+xml;application/geo+json;application/vnd.naviter.seeyou.cup;
|
||||
MimeType=application/gpx+xml;application/tcx+xml;application/vnd.ant.fit;application/vnd.google-earth.kml+xml;application/vnd.fai.igc;application/vnd.nmea.nmea;application/vnd.oziexplorer.plt;application/vnd.oziexplorer.rte;application/vnd.oziexplorer.wpt;application/loc+xml;application/slf+xml;application/geo+json;application/vnd.naviter.seeyou.cup;application/vnd.garmin.gpi;application/sml+xml;
|
||||
|
@ -7,7 +7,7 @@
|
||||
; The name of the installer
|
||||
Name "GPXSee"
|
||||
; Program version
|
||||
!define VERSION "7.16"
|
||||
!define VERSION "7.31"
|
||||
|
||||
; The file to write
|
||||
OutFile "GPXSee-${VERSION}.exe"
|
||||
@ -106,20 +106,21 @@ Section "GPXSee" SEC_APP
|
||||
|
||||
; Associate file formats
|
||||
DetailPrint "Associating file types..."
|
||||
!insertmacro FILE_ASSOCIATION_ADD "gpx" "GPS Exchange Format" 7
|
||||
!insertmacro FILE_ASSOCIATION_ADD "tcx" "Training Center XML" 8
|
||||
!insertmacro FILE_ASSOCIATION_ADD "kml" "Keyhole Markup Language" 9
|
||||
!insertmacro FILE_ASSOCIATION_ADD "fit" "Flexible and Interoperable Data Transfer" 10
|
||||
!insertmacro FILE_ASSOCIATION_ADD "igc" "Flight Recorder Data Format" 11
|
||||
!insertmacro FILE_ASSOCIATION_ADD "nmea" "NMEA 0183 Data" 12
|
||||
!insertmacro FILE_ASSOCIATION_ADD "plt" "OziExplorer Track Point File" 13
|
||||
!insertmacro FILE_ASSOCIATION_ADD "rte" "OziExplorer Route File" 14
|
||||
!insertmacro FILE_ASSOCIATION_ADD "gpx" "GPS Exchange Format" 8
|
||||
!insertmacro FILE_ASSOCIATION_ADD "tcx" "Training Center XML" 9
|
||||
!insertmacro FILE_ASSOCIATION_ADD "kml" "Keyhole Markup Language" 10
|
||||
!insertmacro FILE_ASSOCIATION_ADD "fit" "Flexible and Interoperable Data Transfer" 11
|
||||
!insertmacro FILE_ASSOCIATION_ADD "igc" "Flight Recorder Data Format" 12
|
||||
!insertmacro FILE_ASSOCIATION_ADD "nmea" "NMEA 0183 Data" 13
|
||||
!insertmacro FILE_ASSOCIATION_ADD "plt" "OziExplorer Track Point File" 14
|
||||
!insertmacro FILE_ASSOCIATION_ADD "rte" "OziExplorer Route File" 15
|
||||
!insertmacro FILE_ASSOCIATION_ADD "wpt" "OziExplorer Waypoint File" 1
|
||||
!insertmacro FILE_ASSOCIATION_ADD "loc" "Geocaching.com Waypoint File" 2
|
||||
!insertmacro FILE_ASSOCIATION_ADD "slf" "Sigma Log File" 3
|
||||
!insertmacro FILE_ASSOCIATION_ADD "geojson" "GeoJSON" 4
|
||||
!insertmacro FILE_ASSOCIATION_ADD "cup" "SeeYou CUP File" 5
|
||||
!insertmacro FILE_ASSOCIATION_ADD "gpi" "Garmin POI File" 6
|
||||
!insertmacro FILE_ASSOCIATION_ADD "sml" "Suunto Markup Language" 7
|
||||
System::Call 'shell32.dll::SHChangeNotify(i, i, i, i) v (0x08000000, 0, 0, 0)'
|
||||
|
||||
SectionEnd
|
||||
@ -147,30 +148,17 @@ Section "MSVC runtime" SEC_MSVC
|
||||
|
||||
SectionIn RO
|
||||
|
||||
DetailPrint "Checking whether Visual C++ 2015 Redistributable is already installed..."
|
||||
${If} ${RunningX64}
|
||||
ReadRegDword $R0 HKLM "SOFTWARE\Wow6432Node\Microsoft\VisualStudio\14.0\VC\Runtimes\x86" "Installed"
|
||||
${Else}
|
||||
ReadRegDword $R0 HKLM "SOFTWARE\Microsoft\VisualStudio\14.0\VC\Runtimes\x86" "Installed"
|
||||
${EndIf}
|
||||
|
||||
StrCmp $R0 "1" 0 +3
|
||||
DetailPrint "Visual C++ 2015 Redistributable is already installed, skipping install."
|
||||
Goto done
|
||||
|
||||
DetailPrint "Installing Visual C++ 2015 Redistributable..."
|
||||
SetOutPath $TEMP
|
||||
File "vcredist_x86.exe"
|
||||
ExecWait '"$TEMP\vcredist_x86.exe" /install /quiet /norestart'
|
||||
SetOutPath $INSTDIR
|
||||
File "vc_redist.x86.exe"
|
||||
ExecWait '"$TEMP\vc_redist.x86.exe" /install /quiet /norestart'
|
||||
SetOutPath $INSTDIR
|
||||
|
||||
done:
|
||||
SectionEnd
|
||||
|
||||
Section "OpenSSL" SEC_OPENSSL
|
||||
|
||||
File "libeay32.dll"
|
||||
File "ssleay32.dll"
|
||||
File "libcrypto-1_1.dll"
|
||||
File "libssl-1_1.dll"
|
||||
|
||||
SectionEnd
|
||||
|
||||
@ -188,6 +176,8 @@ SectionGroup "Localization" SEC_LOCALIZATION
|
||||
!insertmacro LOCALIZATION "Finnish" "fi"
|
||||
!insertmacro LOCALIZATION "French" "fr"
|
||||
!insertmacro LOCALIZATION "German" "de"
|
||||
!insertmacro LOCALIZATION "Hungarian" "hu"
|
||||
!insertmacro LOCALIZATION "Italian" "it"
|
||||
!insertmacro LOCALIZATION "Norwegian" "nb"
|
||||
!insertmacro LOCALIZATION "Polish" "pl"
|
||||
!insertmacro LOCALIZATION "Portuguese (Brazil)" "pt_BR"
|
||||
@ -195,6 +185,7 @@ SectionGroup "Localization" SEC_LOCALIZATION
|
||||
!insertmacro LOCALIZATION "Spanish" "es"
|
||||
!insertmacro LOCALIZATION "Swedish" "sv"
|
||||
!insertmacro LOCALIZATION "Turkish" "tr"
|
||||
!insertmacro LOCALIZATION "Ukrainian" "uk"
|
||||
SectionGroupEnd
|
||||
|
||||
;--------------------------------
|
||||
@ -231,6 +222,7 @@ Section "Uninstall"
|
||||
!insertmacro FILE_ASSOCIATION_REMOVE "geojson"
|
||||
!insertmacro FILE_ASSOCIATION_REMOVE "cup"
|
||||
!insertmacro FILE_ASSOCIATION_REMOVE "gpi"
|
||||
!insertmacro FILE_ASSOCIATION_REMOVE "sml"
|
||||
System::Call 'shell32.dll::SHChangeNotify(i, i, i, i) v (0x08000000, 0, 0, 0)'
|
||||
|
||||
SectionEnd
|
||||
@ -243,7 +235,7 @@ SectionEnd
|
||||
LangString DESC_QT ${LANG_ENGLISH} \
|
||||
"QT cross-platform application framework."
|
||||
LangString DESC_MSVC ${LANG_ENGLISH} \
|
||||
"Visual C++ 2015 runtime components. If already installed, will be skipped."
|
||||
"Microsoft Visual C++ 2017 runtime. If already installed, will be skipped."
|
||||
LangString DESC_OPENSSL ${LANG_ENGLISH} \
|
||||
"OpenSSL library. Required for HTTPS to work."
|
||||
LangString DESC_ANGLE ${LANG_ENGLISH} \
|
||||
|
@ -91,4 +91,18 @@
|
||||
<generic-icon name="text-plain"/>
|
||||
<glob pattern="*.cup"/>
|
||||
</mime-type>
|
||||
|
||||
<mime-type type="application/vnd.garmin.gpi">
|
||||
<comment>Garmin POI File</comment>
|
||||
<sub-class-of type="application/octet-stream"/>
|
||||
<generic-icon name="application/octet-stream"/>
|
||||
<glob pattern="*.gpi"/>
|
||||
</mime-type>
|
||||
|
||||
<mime-type type="application/sml+xml">
|
||||
<comment>Suunto Markup Language</comment>
|
||||
<sub-class-of type="application/xml"/>
|
||||
<generic-icon name="application-xml"/>
|
||||
<glob pattern="*.sml"/>
|
||||
</mime-type>
|
||||
</mime-info>
|
||||
|
@ -7,7 +7,7 @@
|
||||
; The name of the installer
|
||||
Name "GPXSee"
|
||||
; Program version
|
||||
!define VERSION "7.16"
|
||||
!define VERSION "7.31"
|
||||
|
||||
; The file to write
|
||||
OutFile "GPXSee-${VERSION}_x64.exe"
|
||||
@ -113,20 +113,21 @@ Section "GPXSee" SEC_APP
|
||||
|
||||
; Associate file formats
|
||||
DetailPrint "Associating file types..."
|
||||
!insertmacro FILE_ASSOCIATION_ADD "gpx" "GPS Exchange Format" 7
|
||||
!insertmacro FILE_ASSOCIATION_ADD "tcx" "Training Center XML" 8
|
||||
!insertmacro FILE_ASSOCIATION_ADD "kml" "Keyhole Markup Language" 9
|
||||
!insertmacro FILE_ASSOCIATION_ADD "fit" "Flexible and Interoperable Data Transfer" 10
|
||||
!insertmacro FILE_ASSOCIATION_ADD "igc" "Flight Recorder Data Format" 11
|
||||
!insertmacro FILE_ASSOCIATION_ADD "nmea" "NMEA 0183 Data" 12
|
||||
!insertmacro FILE_ASSOCIATION_ADD "plt" "OziExplorer Track Point File" 13
|
||||
!insertmacro FILE_ASSOCIATION_ADD "rte" "OziExplorer Route File" 14
|
||||
!insertmacro FILE_ASSOCIATION_ADD "gpx" "GPS Exchange Format" 8
|
||||
!insertmacro FILE_ASSOCIATION_ADD "tcx" "Training Center XML" 9
|
||||
!insertmacro FILE_ASSOCIATION_ADD "kml" "Keyhole Markup Language" 10
|
||||
!insertmacro FILE_ASSOCIATION_ADD "fit" "Flexible and Interoperable Data Transfer" 11
|
||||
!insertmacro FILE_ASSOCIATION_ADD "igc" "Flight Recorder Data Format" 12
|
||||
!insertmacro FILE_ASSOCIATION_ADD "nmea" "NMEA 0183 Data" 13
|
||||
!insertmacro FILE_ASSOCIATION_ADD "plt" "OziExplorer Track Point File" 14
|
||||
!insertmacro FILE_ASSOCIATION_ADD "rte" "OziExplorer Route File" 15
|
||||
!insertmacro FILE_ASSOCIATION_ADD "wpt" "OziExplorer Waypoint File" 1
|
||||
!insertmacro FILE_ASSOCIATION_ADD "loc" "Geocaching.com Waypoint File" 2
|
||||
!insertmacro FILE_ASSOCIATION_ADD "slf" "Sigma Log File" 3
|
||||
!insertmacro FILE_ASSOCIATION_ADD "geojson" "GeoJSON" 4
|
||||
!insertmacro FILE_ASSOCIATION_ADD "cup" "SeeYou CUP File" 5
|
||||
!insertmacro FILE_ASSOCIATION_ADD "gpi" "Garmin POI File" 6
|
||||
!insertmacro FILE_ASSOCIATION_ADD "sml" "Suunto Markup Language" 7
|
||||
System::Call 'shell32.dll::SHChangeNotify(i, i, i, i) v (0x08000000, 0, 0, 0)'
|
||||
|
||||
SectionEnd
|
||||
@ -154,25 +155,17 @@ Section "MSVC runtime" SEC_MSVC
|
||||
|
||||
SectionIn RO
|
||||
|
||||
DetailPrint "Checking whether Visual C++ 2015 Redistributable is already installed..."
|
||||
ReadRegDword $R0 HKLM "SOFTWARE\Wow6432Node\Microsoft\VisualStudio\14.0\VC\Runtimes\x64" "Installed"
|
||||
StrCmp $R0 "1" 0 +3
|
||||
DetailPrint "Visual C++ 2015 Redistributable is already installed, skipping install."
|
||||
Goto done
|
||||
|
||||
DetailPrint "Installing Visual C++ 2015 Redistributable..."
|
||||
SetOutPath $TEMP
|
||||
File "vcredist_x64.exe"
|
||||
ExecWait '"$TEMP\vcredist_x64.exe" /install /quiet /norestart'
|
||||
File "vc_redist.x64.exe"
|
||||
ExecWait '"$TEMP\vc_redist.x64.exe" /install /quiet /norestart'
|
||||
SetOutPath $INSTDIR
|
||||
|
||||
done:
|
||||
SectionEnd
|
||||
|
||||
Section "OpenSSL" SEC_OPENSSL
|
||||
|
||||
File "libeay32.dll"
|
||||
File "ssleay32.dll"
|
||||
File "libcrypto-1_1-x64.dll"
|
||||
File "libssl-1_1-x64.dll"
|
||||
|
||||
SectionEnd
|
||||
|
||||
@ -190,6 +183,8 @@ SectionGroup "Localization" SEC_LOCALIZATION
|
||||
!insertmacro LOCALIZATION "Finnish" "fi"
|
||||
!insertmacro LOCALIZATION "French" "fr"
|
||||
!insertmacro LOCALIZATION "German" "de"
|
||||
!insertmacro LOCALIZATION "Hungarian" "hu"
|
||||
!insertmacro LOCALIZATION "Italian" "it"
|
||||
!insertmacro LOCALIZATION "Norwegian" "nb"
|
||||
!insertmacro LOCALIZATION "Polish" "pl"
|
||||
!insertmacro LOCALIZATION "Portuguese (Brazil)" "pt_BR"
|
||||
@ -197,6 +192,7 @@ SectionGroup "Localization" SEC_LOCALIZATION
|
||||
!insertmacro LOCALIZATION "Spanish" "es"
|
||||
!insertmacro LOCALIZATION "Swedish" "sv"
|
||||
!insertmacro LOCALIZATION "Turkish" "tr"
|
||||
!insertmacro LOCALIZATION "Ukrainian" "uk"
|
||||
SectionGroupEnd
|
||||
|
||||
;--------------------------------
|
||||
@ -234,6 +230,7 @@ Section "Uninstall"
|
||||
!insertmacro FILE_ASSOCIATION_REMOVE "geojson"
|
||||
!insertmacro FILE_ASSOCIATION_REMOVE "cup"
|
||||
!insertmacro FILE_ASSOCIATION_REMOVE "gpi"
|
||||
!insertmacro FILE_ASSOCIATION_REMOVE "sml"
|
||||
System::Call 'shell32.dll::SHChangeNotify(i, i, i, i) v (0x08000000, 0, 0, 0)'
|
||||
|
||||
SectionEnd
|
||||
@ -246,7 +243,7 @@ SectionEnd
|
||||
LangString DESC_QT ${LANG_ENGLISH} \
|
||||
"QT cross-platform application framework."
|
||||
LangString DESC_MSVC ${LANG_ENGLISH} \
|
||||
"Visual C++ 2015 runtime components. If already installed, will be skipped."
|
||||
"Microsoft Visual C++ 2017 runtime. If already installed, will be skipped."
|
||||
LangString DESC_OPENSSL ${LANG_ENGLISH} \
|
||||
"OpenSSL library. Required for HTTPS to work."
|
||||
LangString DESC_ANGLE ${LANG_ENGLISH} \
|
||||
|
@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<map xmlns="http://www.gpxsee.org/map/1.3">
|
||||
<map xmlns="http://www.gpxsee.org/map/1.4">
|
||||
<name>4UMaps</name>
|
||||
<url>https://4umaps.com/$z/$x/$y.png</url>
|
||||
<url>https://tileserver.4umaps.com/$z/$x/$y.png</url>
|
||||
<zoom min="2" max="15"/>
|
||||
<bounds bottom="-65"/>
|
||||
<copyright>Map data: © OpenStreetMap contributors (ODbL) | Rendering: © 4UMaps.eu</copyright>
|
||||
|
@ -1,8 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<map xmlns="http://www.gpxsee.org/map/1.3" type="WMTS">
|
||||
<map xmlns="http://www.gpxsee.org/map/1.4" type="WMTS">
|
||||
<name>Antarctica</name>
|
||||
<url type="REST">https://gis.ngdc.noaa.gov/arcgis/rest/services/antarctic/antarctic_basemap/MapServer/WMTS/1.0.0/WMTSCapabilities.xml</url>
|
||||
<url type="REST">https://tiles.arcgis.com/tiles/C8EMgrsFcRFL6LrL/arcgis/rest/services/Antarctic_Basemap/MapServer/WMTS/1.0.0/WMTSCapabilities.xml</url>
|
||||
<copyright>NOAA National Centers for Environmental Information (NCEI); International Bathymetric Chart of the Southern Ocean (IBCSO); General Bathymetric Chart of the Oceans (GEBCO); Natural Earth</copyright>
|
||||
<layer>antarctic_antarctic_basemap</layer>
|
||||
<layer>Antarctic_Basemap</layer>
|
||||
<set>default028mm</set>
|
||||
</map>
|
||||
|
@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<map xmlns="http://www.gpxsee.org/map/1.3">
|
||||
<map xmlns="http://www.gpxsee.org/map/1.4">
|
||||
<name>Open Street Map</name>
|
||||
<url>http://tile.openstreetmap.org/$z/$x/$y.png</url>
|
||||
<url>https://tile.openstreetmap.org/$z/$x/$y.png</url>
|
||||
<copyright>Map data: © OpenStreetMap contributors (ODbL) | Rendering: © OpenStreetMap (CC-BY-SA)</copyright>
|
||||
</map>
|
||||
|
@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<map xmlns="http://www.gpxsee.org/map/1.3">
|
||||
<map xmlns="http://www.gpxsee.org/map/1.4">
|
||||
<name>Open Topo Map</name>
|
||||
<url>https://a.tile.opentopomap.org/$z/$x/$y.png</url>
|
||||
<zoom max="17"/>
|
||||
|
@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<map xmlns="http://www.gpxsee.org/map/1.3">
|
||||
<map xmlns="http://www.gpxsee.org/map/1.4">
|
||||
<name>USGS Imagery</name>
|
||||
<url>https://basemap.nationalmap.gov/ArcGIS/rest/services/USGSImageryOnly/MapServer/tile/$z/$y/$x</url>
|
||||
<zoom min="2" max="15"/>
|
||||
|
@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<map xmlns="http://www.gpxsee.org/map/1.3">
|
||||
<map xmlns="http://www.gpxsee.org/map/1.4">
|
||||
<name>USGS Topo</name>
|
||||
<url>https://basemap.nationalmap.gov/arcgis/rest/services/USGSTopo/MapServer/tile/$z/$y/$x</url>
|
||||
<zoom min="2" max="15"/>
|
||||
|
@ -8,7 +8,7 @@
|
||||
#include "areaitem.h"
|
||||
|
||||
|
||||
ToolTip AreaItem::toolTip() const
|
||||
QString AreaItem::info() const
|
||||
{
|
||||
ToolTip tt;
|
||||
|
||||
@ -18,11 +18,11 @@ ToolTip AreaItem::toolTip() const
|
||||
tt.insert(qApp->translate("PolygonItem", "Description"),
|
||||
_area.description());
|
||||
|
||||
return tt;
|
||||
return tt.toString();
|
||||
}
|
||||
|
||||
AreaItem::AreaItem(const Area &area, Map *map, QGraphicsItem *parent)
|
||||
: QGraphicsItem(parent), _area(area)
|
||||
AreaItem::AreaItem(const Area &area, Map *map, GraphicsItem *parent)
|
||||
: GraphicsItem(parent), _area(area)
|
||||
{
|
||||
_map = map;
|
||||
_digitalZoom = 0;
|
||||
@ -173,6 +173,6 @@ void AreaItem::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
|
||||
|
||||
void AreaItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
|
||||
{
|
||||
Popup::show(event->screenPos(), toolTip().toString(), event->widget());
|
||||
Popup::show(event->screenPos(), info(), event->widget());
|
||||
QGraphicsItem::mousePressEvent(event);
|
||||
}
|
||||
|
@ -1,16 +1,16 @@
|
||||
#ifndef AREAITEM_H
|
||||
#define AREAITEM_H
|
||||
|
||||
#include <QGraphicsItem>
|
||||
#include "data/area.h"
|
||||
#include "graphicsscene.h"
|
||||
#include "tooltip.h"
|
||||
|
||||
class Map;
|
||||
|
||||
class AreaItem : public QGraphicsItem
|
||||
class AreaItem : public GraphicsItem
|
||||
{
|
||||
public:
|
||||
AreaItem(const Area &area, Map *map, QGraphicsItem *parent = 0);
|
||||
AreaItem(const Area &area, Map *map, GraphicsItem *parent = 0);
|
||||
|
||||
QPainterPath shape() const {return _painterPath;}
|
||||
QRectF boundingRect() const {return _painterPath.boundingRect();}
|
||||
@ -27,6 +27,8 @@ public:
|
||||
void setStyle(Qt::PenStyle style);
|
||||
void setDigitalZoom(int zoom);
|
||||
|
||||
virtual QString info() const;
|
||||
|
||||
protected:
|
||||
void hoverEnterEvent(QGraphicsSceneHoverEvent *event);
|
||||
void hoverLeaveEvent(QGraphicsSceneHoverEvent *event);
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
CadenceGraphItem::CadenceGraphItem(const Graph &graph, GraphType type,
|
||||
int width, const QColor &color, QGraphicsItem *parent)
|
||||
: GraphItem(graph, type, width, color, parent)
|
||||
: GraphItem(graph, type, width, color, Qt::SolidLine, parent)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -65,35 +65,38 @@ void ElevationGraph::setInfo()
|
||||
}
|
||||
}
|
||||
|
||||
GraphItem *ElevationGraph::loadGraph(const Graph &graph, Type type)
|
||||
GraphItem *ElevationGraph::loadGraph(const Graph &graph, PathType type,
|
||||
const QColor &color, bool primary)
|
||||
{
|
||||
if (!graph.isValid()) {
|
||||
_palette.nextColor();
|
||||
if (!graph.isValid())
|
||||
return 0;
|
||||
}
|
||||
|
||||
ElevationGraphItem *gi = new ElevationGraphItem(graph, _graphType, _width,
|
||||
_palette.nextColor());
|
||||
color, primary ? Qt::SolidLine : Qt::DashLine);
|
||||
gi->setUnits(_units);
|
||||
|
||||
if (type == Track) {
|
||||
if (type == TrackPath) {
|
||||
_tracks.append(gi);
|
||||
if (_showTracks)
|
||||
addGraph(gi);
|
||||
|
||||
_trackAscent += gi->ascent();
|
||||
_trackDescent += gi->descent();
|
||||
_trackMax = nMax(_trackMax, gi->max());
|
||||
_trackMin = nMin(_trackMin, gi->min());
|
||||
if (primary) {
|
||||
_trackAscent += gi->ascent();
|
||||
_trackDescent += gi->descent();
|
||||
_trackMax = nMax(_trackMax, gi->max());
|
||||
_trackMin = nMin(_trackMin, gi->min());
|
||||
}
|
||||
} else {
|
||||
_routes.append(gi);
|
||||
if (_showRoutes)
|
||||
addGraph(gi);
|
||||
|
||||
_routeAscent += gi->ascent();
|
||||
_routeDescent += gi->descent();
|
||||
_routeMax = nMax(_routeMax, gi->max());
|
||||
_routeMin = nMin(_routeMin, gi->min());
|
||||
if (primary) {
|
||||
_routeAscent += gi->ascent();
|
||||
_routeDescent += gi->descent();
|
||||
_routeMax = nMax(_routeMax, gi->max());
|
||||
_routeMin = nMin(_routeMin, gi->min());
|
||||
}
|
||||
}
|
||||
|
||||
return gi;
|
||||
@ -102,11 +105,32 @@ GraphItem *ElevationGraph::loadGraph(const Graph &graph, Type type)
|
||||
QList<GraphItem*> ElevationGraph::loadData(const Data &data)
|
||||
{
|
||||
QList<GraphItem*> graphs;
|
||||
GraphItem *primary, *secondary;
|
||||
|
||||
for (int i = 0; i < data.tracks().count(); i++)
|
||||
graphs.append(loadGraph(data.tracks().at(i).elevation(), Track));
|
||||
for (int i = 0; i < data.routes().count(); i++)
|
||||
graphs.append(loadGraph(data.routes().at(i).elevation(), Route));
|
||||
for (int i = 0; i < data.tracks().count(); i++) {
|
||||
QColor color(_palette.nextColor());
|
||||
const GraphPair &gp = data.tracks().at(i).elevation();
|
||||
|
||||
primary = loadGraph(gp.primary(), TrackPath, color, true);
|
||||
secondary = primary
|
||||
? loadGraph(gp.secondary(), TrackPath, color, false) : 0;
|
||||
if (primary && secondary)
|
||||
primary->setSecondaryGraph(secondary);
|
||||
|
||||
graphs.append(primary);
|
||||
}
|
||||
for (int i = 0; i < data.routes().count(); i++) {
|
||||
QColor color(_palette.nextColor());
|
||||
const GraphPair &gp = data.routes().at(i).elevation();
|
||||
|
||||
primary = loadGraph(gp.primary(), RoutePath, color, true);
|
||||
secondary = primary
|
||||
? loadGraph(gp.secondary(), RoutePath, color, false) : 0;
|
||||
if (primary && secondary)
|
||||
primary->setSecondaryGraph(secondary);
|
||||
|
||||
graphs.append(primary);
|
||||
}
|
||||
for (int i = 0; i < data.areas().count(); i++)
|
||||
_palette.nextColor();
|
||||
|
||||
|
@ -21,7 +21,7 @@ public:
|
||||
void showRoutes(bool show);
|
||||
|
||||
private:
|
||||
enum Type {Track, Route};
|
||||
enum PathType {TrackPath, RoutePath};
|
||||
|
||||
qreal max() const;
|
||||
qreal min() const;
|
||||
@ -31,7 +31,8 @@ private:
|
||||
void setYUnits(Units units);
|
||||
void setInfo();
|
||||
|
||||
GraphItem *loadGraph(const Graph &graph, Type type);
|
||||
GraphItem *loadGraph(const Graph &graph, PathType type, const QColor &color,
|
||||
bool primary);
|
||||
void showItems(const QList<ElevationGraphItem *> &list, bool show);
|
||||
|
||||
qreal _trackAscent, _trackDescent;
|
||||
|
@ -4,8 +4,8 @@
|
||||
|
||||
|
||||
ElevationGraphItem::ElevationGraphItem(const Graph &graph, GraphType type,
|
||||
int width, const QColor &color, QGraphicsItem *parent)
|
||||
: GraphItem(graph, type, width, color, parent)
|
||||
int width, const QColor &color, Qt::PenStyle style, QGraphicsItem *parent)
|
||||
: GraphItem(graph, type, width, color, style, parent)
|
||||
{
|
||||
_min = GraphItem::min();
|
||||
_max = GraphItem::max();
|
||||
@ -42,5 +42,6 @@ QString ElevationGraphItem::info() const
|
||||
tt.insert(tr("Minimum"), l.toString(min() * scale, 'f', 0)
|
||||
+ UNIT_SPACE + su);
|
||||
|
||||
|
||||
return tt.toString();
|
||||
}
|
||||
|
@ -8,8 +8,10 @@ class ElevationGraphItem : public GraphItem
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum DataType {GPS, DEM};
|
||||
|
||||
ElevationGraphItem(const Graph &graph, GraphType type, int width,
|
||||
const QColor &color, QGraphicsItem *parent = 0);
|
||||
const QColor &color, Qt::PenStyle style, QGraphicsItem *parent = 0);
|
||||
|
||||
qreal ascent() const {return _ascent;}
|
||||
qreal descent() const {return _descent;}
|
||||
|
@ -6,7 +6,7 @@
|
||||
|
||||
GearRatioGraphItem::GearRatioGraphItem(const Graph &graph, GraphType type,
|
||||
int width, const QColor &color, QGraphicsItem *parent)
|
||||
: GraphItem(graph, type, width, color, parent)
|
||||
: GraphItem(graph, type, width, color, Qt::SolidLine, parent)
|
||||
{
|
||||
for (int i = 0; i < graph.size(); i++) {
|
||||
const GraphSegment &segment = graph.at(i);
|
||||
|
@ -46,3 +46,9 @@ void GraphicsScene::helpEvent(QGraphicsSceneHelpEvent *event)
|
||||
|
||||
/* No need to process QGraphicsScene::helpEvent() */
|
||||
}
|
||||
|
||||
void GraphicsScene::clear()
|
||||
{
|
||||
Popup::clear();
|
||||
QGraphicsScene::clear();
|
||||
}
|
||||
|
@ -18,6 +18,9 @@ class GraphicsScene : public QGraphicsScene
|
||||
public:
|
||||
GraphicsScene(QObject *parent = 0) : QGraphicsScene(parent) {}
|
||||
|
||||
public slots:
|
||||
void clear();
|
||||
|
||||
protected:
|
||||
void helpEvent(QGraphicsSceneHelpEvent *event);
|
||||
|
||||
|
@ -5,13 +5,13 @@
|
||||
|
||||
|
||||
GraphItem::GraphItem(const Graph &graph, GraphType type, int width,
|
||||
const QColor &color, QGraphicsItem *parent)
|
||||
: GraphicsItem(parent), _graph(graph), _type(type)
|
||||
const QColor &color, Qt::PenStyle style, QGraphicsItem *parent)
|
||||
: GraphicsItem(parent), _graph(graph), _type(type), _secondaryGraph(0)
|
||||
{
|
||||
Q_ASSERT(_graph.isValid());
|
||||
|
||||
_units = Metric;
|
||||
_pen = QPen(color, width);
|
||||
_pen = QPen(color, width, style);
|
||||
_sx = 0; _sy = 0;
|
||||
_time = _graph.hasTime();
|
||||
setZValue(2.0);
|
||||
|
@ -12,8 +12,8 @@ class GraphItem : public QObject, public GraphicsItem
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
GraphItem(const Graph &graph, GraphType type, int width, const QColor &color,
|
||||
QGraphicsItem *parent = 0);
|
||||
GraphItem(const Graph &graph, GraphType type, int width,
|
||||
const QColor &color, Qt::PenStyle style, QGraphicsItem *parent = 0);
|
||||
virtual ~GraphItem() {}
|
||||
|
||||
virtual QString info() const = 0;
|
||||
@ -35,6 +35,9 @@ public:
|
||||
void setWidth(int width);
|
||||
void setUnits(Units units) {_units = units;}
|
||||
|
||||
GraphItem *secondaryGraph() const {return _secondaryGraph;}
|
||||
void setSecondaryGraph(GraphItem *graph) {_secondaryGraph = graph;}
|
||||
|
||||
qreal yAtX(qreal x);
|
||||
qreal distanceAtTime(qreal time);
|
||||
|
||||
@ -69,6 +72,8 @@ private:
|
||||
qreal _sx, _sy;
|
||||
QPen _pen;
|
||||
bool _time;
|
||||
|
||||
GraphItem *_secondaryGraph;
|
||||
};
|
||||
|
||||
#endif // GRAPHITEM_H
|
||||
|
@ -1,3 +1,4 @@
|
||||
#include <QSet>
|
||||
#include <QGraphicsScene>
|
||||
#include <QEvent>
|
||||
#include <QMouseEvent>
|
||||
@ -274,8 +275,8 @@ void GraphView::redraw(const QSizeF &size)
|
||||
rx = RangeF(bounds().left() * _xScale, bounds().right() * _xScale);
|
||||
ry = RangeF(bounds().top() * _yScale + _yOffset, bounds().bottom() * _yScale
|
||||
+ _yOffset);
|
||||
if (ry.size() < _minYRange)
|
||||
ry.resize(_minYRange);
|
||||
if (ry.size() < _minYRange * _yScale)
|
||||
ry.resize(_minYRange * _yScale);
|
||||
|
||||
_xAxis->setRange(rx);
|
||||
_yAxis->setRange(ry);
|
||||
@ -419,14 +420,16 @@ void GraphView::updateSliderInfo()
|
||||
{
|
||||
QLocale l(QLocale::system());
|
||||
qreal r = 0, y = 0;
|
||||
GraphItem *cardinal = (_graphs.count() == 1 || (_graphs.count() == 2
|
||||
&& _graphs.first()->secondaryGraph())) ? _graphs.first() : 0;
|
||||
|
||||
if (_graphs.count() == 1) {
|
||||
QRectF br(_graphs.first()->bounds());
|
||||
if (cardinal) {
|
||||
QRectF br(_bounds);
|
||||
if (br.height() < _minYRange)
|
||||
br.adjust(0, -(_minYRange/2 - br.height()/2), 0,
|
||||
_minYRange/2 - br.height()/2);
|
||||
|
||||
y = _graphs.first()->yAtX(_sliderPos);
|
||||
y = cardinal->yAtX(_sliderPos);
|
||||
r = (y - br.bottom()) / br.height();
|
||||
}
|
||||
|
||||
@ -436,11 +439,17 @@ void GraphView::updateSliderInfo()
|
||||
|
||||
_sliderInfo->setSide(s);
|
||||
_sliderInfo->setPos(QPointF(0, _slider->boundingRect().height() * r));
|
||||
_sliderInfo->setText(_graphType == Time ? Format::timeSpan(_sliderPos,
|
||||
QString xText(_graphType == Time ? Format::timeSpan(_sliderPos,
|
||||
bounds().width() > 3600) : l.toString(_sliderPos * _xScale, 'f', 1)
|
||||
+ UNIT_SPACE + _xUnits, (_graphs.count() > 1) ? QString()
|
||||
: l.toString(-y * _yScale + _yOffset, 'f', _precision) + UNIT_SPACE
|
||||
+ _yUnits);
|
||||
+ UNIT_SPACE + _xUnits);
|
||||
QString yText((!cardinal) ? QString() : l.toString(-y * _yScale + _yOffset,
|
||||
'f', _precision) + UNIT_SPACE + _yUnits);
|
||||
if (cardinal && cardinal->secondaryGraph()) {
|
||||
qreal delta = y - cardinal->secondaryGraph()->yAtX(_sliderPos);
|
||||
yText += " " + QChar(0x0394) + l.toString(-delta * _yScale + _yOffset,
|
||||
'f', _precision) + UNIT_SPACE + _yUnits;
|
||||
}
|
||||
_sliderInfo->setText(xText, yText);
|
||||
}
|
||||
|
||||
void GraphView::emitSliderPositionChanged(const QPointF &pos)
|
||||
@ -486,8 +495,23 @@ void GraphView::setPalette(const Palette &palette)
|
||||
_palette = palette;
|
||||
_palette.reset();
|
||||
|
||||
for (int i = 0; i < _graphs.count(); i++)
|
||||
_graphs.at(i)->setColor(_palette.nextColor());
|
||||
QSet<GraphItem*> secondary;
|
||||
for (int i = 0; i < _graphs.count(); i++) {
|
||||
GraphItem *g = _graphs[i];
|
||||
if (g->secondaryGraph())
|
||||
secondary.insert(g->secondaryGraph());
|
||||
}
|
||||
|
||||
for (int i = 0; i < _graphs.count(); i++) {
|
||||
GraphItem *g = _graphs[i];
|
||||
if (secondary.contains(g))
|
||||
continue;
|
||||
|
||||
QColor color(_palette.nextColor());
|
||||
g->setColor(color);
|
||||
if (g->secondaryGraph())
|
||||
g->secondaryGraph()->setColor(color);
|
||||
}
|
||||
}
|
||||
|
||||
void GraphView::setGraphWidth(int width)
|
||||
|
@ -3,7 +3,6 @@
|
||||
|
||||
#include <QGraphicsView>
|
||||
#include <QList>
|
||||
#include <QSet>
|
||||
#include "data/graph.h"
|
||||
#include "palette.h"
|
||||
#include "units.h"
|
||||
|
278
src/GUI/gui.cpp
278
src/GUI/gui.cpp
@ -51,6 +51,7 @@
|
||||
#include "graphtab.h"
|
||||
#include "graphitem.h"
|
||||
#include "pathitem.h"
|
||||
#include "mapaction.h"
|
||||
#include "gui.h"
|
||||
|
||||
|
||||
@ -58,7 +59,6 @@
|
||||
|
||||
GUI::GUI()
|
||||
{
|
||||
loadMaps();
|
||||
loadPOIs();
|
||||
|
||||
createMapView();
|
||||
@ -106,24 +106,13 @@ GUI::GUI()
|
||||
updateStatusBarInfo();
|
||||
}
|
||||
|
||||
void GUI::loadMaps()
|
||||
{
|
||||
_ml = new MapList(this);
|
||||
QString mapDir(ProgramPaths::mapDir());
|
||||
|
||||
if (!mapDir.isNull() && !_ml->loadDir(mapDir))
|
||||
qWarning("%s", qPrintable(_ml->errorString()));
|
||||
|
||||
_map = new EmptyMap(this);
|
||||
}
|
||||
|
||||
void GUI::loadPOIs()
|
||||
{
|
||||
_poi = new POI(this);
|
||||
QString poiDir(ProgramPaths::poiDir());
|
||||
|
||||
if (!poiDir.isNull() && !_poi->loadDir(poiDir))
|
||||
qWarning("%s", qPrintable(_poi->errorString()));
|
||||
QString poiDir(ProgramPaths::poiDir());
|
||||
if (!poiDir.isNull())
|
||||
_poi->loadDir(poiDir);
|
||||
}
|
||||
|
||||
void GUI::createBrowser()
|
||||
@ -134,40 +123,56 @@ void GUI::createBrowser()
|
||||
|
||||
void GUI::createMapActions()
|
||||
{
|
||||
_mapsSignalMapper = new QSignalMapper(this);
|
||||
_mapsActionGroup = new QActionGroup(this);
|
||||
_mapsActionGroup->setExclusive(true);
|
||||
|
||||
for (int i = 0; i < _ml->maps().count(); i++)
|
||||
createMapAction(_ml->maps().at(i));
|
||||
QString mapDir(ProgramPaths::mapDir());
|
||||
if (mapDir.isNull())
|
||||
return;
|
||||
|
||||
connect(_mapsSignalMapper, SIGNAL(mapped(int)), this,
|
||||
SLOT(mapChanged(int)));
|
||||
QString unused;
|
||||
QList<Map*> maps(MapList::loadMaps(mapDir, unused));
|
||||
for (int i = 0; i < maps.count(); i++) {
|
||||
MapAction *a = createMapAction(maps.at(i));
|
||||
connect(a, SIGNAL(loaded()), this, SLOT(mapInitialized()));
|
||||
}
|
||||
}
|
||||
|
||||
QAction *GUI::createMapAction(const Map *map)
|
||||
MapAction *GUI::createMapAction(Map *map)
|
||||
{
|
||||
QAction *a = new QAction(map->name(), this);
|
||||
MapAction *a = new MapAction(map);
|
||||
a->setMenuRole(QAction::NoRole);
|
||||
a->setCheckable(true);
|
||||
a->setActionGroup(_mapsActionGroup);
|
||||
|
||||
_mapActions.append(a);
|
||||
_mapsSignalMapper->setMapping(a, _mapActions.size() - 1);
|
||||
connect(a, SIGNAL(triggered()), _mapsSignalMapper, SLOT(map()));
|
||||
connect(a, SIGNAL(triggered()), this, SLOT(mapChanged()));
|
||||
|
||||
return a;
|
||||
}
|
||||
|
||||
void GUI::mapInitialized()
|
||||
{
|
||||
MapAction *action = static_cast<MapAction*>(QObject::sender());
|
||||
Map *map = action->data().value<Map*>();
|
||||
|
||||
if (map->isValid()) {
|
||||
if (!_mapsActionGroup->checkedAction())
|
||||
action->trigger();
|
||||
_showMapAction->setEnabled(true);
|
||||
_clearMapCacheAction->setEnabled(true);
|
||||
} else {
|
||||
qWarning("%s: %s", qPrintable(map->name()), qPrintable(map->errorString()));
|
||||
action->deleteLater();
|
||||
}
|
||||
}
|
||||
|
||||
void GUI::createPOIFilesActions()
|
||||
{
|
||||
_poiFilesSignalMapper = new QSignalMapper(this);
|
||||
connect(_poiFilesSignalMapper, SIGNAL(mapped(int)), this,
|
||||
SLOT(poiFileChecked(int)));
|
||||
|
||||
for (int i = 0; i < _poi->files().count(); i++)
|
||||
createPOIFileAction(_poi->files().at(i));
|
||||
|
||||
connect(_poiFilesSignalMapper, SIGNAL(mapped(int)), this,
|
||||
SLOT(poiFileChecked(int)));
|
||||
}
|
||||
|
||||
QAction *GUI::createPOIFileAction(const QString &fileName)
|
||||
@ -243,7 +248,7 @@ void GUI::createActions()
|
||||
_reloadFileAction->setMenuRole(QAction::NoRole);
|
||||
_reloadFileAction->setShortcut(RELOAD_SHORTCUT);
|
||||
_reloadFileAction->setActionGroup(_fileActionGroup);
|
||||
connect(_reloadFileAction, SIGNAL(triggered()), this, SLOT(reloadFile()));
|
||||
connect(_reloadFileAction, SIGNAL(triggered()), this, SLOT(reloadFiles()));
|
||||
addAction(_reloadFileAction);
|
||||
_statisticsAction = new QAction(tr("Statistics..."), this);
|
||||
_statisticsAction->setMenuRole(QAction::NoRole);
|
||||
@ -281,8 +286,10 @@ void GUI::createActions()
|
||||
createPOIFilesActions();
|
||||
|
||||
// Map actions
|
||||
createMapActions();
|
||||
_showMapAction = new QAction(QIcon(SHOW_MAP_ICON), tr("Show map"),
|
||||
this);
|
||||
_showMapAction->setEnabled(false);
|
||||
_showMapAction->setMenuRole(QAction::NoRole);
|
||||
_showMapAction->setCheckable(true);
|
||||
_showMapAction->setShortcut(SHOW_MAP_SHORTCUT);
|
||||
@ -294,10 +301,10 @@ void GUI::createActions()
|
||||
_loadMapAction->setMenuRole(QAction::NoRole);
|
||||
connect(_loadMapAction, SIGNAL(triggered()), this, SLOT(loadMap()));
|
||||
_clearMapCacheAction = new QAction(tr("Clear tile cache"), this);
|
||||
_clearMapCacheAction->setEnabled(false);
|
||||
_clearMapCacheAction->setMenuRole(QAction::NoRole);
|
||||
connect(_clearMapCacheAction, SIGNAL(triggered()), _mapView,
|
||||
SLOT(clearMapCache()));
|
||||
createMapActions();
|
||||
_nextMapAction = new QAction(tr("Next map"), this);
|
||||
_nextMapAction->setMenuRole(QAction::NoRole);
|
||||
_nextMapAction->setShortcut(NEXT_MAP_SHORTCUT);
|
||||
@ -308,10 +315,6 @@ void GUI::createActions()
|
||||
_prevMapAction->setShortcut(PREV_MAP_SHORTCUT);
|
||||
connect(_prevMapAction, SIGNAL(triggered()), this, SLOT(prevMap()));
|
||||
addAction(_prevMapAction);
|
||||
if (_ml->maps().isEmpty()) {
|
||||
_showMapAction->setEnabled(false);
|
||||
_clearMapCacheAction->setEnabled(false);
|
||||
}
|
||||
_showCoordinatesAction = new QAction(tr("Show cursor coordinates"), this);
|
||||
_showCoordinatesAction->setMenuRole(QAction::NoRole);
|
||||
_showCoordinatesAction->setCheckable(true);
|
||||
@ -451,11 +454,11 @@ void GUI::createActions()
|
||||
_degreesMinutesAction->setActionGroup(ag);
|
||||
connect(_degreesMinutesAction, SIGNAL(triggered()), this,
|
||||
SLOT(setDegreesMinutes()));
|
||||
_DMSAction = new QAction(tr("Degrees, minutes, seconds (DMS)"), this);
|
||||
_DMSAction->setMenuRole(QAction::NoRole);
|
||||
_DMSAction->setCheckable(true);
|
||||
_DMSAction->setActionGroup(ag);
|
||||
connect(_DMSAction, SIGNAL(triggered()), this, SLOT(setDMS()));
|
||||
_dmsAction = new QAction(tr("Degrees, minutes, seconds (DMS)"), this);
|
||||
_dmsAction->setMenuRole(QAction::NoRole);
|
||||
_dmsAction->setCheckable(true);
|
||||
_dmsAction->setActionGroup(ag);
|
||||
connect(_dmsAction, SIGNAL(triggered()), this, SLOT(setDMS()));
|
||||
_fullscreenAction = new QAction(QIcon(FULLSCREEN_ICON),
|
||||
tr("Fullscreen mode"), this);
|
||||
_fullscreenAction->setMenuRole(QAction::NoRole);
|
||||
@ -506,7 +509,7 @@ void GUI::createMenus()
|
||||
#endif // Q_OS_MAC
|
||||
|
||||
_mapMenu = menuBar()->addMenu(tr("&Map"));
|
||||
_mapMenu->addActions(_mapActions);
|
||||
_mapMenu->addActions(_mapsActionGroup->actions());
|
||||
_mapsEnd = _mapMenu->addSeparator();
|
||||
_mapMenu->addAction(_loadMapAction);
|
||||
_mapMenu->addAction(_clearMapCacheAction);
|
||||
@ -559,7 +562,7 @@ void GUI::createMenus()
|
||||
QMenu *coordinatesMenu = settingsMenu->addMenu(tr("Coordinates format"));
|
||||
coordinatesMenu->addAction(_decimalDegreesAction);
|
||||
coordinatesMenu->addAction(_degreesMinutesAction);
|
||||
coordinatesMenu->addAction(_DMSAction);
|
||||
coordinatesMenu->addAction(_dmsAction);
|
||||
settingsMenu->addSeparator();
|
||||
settingsMenu->addAction(_showToolbarsAction);
|
||||
settingsMenu->addAction(_fullscreenAction);
|
||||
@ -608,6 +611,7 @@ void GUI::createToolBars()
|
||||
|
||||
void GUI::createMapView()
|
||||
{
|
||||
_map = new EmptyMap(this);
|
||||
_mapView = new MapView(_map, _poi, this);
|
||||
_mapView->setSizePolicy(QSizePolicy(QSizePolicy::Ignored,
|
||||
QSizePolicy::Expanding));
|
||||
@ -787,7 +791,12 @@ bool GUI::loadFile(const QString &fileName)
|
||||
_trackDistance += track.distance();
|
||||
_time += track.time();
|
||||
_movingTime += track.movingTime();
|
||||
const QDate &date = track.date().date();
|
||||
#ifdef ENABLE_TIMEZONES
|
||||
const QDateTime date = track.date().toTimeZone(
|
||||
_options.timeZone.zone());
|
||||
#else // ENABLE_TIMEZONES
|
||||
const QDateTime &date = track.date();
|
||||
#endif // ENABLE_TIMEZONES
|
||||
if (_dateRange.first.isNull() || _dateRange.first > date)
|
||||
_dateRange.first = date;
|
||||
if (_dateRange.second.isNull() || _dateRange.second < date)
|
||||
@ -905,9 +914,14 @@ void GUI::openOptions()
|
||||
Track::action(options.option); \
|
||||
reload = true; \
|
||||
}
|
||||
#define SET_DATA_OPTION(option, action) \
|
||||
#define SET_ROUTE_OPTION(option, action) \
|
||||
if (options.option != _options.option) { \
|
||||
Data::action(options.option); \
|
||||
Route::action(options.option); \
|
||||
reload = true; \
|
||||
}
|
||||
#define SET_WAYPOINT_OPTION(option, action) \
|
||||
if (options.option != _options.option) { \
|
||||
Waypoint::action(options.option); \
|
||||
reload = true; \
|
||||
}
|
||||
|
||||
@ -949,16 +963,22 @@ void GUI::openOptions()
|
||||
SET_TRACK_OPTION(cadenceFilter, setCadenceFilter);
|
||||
SET_TRACK_OPTION(powerFilter, setPowerFilter);
|
||||
SET_TRACK_OPTION(outlierEliminate, setOutlierElimination);
|
||||
SET_TRACK_OPTION(automaticPause, setAutomaticPause);
|
||||
SET_TRACK_OPTION(pauseSpeed, setPauseSpeed);
|
||||
SET_TRACK_OPTION(pauseInterval, setPauseInterval);
|
||||
SET_TRACK_OPTION(useReportedSpeed, useReportedSpeed);
|
||||
SET_TRACK_OPTION(dataUseDEM, useDEM);
|
||||
SET_TRACK_OPTION(showSecondaryElevation, showSecondaryElevation);
|
||||
SET_TRACK_OPTION(showSecondarySpeed, showSecondarySpeed);
|
||||
|
||||
SET_DATA_OPTION(dataUseDEM, useDEM);
|
||||
SET_ROUTE_OPTION(dataUseDEM, useDEM);
|
||||
SET_ROUTE_OPTION(showSecondaryElevation, showSecondaryElevation);
|
||||
|
||||
SET_WAYPOINT_OPTION(dataUseDEM, useDEM);
|
||||
SET_WAYPOINT_OPTION(showSecondaryElevation, showSecondaryElevation);
|
||||
|
||||
if (options.poiRadius != _options.poiRadius)
|
||||
_poi->setRadius(options.poiRadius);
|
||||
if (options.poiUseDEM != _options.poiUseDEM)
|
||||
_poi->useDEM(options.poiUseDEM);
|
||||
|
||||
if (options.pixmapCache != _options.pixmapCache)
|
||||
QPixmapCache::setCacheLimit(options.pixmapCache * 1024);
|
||||
@ -975,9 +995,16 @@ void GUI::openOptions()
|
||||
_mapView->setDevicePixelRatio(devicePixelRatioF(),
|
||||
options.hidpiMap ? devicePixelRatioF() : 1.0);
|
||||
#endif // ENABLE_HIDPI
|
||||
#ifdef ENABLE_TIMEZONES
|
||||
if (options.timeZone != _options.timeZone) {
|
||||
_mapView->setTimeZone(options.timeZone.zone());
|
||||
_dateRange.first = _dateRange.first.toTimeZone(options.timeZone.zone());
|
||||
_dateRange.second = _dateRange.second.toTimeZone(options.timeZone.zone());
|
||||
}
|
||||
#endif // ENABLE_TIMEZONES
|
||||
|
||||
if (reload)
|
||||
reloadFile();
|
||||
reloadFiles();
|
||||
|
||||
_options = options;
|
||||
}
|
||||
@ -1170,7 +1197,7 @@ void GUI::plot(QPrinter *printer)
|
||||
}
|
||||
}
|
||||
|
||||
void GUI::reloadFile()
|
||||
void GUI::reloadFiles()
|
||||
{
|
||||
_trackCount = 0;
|
||||
_routeCount = 0;
|
||||
@ -1180,7 +1207,7 @@ void GUI::reloadFile()
|
||||
_routeDistance = 0;
|
||||
_time = 0;
|
||||
_movingTime = 0;
|
||||
_dateRange = DateRange(QDate(), QDate());
|
||||
_dateRange = DateTimeRange(QDateTime(), QDateTime());
|
||||
_pathName = QString();
|
||||
|
||||
for (int i = 0; i < _tabs.count(); i++)
|
||||
@ -1214,7 +1241,7 @@ void GUI::closeFiles()
|
||||
_routeDistance = 0;
|
||||
_time = 0;
|
||||
_movingTime = 0;
|
||||
_dateRange = DateRange(QDate(), QDate());
|
||||
_dateRange = DateTimeRange(QDateTime(), QDateTime());
|
||||
_pathName = QString();
|
||||
|
||||
_sliderPos = 0;
|
||||
@ -1321,22 +1348,49 @@ void GUI::loadMap()
|
||||
|
||||
bool GUI::loadMap(const QString &fileName)
|
||||
{
|
||||
// On OS X fileName may be a directory!
|
||||
|
||||
if (fileName.isEmpty())
|
||||
return false;
|
||||
|
||||
if (_ml->loadFile(fileName)) {
|
||||
QAction *a = createMapAction(_ml->maps().last());
|
||||
QString error;
|
||||
QList<Map*> maps = MapList::loadMaps(fileName, error);
|
||||
if (maps.isEmpty()) {
|
||||
error = tr("Error loading map:") + "\n\n"
|
||||
+ fileName + "\n\n" + error;
|
||||
QMessageBox::critical(this, APP_NAME, error);
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < maps.size(); i++) {
|
||||
Map *map = maps.at(i);
|
||||
MapAction *a = createMapAction(map);
|
||||
_mapMenu->insertAction(_mapsEnd, a);
|
||||
if (map->isReady()) {
|
||||
a->trigger();
|
||||
_showMapAction->setEnabled(true);
|
||||
_clearMapCacheAction->setEnabled(true);
|
||||
} else
|
||||
connect(a, SIGNAL(loaded()), this, SLOT(mapLoaded()));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void GUI::mapLoaded()
|
||||
{
|
||||
MapAction *action = static_cast<MapAction*>(QObject::sender());
|
||||
Map *map = action->data().value<Map*>();
|
||||
|
||||
if (map->isValid()) {
|
||||
action->trigger();
|
||||
_showMapAction->setEnabled(true);
|
||||
_clearMapCacheAction->setEnabled(true);
|
||||
a->trigger();
|
||||
return true;
|
||||
} else {
|
||||
QString error = tr("Error loading map:") + "\n\n"
|
||||
+ fileName + "\n\n" + _ml->errorString();
|
||||
+ map->name() + "\n\n" + map->errorString();
|
||||
QMessageBox::critical(this, APP_NAME, error);
|
||||
|
||||
return false;
|
||||
action->deleteLater();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1378,31 +1432,42 @@ void GUI::updateWindowTitle()
|
||||
setWindowTitle(APP_NAME);
|
||||
}
|
||||
|
||||
void GUI::mapChanged(int index)
|
||||
void GUI::mapChanged()
|
||||
{
|
||||
_map = _ml->maps().at(index);
|
||||
_map = _mapsActionGroup->checkedAction()->data().value<Map*>();
|
||||
_mapView->setMap(_map);
|
||||
}
|
||||
|
||||
void GUI::nextMap()
|
||||
{
|
||||
if (_ml->maps().count() < 2)
|
||||
QAction *checked = _mapsActionGroup->checkedAction();
|
||||
if (!checked)
|
||||
return;
|
||||
|
||||
int next = (_ml->maps().indexOf(_map) + 1) % _ml->maps().count();
|
||||
_mapActions.at(next)->setChecked(true);
|
||||
mapChanged(next);
|
||||
QList<QAction*> maps = _mapsActionGroup->actions();
|
||||
for (int i = 1; i < maps.size(); i++) {
|
||||
int next = (maps.indexOf(checked) + i) % maps.count();
|
||||
if (maps.at(next)->isEnabled()) {
|
||||
maps.at(next)->trigger();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GUI::prevMap()
|
||||
{
|
||||
if (_ml->maps().count() < 2)
|
||||
QAction *checked = _mapsActionGroup->checkedAction();
|
||||
if (!checked)
|
||||
return;
|
||||
|
||||
int prev = (_ml->maps().indexOf(_map) + _ml->maps().count() - 1)
|
||||
% _ml->maps().count();
|
||||
_mapActions.at(prev)->setChecked(true);
|
||||
mapChanged(prev);
|
||||
QList<QAction*> maps = _mapsActionGroup->actions();
|
||||
for (int i = 1; i < maps.size(); i++) {
|
||||
int prev = (maps.indexOf(checked) + maps.count() - i) % maps.count();
|
||||
if (maps.at(prev)->isEnabled()) {
|
||||
maps.at(prev)->trigger();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GUI::poiFileChecked(int index)
|
||||
@ -1654,7 +1719,7 @@ void GUI::writeSettings()
|
||||
: _nauticalUnitsAction->isChecked() ? Nautical : Metric;
|
||||
if (units != UNITS_DEFAULT)
|
||||
settings.setValue(UNITS_SETTING, units);
|
||||
CoordinatesFormat format = _DMSAction->isChecked() ? DMS
|
||||
CoordinatesFormat format = _dmsAction->isChecked() ? DMS
|
||||
: _degreesMinutesAction->isChecked() ? DegreesMinutes : DecimalDegrees;
|
||||
if (format != COORDINATES_DEFAULT)
|
||||
settings.setValue(COORDINATES_SETTING, format);
|
||||
@ -1798,6 +1863,8 @@ void GUI::writeSettings()
|
||||
settings.setValue(POWER_FILTER_SETTING, _options.powerFilter);
|
||||
if (_options.outlierEliminate != OUTLIER_ELIMINATE_DEFAULT)
|
||||
settings.setValue(OUTLIER_ELIMINATE_SETTING, _options.outlierEliminate);
|
||||
if (_options.automaticPause != AUTOMATIC_PAUSE_DEFAULT)
|
||||
settings.setValue(AUTOMATIC_PAUSE_SETTING, _options.automaticPause);
|
||||
if (_options.pauseSpeed != PAUSE_SPEED_DEFAULT)
|
||||
settings.setValue(PAUSE_SPEED_SETTING, _options.pauseSpeed);
|
||||
if (_options.pauseInterval != PAUSE_INTERVAL_DEFAULT)
|
||||
@ -1806,10 +1873,19 @@ void GUI::writeSettings()
|
||||
settings.setValue(USE_REPORTED_SPEED_SETTING, _options.useReportedSpeed);
|
||||
if (_options.dataUseDEM != DATA_USE_DEM_DEFAULT)
|
||||
settings.setValue(DATA_USE_DEM_SETTING, _options.dataUseDEM);
|
||||
if (_options.showSecondaryElevation != SHOW_SECONDARY_ELEVATION_DEFAULT)
|
||||
settings.setValue(SHOW_SECONDARY_ELEVATION_SETTING,
|
||||
_options.showSecondaryElevation);
|
||||
if (_options.showSecondarySpeed != SHOW_SECONDARY_SPEED_DEFAULT)
|
||||
settings.setValue(SHOW_SECONDARY_SPEED_SETTING,
|
||||
_options.showSecondarySpeed);
|
||||
#ifdef ENABLE_TIMEZONES
|
||||
if (_options.timeZone != TimeZoneInfo())
|
||||
settings.setValue(TIME_ZONE_SETTING, QVariant::fromValue(
|
||||
_options.timeZone));
|
||||
#endif // ENABLE_TIMEZONES
|
||||
if (_options.poiRadius != POI_RADIUS_DEFAULT)
|
||||
settings.setValue(POI_RADIUS_SETTING, _options.poiRadius);
|
||||
if (_options.poiUseDEM != POI_USE_DEM_DEFAULT)
|
||||
settings.setValue(POI_USE_DEM_SETTING, _options.poiUseDEM);
|
||||
if (_options.useOpenGL != USE_OPENGL_DEFAULT)
|
||||
settings.setValue(USE_OPENGL_SETTING, _options.useOpenGL);
|
||||
#ifdef ENABLE_HTTP2
|
||||
@ -1876,7 +1952,7 @@ void GUI::readSettings()
|
||||
|
||||
value = settings.value(COORDINATES_SETTING, COORDINATES_DEFAULT).toInt();
|
||||
if (value == DMS)
|
||||
_DMSAction->trigger();
|
||||
_dmsAction->trigger();
|
||||
else if (value == DegreesMinutes)
|
||||
_degreesMinutesAction->trigger();
|
||||
else
|
||||
@ -1893,9 +1969,11 @@ void GUI::readSettings()
|
||||
_showMapAction->setChecked(true);
|
||||
else
|
||||
_mapView->showMap(false);
|
||||
if (_ml->maps().count()) {
|
||||
int index = mapIndex(settings.value(CURRENT_MAP_SETTING).toString());
|
||||
_mapActions.at(index)->trigger();
|
||||
QAction *ma = mapAction(settings.value(CURRENT_MAP_SETTING).toString());
|
||||
if (ma) {
|
||||
ma->trigger();
|
||||
_showMapAction->setEnabled(true);
|
||||
_clearMapCacheAction->setEnabled(true);
|
||||
}
|
||||
if (settings.value(SHOW_COORDINATES_SETTING, SHOW_COORDINATES_DEFAULT)
|
||||
.toBool()) {
|
||||
@ -2072,12 +2150,21 @@ void GUI::readSettings()
|
||||
USE_REPORTED_SPEED_DEFAULT).toBool();
|
||||
_options.dataUseDEM = settings.value(DATA_USE_DEM_SETTING,
|
||||
DATA_USE_DEM_DEFAULT).toBool();
|
||||
_options.showSecondaryElevation = settings.value(
|
||||
SHOW_SECONDARY_ELEVATION_SETTING,
|
||||
SHOW_SECONDARY_ELEVATION_DEFAULT).toBool();
|
||||
_options.showSecondarySpeed = settings.value(
|
||||
SHOW_SECONDARY_SPEED_SETTING,
|
||||
SHOW_SECONDARY_SPEED_DEFAULT).toBool();
|
||||
#ifdef ENABLE_TIMEZONES
|
||||
_options.timeZone = settings.value(TIME_ZONE_SETTING).value<TimeZoneInfo>();
|
||||
#endif // ENABLE_TIMEZONES
|
||||
_options.automaticPause = settings.value(AUTOMATIC_PAUSE_SETTING,
|
||||
AUTOMATIC_PAUSE_DEFAULT).toBool();
|
||||
_options.pauseInterval = settings.value(PAUSE_INTERVAL_SETTING,
|
||||
PAUSE_INTERVAL_DEFAULT).toInt();
|
||||
_options.poiRadius = settings.value(POI_RADIUS_SETTING, POI_RADIUS_DEFAULT)
|
||||
.toInt();
|
||||
_options.poiUseDEM = settings.value(POI_USE_DEM_SETTING,
|
||||
POI_USE_DEM_DEFAULT).toBool();
|
||||
_options.useOpenGL = settings.value(USE_OPENGL_SETTING, USE_OPENGL_DEFAULT)
|
||||
.toBool();
|
||||
#ifdef ENABLE_HTTP2
|
||||
@ -2136,6 +2223,9 @@ void GUI::readSettings()
|
||||
_options.hidpiMap ? devicePixelRatioF() : 1.0);
|
||||
#endif // ENABLE_HIDPI
|
||||
_mapView->setProjection(_options.projection);
|
||||
#ifdef ENABLE_TIMEZONES
|
||||
_mapView->setTimeZone(_options.timeZone.zone());
|
||||
#endif // ENABLE_TIMEZONES
|
||||
|
||||
for (int i = 0; i < _tabs.count(); i++) {
|
||||
_tabs.at(i)->setPalette(_options.palette);
|
||||
@ -2153,24 +2243,42 @@ void GUI::readSettings()
|
||||
Track::setCadenceFilter(_options.cadenceFilter);
|
||||
Track::setPowerFilter(_options.powerFilter);
|
||||
Track::setOutlierElimination(_options.outlierEliminate);
|
||||
Track::setAutomaticPause(_options.automaticPause);
|
||||
Track::setPauseSpeed(_options.pauseSpeed);
|
||||
Track::setPauseInterval(_options.pauseInterval);
|
||||
Track::useReportedSpeed(_options.useReportedSpeed);
|
||||
Data::useDEM(_options.dataUseDEM);
|
||||
Track::useDEM(_options.dataUseDEM);
|
||||
Track::showSecondaryElevation(_options.showSecondaryElevation);
|
||||
Track::showSecondarySpeed(_options.showSecondarySpeed);
|
||||
Route::useDEM(_options.dataUseDEM);
|
||||
Route::showSecondaryElevation(_options.showSecondaryElevation);
|
||||
Waypoint::useDEM(_options.dataUseDEM);
|
||||
Waypoint::showSecondaryElevation(_options.showSecondaryElevation);
|
||||
|
||||
_poi->setRadius(_options.poiRadius);
|
||||
_poi->useDEM(_options.poiUseDEM);
|
||||
|
||||
QPixmapCache::setCacheLimit(_options.pixmapCache * 1024);
|
||||
|
||||
settings.endGroup();
|
||||
}
|
||||
|
||||
int GUI::mapIndex(const QString &name)
|
||||
QAction *GUI::mapAction(const QString &name)
|
||||
{
|
||||
for (int i = 0; i < _ml->maps().count(); i++)
|
||||
if (_ml->maps().at(i)->name() == name)
|
||||
return i;
|
||||
QList<QAction *> maps = _mapsActionGroup->actions();
|
||||
|
||||
// Last map
|
||||
for (int i = 0; i < maps.count(); i++) {
|
||||
Map *map = maps.at(i)->data().value<Map*>();
|
||||
if (map->name() == name && map->isReady())
|
||||
return maps.at(i);
|
||||
}
|
||||
|
||||
// Any usable map
|
||||
for (int i = 0; i < maps.count(); i++) {
|
||||
Map *map = maps.at(i)->data().value<Map*>();
|
||||
if (map->isReady())
|
||||
return maps.at(i);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -26,9 +26,9 @@ class FileBrowser;
|
||||
class GraphTab;
|
||||
class MapView;
|
||||
class Map;
|
||||
class MapList;
|
||||
class POI;
|
||||
class QScreen;
|
||||
class MapAction;
|
||||
|
||||
class GUI : public QMainWindow
|
||||
{
|
||||
@ -48,7 +48,7 @@ private slots:
|
||||
void exportFile();
|
||||
void openFile();
|
||||
void closeAll();
|
||||
void reloadFile();
|
||||
void reloadFiles();
|
||||
void statistics();
|
||||
void openPOIFile();
|
||||
void closePOIFiles();
|
||||
@ -64,7 +64,7 @@ private slots:
|
||||
void prevMap();
|
||||
void openOptions();
|
||||
|
||||
void mapChanged(int);
|
||||
void mapChanged();
|
||||
void graphChanged(int);
|
||||
void poiFileChecked(int);
|
||||
|
||||
@ -88,16 +88,18 @@ private slots:
|
||||
void screenChanged(QScreen *screen);
|
||||
void logicalDotsPerInchChanged(qreal dpi);
|
||||
|
||||
private:
|
||||
typedef QPair<QDate, QDate> DateRange;
|
||||
void mapLoaded();
|
||||
void mapInitialized();
|
||||
|
||||
private:
|
||||
typedef QPair<QDateTime, QDateTime> DateTimeRange;
|
||||
|
||||
void loadMaps();
|
||||
void loadPOIs();
|
||||
void closeFiles();
|
||||
void plot(QPrinter *printer);
|
||||
|
||||
QAction *createPOIFileAction(const QString &fileName);
|
||||
QAction *createMapAction(const Map *map);
|
||||
MapAction *createMapAction(Map *map);
|
||||
void createPOIFilesActions();
|
||||
void createMapActions();
|
||||
void createActions();
|
||||
@ -127,7 +129,7 @@ private:
|
||||
qreal distance() const;
|
||||
qreal time() const;
|
||||
qreal movingTime() const;
|
||||
int mapIndex(const QString &name);
|
||||
QAction *mapAction(const QString &name);
|
||||
void readSettings();
|
||||
void writeSettings();
|
||||
|
||||
@ -180,7 +182,7 @@ private:
|
||||
QAction *_nauticalUnitsAction;
|
||||
QAction *_decimalDegreesAction;
|
||||
QAction *_degreesMinutesAction;
|
||||
QAction *_DMSAction;
|
||||
QAction *_dmsAction;
|
||||
QAction *_totalTimeAction;
|
||||
QAction *_movingTimeAction;
|
||||
QAction *_nextMapAction;
|
||||
@ -196,11 +198,9 @@ private:
|
||||
QAction *_showCoordinatesAction;
|
||||
QAction *_openOptionsAction;
|
||||
QAction *_mapsEnd;
|
||||
QList<QAction*> _mapActions;
|
||||
QList<QAction*> _poiFilesActions;
|
||||
|
||||
QList<QAction*> _poiFilesActions;
|
||||
QSignalMapper *_poiFilesSignalMapper;
|
||||
QSignalMapper *_mapsSignalMapper;
|
||||
|
||||
QLabel *_fileNameLabel;
|
||||
QLabel *_distanceLabel;
|
||||
@ -212,7 +212,6 @@ private:
|
||||
QList<GraphTab*> _tabs;
|
||||
|
||||
POI *_poi;
|
||||
MapList *_ml;
|
||||
Map *_map;
|
||||
|
||||
FileBrowser *_browser;
|
||||
@ -221,7 +220,7 @@ private:
|
||||
int _trackCount, _routeCount, _areaCount, _waypointCount;
|
||||
qreal _trackDistance, _routeDistance;
|
||||
qreal _time, _movingTime;
|
||||
DateRange _dateRange;
|
||||
DateTimeRange _dateRange;
|
||||
QString _pathName;
|
||||
|
||||
qreal _sliderPos;
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
HeartRateGraphItem::HeartRateGraphItem(const Graph &graph, GraphType type,
|
||||
int width, const QColor &color, QGraphicsItem *parent)
|
||||
: GraphItem(graph, type, width, color, parent)
|
||||
: GraphItem(graph, type, width, color, Qt::SolidLine, parent)
|
||||
{
|
||||
}
|
||||
|
||||
|
32
src/GUI/mapaction.h
Normal file
32
src/GUI/mapaction.h
Normal file
@ -0,0 +1,32 @@
|
||||
#ifndef MAPACTION_H
|
||||
#define MAPACTION_H
|
||||
|
||||
#include <QAction>
|
||||
#include "map/map.h"
|
||||
|
||||
class MapAction : public QAction
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
MapAction(Map *map, QObject *parent = 0) : QAction(map->name(), parent)
|
||||
{
|
||||
map->setParent(this);
|
||||
setData(QVariant::fromValue(map));
|
||||
setEnabled(map->isReady());
|
||||
connect(map, SIGNAL(mapLoaded()), this, SLOT(mapLoaded()));
|
||||
}
|
||||
|
||||
signals:
|
||||
void loaded();
|
||||
|
||||
private slots:
|
||||
void mapLoaded()
|
||||
{
|
||||
Map *map = data().value<Map*>();
|
||||
setEnabled(map->isValid());
|
||||
emit loaded();
|
||||
}
|
||||
};
|
||||
|
||||
#endif // MAPACTION_H
|
@ -2,7 +2,6 @@
|
||||
#include <QGraphicsScene>
|
||||
#include <QWheelEvent>
|
||||
#include <QApplication>
|
||||
#include <QPixmapCache>
|
||||
#include <QScrollBar>
|
||||
#include "data/poi.h"
|
||||
#include "data/data.h"
|
||||
@ -55,13 +54,11 @@ MapView::MapView(Map *map, POI *poi, QWidget *parent)
|
||||
_map = map;
|
||||
_map->load();
|
||||
_map->setProjection(_projection);
|
||||
connect(_map, SIGNAL(loaded()), this, SLOT(reloadMap()));
|
||||
connect(_map, SIGNAL(tilesLoaded()), this, SLOT(reloadMap()));
|
||||
|
||||
_poi = poi;
|
||||
connect(_poi, SIGNAL(pointsChanged()), this, SLOT(updatePOI()));
|
||||
|
||||
_units = Metric;
|
||||
_coordinatesFormat = DecimalDegrees;
|
||||
_mapOpacity = 1.0;
|
||||
_backgroundColor = Qt::white;
|
||||
_markerColor = Qt::red;
|
||||
@ -123,7 +120,6 @@ PathItem *MapView::addTrack(const Track &track)
|
||||
ti->setColor(_palette.nextColor());
|
||||
ti->setWidth(_trackWidth);
|
||||
ti->setStyle(_trackStyle);
|
||||
ti->setUnits(_units);
|
||||
ti->setVisible(_showTracks);
|
||||
ti->setDigitalZoom(_digitalZoom);
|
||||
ti->setMarkerColor(_markerColor);
|
||||
@ -150,8 +146,6 @@ PathItem *MapView::addRoute(const Route &route)
|
||||
ri->setColor(_palette.nextColor());
|
||||
ri->setWidth(_routeWidth);
|
||||
ri->setStyle(_routeStyle);
|
||||
ri->setUnits(_units);
|
||||
ri->setCoordinatesFormat(_coordinatesFormat);
|
||||
ri->setVisible(_showRoutes);
|
||||
ri->showWaypoints(_showRouteWaypoints);
|
||||
ri->showWaypointLabels(_showWaypointLabels);
|
||||
@ -201,7 +195,6 @@ void MapView::addWaypoints(const QVector<Waypoint> &waypoints)
|
||||
wi->setSize(_waypointSize);
|
||||
wi->setColor(_waypointColor);
|
||||
wi->showLabel(_showWaypointLabels);
|
||||
wi->setToolTipFormat(_units, _coordinatesFormat);
|
||||
wi->setVisible(_showWaypoints);
|
||||
wi->setDigitalZoom(_digitalZoom);
|
||||
_scene->addItem(wi);
|
||||
@ -317,7 +310,7 @@ void MapView::setMap(Map *map)
|
||||
RectC cr(_map->xy2ll(vr.topLeft()), _map->xy2ll(vr.bottomRight()));
|
||||
|
||||
_map->unload();
|
||||
disconnect(_map, SIGNAL(loaded()), this, SLOT(reloadMap()));
|
||||
disconnect(_map, SIGNAL(tilesLoaded()), this, SLOT(reloadMap()));
|
||||
|
||||
_map = map;
|
||||
_map->load();
|
||||
@ -325,7 +318,7 @@ void MapView::setMap(Map *map)
|
||||
#ifdef ENABLE_HIDPI
|
||||
_map->setDevicePixelRatio(_deviceRatio, _mapRatio);
|
||||
#endif // ENABLE_HIDPI
|
||||
connect(_map, SIGNAL(loaded()), this, SLOT(reloadMap()));
|
||||
connect(_map, SIGNAL(tilesLoaded()), this, SLOT(reloadMap()));
|
||||
|
||||
digitalZoom(0);
|
||||
|
||||
@ -351,7 +344,6 @@ void MapView::setMap(Map *map)
|
||||
centerOn(nc);
|
||||
|
||||
reloadMap();
|
||||
QPixmapCache::clear();
|
||||
}
|
||||
|
||||
void MapView::setPOI(POI *poi)
|
||||
@ -403,7 +395,6 @@ void MapView::addPOI(const QList<Waypoint> &waypoints)
|
||||
pi->showLabel(_showPOILabels);
|
||||
pi->setVisible(_showPOI);
|
||||
pi->setDigitalZoom(_digitalZoom);
|
||||
pi->setToolTipFormat(_units, _coordinatesFormat);
|
||||
_scene->addItem(pi);
|
||||
|
||||
_pois.insert(SearchPointer<Waypoint>(&(pi->waypoint())), pi);
|
||||
@ -412,51 +403,38 @@ void MapView::addPOI(const QList<Waypoint> &waypoints)
|
||||
|
||||
void MapView::setUnits(Units units)
|
||||
{
|
||||
if (_units == units)
|
||||
return;
|
||||
|
||||
_units = units;
|
||||
|
||||
_mapScale->setUnits(_units);
|
||||
WaypointItem::setUnits(units);
|
||||
PathItem::setUnits(units);
|
||||
|
||||
for (int i = 0; i < _tracks.count(); i++)
|
||||
_tracks[i]->setUnits(_units);
|
||||
_tracks[i]->updateTicks();
|
||||
for (int i = 0; i < _routes.count(); i++)
|
||||
_routes[i]->setUnits(_units);
|
||||
for (int i = 0; i < _waypoints.size(); i++)
|
||||
_waypoints.at(i)->setToolTipFormat(_units, _coordinatesFormat);
|
||||
_routes[i]->updateTicks();
|
||||
|
||||
for (POIHash::const_iterator it = _pois.constBegin();
|
||||
it != _pois.constEnd(); it++)
|
||||
it.value()->setToolTipFormat(_units, _coordinatesFormat);
|
||||
_mapScale->setUnits(units);
|
||||
}
|
||||
|
||||
void MapView::setCoordinatesFormat(CoordinatesFormat format)
|
||||
{
|
||||
if (_coordinatesFormat == format)
|
||||
return;
|
||||
WaypointItem::setCoordinatesFormat(format);
|
||||
|
||||
_coordinatesFormat = format;
|
||||
_coordinates->setFormat(format);
|
||||
}
|
||||
|
||||
_coordinates->setFormat(_coordinatesFormat);
|
||||
|
||||
for (int i = 0; i < _waypoints.count(); i++)
|
||||
_waypoints.at(i)->setToolTipFormat(_units, _coordinatesFormat);
|
||||
for (int i = 0; i < _routes.count(); i++)
|
||||
_routes[i]->setCoordinatesFormat(_coordinatesFormat);
|
||||
|
||||
for (POIHash::const_iterator it = _pois.constBegin();
|
||||
it != _pois.constEnd(); it++)
|
||||
it.value()->setToolTipFormat(_units, _coordinatesFormat);
|
||||
void MapView::setTimeZone(const QTimeZone &zone)
|
||||
{
|
||||
#ifdef ENABLE_TIMEZONES
|
||||
WaypointItem::setTimeZone(zone);
|
||||
PathItem::setTimeZone(zone);
|
||||
#else // ENABLE_TIMEZONES
|
||||
Q_UNUSED(zone);
|
||||
#endif // ENABLE_TIMEZONES
|
||||
}
|
||||
|
||||
void MapView::clearMapCache()
|
||||
{
|
||||
_map->clearCache();
|
||||
|
||||
fitMapZoom();
|
||||
rescale();
|
||||
centerOn(contentCenter());
|
||||
reloadMap();
|
||||
}
|
||||
|
||||
void MapView::digitalZoom(int zoom)
|
||||
@ -982,7 +960,6 @@ void MapView::setDevicePixelRatio(qreal deviceRatio, qreal mapRatio)
|
||||
|
||||
_deviceRatio = deviceRatio;
|
||||
_mapRatio = mapRatio;
|
||||
QPixmapCache::clear();
|
||||
|
||||
QRectF vr(mapToScene(viewport()->rect()).boundingRect()
|
||||
.intersected(_map->bounds()));
|
||||
|
@ -31,6 +31,7 @@ class GraphItem;
|
||||
class AreaItem;
|
||||
class Area;
|
||||
class GraphicsScene;
|
||||
class QTimeZone;
|
||||
|
||||
class MapView : public QGraphicsView
|
||||
{
|
||||
@ -83,6 +84,7 @@ public slots:
|
||||
void showTicks(bool show);
|
||||
void clearMapCache();
|
||||
void setCoordinatesFormat(CoordinatesFormat format);
|
||||
void setTimeZone(const QTimeZone &zone);
|
||||
void setDevicePixelRatio(qreal deviceRatio, qreal mapRatio);
|
||||
void setProjection(int id);
|
||||
|
||||
@ -137,8 +139,6 @@ private:
|
||||
POI *_poi;
|
||||
|
||||
Palette _palette;
|
||||
Units _units;
|
||||
CoordinatesFormat _coordinatesFormat;
|
||||
qreal _mapOpacity;
|
||||
Projection _projection;
|
||||
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include <QRadioButton>
|
||||
#include <QLabel>
|
||||
#include <QSysInfo>
|
||||
#include <QButtonGroup>
|
||||
#include "map/pcs.h"
|
||||
#include "icons.h"
|
||||
#include "colorbox.h"
|
||||
@ -37,6 +38,12 @@ static QFrame *line()
|
||||
#endif // Q_OS_MAC
|
||||
|
||||
|
||||
void OptionsDialog::automaticPauseDetectionSet(bool set)
|
||||
{
|
||||
_pauseInterval->setEnabled(!set);
|
||||
_pauseSpeed->setEnabled(!set);
|
||||
}
|
||||
|
||||
QWidget *OptionsDialog::createMapPage()
|
||||
{
|
||||
_projection = new LimitedComboBox(200);
|
||||
@ -160,11 +167,8 @@ QWidget *OptionsDialog::createAppearancePage()
|
||||
// Palette & antialiasing
|
||||
_baseColor = new ColorBox();
|
||||
_baseColor->setColor(_options->palette.color());
|
||||
_colorOffset = new QDoubleSpinBox();
|
||||
_colorOffset->setMinimum(0);
|
||||
_colorOffset->setMaximum(1.0);
|
||||
_colorOffset->setSingleStep(0.01);
|
||||
_colorOffset->setValue(_options->palette.shift());
|
||||
_colorOffset = new PercentSlider();
|
||||
_colorOffset->setValue(_options->palette.shift() * 100);
|
||||
QFormLayout *paletteLayout = new QFormLayout();
|
||||
paletteLayout->addRow(tr("Base color:"), _baseColor);
|
||||
paletteLayout->addRow(tr("Palette shift:"), _colorOffset);
|
||||
@ -343,10 +347,18 @@ QWidget *OptionsDialog::createDataPage()
|
||||
filterTab->setLayout(filterTabLayout);
|
||||
|
||||
|
||||
_automaticPause = new QRadioButton(tr("Automatic"));
|
||||
_manualPause = new QRadioButton(tr("Custom"));
|
||||
if (_options->automaticPause)
|
||||
_automaticPause->setChecked(true);
|
||||
else
|
||||
_manualPause->setChecked(true);
|
||||
|
||||
_pauseSpeed = new QDoubleSpinBox();
|
||||
_pauseSpeed->setDecimals(1);
|
||||
_pauseSpeed->setSingleStep(0.1);
|
||||
_pauseSpeed->setMinimum(0.1);
|
||||
_pauseSpeed->setEnabled(_manualPause->isChecked());
|
||||
if (_options->units == Imperial) {
|
||||
_pauseSpeed->setValue(_options->pauseSpeed * MS2MIH);
|
||||
_pauseSpeed->setSuffix(UNIT_SPACE + tr("mi/h"));
|
||||
@ -361,10 +373,26 @@ QWidget *OptionsDialog::createDataPage()
|
||||
_pauseInterval->setMinimum(1);
|
||||
_pauseInterval->setSuffix(UNIT_SPACE + tr("s"));
|
||||
_pauseInterval->setValue(_options->pauseInterval);
|
||||
_pauseInterval->setEnabled(_manualPause->isChecked());
|
||||
|
||||
QFormLayout *pauseLayout = new QFormLayout();
|
||||
pauseLayout->addRow(tr("Minimal speed:"), _pauseSpeed);
|
||||
pauseLayout->addRow(tr("Minimal duration:"), _pauseInterval);
|
||||
connect(_automaticPause, SIGNAL(toggled(bool)), this,
|
||||
SLOT(automaticPauseDetectionSet(bool)));
|
||||
|
||||
QHBoxLayout *pauseTypeLayout = new QHBoxLayout();
|
||||
#ifdef Q_OS_MAC
|
||||
pauseTypeLayout->addStretch();
|
||||
#endif
|
||||
pauseTypeLayout->addWidget(_automaticPause);
|
||||
pauseTypeLayout->addWidget(_manualPause);
|
||||
pauseTypeLayout->addStretch();
|
||||
|
||||
QFormLayout *pauseValuesLayout = new QFormLayout();
|
||||
pauseValuesLayout->addRow(tr("Minimal speed:"), _pauseSpeed);
|
||||
pauseValuesLayout->addRow(tr("Minimal duration:"), _pauseInterval);
|
||||
|
||||
QVBoxLayout *pauseLayout = new QVBoxLayout();
|
||||
pauseLayout->addLayout(pauseTypeLayout);
|
||||
pauseLayout->addLayout(pauseValuesLayout);
|
||||
|
||||
QWidget *pauseTab = new QWidget();
|
||||
pauseTab->setLayout(pauseLayout);
|
||||
@ -376,6 +404,8 @@ QWidget *OptionsDialog::createDataPage()
|
||||
_reportedSpeed->setChecked(true);
|
||||
else
|
||||
_computedSpeed->setChecked(true);
|
||||
_showSecondarySpeed = new QCheckBox(tr("Show secondary speed"));
|
||||
_showSecondarySpeed->setChecked(_options->showSecondarySpeed);
|
||||
|
||||
_dataGPSElevation = new QRadioButton(tr("GPS data"));
|
||||
_dataDEMElevation = new QRadioButton(tr("DEM data"));
|
||||
@ -383,43 +413,108 @@ QWidget *OptionsDialog::createDataPage()
|
||||
_dataDEMElevation->setChecked(true);
|
||||
else
|
||||
_dataGPSElevation->setChecked(true);
|
||||
_showSecondaryElevation = new QCheckBox(tr("Show secondary elevation"));
|
||||
_showSecondaryElevation->setChecked(_options->showSecondaryElevation);
|
||||
|
||||
#ifdef ENABLE_TIMEZONES
|
||||
_utcZone = new QRadioButton(tr("UTC"));
|
||||
_systemZone = new QRadioButton(tr("System"));
|
||||
_customZone = new QRadioButton(tr("Custom"));
|
||||
if (_options->timeZone.type() == TimeZoneInfo::UTC)
|
||||
_utcZone->setChecked(true);
|
||||
else if (_options->timeZone.type() == TimeZoneInfo::System)
|
||||
_systemZone->setChecked(true);
|
||||
else
|
||||
_customZone->setChecked(true);
|
||||
_timeZone = new QComboBox();
|
||||
_timeZone->setEnabled(_customZone->isChecked());
|
||||
QList<QByteArray> zones = QTimeZone::availableTimeZoneIds();
|
||||
for (int i = 0; i < zones.size(); i++)
|
||||
_timeZone->addItem(zones.at(i));
|
||||
_timeZone->setCurrentText(_options->timeZone.customZone().id());
|
||||
connect(_customZone, SIGNAL(toggled(bool)), _timeZone,
|
||||
SLOT(setEnabled(bool)));
|
||||
QHBoxLayout *customZoneLayout = new QHBoxLayout();
|
||||
customZoneLayout->addSpacing(20);
|
||||
customZoneLayout->addWidget(_timeZone);
|
||||
#endif // ENABLE_TIMEZONES
|
||||
|
||||
QWidget *sourceTab = new QWidget();
|
||||
QVBoxLayout *sourceTabLayout = new QVBoxLayout();
|
||||
|
||||
#ifdef Q_OS_MAC
|
||||
QButtonGroup *speedGroup = new QButtonGroup(this);
|
||||
speedGroup->addButton(_computedSpeed);
|
||||
speedGroup->addButton(_reportedSpeed);
|
||||
QVBoxLayout *speedOptions = new QVBoxLayout();
|
||||
speedOptions->addWidget(_computedSpeed);
|
||||
speedOptions->addWidget(_reportedSpeed);
|
||||
speedOptions->addWidget(_showSecondarySpeed);
|
||||
|
||||
QButtonGroup *elevationGroup = new QButtonGroup(this);
|
||||
elevationGroup->addButton(_dataGPSElevation);
|
||||
elevationGroup->addButton(_dataDEMElevation);
|
||||
QVBoxLayout *elevationOptions = new QVBoxLayout();
|
||||
elevationOptions->addWidget(_dataGPSElevation);
|
||||
elevationOptions->addWidget(_dataDEMElevation);
|
||||
elevationOptions->addWidget(_showSecondaryElevation);
|
||||
|
||||
#ifdef ENABLE_TIMEZONES
|
||||
QButtonGroup *timeZoneGroup = new QButtonGroup(this);
|
||||
timeZoneGroup->addButton(_utcZone);
|
||||
timeZoneGroup->addButton(_systemZone);
|
||||
timeZoneGroup->addButton(_customZone);
|
||||
QVBoxLayout *zoneOptions = new QVBoxLayout();
|
||||
zoneOptions->addWidget(_utcZone);
|
||||
zoneOptions->addWidget(_systemZone);
|
||||
zoneOptions->addWidget(_customZone);
|
||||
zoneOptions->addItem(customZoneLayout);
|
||||
#endif // ENABLE_TIMEZONES
|
||||
|
||||
QFormLayout *formLayout = new QFormLayout();
|
||||
formLayout->addRow(tr("Speed:"), speedOptions);
|
||||
formLayout->addRow(tr("Elevation:"), elevationOptions);
|
||||
#ifdef ENABLE_TIMEZONES
|
||||
formLayout->addRow(tr("Time zone:"), zoneOptions);
|
||||
#endif // ENABLE_TIMEZONES
|
||||
|
||||
sourceTabLayout->addLayout(formLayout);
|
||||
#else // Q_OS_MAC
|
||||
QFormLayout *speedLayout = new QFormLayout();
|
||||
QFormLayout *elevationLayout = new QFormLayout();
|
||||
#ifdef ENABLE_TIMEZONES
|
||||
QFormLayout *timeZoneLayout = new QFormLayout();
|
||||
#endif // ENABLE_TIMEZONES
|
||||
|
||||
speedLayout->addWidget(_computedSpeed);
|
||||
speedLayout->addWidget(_reportedSpeed);
|
||||
speedLayout->addWidget(_showSecondarySpeed);
|
||||
|
||||
QGroupBox *speedBox = new QGroupBox(tr("Speed"));
|
||||
speedBox->setLayout(speedLayout);
|
||||
|
||||
elevationLayout->addWidget(_dataGPSElevation);
|
||||
elevationLayout->addWidget(_dataDEMElevation);
|
||||
elevationLayout->addWidget(_showSecondaryElevation);
|
||||
|
||||
QGroupBox *elevationBox = new QGroupBox(tr("Elevation"));
|
||||
elevationBox->setLayout(elevationLayout);
|
||||
|
||||
#ifdef ENABLE_TIMEZONES
|
||||
timeZoneLayout->addWidget(_utcZone);
|
||||
timeZoneLayout->addWidget(_systemZone);
|
||||
timeZoneLayout->addWidget(_customZone);
|
||||
timeZoneLayout->addItem(customZoneLayout);
|
||||
|
||||
QGroupBox *timeZoneBox = new QGroupBox(tr("Time zone"));
|
||||
timeZoneBox->setLayout(timeZoneLayout);
|
||||
#endif // ENABLE_TIMEZONES
|
||||
|
||||
sourceTabLayout->addWidget(speedBox);
|
||||
sourceTabLayout->addWidget(elevationBox);
|
||||
#ifdef ENABLE_TIMEZONES
|
||||
sourceTabLayout->addWidget(timeZoneBox);
|
||||
#endif // ENABLE_TIMEZONES
|
||||
#endif // Q_OS_MAC
|
||||
sourceTabLayout->addStretch();
|
||||
sourceTab->setLayout(sourceTabLayout);
|
||||
@ -435,13 +530,6 @@ QWidget *OptionsDialog::createDataPage()
|
||||
|
||||
QWidget *OptionsDialog::createPOIPage()
|
||||
{
|
||||
_poiGPSElevation = new QRadioButton(tr("GPS data"));
|
||||
_poiDEMElevation = new QRadioButton(tr("DEM data"));
|
||||
if (_options->poiUseDEM)
|
||||
_poiDEMElevation->setChecked(true);
|
||||
else
|
||||
_poiGPSElevation->setChecked(true);
|
||||
|
||||
_poiRadius = new QDoubleSpinBox();
|
||||
_poiRadius->setSingleStep(1);
|
||||
_poiRadius->setDecimals(1);
|
||||
@ -456,13 +544,8 @@ QWidget *OptionsDialog::createPOIPage()
|
||||
_poiRadius->setSuffix(UNIT_SPACE + tr("km"));
|
||||
}
|
||||
|
||||
QVBoxLayout *elevationLayout = new QVBoxLayout();
|
||||
elevationLayout->addWidget(_poiGPSElevation);
|
||||
elevationLayout->addWidget(_poiDEMElevation);
|
||||
|
||||
QFormLayout *poiLayout = new QFormLayout();
|
||||
poiLayout->addRow(tr("Radius:"), _poiRadius);
|
||||
poiLayout->addRow(tr("Elevation:"), elevationLayout);
|
||||
|
||||
QWidget *poiTab = new QWidget();
|
||||
poiTab->setLayout(poiLayout);
|
||||
@ -645,7 +728,7 @@ OptionsDialog::OptionsDialog(Options *options, QWidget *parent)
|
||||
void OptionsDialog::accept()
|
||||
{
|
||||
_options->palette.setColor(_baseColor->color());
|
||||
_options->palette.setShift(_colorOffset->value());
|
||||
_options->palette.setShift(_colorOffset->value() / 100.0);
|
||||
_options->mapOpacity = _mapOpacity->value();
|
||||
_options->backgroundColor = _backgroundColor->color();
|
||||
_options->trackWidth = _trackWidth->value();
|
||||
@ -679,6 +762,7 @@ void OptionsDialog::accept()
|
||||
_options->cadenceFilter = _cadenceFilter->value();
|
||||
_options->powerFilter = _powerFilter->value();
|
||||
_options->outlierEliminate = _outlierEliminate->isChecked();
|
||||
_options->automaticPause = _automaticPause->isChecked();
|
||||
qreal pauseSpeed = (_options->units == Imperial)
|
||||
? _pauseSpeed->value() / MS2MIH : (_options->units == Nautical)
|
||||
? _pauseSpeed->value() / MS2KN : _pauseSpeed->value() / MS2KMH;
|
||||
@ -687,13 +771,21 @@ void OptionsDialog::accept()
|
||||
_options->pauseInterval = _pauseInterval->value();
|
||||
_options->useReportedSpeed = _reportedSpeed->isChecked();
|
||||
_options->dataUseDEM = _dataDEMElevation->isChecked();
|
||||
_options->showSecondaryElevation = _showSecondaryElevation->isChecked();
|
||||
_options->showSecondarySpeed = _showSecondarySpeed->isChecked();
|
||||
#ifdef ENABLE_TIMEZONES
|
||||
_options->timeZone.setType(_utcZone->isChecked()
|
||||
? TimeZoneInfo::UTC : _systemZone->isChecked()
|
||||
? TimeZoneInfo::System : TimeZoneInfo::Custom);
|
||||
_options->timeZone.setCustomZone(QTimeZone(_timeZone->currentText()
|
||||
.toLatin1()));
|
||||
#endif // ENABLE_TIMEZONES
|
||||
|
||||
qreal poiRadius = (_options->units == Imperial)
|
||||
? _poiRadius->value() * MIINM : (_options->units == Nautical)
|
||||
? _poiRadius->value() * NMIINM : _poiRadius->value() * KMINM;
|
||||
if (qAbs(poiRadius - _options->poiRadius) > 0.01)
|
||||
_options->poiRadius = poiRadius;
|
||||
_options->poiUseDEM = _poiDEMElevation->isChecked();
|
||||
|
||||
_options->useOpenGL = _useOpenGL->isChecked();
|
||||
#ifdef ENABLE_HTTP2
|
||||
|
@ -5,6 +5,9 @@
|
||||
#include "common/config.h"
|
||||
#include "palette.h"
|
||||
#include "units.h"
|
||||
#ifdef ENABLE_TIMEZONES
|
||||
#include "timezoneinfo.h"
|
||||
#endif // ENABLE_TIMEZONES
|
||||
|
||||
class ColorBox;
|
||||
class StyleComboBox;
|
||||
@ -17,6 +20,7 @@ class QRadioButton;
|
||||
class PercentSlider;
|
||||
class LimitedComboBox;
|
||||
|
||||
|
||||
struct Options {
|
||||
// Appearance
|
||||
Palette palette;
|
||||
@ -49,13 +53,18 @@ struct Options {
|
||||
int cadenceFilter;
|
||||
int powerFilter;
|
||||
bool outlierEliminate;
|
||||
bool automaticPause;
|
||||
qreal pauseSpeed;
|
||||
int pauseInterval;
|
||||
bool useReportedSpeed;
|
||||
bool dataUseDEM;
|
||||
bool showSecondaryElevation;
|
||||
bool showSecondarySpeed;
|
||||
#ifdef ENABLE_TIMEZONES
|
||||
TimeZoneInfo timeZone;
|
||||
#endif // ENABLE_TIMEZONES
|
||||
// POI
|
||||
int poiRadius;
|
||||
bool poiUseDEM;
|
||||
// System
|
||||
bool useOpenGL;
|
||||
#ifdef ENABLE_HTTP2
|
||||
@ -86,6 +95,9 @@ public slots:
|
||||
public:
|
||||
OptionsDialog(Options *options, QWidget *parent = 0);
|
||||
|
||||
private slots:
|
||||
void automaticPauseDetectionSet(bool set);
|
||||
|
||||
private:
|
||||
QWidget *createMapPage();
|
||||
QWidget *createAppearancePage();
|
||||
@ -98,7 +110,7 @@ private:
|
||||
|
||||
// Appearance
|
||||
ColorBox *_baseColor;
|
||||
QDoubleSpinBox *_colorOffset;
|
||||
PercentSlider *_colorOffset;
|
||||
PercentSlider *_mapOpacity;
|
||||
ColorBox *_backgroundColor;
|
||||
QSpinBox *_trackWidth;
|
||||
@ -129,16 +141,24 @@ private:
|
||||
OddSpinBox *_cadenceFilter;
|
||||
OddSpinBox *_powerFilter;
|
||||
QCheckBox *_outlierEliminate;
|
||||
QRadioButton *_automaticPause;
|
||||
QRadioButton *_manualPause;
|
||||
QDoubleSpinBox *_pauseSpeed;
|
||||
QSpinBox *_pauseInterval;
|
||||
QRadioButton *_computedSpeed;
|
||||
QRadioButton *_reportedSpeed;
|
||||
QRadioButton *_dataGPSElevation;
|
||||
QRadioButton *_dataDEMElevation;
|
||||
QCheckBox *_showSecondaryElevation;
|
||||
QCheckBox *_showSecondarySpeed;
|
||||
#ifdef ENABLE_TIMEZONES
|
||||
QRadioButton *_utcZone;
|
||||
QRadioButton *_systemZone;
|
||||
QRadioButton *_customZone;
|
||||
QComboBox *_timeZone;
|
||||
#endif // ENABLE_TIMEZONES
|
||||
// POI
|
||||
QDoubleSpinBox *_poiRadius;
|
||||
QRadioButton *_poiGPSElevation;
|
||||
QRadioButton *_poiDEMElevation;
|
||||
// System
|
||||
QSpinBox *_pixmapCache;
|
||||
QSpinBox *_connectionTimeout;
|
||||
|
@ -21,12 +21,16 @@ static inline unsigned segments(qreal distance)
|
||||
return ceil(distance / GEOGRAPHICAL_MILE);
|
||||
}
|
||||
|
||||
Units PathItem::_units = Metric;
|
||||
#ifdef ENABLE_TIMEZONES
|
||||
QTimeZone PathItem::_timeZone = QTimeZone::utc();
|
||||
#endif // ENABLE_TIMEZONES
|
||||
|
||||
PathItem::PathItem(const Path &path, Map *map, QGraphicsItem *parent)
|
||||
: GraphicsItem(parent), _path(path), _map(map)
|
||||
{
|
||||
Q_ASSERT(_path.isValid());
|
||||
|
||||
_units = Metric;
|
||||
_digitalZoom = 0;
|
||||
_width = 3;
|
||||
QBrush brush(Qt::SolidPattern);
|
||||
@ -352,16 +356,6 @@ void PathItem::showTicks(bool show)
|
||||
updateTicks();
|
||||
}
|
||||
|
||||
void PathItem::setUnits(Units units)
|
||||
{
|
||||
if (_units == units)
|
||||
return;
|
||||
|
||||
prepareGeometryChange();
|
||||
_units = units;
|
||||
updateTicks();
|
||||
}
|
||||
|
||||
void PathItem::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
|
||||
{
|
||||
Q_UNUSED(event);
|
||||
|
@ -1,8 +1,12 @@
|
||||
#ifndef PATHITEM_H
|
||||
#define PATHITEM_H
|
||||
|
||||
#include "common/config.h"
|
||||
#include <QGraphicsObject>
|
||||
#include <QPen>
|
||||
#ifdef ENABLE_TIMEZONES
|
||||
#include <QTimeZone>
|
||||
#endif // ENABLE_TIMEZONES
|
||||
#include "data/path.h"
|
||||
#include "markeritem.h"
|
||||
#include "units.h"
|
||||
@ -28,7 +32,6 @@ public:
|
||||
|
||||
void setMap(Map *map);
|
||||
|
||||
void setUnits(Units units);
|
||||
void setColor(const QColor &color);
|
||||
void setWidth(qreal width);
|
||||
void setStyle(Qt::PenStyle style);
|
||||
@ -37,6 +40,13 @@ public:
|
||||
void showMarker(bool show);
|
||||
void showTicks(bool show);
|
||||
|
||||
void updateTicks();
|
||||
|
||||
static void setUnits(Units units) {_units = units;}
|
||||
#ifdef ENABLE_TIMEZONES
|
||||
static void setTimeZone(const QTimeZone &zone) {_timeZone = zone;}
|
||||
#endif // ENABLE_TIMEZONES
|
||||
|
||||
public slots:
|
||||
void moveMarker(qreal distance);
|
||||
void hover(bool hover);
|
||||
@ -49,7 +59,10 @@ protected:
|
||||
void hoverLeaveEvent(QGraphicsSceneHoverEvent *event);
|
||||
void mousePressEvent(QGraphicsSceneMouseEvent *event);
|
||||
|
||||
Units _units;
|
||||
static Units _units;
|
||||
#ifdef ENABLE_TIMEZONES
|
||||
static QTimeZone _timeZone;
|
||||
#endif // ENABLE_TIMEZONES
|
||||
|
||||
private:
|
||||
const PathSegment *segment(qreal x) const;
|
||||
@ -60,7 +73,6 @@ private:
|
||||
|
||||
qreal xInM() const;
|
||||
unsigned tickSize() const;
|
||||
void updateTicks();
|
||||
|
||||
Path _path;
|
||||
Map *_map;
|
||||
|
@ -163,3 +163,9 @@ void Popup::show(const QPoint &pos, const QString &text, QWidget *w)
|
||||
PopupLabel::_instance->place(pos, w);
|
||||
PopupLabel::_instance->showNormal();
|
||||
}
|
||||
|
||||
void Popup::clear()
|
||||
{
|
||||
if (PopupLabel::_instance)
|
||||
delete PopupLabel::_instance;
|
||||
}
|
||||
|
@ -9,6 +9,7 @@ class Popup
|
||||
{
|
||||
public:
|
||||
static void show(const QPoint &pos, const QString &text, QWidget *w);
|
||||
static void clear();
|
||||
};
|
||||
|
||||
#endif // POPUP_H
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
PowerGraphItem::PowerGraphItem(const Graph &graph, GraphType type, int width,
|
||||
const QColor &color, QGraphicsItem *parent)
|
||||
: GraphItem(graph, type, width, color, parent)
|
||||
: GraphItem(graph, type, width, color, Qt::SolidLine, parent)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -15,6 +15,8 @@ QString RouteItem::info() const
|
||||
tt.insert(tr("Name"), _name);
|
||||
if (!_desc.isEmpty())
|
||||
tt.insert(tr("Description"), _desc);
|
||||
if (!_comment.isEmpty() && _comment != _desc)
|
||||
tt.insert(tr("Comment"), _comment);
|
||||
tt.insert(tr("Distance"), Format::distance(path().last().last().distance(),
|
||||
_units));
|
||||
if (!_links.isEmpty()) {
|
||||
@ -43,8 +45,8 @@ RouteItem::RouteItem(const Route &route, Map *map, QGraphicsItem *parent)
|
||||
|
||||
_name = route.name();
|
||||
_desc = route.description();
|
||||
_comment = route.comment();
|
||||
_links = route.links();
|
||||
_coordinatesFormat = DecimalDegrees;
|
||||
}
|
||||
|
||||
void RouteItem::setMap(Map *map)
|
||||
@ -55,28 +57,6 @@ void RouteItem::setMap(Map *map)
|
||||
PathItem::setMap(map);
|
||||
}
|
||||
|
||||
void RouteItem::setUnits(Units u)
|
||||
{
|
||||
if (_units == u)
|
||||
return;
|
||||
|
||||
for (int i = 0; i < _waypoints.count(); i++)
|
||||
_waypoints[i]->setToolTipFormat(u, _coordinatesFormat);
|
||||
|
||||
PathItem::setUnits(u);
|
||||
}
|
||||
|
||||
void RouteItem::setCoordinatesFormat(CoordinatesFormat format)
|
||||
{
|
||||
if (_coordinatesFormat == format)
|
||||
return;
|
||||
|
||||
_coordinatesFormat = format;
|
||||
|
||||
for (int i = 0; i < _waypoints.count(); i++)
|
||||
_waypoints[i]->setToolTipFormat(_units, _coordinatesFormat);
|
||||
}
|
||||
|
||||
void RouteItem::showWaypoints(bool show)
|
||||
{
|
||||
for (int i = 0; i < _waypoints.count(); i++)
|
||||
|
@ -19,8 +19,6 @@ public:
|
||||
|
||||
void setMap(Map *map);
|
||||
|
||||
void setUnits(Units u);
|
||||
void setCoordinatesFormat(CoordinatesFormat format);
|
||||
void showWaypoints(bool show);
|
||||
void showWaypointLabels(bool show);
|
||||
|
||||
@ -29,8 +27,8 @@ public:
|
||||
private:
|
||||
QString _name;
|
||||
QString _desc;
|
||||
QString _comment;
|
||||
QVector<Link> _links;
|
||||
CoordinatesFormat _coordinatesFormat;
|
||||
|
||||
QVector<WaypointItem*> _waypoints;
|
||||
};
|
||||
|
@ -135,6 +135,8 @@
|
||||
#define POWER_FILTER_DEFAULT 3
|
||||
#define OUTLIER_ELIMINATE_SETTING "outlierEliminate"
|
||||
#define OUTLIER_ELIMINATE_DEFAULT true
|
||||
#define AUTOMATIC_PAUSE_SETTING "automaticPause"
|
||||
#define AUTOMATIC_PAUSE_DEFAULT true
|
||||
#define PAUSE_SPEED_SETTING "pauseSpeed"
|
||||
#define PAUSE_SPEED_DEFAULT 0.5 /* m/s */
|
||||
#define PAUSE_INTERVAL_SETTING "pauseInterval"
|
||||
@ -143,10 +145,13 @@
|
||||
#define USE_REPORTED_SPEED_DEFAULT false
|
||||
#define DATA_USE_DEM_SETTING "dataUseDEM"
|
||||
#define DATA_USE_DEM_DEFAULT false
|
||||
#define SHOW_SECONDARY_ELEVATION_SETTING "showSecondaryElevation"
|
||||
#define SHOW_SECONDARY_ELEVATION_DEFAULT false
|
||||
#define SHOW_SECONDARY_SPEED_SETTING "showSecondarySpeed"
|
||||
#define SHOW_SECONDARY_SPEED_DEFAULT false
|
||||
#define TIME_ZONE_SETTING "timeZone"
|
||||
#define POI_RADIUS_SETTING "poiRadius"
|
||||
#define POI_RADIUS_DEFAULT (int)(IMPERIAL_UNITS() ? MIINM : KMINM)
|
||||
#define POI_USE_DEM_SETTING "poiUseDEM"
|
||||
#define POI_USE_DEM_DEFAULT false
|
||||
#define USE_OPENGL_SETTING "useOpenGL"
|
||||
#define USE_OPENGL_DEFAULT false
|
||||
#define ENABLE_HTTP2_SETTING "enableHTTP2"
|
||||
|
@ -40,31 +40,46 @@ void SpeedGraph::setInfo()
|
||||
clearInfo();
|
||||
}
|
||||
|
||||
GraphItem *SpeedGraph::loadGraph(const Graph &graph, const Track &track,
|
||||
const QColor &color, bool primary)
|
||||
{
|
||||
if (!graph.isValid())
|
||||
return 0;
|
||||
|
||||
SpeedGraphItem *gi = new SpeedGraphItem(graph, _graphType, _width,
|
||||
color, primary ? Qt::SolidLine : Qt::DashLine, track.movingTime());
|
||||
gi->setTimeType(_timeType);
|
||||
gi->setUnits(_units);
|
||||
|
||||
_tracks.append(gi);
|
||||
if (_showTracks)
|
||||
addGraph(gi);
|
||||
|
||||
if (primary) {
|
||||
_avg.append(QPointF(track.distance(), gi->avg()));
|
||||
_mavg.append(QPointF(track.distance(), gi->mavg()));
|
||||
}
|
||||
|
||||
return gi;
|
||||
}
|
||||
|
||||
QList<GraphItem*> SpeedGraph::loadData(const Data &data)
|
||||
{
|
||||
QList<GraphItem*> graphs;
|
||||
|
||||
for (int i = 0; i < data.tracks().count(); i++) {
|
||||
GraphItem *primary, *secondary;
|
||||
QColor color(_palette.nextColor());
|
||||
const Track &track = data.tracks().at(i);
|
||||
const Graph &graph = track.speed();
|
||||
const GraphPair &gp = track.speed();
|
||||
|
||||
if (!graph.isValid()) {
|
||||
_palette.nextColor();
|
||||
graphs.append(0);
|
||||
} else {
|
||||
SpeedGraphItem *gi = new SpeedGraphItem(graph, _graphType, _width,
|
||||
_palette.nextColor(), track.movingTime());
|
||||
gi->setTimeType(_timeType);
|
||||
gi->setUnits(_units);
|
||||
primary = loadGraph(gp.primary(), track, color, true);
|
||||
secondary = primary
|
||||
? loadGraph(gp.secondary(), track, color, false) : 0;
|
||||
if (primary && secondary)
|
||||
primary->setSecondaryGraph(secondary);
|
||||
|
||||
_tracks.append(gi);
|
||||
if (_showTracks)
|
||||
addGraph(gi);
|
||||
|
||||
_avg.append(QPointF(track.distance(), gi->avg()));
|
||||
_mavg.append(QPointF(track.distance(), gi->mavg()));
|
||||
graphs.append(gi);
|
||||
}
|
||||
graphs.append(primary);
|
||||
}
|
||||
|
||||
for (int i = 0; i < data.routes().count(); i++) {
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include "graphtab.h"
|
||||
|
||||
class SpeedGraphItem;
|
||||
class Track;
|
||||
|
||||
class SpeedGraph : public GraphTab
|
||||
{
|
||||
@ -22,6 +23,8 @@ public:
|
||||
void showTracks(bool show);
|
||||
|
||||
private:
|
||||
GraphItem *loadGraph(const Graph &graph, const Track &track,
|
||||
const QColor &color, bool primary);
|
||||
qreal avg() const;
|
||||
qreal max() const {return bounds().bottom();}
|
||||
void setYUnits();
|
||||
|
@ -5,8 +5,8 @@
|
||||
|
||||
|
||||
SpeedGraphItem::SpeedGraphItem(const Graph &graph, GraphType type, int width,
|
||||
const QColor &color, qreal movingTime, QGraphicsItem *parent)
|
||||
: GraphItem(graph, type, width, color, parent)
|
||||
const QColor &color, Qt::PenStyle style, qreal movingTime,
|
||||
QGraphicsItem *parent) : GraphItem(graph, type, width, color, style, parent)
|
||||
{
|
||||
_timeType = Total;
|
||||
|
||||
|
@ -10,7 +10,8 @@ class SpeedGraphItem : public GraphItem
|
||||
|
||||
public:
|
||||
SpeedGraphItem(const Graph &graph, GraphType type, int width,
|
||||
const QColor &color, qreal movingTime, QGraphicsItem *parent = 0);
|
||||
const QColor &color, Qt::PenStyle style, qreal movingTime,
|
||||
QGraphicsItem *parent = 0);
|
||||
|
||||
qreal avg() const {return _avg;}
|
||||
qreal mavg() const {return _mavg;}
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
TemperatureGraphItem::TemperatureGraphItem(const Graph &graph, GraphType type,
|
||||
int width, const QColor &color, QGraphicsItem *parent)
|
||||
: GraphItem(graph, type, width, color, parent)
|
||||
: GraphItem(graph, type, width, color, Qt::SolidLine, parent)
|
||||
{
|
||||
_min = GraphItem::min();
|
||||
_max = GraphItem::max();
|
||||
|
69
src/GUI/timezoneinfo.h
Normal file
69
src/GUI/timezoneinfo.h
Normal file
@ -0,0 +1,69 @@
|
||||
#ifndef TIMEZONEINFO_H
|
||||
#define TIMEZONEINFO_H
|
||||
|
||||
#include <QTimeZone>
|
||||
#include <QDataStream>
|
||||
|
||||
class TimeZoneInfo
|
||||
{
|
||||
public:
|
||||
enum Type {
|
||||
UTC,
|
||||
System,
|
||||
Custom
|
||||
};
|
||||
|
||||
TimeZoneInfo() : _type(UTC), _customZone(QTimeZone::systemTimeZone()) {}
|
||||
|
||||
Type type() const {return _type;}
|
||||
const QTimeZone &customZone() const {return _customZone;}
|
||||
QTimeZone zone() const
|
||||
{
|
||||
if (_type == UTC)
|
||||
return QTimeZone::utc();
|
||||
else if (_type == System)
|
||||
return QTimeZone::systemTimeZone();
|
||||
else
|
||||
return _customZone;
|
||||
}
|
||||
|
||||
void setType(Type type) {_type = type;}
|
||||
void setCustomZone(const QTimeZone &zone) {_customZone = zone;}
|
||||
|
||||
bool operator==(const TimeZoneInfo &other) const
|
||||
{
|
||||
if (_type == UTC || _type == System)
|
||||
return _type == other._type;
|
||||
else
|
||||
return (other._type == Custom && _customZone == other._customZone);
|
||||
}
|
||||
bool operator!=(const TimeZoneInfo &other) {return !(*this == other);}
|
||||
|
||||
private:
|
||||
friend QDataStream& operator<<(QDataStream &out, const TimeZoneInfo &info);
|
||||
friend QDataStream& operator>>(QDataStream &in, TimeZoneInfo &info);
|
||||
|
||||
Type _type;
|
||||
QTimeZone _customZone;
|
||||
};
|
||||
|
||||
Q_DECLARE_METATYPE(TimeZoneInfo)
|
||||
|
||||
inline QDataStream &operator<<(QDataStream &out, const TimeZoneInfo &info)
|
||||
{
|
||||
out << static_cast<int>(info._type) << info._customZone;
|
||||
return out;
|
||||
}
|
||||
|
||||
inline QDataStream &operator>>(QDataStream &in, TimeZoneInfo &info)
|
||||
{
|
||||
int t;
|
||||
|
||||
in >> t;
|
||||
info._type = static_cast<TimeZoneInfo::Type>(t);
|
||||
in >> info._customZone;
|
||||
|
||||
return in;
|
||||
}
|
||||
|
||||
#endif // TIMEZONEINFO_H
|
@ -1,10 +1,21 @@
|
||||
#include <QImageReader>
|
||||
#include <QLabel>
|
||||
#include "popup.h"
|
||||
#include "tooltip.h"
|
||||
|
||||
static QSize thumbnailSize(const ImageInfo &img, int limit)
|
||||
{
|
||||
int width, height;
|
||||
if (img.size().width() > img.size().height()) {
|
||||
width = qMin(img.size().width(), limit);
|
||||
qreal ratio = img.size().width() / (qreal)img.size().height();
|
||||
height = (int)(width / ratio);
|
||||
} else {
|
||||
height = qMin(img.size().height(), limit);
|
||||
qreal ratio = img.size().height() / (qreal)img.size().width();
|
||||
width = (int)(height / ratio);
|
||||
}
|
||||
|
||||
#define THUMBNAIL_MAX_SIZE 240
|
||||
return QSize(width, height);
|
||||
}
|
||||
|
||||
void ToolTip::insert(const QString &key, const QString &value)
|
||||
{
|
||||
@ -15,22 +26,17 @@ QString ToolTip::toString() const
|
||||
{
|
||||
QString html;
|
||||
|
||||
if (_img.isValid()) {
|
||||
int width, height;
|
||||
if (_img.size().width() > _img.size().height()) {
|
||||
width = qMin(_img.size().width(), THUMBNAIL_MAX_SIZE);
|
||||
qreal ratio = _img.size().width() / (qreal)_img.size().height();
|
||||
height = (int)(width / ratio);
|
||||
} else {
|
||||
height = qMin(_img.size().height(), THUMBNAIL_MAX_SIZE);
|
||||
qreal ratio = _img.size().height() / (qreal)_img.size().width();
|
||||
width = (int)(height / ratio);
|
||||
}
|
||||
if (_images.size()) {
|
||||
html = "<div align=\"center\">";
|
||||
for (int i = 0; i < _images.size(); i++) {
|
||||
const ImageInfo &img = _images.at(i);
|
||||
QSize size(thumbnailSize(img, qMin(960/_images.size(), 240)));
|
||||
|
||||
html += "<div align=\"center\">";
|
||||
html += QString("<a href=\"file:%0\">"
|
||||
"<img src=\"%0\" width=\"%1\" height=\"%2\"/></a>")
|
||||
.arg(_img.path(), QString::number(width), QString::number(height));
|
||||
html += QString("<a href=\"file:%0\">"
|
||||
"<img src=\"%0\" width=\"%1\" height=\"%2\"/></a>")
|
||||
.arg(img.path(), QString::number(size.width()),
|
||||
QString::number(size.height()));
|
||||
}
|
||||
html += "</div>";
|
||||
}
|
||||
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
#include <QString>
|
||||
#include <QList>
|
||||
#include <QVector>
|
||||
#include "common/kv.h"
|
||||
#include "data/imageinfo.h"
|
||||
|
||||
@ -10,12 +11,12 @@ class ToolTip
|
||||
{
|
||||
public:
|
||||
void insert(const QString &key, const QString &value);
|
||||
void setImage(const ImageInfo &image) {_img = image;}
|
||||
void setImages(const QVector<ImageInfo> &images) {_images = images;}
|
||||
QString toString() const;
|
||||
|
||||
private:
|
||||
QList<KV<QString, QString> > _list;
|
||||
ImageInfo _img;
|
||||
QVector<ImageInfo> _images;
|
||||
};
|
||||
|
||||
#endif // TOOLTIP_H
|
||||
|
@ -13,6 +13,8 @@ QString TrackItem::info() const
|
||||
tt.insert(tr("Name"), _name);
|
||||
if (!_desc.isEmpty())
|
||||
tt.insert(tr("Description"), _desc);
|
||||
if (!_comment.isEmpty() && _comment != _desc)
|
||||
tt.insert(tr("Comment"), _comment);
|
||||
tt.insert(tr("Distance"), Format::distance(path().last().last().distance(),
|
||||
_units));
|
||||
if (_time > 0)
|
||||
@ -20,7 +22,13 @@ QString TrackItem::info() const
|
||||
if (_movingTime > 0)
|
||||
tt.insert(tr("Moving time"), Format::timeSpan(_movingTime));
|
||||
if (!_date.isNull())
|
||||
tt.insert(tr("Date"), _date.toString(Qt::SystemLocaleShortDate));
|
||||
tt.insert(tr("Date"),
|
||||
#ifdef ENABLE_TIMEZONES
|
||||
_date.toTimeZone(_timeZone)
|
||||
#else // ENABLE_TIMEZONES
|
||||
_date
|
||||
#endif // ENABLE_TIMEZONES
|
||||
.toString(Qt::SystemLocaleShortDate));
|
||||
if (!_links.isEmpty()) {
|
||||
QString links;
|
||||
for (int i = 0; i < _links.size(); i++) {
|
||||
@ -41,6 +49,7 @@ TrackItem::TrackItem(const Track &track, Map *map, QGraphicsItem *parent)
|
||||
{
|
||||
_name = track.name();
|
||||
_desc = track.description();
|
||||
_comment = track.comment();
|
||||
_links = track.links();
|
||||
_date = track.date();
|
||||
_time = track.time();
|
||||
|
@ -22,6 +22,7 @@ public:
|
||||
private:
|
||||
QString _name;
|
||||
QString _desc;
|
||||
QString _comment;
|
||||
QVector<Link> _links;
|
||||
QDateTime _date;
|
||||
qreal _time;
|
||||
|
@ -13,6 +13,13 @@
|
||||
#define FS(size) \
|
||||
((int)((qreal)size * 1.41))
|
||||
|
||||
|
||||
Units WaypointItem::_units = Metric;
|
||||
CoordinatesFormat WaypointItem::_format = DecimalDegrees;
|
||||
#ifdef ENABLE_TIMEZONES
|
||||
QTimeZone WaypointItem::_timeZone = QTimeZone::utc();
|
||||
#endif // ENABLE_TIMEZONES
|
||||
|
||||
QString WaypointItem::info() const
|
||||
{
|
||||
ToolTip tt;
|
||||
@ -21,15 +28,41 @@ QString WaypointItem::info() const
|
||||
tt.insert(qApp->translate("WaypointItem", "Name"), _waypoint.name());
|
||||
tt.insert(qApp->translate("WaypointItem", "Coordinates"),
|
||||
Format::coordinates(_waypoint.coordinates(), _format));
|
||||
if (_waypoint.hasElevation())
|
||||
tt.insert(qApp->translate("WaypointItem", "Elevation"),
|
||||
Format::elevation(_waypoint.elevation(), _units));
|
||||
if (!std::isnan(_waypoint.elevations().first)) {
|
||||
QString val = Format::elevation(_waypoint.elevations().first, _units);
|
||||
if (!std::isnan(_waypoint.elevations().second))
|
||||
val += " (" + Format::elevation(_waypoint.elevations().second,
|
||||
_units) + ")";
|
||||
tt.insert(qApp->translate("WaypointItem", "Elevation"), val);
|
||||
}
|
||||
if (_waypoint.timestamp().isValid())
|
||||
tt.insert(qApp->translate("WaypointItem", "Date"),
|
||||
_waypoint.timestamp().toString(Qt::SystemLocaleShortDate));
|
||||
#ifdef ENABLE_TIMEZONES
|
||||
_waypoint.timestamp().toTimeZone(_timeZone)
|
||||
#else // ENABLE_TIMEZONES
|
||||
_waypoint.timestamp()
|
||||
#endif // ENABLE_TIMEZONES
|
||||
.toString(Qt::SystemLocaleShortDate));
|
||||
if (!_waypoint.description().isEmpty())
|
||||
tt.insert(qApp->translate("WaypointItem", "Description"),
|
||||
_waypoint.description());
|
||||
if (!_waypoint.comment().isEmpty()
|
||||
&& _waypoint.comment() != _waypoint.description())
|
||||
tt.insert(qApp->translate("WaypointItem", "Comment"),
|
||||
_waypoint.comment());
|
||||
if (_waypoint.address().isValid()) {
|
||||
QString addr("<address>");
|
||||
addr += _waypoint.address().street();
|
||||
addr += "<br/>" + _waypoint.address().city();
|
||||
if (!_waypoint.address().postalCode().isEmpty())
|
||||
addr += "<br/>" + _waypoint.address().postalCode();
|
||||
if (!_waypoint.address().state().isEmpty())
|
||||
addr += "<br/>" + _waypoint.address().state();
|
||||
if (!_waypoint.address().country().isEmpty())
|
||||
addr += "<br/>" + _waypoint.address().country();
|
||||
addr += "</address>";
|
||||
tt.insert(qApp->translate("WaypointItem", "Address"), addr);
|
||||
}
|
||||
if (!_waypoint.links().isEmpty()) {
|
||||
QString links;
|
||||
for (int i = 0; i < _waypoint.links().size(); i++) {
|
||||
@ -41,7 +74,7 @@ QString WaypointItem::info() const
|
||||
}
|
||||
tt.insert(qApp->translate("WaypointItem", "Links"), links);
|
||||
}
|
||||
tt.setImage(_waypoint.image());
|
||||
tt.setImages(_waypoint.images());
|
||||
|
||||
return tt.toString();
|
||||
}
|
||||
@ -57,9 +90,6 @@ WaypointItem::WaypointItem(const Waypoint &waypoint, Map *map,
|
||||
_font.setPixelSize(FS(_size));
|
||||
_font.setFamily(FONT_FAMILY);
|
||||
|
||||
_units = Metric;
|
||||
_format = DecimalDegrees;
|
||||
|
||||
updateCache();
|
||||
|
||||
setPos(map->ll2xy(waypoint.coordinates()));
|
||||
@ -130,12 +160,6 @@ void WaypointItem::setColor(const QColor &color)
|
||||
update();
|
||||
}
|
||||
|
||||
void WaypointItem::setToolTipFormat(Units units, CoordinatesFormat format)
|
||||
{
|
||||
_units = units;
|
||||
_format = format;
|
||||
}
|
||||
|
||||
void WaypointItem::showLabel(bool show)
|
||||
{
|
||||
if (_showLabel == show)
|
||||
|
@ -1,9 +1,13 @@
|
||||
#ifndef WAYPOINTITEM_H
|
||||
#define WAYPOINTITEM_H
|
||||
|
||||
#include "common/config.h"
|
||||
#include <cmath>
|
||||
#include <QGraphicsItem>
|
||||
#include <QFont>
|
||||
#ifdef ENABLE_TIMEZONES
|
||||
#include <QTimeZone>
|
||||
#endif // ENABLE_TIMEZONES
|
||||
#include "data/waypoint.h"
|
||||
#include "map/map.h"
|
||||
#include "units.h"
|
||||
@ -23,7 +27,6 @@ public:
|
||||
void setColor(const QColor &color);
|
||||
void showLabel(bool show);
|
||||
void setDigitalZoom(int zoom) {setScale(pow(2, -zoom));}
|
||||
void setToolTipFormat(Units units, CoordinatesFormat format);
|
||||
|
||||
QPainterPath shape() const {return _shape;}
|
||||
QRectF boundingRect() const {return _shape.boundingRect();}
|
||||
@ -32,6 +35,13 @@ public:
|
||||
|
||||
QString info() const;
|
||||
|
||||
static void setUnits(Units units) {_units = units;}
|
||||
static void setCoordinatesFormat(CoordinatesFormat format)
|
||||
{_format = format;}
|
||||
#ifdef ENABLE_TIMEZONES
|
||||
static void setTimeZone(const QTimeZone &zone) {_timeZone = zone;}
|
||||
#endif // ENABLE_TIMEZONES
|
||||
|
||||
protected:
|
||||
void hoverEnterEvent(QGraphicsSceneHoverEvent *event);
|
||||
void hoverLeaveEvent(QGraphicsSceneHoverEvent *event);
|
||||
@ -48,8 +58,11 @@ private:
|
||||
QFont _font;
|
||||
QRect _labelBB;
|
||||
|
||||
Units _units;
|
||||
CoordinatesFormat _format;
|
||||
static Units _units;
|
||||
static CoordinatesFormat _format;
|
||||
#ifdef ENABLE_TIMEZONES
|
||||
static QTimeZone _timeZone;
|
||||
#endif // ENABLE_TIMEZONES
|
||||
};
|
||||
|
||||
#endif // WAYPOINTITEM_H
|
||||
|
@ -18,4 +18,8 @@
|
||||
#define ENABLE_GEOJSON
|
||||
#endif // QT >= 5.0
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 5, 0)
|
||||
#define ENABLE_TIMEZONES
|
||||
#endif // QT >= 5.5
|
||||
|
||||
#endif /* CONFIG_H */
|
||||
|
@ -14,7 +14,8 @@ double Coordinates::distanceTo(const Coordinates &c) const
|
||||
#ifndef QT_NO_DEBUG
|
||||
QDebug operator<<(QDebug dbg, const Coordinates &c)
|
||||
{
|
||||
dbg.nospace() << "Coordinates(" << c.lon() << ", " << c.lat() << ")";
|
||||
dbg.nospace() << qSetRealNumberPrecision(10) << "Coordinates(" << c.lon()
|
||||
<< ", " << c.lat() << ")";
|
||||
return dbg.space();
|
||||
}
|
||||
#endif // QT_NO_DEBUG
|
||||
|
18
src/common/garmin.h
Normal file
18
src/common/garmin.h
Normal file
@ -0,0 +1,18 @@
|
||||
#ifndef GARMIN_H
|
||||
#define GARMIN_H
|
||||
|
||||
#include <QtGlobal>
|
||||
|
||||
#define LS(val, bits) ((qint32)(((quint32)(val))<<(bits)))
|
||||
|
||||
inline double toWGS32(qint32 v)
|
||||
{
|
||||
return ((double)v / (double)(1U<<31)) * 180.0;
|
||||
}
|
||||
|
||||
inline double toWGS24(qint32 v)
|
||||
{
|
||||
return toWGS32(LS(v, 8));
|
||||
}
|
||||
|
||||
#endif // GARMIN_H
|
@ -28,6 +28,9 @@ public:
|
||||
double left() const {return _tl.lon();}
|
||||
double right() const {return _br.lon();}
|
||||
|
||||
double width() const {return (right() - left());}
|
||||
double height() const {return (top() - bottom());}
|
||||
|
||||
void setLeft(double val) {_tl.rlon() = val;}
|
||||
void setRight(double val) {_br.rlon() = val;}
|
||||
void setTop(double val) {_tl.rlat() = val;}
|
||||
|
@ -9,6 +9,7 @@
|
||||
#define TIFF_SHORT 3
|
||||
#define TIFF_LONG 4
|
||||
#define TIFF_RATIONAL 5
|
||||
#define TIFF_SRATIONAL 10
|
||||
#define TIFF_DOUBLE 12
|
||||
|
||||
class TIFFFile
|
||||
|
35
src/data/address.h
Normal file
35
src/data/address.h
Normal file
@ -0,0 +1,35 @@
|
||||
#ifndef ADDRESS_H
|
||||
#define ADDRESS_H
|
||||
|
||||
#include <QString>
|
||||
|
||||
class Address
|
||||
{
|
||||
public:
|
||||
Address() {}
|
||||
Address(const QString &street, const QString &city)
|
||||
: _street(street), _city(city) {}
|
||||
|
||||
const QString &street() const {return _street;}
|
||||
const QString &city() const {return _city;}
|
||||
const QString &state() const {return _state;}
|
||||
const QString &country() const {return _country;}
|
||||
const QString &postalCode() const {return _postalCode;}
|
||||
|
||||
void setStreet(const QString &street) {_street = street;}
|
||||
void setCity(const QString &city) {_city = city;}
|
||||
void setState(const QString &state) {_state = state;}
|
||||
void setCountry(const QString &country) {_country = country;}
|
||||
void setPostalCode(const QString &postalCode) {_postalCode = postalCode;}
|
||||
|
||||
bool isValid() const {return !(_street.isEmpty() || _city.isEmpty());}
|
||||
|
||||
private:
|
||||
QString _street;
|
||||
QString _city;
|
||||
QString _state;
|
||||
QString _country;
|
||||
QString _postalCode;
|
||||
};
|
||||
|
||||
#endif // ADDRESS_H
|
@ -19,7 +19,7 @@
|
||||
#include "exifparser.h"
|
||||
#include "cupparser.h"
|
||||
#include "gpiparser.h"
|
||||
#include "dem.h"
|
||||
#include "smlparser.h"
|
||||
#include "data.h"
|
||||
|
||||
|
||||
@ -41,78 +41,48 @@ static GeoJSONParser geojson;
|
||||
static EXIFParser exif;
|
||||
static CUPParser cup;
|
||||
static GPIParser gpi;
|
||||
static SMLParser sml;
|
||||
|
||||
static QHash<QString, Parser*> parsers()
|
||||
static QMap<QString, Parser*> parsers()
|
||||
{
|
||||
QHash<QString, Parser*> hash;
|
||||
QMap<QString, Parser*> map;
|
||||
|
||||
hash.insert("gpx", &gpx);
|
||||
hash.insert("tcx", &tcx);
|
||||
hash.insert("kml", &kml);
|
||||
hash.insert("fit", &fit);
|
||||
hash.insert("csv", &csv);
|
||||
hash.insert("igc", &igc);
|
||||
hash.insert("nmea", &nmea);
|
||||
hash.insert("plt", &plt);
|
||||
hash.insert("wpt", &wpt);
|
||||
hash.insert("rte", &rte);
|
||||
hash.insert("loc", &loc);
|
||||
hash.insert("slf", &slf);
|
||||
map.insert("gpx", &gpx);
|
||||
map.insert("tcx", &tcx);
|
||||
map.insert("kml", &kml);
|
||||
map.insert("fit", &fit);
|
||||
map.insert("csv", &csv);
|
||||
map.insert("igc", &igc);
|
||||
map.insert("nmea", &nmea);
|
||||
map.insert("plt", &plt);
|
||||
map.insert("wpt", &wpt);
|
||||
map.insert("rte", &rte);
|
||||
map.insert("loc", &loc);
|
||||
map.insert("slf", &slf);
|
||||
#ifdef ENABLE_GEOJSON
|
||||
hash.insert("json", &geojson);
|
||||
hash.insert("geojson", &geojson);
|
||||
map.insert("json", &geojson);
|
||||
map.insert("geojson", &geojson);
|
||||
#endif // ENABLE_GEOJSON
|
||||
hash.insert("jpeg", &exif);
|
||||
hash.insert("jpg", &exif);
|
||||
hash.insert("cup", &cup);
|
||||
hash.insert("gpi", &gpi);
|
||||
map.insert("jpeg", &exif);
|
||||
map.insert("jpg", &exif);
|
||||
map.insert("cup", &cup);
|
||||
map.insert("gpi", &gpi);
|
||||
map.insert("sml", &sml);
|
||||
|
||||
return hash;
|
||||
return map;
|
||||
}
|
||||
|
||||
|
||||
QHash<QString, Parser*> Data::_parsers = parsers();
|
||||
bool Data::_useDEM = false;
|
||||
QMap<QString, Parser*> Data::_parsers = parsers();
|
||||
|
||||
void Data::processData(QList<TrackData> &trackData, QList<RouteData> &routeData)
|
||||
{
|
||||
for (int i = 0; i < trackData.count(); i++) {
|
||||
TrackData &track = trackData[i];
|
||||
for (int j = 0; j < track.size(); j++) {
|
||||
SegmentData &segment = track[j];
|
||||
for (int k = 0; k < segment.size(); k++) {
|
||||
Trackpoint &t = segment[k];
|
||||
if (!t.hasElevation() || _useDEM) {
|
||||
qreal elevation = DEM::elevation(t.coordinates());
|
||||
if (!std::isnan(elevation))
|
||||
t.setElevation(elevation);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < trackData.count(); i++)
|
||||
_tracks.append(Track(trackData.at(i)));
|
||||
}
|
||||
for (int i = 0; i < routeData.count(); i++) {
|
||||
RouteData &route = routeData[i];
|
||||
for (int j = 0; j < route.size(); j++) {
|
||||
Waypoint &w = route[j];
|
||||
if (!w.hasElevation() || _useDEM) {
|
||||
qreal elevation = DEM::elevation(w.coordinates());
|
||||
if (!std::isnan(elevation))
|
||||
w.setElevation(elevation);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < routeData.count(); i++)
|
||||
_routes.append(Route(routeData.at(i)));
|
||||
}
|
||||
for (int i = 0; i < _waypoints.size(); i++) {
|
||||
if (!_waypoints.at(i).hasElevation() || _useDEM) {
|
||||
qreal elevation = DEM::elevation(_waypoints.at(i).coordinates());
|
||||
if (!std::isnan(elevation))
|
||||
_waypoints[i].setElevation(elevation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Data::Data(const QString &fileName, bool poi)
|
||||
Data::Data(const QString &fileName)
|
||||
{
|
||||
QFile file(fileName);
|
||||
QFileInfo fi(fileName);
|
||||
@ -127,12 +97,11 @@ Data::Data(const QString &fileName, bool poi)
|
||||
return;
|
||||
}
|
||||
|
||||
QHash<QString, Parser*>::iterator it;
|
||||
QMap<QString, Parser*>::iterator it;
|
||||
if ((it = _parsers.find(fi.suffix().toLower())) != _parsers.end()) {
|
||||
if (it.value()->parse(&file, trackData, routeData, _polygons,
|
||||
_waypoints)) {
|
||||
if (!poi)
|
||||
processData(trackData, routeData);
|
||||
processData(trackData, routeData);
|
||||
_valid = true;
|
||||
return;
|
||||
} else {
|
||||
@ -143,8 +112,7 @@ Data::Data(const QString &fileName, bool poi)
|
||||
for (it = _parsers.begin(); it != _parsers.end(); it++) {
|
||||
if (it.value()->parse(&file, trackData, routeData, _polygons,
|
||||
_waypoints)) {
|
||||
if (!poi)
|
||||
processData(trackData, routeData);
|
||||
processData(trackData, routeData);
|
||||
_valid = true;
|
||||
return;
|
||||
}
|
||||
@ -163,17 +131,8 @@ Data::Data(const QString &fileName, bool poi)
|
||||
|
||||
QString Data::formats()
|
||||
{
|
||||
QStringList l(filter());
|
||||
qSort(l);
|
||||
QString supported;
|
||||
for (int i = 0; i < l.size(); i++) {
|
||||
supported += l.at(i);
|
||||
if (i != l.size() - 1)
|
||||
supported += " ";
|
||||
}
|
||||
|
||||
return
|
||||
qApp->translate("Data", "Supported files") + " (" + supported + ");;"
|
||||
qApp->translate("Data", "Supported files") + " (" + filter().join(" ") + ");;"
|
||||
+ qApp->translate("Data", "CSV files") + " (*.csv);;"
|
||||
+ qApp->translate("Data", "CUP files") + " (*.cup);;"
|
||||
+ qApp->translate("Data", "FIT files") + " (*.fit);;"
|
||||
@ -189,6 +148,7 @@ QString Data::formats()
|
||||
+ qApp->translate("Data", "NMEA files") + " (*.nmea);;"
|
||||
+ qApp->translate("Data", "OziExplorer files") + " (*.plt *.rte *.wpt);;"
|
||||
+ qApp->translate("Data", "SLF files") + " (*.slf);;"
|
||||
+ qApp->translate("Data", "SML files") + " (*.sml);;"
|
||||
+ qApp->translate("Data", "TCX files") + " (*.tcx);;"
|
||||
+ qApp->translate("Data", "All files") + " (*)";
|
||||
}
|
||||
@ -196,15 +156,10 @@ QString Data::formats()
|
||||
QStringList Data::filter()
|
||||
{
|
||||
QStringList filter;
|
||||
QHash<QString, Parser*>::iterator it;
|
||||
|
||||
for (it = _parsers.begin(); it != _parsers.end(); it++)
|
||||
filter << QString("*.%1").arg(it.key());
|
||||
for (QMap<QString, Parser*>::iterator it = _parsers.begin();
|
||||
it != _parsers.end(); it++)
|
||||
filter << "*." + it.key();
|
||||
|
||||
return filter;
|
||||
}
|
||||
|
||||
void Data::useDEM(bool use)
|
||||
{
|
||||
_useDEM = use;
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
#define DATA_H
|
||||
|
||||
#include <QList>
|
||||
#include <QHash>
|
||||
#include <QMap>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include "waypoint.h"
|
||||
@ -14,7 +14,7 @@
|
||||
class Data
|
||||
{
|
||||
public:
|
||||
Data(const QString &fileName, bool poi = false);
|
||||
Data(const QString &fileName);
|
||||
|
||||
bool isValid() const {return _valid;}
|
||||
const QString &errorString() const {return _errorString;}
|
||||
@ -28,8 +28,6 @@ public:
|
||||
static QString formats();
|
||||
static QStringList filter();
|
||||
|
||||
static void useDEM(bool use);
|
||||
|
||||
private:
|
||||
void processData(QList<TrackData> &trackData, QList<RouteData> &routeData);
|
||||
|
||||
@ -42,8 +40,7 @@ private:
|
||||
QList<Area> _polygons;
|
||||
QVector<Waypoint> _waypoints;
|
||||
|
||||
static QHash<QString, Parser*> _parsers;
|
||||
static bool _useDEM;
|
||||
static QMap<QString, Parser*> _parsers;
|
||||
};
|
||||
|
||||
#endif // DATA_H
|
||||
|
@ -1,4 +1,9 @@
|
||||
#include <QtEndian>
|
||||
#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
|
||||
#include <QtCore/qmath.h>
|
||||
#else // QT5
|
||||
#include <QtMath>
|
||||
#endif // QT5
|
||||
#include <QDir>
|
||||
#include <QFile>
|
||||
#include "common/coordinates.h"
|
||||
@ -37,10 +42,10 @@ static qreal height(const Coordinates &c, const QByteArray *data)
|
||||
else
|
||||
return NAN;
|
||||
|
||||
int row = (int)((c.lat() - (int)c.lat()) * (samples - 1));
|
||||
int col = (int)((c.lon() - (int)c.lon()) * (samples - 1));
|
||||
qreal dx = ((c.lon() - (int)c.lon()) * (samples - 1)) - col;
|
||||
qreal dy = ((c.lat() - (int)c.lat()) * (samples - 1)) - row;
|
||||
int row = (int)((c.lat() - qFloor(c.lat())) * (samples - 1));
|
||||
int col = (int)((c.lon() - qFloor(c.lon())) * (samples - 1));
|
||||
qreal dx = ((c.lon() - qFloor(c.lon())) * (samples - 1)) - col;
|
||||
qreal dy = ((c.lat() - qFloor(c.lat())) * (samples - 1)) - row;
|
||||
|
||||
qreal p0 = value(col, row, samples, data);
|
||||
qreal p1 = value(col + 1, row, samples, data);
|
||||
@ -75,7 +80,7 @@ qreal DEM::elevation(const Coordinates &c)
|
||||
if (_dir.isEmpty())
|
||||
return NAN;
|
||||
|
||||
Key k((int)c.lon(), (int)c.lat());
|
||||
Key k(qFloor(c.lon()), qFloor(c.lat()));
|
||||
|
||||
QByteArray *ba = _data[k];
|
||||
if (!ba) {
|
||||
|
@ -82,7 +82,10 @@ double EXIFParser::altitude(TIFFFile &file, const IFDEntry &alt,
|
||||
|
||||
double EXIFParser::coordinate(TIFFFile &file, const IFDEntry &ll) const
|
||||
{
|
||||
if (!(ll.type == TIFF_RATIONAL && ll.count == 3))
|
||||
// Some broken image creators like NOKIA phones use a wrong (SRATIONAL)
|
||||
// data type
|
||||
if (!((ll.type == TIFF_RATIONAL || ll.type == TIFF_SRATIONAL)
|
||||
&& ll.count == 3))
|
||||
return NAN;
|
||||
|
||||
if (!file.seek(ll.offset))
|
||||
@ -209,7 +212,7 @@ bool EXIFParser::parseTIFF(QFile *file, QVector<Waypoint> &waypoints)
|
||||
|
||||
Waypoint wp(c);
|
||||
wp.setName(QFileInfo(file->fileName()).baseName());
|
||||
wp.setImage(img);
|
||||
wp.addImage(img);
|
||||
wp.setElevation(altitude(tiff, GPSIFD.value(GPSAltitude),
|
||||
GPSIFD.value(GPSAltitudeRef)));
|
||||
wp.setTimestamp(QDateTime(QDate::fromString(text(tiff,
|
||||
|
@ -7,6 +7,7 @@
|
||||
|
||||
#define RECORD_MESSAGE 20
|
||||
#define EVENT_MESSAGE 21
|
||||
#define COURSE_POINT 32
|
||||
#define TIMESTAMP_FIELD 253
|
||||
|
||||
class Event {
|
||||
@ -48,10 +49,12 @@ public:
|
||||
|
||||
class FITParser::CTX {
|
||||
public:
|
||||
CTX(QFile *file) : file(file), len(0), endian(0), timestamp(0),
|
||||
lastWrite(0), ratio(NAN) {}
|
||||
CTX(QFile *file, QVector<Waypoint> &waypoints)
|
||||
: file(file), waypoints(waypoints), len(0), endian(0), timestamp(0),
|
||||
lastWrite(0), ratio(NAN) {}
|
||||
|
||||
QFile *file;
|
||||
QVector<Waypoint> &waypoints;
|
||||
quint32 len;
|
||||
quint8 endian;
|
||||
quint32 timestamp, lastWrite;
|
||||
@ -61,6 +64,41 @@ public:
|
||||
SegmentData segment;
|
||||
};
|
||||
|
||||
static QMap<int, QString> coursePointDescInit()
|
||||
{
|
||||
QMap<int, QString> map;
|
||||
|
||||
map.insert(1, "Summit");
|
||||
map.insert(2, "Valley");
|
||||
map.insert(3, "Water");
|
||||
map.insert(4, "Food");
|
||||
map.insert(5, "Danger");
|
||||
map.insert(6, "Left");
|
||||
map.insert(7, "Right");
|
||||
map.insert(8, "Straight");
|
||||
map.insert(9, "First aid");
|
||||
map.insert(10, "Fourth category");
|
||||
map.insert(11, "Third category");
|
||||
map.insert(12, "Second category");
|
||||
map.insert(13, "First category");
|
||||
map.insert(14, "Hors category");
|
||||
map.insert(15, "Sprint");
|
||||
map.insert(16, "Left fork");
|
||||
map.insert(17, "Right fork");
|
||||
map.insert(18, "Middle fork");
|
||||
map.insert(19, "Slight left");
|
||||
map.insert(20, "Sharp left");
|
||||
map.insert(21, "Slight right");
|
||||
map.insert(22, "Sharp right");
|
||||
map.insert(23, "U-Turn");
|
||||
map.insert(24, "Segment start");
|
||||
map.insert(25, "Segment end");
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
static QMap<int, QString> coursePointDesc = coursePointDescInit();
|
||||
|
||||
|
||||
bool FITParser::readData(QFile *file, char *data, size_t size)
|
||||
{
|
||||
@ -80,17 +118,12 @@ bool FITParser::readData(QFile *file, char *data, size_t size)
|
||||
|
||||
template<class T> bool FITParser::readValue(CTX &ctx, T &val)
|
||||
{
|
||||
T data;
|
||||
|
||||
if (!readData(ctx.file, (char*)&data, sizeof(T)))
|
||||
if (!readData(ctx.file, (char*)&val, sizeof(T)))
|
||||
return false;
|
||||
|
||||
ctx.len -= sizeof(T);
|
||||
|
||||
if (ctx.endian)
|
||||
val = qFromBigEndian(data);
|
||||
else
|
||||
val = qFromLittleEndian(data);
|
||||
if (sizeof(T) > 1)
|
||||
val = (ctx.endian) ? qFromBigEndian(val) : qFromLittleEndian(val);
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -167,41 +200,51 @@ bool FITParser::parseDefinitionMessage(CTX &ctx, quint8 header)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FITParser::readField(CTX &ctx, Field *field, quint32 &val)
|
||||
bool FITParser::readField(CTX &ctx, Field *field, QVariant &val, bool &valid)
|
||||
{
|
||||
quint8 v8 = (quint8)-1;
|
||||
quint16 v16 = (quint16)-1;
|
||||
bool ret;
|
||||
|
||||
val = (quint32)-1;
|
||||
#define VAL(type, inval) \
|
||||
{type var; \
|
||||
if (field->size == sizeof(var)) { \
|
||||
ret = readValue(ctx, var); \
|
||||
val = var; \
|
||||
valid = (var != (inval)); \
|
||||
} else { \
|
||||
ret = skipValue(ctx, field->size); \
|
||||
valid = false; \
|
||||
}}
|
||||
|
||||
switch (field->type) {
|
||||
case 0: // enum
|
||||
case 1: // sint8
|
||||
VAL(qint8, 0x7fU);
|
||||
break;
|
||||
case 2: // uint8
|
||||
if (field->size == 1) {
|
||||
ret = readValue(ctx, v8);
|
||||
val = v8;
|
||||
} else
|
||||
ret = skipValue(ctx, field->size);
|
||||
case 0: // enum
|
||||
VAL(quint8, 0xffU);
|
||||
break;
|
||||
case 7: // UTF8 nul terminated string
|
||||
{QByteArray ba(ctx.file->read(field->size));
|
||||
ctx.len -= field->size;
|
||||
ret = (ba.size() == field->size);
|
||||
val = ret ? ba : QString();
|
||||
valid = !ba.isEmpty();}
|
||||
break;
|
||||
case 0x83: // sint16
|
||||
VAL(qint16, 0x7fffU);
|
||||
break;
|
||||
case 0x84: // uint16
|
||||
if (field->size == 2) {
|
||||
ret = readValue(ctx, v16);
|
||||
val = v16;
|
||||
} else
|
||||
ret = skipValue(ctx, field->size);
|
||||
VAL(quint16, 0xffffU);
|
||||
break;
|
||||
case 0x85: // sint32
|
||||
VAL(qint32, 0x7fffffffU);
|
||||
break;
|
||||
case 0x86: // uint32
|
||||
if (field->size == 4)
|
||||
ret = readValue(ctx, val);
|
||||
else
|
||||
ret = skipValue(ctx, field->size);
|
||||
VAL(quint32, 0xffffffffU);
|
||||
break;
|
||||
default:
|
||||
ret = skipValue(ctx, field->size);
|
||||
valid = false;
|
||||
break;
|
||||
}
|
||||
|
||||
@ -211,8 +254,10 @@ bool FITParser::readField(CTX &ctx, Field *field, quint32 &val)
|
||||
bool FITParser::parseData(CTX &ctx, const MessageDefinition *def)
|
||||
{
|
||||
Field *field;
|
||||
QVariant val;
|
||||
bool valid;
|
||||
Event event;
|
||||
quint32 val;
|
||||
Waypoint waypoint;
|
||||
|
||||
|
||||
if (!def->fields && !def->devFields) {
|
||||
@ -224,69 +269,79 @@ bool FITParser::parseData(CTX &ctx, const MessageDefinition *def)
|
||||
|
||||
for (int i = 0; i < def->numFields; i++) {
|
||||
field = &def->fields[i];
|
||||
if (!readField(ctx, field, val))
|
||||
if (!readField(ctx, field, val, valid))
|
||||
return false;
|
||||
if (!valid)
|
||||
continue;
|
||||
|
||||
if (field->id == TIMESTAMP_FIELD)
|
||||
ctx.timestamp = val;
|
||||
ctx.timestamp = val.toUInt();
|
||||
else if (def->globalId == RECORD_MESSAGE) {
|
||||
switch (field->id) {
|
||||
case 0:
|
||||
if (val != 0x7fffffff)
|
||||
ctx.trackpoint.rcoordinates().setLat(
|
||||
((qint32)val / (double)0x7fffffff) * 180);
|
||||
ctx.trackpoint.rcoordinates().setLat(
|
||||
(val.toInt() / (double)0x7fffffff) * 180);
|
||||
break;
|
||||
case 1:
|
||||
if (val != 0x7fffffff)
|
||||
ctx.trackpoint.rcoordinates().setLon(
|
||||
((qint32)val / (double)0x7fffffff) * 180);
|
||||
ctx.trackpoint.rcoordinates().setLon(
|
||||
(val.toInt() / (double)0x7fffffff) * 180);
|
||||
break;
|
||||
case 2:
|
||||
if (val != 0xffff)
|
||||
ctx.trackpoint.setElevation((val / 5.0) - 500);
|
||||
ctx.trackpoint.setElevation((val.toUInt() / 5.0) - 500);
|
||||
break;
|
||||
case 3:
|
||||
if (val != 0xff)
|
||||
ctx.trackpoint.setHeartRate(val);
|
||||
ctx.trackpoint.setHeartRate(val.toUInt());
|
||||
break;
|
||||
case 4:
|
||||
if (val != 0xff)
|
||||
ctx.trackpoint.setCadence(val);
|
||||
ctx.trackpoint.setCadence(val.toUInt());
|
||||
break;
|
||||
case 6:
|
||||
if (val != 0xffff)
|
||||
ctx.trackpoint.setSpeed(val / 1000.0f);
|
||||
ctx.trackpoint.setSpeed(val.toUInt() / 1000.0f);
|
||||
break;
|
||||
case 7:
|
||||
if (val != 0xffff)
|
||||
ctx.trackpoint.setPower(val);
|
||||
ctx.trackpoint.setPower(val.toUInt());
|
||||
break;
|
||||
case 13:
|
||||
if (val != 0x7f)
|
||||
ctx.trackpoint.setTemperature((qint8)val);
|
||||
ctx.trackpoint.setTemperature(val.toInt());
|
||||
break;
|
||||
case 73:
|
||||
if (val != 0xffffffff)
|
||||
ctx.trackpoint.setSpeed(val / 1000.0f);
|
||||
ctx.trackpoint.setSpeed(val.toUInt() / 1000.0f);
|
||||
break;
|
||||
case 78:
|
||||
if (val != 0xffffffff)
|
||||
ctx.trackpoint.setElevation((val / 5.0) - 500);
|
||||
ctx.trackpoint.setElevation((val.toUInt() / 5.0) - 500);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
||||
}
|
||||
} else if (def->globalId == EVENT_MESSAGE) {
|
||||
switch (field->id) {
|
||||
case 0:
|
||||
event.id = val;
|
||||
event.id = val.toUInt();
|
||||
break;
|
||||
case 1:
|
||||
event.type = val;
|
||||
event.type = val.toUInt();
|
||||
break;
|
||||
case 3:
|
||||
event.data = val;
|
||||
event.data = val.toUInt();
|
||||
break;
|
||||
}
|
||||
} else if (def->globalId == COURSE_POINT) {
|
||||
switch (field->id) {
|
||||
case 1:
|
||||
waypoint.setTimestamp(QDateTime::fromTime_t(val.toUInt()
|
||||
+ 631065600));
|
||||
break;
|
||||
case 2:
|
||||
waypoint.rcoordinates().setLat(
|
||||
(val.toInt() / (double)0x7fffffff) * 180);
|
||||
break;
|
||||
case 3:
|
||||
waypoint.rcoordinates().setLon(
|
||||
(val.toInt() / (double)0x7fffffff) * 180);
|
||||
break;
|
||||
case 5:
|
||||
waypoint.setDescription(coursePointDesc.value(val.toUInt()));
|
||||
break;
|
||||
case 6:
|
||||
waypoint.setName(val.toString());
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -294,7 +349,7 @@ bool FITParser::parseData(CTX &ctx, const MessageDefinition *def)
|
||||
|
||||
for (int i = 0; i < def->numDevFields; i++) {
|
||||
field = &def->devFields[i];
|
||||
if (!readField(ctx, field, val))
|
||||
if (!readField(ctx, field, val, valid))
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -315,7 +370,9 @@ bool FITParser::parseData(CTX &ctx, const MessageDefinition *def)
|
||||
ctx.trackpoint = Trackpoint();
|
||||
ctx.lastWrite = ctx.timestamp;
|
||||
}
|
||||
}
|
||||
} else if (def->globalId == COURSE_POINT)
|
||||
if (waypoint.coordinates().isValid())
|
||||
ctx.waypoints.append(waypoint);
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -381,9 +438,8 @@ bool FITParser::parse(QFile *file, QList<TrackData> &tracks,
|
||||
QList<Area> &polygons, QVector<Waypoint> &waypoints)
|
||||
{
|
||||
Q_UNUSED(routes);
|
||||
Q_UNUSED(waypoints);
|
||||
Q_UNUSED(polygons);
|
||||
CTX ctx(file);
|
||||
CTX ctx(file, waypoints);
|
||||
|
||||
|
||||
if (!parseHeader(ctx))
|
||||
|
@ -21,7 +21,7 @@ private:
|
||||
bool readData(QFile *file, char *data, size_t size);
|
||||
template<class T> bool readValue(CTX &ctx, T &val);
|
||||
bool skipValue(CTX &ctx, quint8 size);
|
||||
bool readField(CTX &ctx, Field *field, quint32 &val);
|
||||
bool readField(CTX &ctx, Field *field, QVariant &val, bool &valid);
|
||||
|
||||
bool parseHeader(CTX &ctx);
|
||||
bool parseRecord(CTX &ctx);
|
||||
|
@ -1,7 +1,17 @@
|
||||
#include <cstring>
|
||||
#include <QDataStream>
|
||||
#include <QTextCodec>
|
||||
#include <QtEndian>
|
||||
#include <QUrl>
|
||||
#include <QIODevice>
|
||||
#include <QApplication>
|
||||
#include <QBuffer>
|
||||
#include <QImageReader>
|
||||
#include <QCryptographicHash>
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
|
||||
#include <QTemporaryDir>
|
||||
#endif // QT_VERSION >= 5
|
||||
#include "common/garmin.h"
|
||||
#include "gpiparser.h"
|
||||
|
||||
|
||||
@ -26,16 +36,105 @@ private:
|
||||
QString _str;
|
||||
};
|
||||
|
||||
static inline double toWGS(qint32 v)
|
||||
class CryptDevice : public QIODevice
|
||||
{
|
||||
return (double)(((double)v / (double)(1U<<31)) * (double)180);
|
||||
public:
|
||||
CryptDevice(QIODevice *device, quint32 key, quint32 blockSize,
|
||||
QObject *parent = 0);
|
||||
bool isSequential() const {return true;}
|
||||
|
||||
protected:
|
||||
qint64 readData(char *data, qint64 maxSize);
|
||||
qint64 writeData(const char *, qint64) {return -1;}
|
||||
|
||||
private:
|
||||
QIODevice *_device;
|
||||
quint32 _key;
|
||||
QByteArray _block;
|
||||
int _available;
|
||||
};
|
||||
|
||||
static void demangle(quint8 *data, quint32 size, quint32 key)
|
||||
{
|
||||
static const unsigned char shuf[] = {
|
||||
0xb, 0xc, 0xa, 0x0,
|
||||
0x8, 0xf, 0x2, 0x1,
|
||||
0x6, 0x4, 0x9, 0x3,
|
||||
0xd, 0x5, 0x7, 0xe
|
||||
};
|
||||
|
||||
int hiCnt = 0, loCnt;
|
||||
quint8 sum = shuf[((key >> 24) + (key >> 16) + (key >> 8) + key) & 0xf];
|
||||
|
||||
for (quint32 i = 0; i < size; i++) {
|
||||
quint8 hiAdd = shuf[key >> (hiCnt << 2) & 0xf] + sum;
|
||||
loCnt = (hiCnt > 6) ? 0 : hiCnt + 1;
|
||||
quint8 loAdd = shuf[key >> (loCnt << 2) & 0xf] + sum;
|
||||
quint8 hi = data[i] - (hiAdd << 4);
|
||||
quint8 lo = data[i] - loAdd;
|
||||
data[i] = (hi & 0xf0) | (lo & 0x0f);
|
||||
hiCnt = (loCnt > 6) ? 0 : loCnt + 1;
|
||||
}
|
||||
}
|
||||
|
||||
CryptDevice::CryptDevice(QIODevice *device, quint32 key, quint32 blockSize,
|
||||
QObject *parent) : QIODevice(parent), _device(device), _key(key), _available(0)
|
||||
{
|
||||
_block.resize(blockSize);
|
||||
setOpenMode(_device->openMode());
|
||||
}
|
||||
|
||||
qint64 CryptDevice::readData(char *data, qint64 maxSize)
|
||||
{
|
||||
qint64 rs, ts = 0;
|
||||
int cs;
|
||||
|
||||
if (_available) {
|
||||
cs = qMin(maxSize, (qint64)_available);
|
||||
memcpy(data, _block.constData() + _block.size() - _available, cs);
|
||||
_available -= cs;
|
||||
maxSize -= cs;
|
||||
ts = cs;
|
||||
}
|
||||
|
||||
while (maxSize) {
|
||||
if ((rs = _device->read(_block.data(), _block.size())) < 0)
|
||||
return -1;
|
||||
else if (!rs)
|
||||
break;
|
||||
_available = rs;
|
||||
demangle((quint8*)_block.data(), _available, _key);
|
||||
cs = qMin(maxSize, (qint64)_available);
|
||||
memcpy(data + ts, _block.constData(), cs);
|
||||
_available -= cs;
|
||||
maxSize -= cs;
|
||||
ts += cs;
|
||||
}
|
||||
|
||||
return ts;
|
||||
}
|
||||
|
||||
|
||||
static qint32 readInt24(QDataStream &stream)
|
||||
{
|
||||
unsigned char data[3];
|
||||
quint32 val;
|
||||
|
||||
stream.readRawData((char*)data, sizeof(data));
|
||||
val = data[0] | ((quint32)data[1]) << 8 | ((quint32)data[2]) << 16;
|
||||
return (val > 0x7FFFFF) ? (val & 0x7FFFFF) - 0x800000 : val;
|
||||
}
|
||||
|
||||
static quint16 nextHeaderType(QDataStream &stream)
|
||||
{
|
||||
quint16 type = 0;
|
||||
stream.device()->peek((char*)&type, sizeof(type));
|
||||
return qFromLittleEndian(type);
|
||||
|
||||
if (stream.device()->peek((char*)&type, sizeof(type))
|
||||
< (qint64)sizeof(type)) {
|
||||
stream.setStatus(QDataStream::ReadCorruptData);
|
||||
return 0xFFFF;
|
||||
} else
|
||||
return qFromLittleEndian(type);
|
||||
}
|
||||
|
||||
static quint8 readRecordHeader(QDataStream &stream, RecordHeader &hdr)
|
||||
@ -55,18 +154,6 @@ static quint32 skipRecord(QDataStream &stream)
|
||||
return rs + rh.size;
|
||||
}
|
||||
|
||||
static quint32 readFprsRecord(QDataStream &stream)
|
||||
{
|
||||
RecordHeader rh;
|
||||
quint16 s1;
|
||||
quint8 rs, s2, s3, s4;
|
||||
|
||||
rs = readRecordHeader(stream, rh);
|
||||
stream >> s1 >> s2 >> s3 >> s4;
|
||||
|
||||
return rs + 5;
|
||||
}
|
||||
|
||||
static quint16 readString(QDataStream &stream, QTextCodec *codec, QString &str)
|
||||
{
|
||||
quint16 len;
|
||||
@ -83,15 +170,16 @@ static quint32 readTranslatedObjects(QDataStream &stream, QTextCodec *codec,
|
||||
QList<TranslatedString> &objects)
|
||||
{
|
||||
qint32 size = 0, ret;
|
||||
char lang[2];
|
||||
char lang[3];
|
||||
|
||||
memset(lang, 0, sizeof(lang));
|
||||
objects.clear();
|
||||
|
||||
stream >> size;
|
||||
ret = size + 4;
|
||||
while (size > 0) {
|
||||
while (stream.status() == QDataStream::Ok && size > 0) {
|
||||
QString str;
|
||||
stream.readRawData(lang, sizeof(lang));
|
||||
stream.readRawData(lang, sizeof(lang) - 1);
|
||||
size -= readString(stream, codec, str) + 2;
|
||||
objects.append(TranslatedString(lang, str));
|
||||
}
|
||||
@ -102,163 +190,16 @@ static quint32 readTranslatedObjects(QDataStream &stream, QTextCodec *codec,
|
||||
return ret;
|
||||
}
|
||||
|
||||
static quint32 readDescription(QDataStream &stream, QTextCodec *codec,
|
||||
Waypoint &waypoint)
|
||||
static quint32 readFprsRecord(QDataStream &stream)
|
||||
{
|
||||
RecordHeader rh;
|
||||
quint8 rs;
|
||||
quint32 ds;
|
||||
QList<TranslatedString> obj;
|
||||
|
||||
rs = readRecordHeader(stream, rh);
|
||||
ds = readTranslatedObjects(stream, codec, obj);
|
||||
if (!obj.isEmpty())
|
||||
waypoint.setDescription(obj.first().str());
|
||||
|
||||
if (ds != rh.size)
|
||||
stream.setStatus(QDataStream::ReadCorruptData);
|
||||
|
||||
return rs + rh.size;
|
||||
}
|
||||
|
||||
static quint32 readNotes(QDataStream &stream, QTextCodec *codec,
|
||||
Waypoint &waypoint)
|
||||
{
|
||||
RecordHeader rh;
|
||||
quint8 rs, s1;
|
||||
quint32 ds = 1;
|
||||
|
||||
rs = readRecordHeader(stream, rh);
|
||||
stream >> s1;
|
||||
if (s1 & 0x1) {
|
||||
QList<TranslatedString> obj;
|
||||
ds += readTranslatedObjects(stream, codec, obj);
|
||||
if (!obj.isEmpty() && waypoint.description().isNull())
|
||||
waypoint.setDescription(obj.first().str());
|
||||
}
|
||||
if (s1 & 0x2) {
|
||||
QString str;
|
||||
ds += readString(stream, codec, str);
|
||||
if (!str.isEmpty() && waypoint.description().isNull())
|
||||
waypoint.setDescription(str);
|
||||
}
|
||||
|
||||
if (ds != rh.size)
|
||||
stream.setStatus(QDataStream::ReadCorruptData);
|
||||
|
||||
return rs + rh.size;
|
||||
}
|
||||
|
||||
static quint32 readContact(QDataStream &stream, QTextCodec *codec,
|
||||
Waypoint &waypoint)
|
||||
{
|
||||
RecordHeader rh;
|
||||
quint8 rs;
|
||||
quint16 s1;
|
||||
quint32 ds = 2;
|
||||
QString str;
|
||||
QList<TranslatedString> obj;
|
||||
quint8 rs, s2, s3, s4;
|
||||
|
||||
rs = readRecordHeader(stream, rh);
|
||||
stream >> s1;
|
||||
stream >> s1 >> s2 >> s3 >> s4;
|
||||
|
||||
if (s1 & 0x1) // phone
|
||||
ds += readString(stream, codec, str);
|
||||
if (s1 & 0x2) // phone2
|
||||
ds += readString(stream, codec, str);
|
||||
if (s1 & 0x4) // fax
|
||||
ds += readString(stream, codec, str);
|
||||
if (s1 & 0x8) // mail
|
||||
ds += readString(stream, codec, str);
|
||||
if (s1 & 0x10) { // web
|
||||
ds += readString(stream, codec, str);
|
||||
QUrl url(str);
|
||||
waypoint.addLink(Link(url.scheme().isEmpty()
|
||||
? "http://" + str : str, str));
|
||||
}
|
||||
if (s1 & 0x20) // unknown
|
||||
ds += readTranslatedObjects(stream, codec, obj);
|
||||
|
||||
if (ds != rh.size)
|
||||
stream.setStatus(QDataStream::ReadCorruptData);
|
||||
|
||||
return rs + rh.size;
|
||||
}
|
||||
|
||||
static quint32 readPOI(QDataStream &stream, QTextCodec *codec,
|
||||
QVector<Waypoint> &waypoints)
|
||||
{
|
||||
RecordHeader rh;
|
||||
quint8 rs;
|
||||
quint32 ds;
|
||||
qint32 s1, s2;
|
||||
quint16 s3;
|
||||
QList<TranslatedString> obj;
|
||||
|
||||
rs = readRecordHeader(stream, rh);
|
||||
stream >> s1 >> s2 >> s3;
|
||||
stream.skipRawData(s3);
|
||||
ds = 10 + s3;
|
||||
ds += readTranslatedObjects(stream, codec, obj);
|
||||
|
||||
waypoints.append(Waypoint(Coordinates(toWGS(s2), toWGS(s1))));
|
||||
if (!obj.isEmpty())
|
||||
waypoints.last().setName(obj.first().str());
|
||||
|
||||
while (ds < rh.size) {
|
||||
switch(nextHeaderType(stream)) {
|
||||
case 10:
|
||||
ds += readDescription(stream, codec, waypoints.last());
|
||||
break;
|
||||
case 12:
|
||||
ds += readContact(stream, codec, waypoints.last());
|
||||
break;
|
||||
case 14:
|
||||
ds += readNotes(stream, codec, waypoints.last());
|
||||
break;
|
||||
default:
|
||||
ds += skipRecord(stream);
|
||||
}
|
||||
}
|
||||
|
||||
if (ds != rh.size)
|
||||
stream.setStatus(QDataStream::ReadCorruptData);
|
||||
|
||||
return rs + rh.size;
|
||||
}
|
||||
|
||||
static quint32 readSpatialIndex(QDataStream &stream, QTextCodec *codec,
|
||||
QVector<Waypoint> &waypoints)
|
||||
{
|
||||
RecordHeader rh;
|
||||
quint32 ds, s5;
|
||||
qint32 top, right, bottom, left;
|
||||
quint16 s6;
|
||||
quint8 rs;
|
||||
|
||||
rs = readRecordHeader(stream, rh);
|
||||
stream >> top >> right >> bottom >> left >> s5 >> s6;
|
||||
stream.skipRawData(s6);
|
||||
ds = 22 + s6;
|
||||
if (rh.flags & 0x8) {
|
||||
while (ds < rh.size) {
|
||||
switch(nextHeaderType(stream)) {
|
||||
case 2:
|
||||
ds += readPOI(stream, codec, waypoints);
|
||||
break;
|
||||
case 8:
|
||||
ds += readSpatialIndex(stream, codec, waypoints);
|
||||
break;
|
||||
default:
|
||||
ds += skipRecord(stream);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ds != rh.size)
|
||||
stream.setStatus(QDataStream::ReadCorruptData);
|
||||
|
||||
return rs + rh.size;
|
||||
return rs + 5;
|
||||
}
|
||||
|
||||
static quint32 readFileDataRecord(QDataStream &stream, QTextCodec *codec)
|
||||
@ -299,6 +240,29 @@ static quint32 readFileDataRecord(QDataStream &stream, QTextCodec *codec)
|
||||
stream.skipRawData(ss1);
|
||||
ds += ss1 + 2;
|
||||
}
|
||||
// structure of higher fields not known
|
||||
|
||||
if (ds > rh.size)
|
||||
stream.setStatus(QDataStream::ReadCorruptData);
|
||||
else if (ds < rh.size)
|
||||
// skip remaining unknown fields
|
||||
stream.skipRawData(rh.size - ds);
|
||||
|
||||
return rs + rh.size;
|
||||
}
|
||||
|
||||
static quint32 readDescription(QDataStream &stream, QTextCodec *codec,
|
||||
Waypoint &waypoint)
|
||||
{
|
||||
RecordHeader rh;
|
||||
quint8 rs;
|
||||
quint32 ds;
|
||||
QList<TranslatedString> obj;
|
||||
|
||||
rs = readRecordHeader(stream, rh);
|
||||
ds = readTranslatedObjects(stream, codec, obj);
|
||||
if (!obj.isEmpty())
|
||||
waypoint.setDescription(obj.first().str());
|
||||
|
||||
if (ds != rh.size)
|
||||
stream.setStatus(QDataStream::ReadCorruptData);
|
||||
@ -306,7 +270,432 @@ static quint32 readFileDataRecord(QDataStream &stream, QTextCodec *codec)
|
||||
return rs + rh.size;
|
||||
}
|
||||
|
||||
bool GPIParser::readFileHeader(QDataStream &stream)
|
||||
static quint32 readNotes(QDataStream &stream, QTextCodec *codec,
|
||||
Waypoint &waypoint)
|
||||
{
|
||||
RecordHeader rh;
|
||||
quint8 rs, s1;
|
||||
quint32 ds = 1;
|
||||
|
||||
rs = readRecordHeader(stream, rh);
|
||||
stream >> s1;
|
||||
if (s1 & 0x1) {
|
||||
QList<TranslatedString> obj;
|
||||
ds += readTranslatedObjects(stream, codec, obj);
|
||||
if (!obj.isEmpty())
|
||||
waypoint.setComment(obj.first().str());
|
||||
}
|
||||
if (s1 & 0x2) {
|
||||
QString str;
|
||||
ds += readString(stream, codec, str);
|
||||
if (!str.isEmpty())
|
||||
waypoint.setComment(str);
|
||||
}
|
||||
|
||||
if (ds != rh.size)
|
||||
stream.setStatus(QDataStream::ReadCorruptData);
|
||||
|
||||
return rs + rh.size;
|
||||
}
|
||||
|
||||
static quint32 readContact(QDataStream &stream, QTextCodec *codec,
|
||||
Waypoint &waypoint)
|
||||
{
|
||||
RecordHeader rh;
|
||||
quint8 rs;
|
||||
quint16 flags;
|
||||
quint32 ds = 2;
|
||||
QString str;
|
||||
QList<TranslatedString> obj;
|
||||
|
||||
rs = readRecordHeader(stream, rh);
|
||||
stream >> flags;
|
||||
|
||||
if (flags & 0x1) // phone
|
||||
ds += readString(stream, codec, str);
|
||||
if (flags & 0x2) // phone2
|
||||
ds += readString(stream, codec, str);
|
||||
if (flags & 0x4) // fax
|
||||
ds += readString(stream, codec, str);
|
||||
if (flags & 0x8) // mail
|
||||
ds += readString(stream, codec, str);
|
||||
if (flags & 0x10) { // web
|
||||
ds += readString(stream, codec, str);
|
||||
QUrl url(str);
|
||||
waypoint.addLink(Link(url.scheme().isEmpty()
|
||||
? "http://" + str : str, str));
|
||||
}
|
||||
if (flags & 0x20) // unknown
|
||||
ds += readTranslatedObjects(stream, codec, obj);
|
||||
|
||||
if (ds != rh.size)
|
||||
stream.setStatus(QDataStream::ReadCorruptData);
|
||||
|
||||
return rs + rh.size;
|
||||
}
|
||||
|
||||
static quint32 readAddress(QDataStream &stream, QTextCodec *codec,
|
||||
Waypoint &waypoint)
|
||||
{
|
||||
RecordHeader rh;
|
||||
quint8 rs;
|
||||
quint16 flags;
|
||||
quint32 ds = 2;
|
||||
QList<TranslatedString> obj;
|
||||
QString str;
|
||||
Address addr;
|
||||
|
||||
rs = readRecordHeader(stream, rh);
|
||||
stream >> flags;
|
||||
|
||||
if (flags & 0x1) {
|
||||
ds += readTranslatedObjects(stream, codec, obj);
|
||||
if (!obj.isEmpty())
|
||||
addr.setCity(obj.first().str());
|
||||
}
|
||||
if (flags & 0x2) {
|
||||
ds += readTranslatedObjects(stream, codec, obj);
|
||||
if (!obj.isEmpty())
|
||||
addr.setCountry(obj.first().str());
|
||||
}
|
||||
if (flags & 0x4) {
|
||||
ds += readTranslatedObjects(stream, codec, obj);
|
||||
if (!obj.isEmpty())
|
||||
addr.setState(obj.first().str());
|
||||
}
|
||||
if (flags & 0x8) {
|
||||
ds += readString(stream, codec, str);
|
||||
addr.setPostalCode(str);
|
||||
}
|
||||
if (flags & 0x10) {
|
||||
ds += readTranslatedObjects(stream, codec, obj);
|
||||
if (!obj.isEmpty())
|
||||
addr.setStreet(obj.first().str());
|
||||
}
|
||||
if (flags & 0x20) // unknown
|
||||
ds += readString(stream, codec, str);
|
||||
|
||||
waypoint.setAddress(addr);
|
||||
|
||||
if (ds != rh.size)
|
||||
stream.setStatus(QDataStream::ReadCorruptData);
|
||||
|
||||
return rs + rh.size;
|
||||
}
|
||||
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
|
||||
static const QTemporaryDir &tempDir()
|
||||
{
|
||||
static QTemporaryDir dir;
|
||||
return dir;
|
||||
}
|
||||
|
||||
static quint32 readImageInfo(QDataStream &stream, Waypoint &waypoint,
|
||||
const QString &fileName, int &imgId)
|
||||
{
|
||||
RecordHeader rh;
|
||||
quint8 rs, s1;
|
||||
quint32 size;
|
||||
|
||||
rs = readRecordHeader(stream, rh);
|
||||
stream >> s1 >> size;
|
||||
|
||||
QByteArray ba;
|
||||
ba.resize(size);
|
||||
stream.readRawData(ba.data(), ba.size());
|
||||
|
||||
if (tempDir().isValid()) {
|
||||
QBuffer buf(&ba);
|
||||
QImageReader ir(&buf);
|
||||
|
||||
QByteArray id(fileName.toUtf8() + QByteArray::number(imgId++));
|
||||
QFile imgFile(tempDir().path() + "/" + QString("%0.%1").arg(
|
||||
QCryptographicHash::hash(id, QCryptographicHash::Sha1).toHex(),
|
||||
QString(ir.format())));
|
||||
imgFile.open(QIODevice::WriteOnly);
|
||||
imgFile.write(ba);
|
||||
imgFile.close();
|
||||
|
||||
waypoint.addImage(ImageInfo(imgFile.fileName(), ir.size()));
|
||||
}
|
||||
|
||||
if (size + 5 != rh.size)
|
||||
stream.setStatus(QDataStream::ReadCorruptData);
|
||||
|
||||
return rs + rh.size;
|
||||
}
|
||||
#endif // QT_VERSION >= 5
|
||||
|
||||
static int speed(quint8 flags)
|
||||
{
|
||||
switch (flags >> 4) {
|
||||
case 0x8:
|
||||
return 40;
|
||||
case 0x9:
|
||||
return 30;
|
||||
case 0xA:
|
||||
return 50;
|
||||
case 0xB:
|
||||
return 70;
|
||||
case 0xC:
|
||||
return 80;
|
||||
case 0xD:
|
||||
return 90;
|
||||
case 0xE:
|
||||
return 100;
|
||||
case 0xF:
|
||||
return 120;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static quint32 readCamera(QDataStream &stream, QVector<Waypoint> &waypoints,
|
||||
QList<Area> &polygons)
|
||||
{
|
||||
RecordHeader rh;
|
||||
quint8 flags, type, s7, rs;
|
||||
qint32 top, right, bottom, left, lat, lon;
|
||||
quint32 ds = 15;
|
||||
|
||||
|
||||
rs = readRecordHeader(stream, rh);
|
||||
top = readInt24(stream);
|
||||
right = readInt24(stream);
|
||||
bottom = readInt24(stream);
|
||||
left = readInt24(stream);
|
||||
stream >> flags >> type >> s7;
|
||||
|
||||
if (s7) {
|
||||
quint32 skip = s7 + 2 + s7/4;
|
||||
stream.skipRawData(skip);
|
||||
lat = readInt24(stream);
|
||||
lon = readInt24(stream);
|
||||
ds += skip + 6;
|
||||
} else {
|
||||
quint8 s8;
|
||||
stream.skipRawData(9);
|
||||
stream >> s8;
|
||||
quint32 skip = 3 + s8 + s8/4;
|
||||
stream.skipRawData(skip);
|
||||
lat = readInt24(stream);
|
||||
lon = readInt24(stream);
|
||||
ds += skip + 16;
|
||||
}
|
||||
|
||||
waypoints.append(Coordinates(toWGS24(lon), toWGS24(lat)));
|
||||
|
||||
Area area;
|
||||
Polygon polygon;
|
||||
QVector<Coordinates> v(4);
|
||||
v[0] = Coordinates(toWGS24(left), toWGS24(top));
|
||||
v[1] = Coordinates(toWGS24(right), toWGS24(top));
|
||||
v[2] = Coordinates(toWGS24(right), toWGS24(bottom));
|
||||
v[3] = Coordinates(toWGS24(left), toWGS24(bottom));
|
||||
polygon.append(v);
|
||||
area.append(polygon);
|
||||
|
||||
switch (type) {
|
||||
case 8:
|
||||
area.setDescription(QString("%1 mi/h")
|
||||
.arg(speed(flags)));
|
||||
break;
|
||||
case 9:
|
||||
area.setDescription(QString("%1 km/h")
|
||||
.arg(speed(flags)));
|
||||
break;
|
||||
case 10:
|
||||
case 11:
|
||||
area.setDescription("Red light camera");
|
||||
break;
|
||||
}
|
||||
|
||||
polygons.append(area);
|
||||
|
||||
if (ds > rh.size)
|
||||
stream.setStatus(QDataStream::ReadCorruptData);
|
||||
else if (ds < rh.size)
|
||||
stream.skipRawData(rh.size - ds);
|
||||
|
||||
return rs + rh.size;
|
||||
}
|
||||
|
||||
static quint32 readPOI(QDataStream &stream, QTextCodec *codec,
|
||||
QVector<Waypoint> &waypoints, const QString &fileName, int &imgId)
|
||||
{
|
||||
RecordHeader rh;
|
||||
quint8 rs;
|
||||
quint32 ds;
|
||||
qint32 lat, lon;
|
||||
quint16 s3;
|
||||
QList<TranslatedString> obj;
|
||||
|
||||
rs = readRecordHeader(stream, rh);
|
||||
stream >> lat >> lon >> s3;
|
||||
stream.skipRawData(s3);
|
||||
ds = 10 + s3;
|
||||
ds += readTranslatedObjects(stream, codec, obj);
|
||||
|
||||
waypoints.append(Waypoint(Coordinates(toWGS32(lon), toWGS32(lat))));
|
||||
if (!obj.isEmpty())
|
||||
waypoints.last().setName(obj.first().str());
|
||||
|
||||
while (stream.status() == QDataStream::Ok && ds < rh.size) {
|
||||
switch(nextHeaderType(stream)) {
|
||||
case 10:
|
||||
ds += readDescription(stream, codec, waypoints.last());
|
||||
break;
|
||||
case 11:
|
||||
ds += readAddress(stream, codec, waypoints.last());
|
||||
break;
|
||||
case 12:
|
||||
ds += readContact(stream, codec, waypoints.last());
|
||||
break;
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
|
||||
case 13:
|
||||
ds += readImageInfo(stream, waypoints.last(), fileName, imgId);
|
||||
break;
|
||||
#endif // QT_VERSION >= 5
|
||||
case 14:
|
||||
ds += readNotes(stream, codec, waypoints.last());
|
||||
break;
|
||||
default:
|
||||
ds += skipRecord(stream);
|
||||
}
|
||||
}
|
||||
|
||||
if (ds != rh.size)
|
||||
stream.setStatus(QDataStream::ReadCorruptData);
|
||||
|
||||
return rs + rh.size;
|
||||
}
|
||||
|
||||
static quint32 readSpatialIndex(QDataStream &stream, QTextCodec *codec,
|
||||
QVector<Waypoint> &waypoints, QList<Area> &polygons, const QString &fileName,
|
||||
int &imgId)
|
||||
{
|
||||
RecordHeader rh;
|
||||
quint32 ds, s5;
|
||||
qint32 top, right, bottom, left;
|
||||
quint16 s6;
|
||||
quint8 rs;
|
||||
|
||||
rs = readRecordHeader(stream, rh);
|
||||
stream >> top >> right >> bottom >> left >> s5 >> s6;
|
||||
stream.skipRawData(s6);
|
||||
ds = 22 + s6;
|
||||
if (rh.flags & 0x8) {
|
||||
while (stream.status() == QDataStream::Ok && ds < rh.size) {
|
||||
switch(nextHeaderType(stream)) {
|
||||
case 2:
|
||||
ds += readPOI(stream, codec, waypoints, fileName, imgId);
|
||||
break;
|
||||
case 8:
|
||||
ds += readSpatialIndex(stream, codec, waypoints, polygons,
|
||||
fileName, imgId);
|
||||
break;
|
||||
case 19:
|
||||
ds += readCamera(stream, waypoints, polygons);
|
||||
break;
|
||||
default:
|
||||
ds += skipRecord(stream);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ds != rh.size)
|
||||
stream.setStatus(QDataStream::ReadCorruptData);
|
||||
|
||||
return rs + rh.size;
|
||||
}
|
||||
|
||||
static void readPOIDatabase(QDataStream &stream, QTextCodec *codec,
|
||||
QVector<Waypoint> &waypoints, QList<Area> &polygons, const QString &fileName,
|
||||
int &imgId)
|
||||
{
|
||||
RecordHeader rh;
|
||||
QList<TranslatedString> obj;
|
||||
quint32 ds;
|
||||
|
||||
readRecordHeader(stream, rh);
|
||||
ds = readTranslatedObjects(stream, codec, obj);
|
||||
ds += readSpatialIndex(stream, codec, waypoints, polygons, fileName, imgId);
|
||||
if (rh.flags & 0x8) {
|
||||
while (stream.status() == QDataStream::Ok && ds < rh.size) {
|
||||
switch(nextHeaderType(stream)) {
|
||||
case 5: // symbol
|
||||
case 7: // category
|
||||
default:
|
||||
ds += skipRecord(stream);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ds != rh.size)
|
||||
stream.setStatus(QDataStream::ReadCorruptData);
|
||||
}
|
||||
|
||||
bool GPIParser::readData(QDataStream &stream, QTextCodec *codec,
|
||||
QVector<Waypoint> &waypoints, QList<Area> &polygons, const QString &fileName)
|
||||
{
|
||||
int imgId = 0;
|
||||
|
||||
while (stream.status() == QDataStream::Ok) {
|
||||
switch (nextHeaderType(stream)) {
|
||||
case 0x09: // POI database
|
||||
readPOIDatabase(stream, codec, waypoints, polygons, fileName,
|
||||
imgId);
|
||||
break;
|
||||
case 0xffff: // EOF
|
||||
skipRecord(stream);
|
||||
if (stream.status() == QDataStream::Ok)
|
||||
return true;
|
||||
break;
|
||||
case 0x16: // route
|
||||
case 0x15: // info header
|
||||
default:
|
||||
skipRecord(stream);
|
||||
}
|
||||
}
|
||||
|
||||
_errorString = "Invalid/corrupted GPI data";
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GPIParser::readGPIHeader(QDataStream &stream, QTextCodec **codec)
|
||||
{
|
||||
RecordHeader rh;
|
||||
char m1[6], m2[2];
|
||||
quint16 codepage = 0;
|
||||
quint8 s2, s3;
|
||||
quint32 ds;
|
||||
|
||||
readRecordHeader(stream, rh);
|
||||
stream.readRawData(m1, sizeof(m1));
|
||||
stream.readRawData(m2, sizeof(m2));
|
||||
stream >> codepage >> s2 >> s3;
|
||||
ds = sizeof(m1) + sizeof(m2) + 4;
|
||||
|
||||
if (codepage == 65001)
|
||||
*codec = QTextCodec::codecForName("UTF-8");
|
||||
else if (codepage == 0)
|
||||
*codec = 0;
|
||||
else
|
||||
*codec = QTextCodec::codecForName(QString("CP%1").arg(codepage)
|
||||
.toLatin1());
|
||||
|
||||
if (s2 & 0x10)
|
||||
ds += readFileDataRecord(stream, *codec);
|
||||
|
||||
if (stream.status() != QDataStream::Ok || ds != rh.size) {
|
||||
_errorString = "Invalid GPI header";
|
||||
return false;
|
||||
} else
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GPIParser::readFileHeader(QDataStream &stream, quint32 &ebs)
|
||||
{
|
||||
RecordHeader rh;
|
||||
quint32 ds, s7;
|
||||
@ -326,10 +715,7 @@ bool GPIParser::readFileHeader(QDataStream &stream)
|
||||
if (rh.flags & 8)
|
||||
ds += readFprsRecord(stream);
|
||||
|
||||
if (s8 & 0x4) {
|
||||
_errorString = "Encrypted GPI files not supported";
|
||||
return false;
|
||||
}
|
||||
ebs = (s8 & 0x4) ? s9 * 8 + 8 : 0;
|
||||
|
||||
if (stream.status() != QDataStream::Ok || ds != rh.size) {
|
||||
_errorString = "Invalid file header";
|
||||
@ -338,109 +724,26 @@ bool GPIParser::readFileHeader(QDataStream &stream)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GPIParser::readGPIHeader(QDataStream &stream, QTextCodec *codec)
|
||||
{
|
||||
RecordHeader rh;
|
||||
char m1[6], m2[2];
|
||||
quint16 codepage = 0;
|
||||
quint8 s2, s3;
|
||||
quint32 ds;
|
||||
|
||||
readRecordHeader(stream, rh);
|
||||
stream.readRawData(m1, sizeof(m1));
|
||||
stream.readRawData(m2, sizeof(m2));
|
||||
stream >> codepage >> s2 >> s3;
|
||||
ds = sizeof(m1) + sizeof(m2) + 4;
|
||||
|
||||
if (codepage == 65001)
|
||||
codec = QTextCodec::codecForName("UTF-8");
|
||||
else if (codepage == 0)
|
||||
codec = 0;
|
||||
else
|
||||
codec = QTextCodec::codecForName(QString("CP%1").arg(codepage)
|
||||
.toLatin1());
|
||||
|
||||
if (s2 & 0x10)
|
||||
ds += readFileDataRecord(stream, codec);
|
||||
|
||||
if (stream.status() != QDataStream::Ok || ds != rh.size) {
|
||||
_errorString = "Invalid GPI header";
|
||||
return false;
|
||||
} else
|
||||
return true;
|
||||
}
|
||||
|
||||
void GPIParser::readPOIDatabase(QDataStream &stream, QTextCodec *codec,
|
||||
QVector<Waypoint> &waypoints)
|
||||
{
|
||||
RecordHeader rh;
|
||||
QList<TranslatedString> obj;
|
||||
quint32 ds;
|
||||
|
||||
readRecordHeader(stream, rh);
|
||||
ds = readTranslatedObjects(stream, codec, obj);
|
||||
ds += readSpatialIndex(stream, codec, waypoints);
|
||||
if (rh.flags & 0x8) {
|
||||
while (ds < rh.size) {
|
||||
switch(nextHeaderType(stream)) {
|
||||
case 5: // symbol
|
||||
case 7: // category
|
||||
default:
|
||||
ds += skipRecord(stream);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ds != rh.size)
|
||||
stream.setStatus(QDataStream::ReadCorruptData);
|
||||
}
|
||||
|
||||
bool GPIParser::readEntry(QDataStream &stream, QTextCodec *codec,
|
||||
QVector<Waypoint> &waypoints)
|
||||
{
|
||||
switch (nextHeaderType(stream)) {
|
||||
case 0x09: // POI database
|
||||
readPOIDatabase(stream, codec, waypoints);
|
||||
break;
|
||||
case 0xffff: // EOF
|
||||
skipRecord(stream);
|
||||
return false;
|
||||
case 0x16: // route
|
||||
case 0x15: // info header
|
||||
default:
|
||||
skipRecord(stream);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GPIParser::readData(QDataStream &stream, QTextCodec *codec,
|
||||
QVector<Waypoint> &waypoints)
|
||||
{
|
||||
while (stream.status() == QDataStream::Ok)
|
||||
if (!readEntry(stream, codec, waypoints))
|
||||
return stream.atEnd();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool GPIParser::parse(QFile *file, QList<TrackData> &tracks,
|
||||
QList<RouteData> &routes, QList<Area> &polygons, QVector<Waypoint> &waypoints)
|
||||
{
|
||||
Q_UNUSED(tracks);
|
||||
Q_UNUSED(routes);
|
||||
Q_UNUSED(polygons);
|
||||
QDataStream stream(file);
|
||||
QTextCodec *codec = 0;
|
||||
quint32 ebs;
|
||||
|
||||
stream.setByteOrder(QDataStream::LittleEndian);
|
||||
|
||||
if (!readFileHeader(stream) || !readGPIHeader(stream, codec))
|
||||
if (!readFileHeader(stream, ebs) || !readGPIHeader(stream, &codec))
|
||||
return false;
|
||||
|
||||
if (!readData(stream, codec, waypoints)) {
|
||||
_errorString = "Invalid/corrupted GPI data";
|
||||
return false;
|
||||
if (ebs) {
|
||||
CryptDevice dev(stream.device(), 0xf870b5, ebs);
|
||||
QDataStream cryptStream(&dev);
|
||||
cryptStream.setByteOrder(QDataStream::LittleEndian);
|
||||
return readData(cryptStream, codec, waypoints, polygons,
|
||||
file->fileName());
|
||||
} else
|
||||
return true;
|
||||
return readData(stream, codec, waypoints, polygons, file->fileName());
|
||||
}
|
||||
|
@ -15,14 +15,11 @@ public:
|
||||
int errorLine() const {return 0;}
|
||||
|
||||
private:
|
||||
bool readFileHeader(QDataStream &stream);
|
||||
bool readGPIHeader(QDataStream &stream, QTextCodec *codec);
|
||||
bool readFileHeader(QDataStream &stream, quint32 &ebs);
|
||||
bool readGPIHeader(QDataStream &stream, QTextCodec **codec);
|
||||
bool readData(QDataStream &stream, QTextCodec *codec,
|
||||
QVector<Waypoint> &waypoints);
|
||||
bool readEntry(QDataStream &stream, QTextCodec *codec,
|
||||
QVector<Waypoint> &waypoints);
|
||||
void readPOIDatabase(QDataStream &stream, QTextCodec *codec,
|
||||
QVector<Waypoint> &waypoints);
|
||||
QVector<Waypoint> &waypoints, QList<Area> &polygons,
|
||||
const QString &fileName);
|
||||
|
||||
QString _errorString;
|
||||
};
|
||||
|
@ -69,8 +69,10 @@ Coordinates GPXParser::coordinates()
|
||||
void GPXParser::rpExtension(SegmentData *autoRoute)
|
||||
{
|
||||
while (_reader.readNextStartElement()) {
|
||||
if (_reader.name() == QLatin1String("rpt"))
|
||||
autoRoute->append(Trackpoint(coordinates()));
|
||||
if (_reader.name() == QLatin1String("rpt")) {
|
||||
if (autoRoute)
|
||||
autoRoute->append(Trackpoint(coordinates()));
|
||||
}
|
||||
_reader.skipCurrentElement();
|
||||
}
|
||||
}
|
||||
@ -91,11 +93,45 @@ void GPXParser::tpExtension(Trackpoint &trackpoint)
|
||||
}
|
||||
}
|
||||
|
||||
void GPXParser::rteptExtensions(SegmentData *autoRoute)
|
||||
void GPXParser::address(Waypoint &waypoint)
|
||||
{
|
||||
Address addr;
|
||||
|
||||
while (_reader.readNextStartElement()) {
|
||||
if (_reader.name() == QLatin1String("StreetAddress"))
|
||||
addr.setStreet(_reader.readElementText());
|
||||
else if (_reader.name() == QLatin1String("City"))
|
||||
addr.setCity(_reader.readElementText());
|
||||
else if (_reader.name() == QLatin1String("PostalCode"))
|
||||
addr.setPostalCode(_reader.readElementText());
|
||||
else if (_reader.name() == QLatin1String("State"))
|
||||
addr.setState(_reader.readElementText());
|
||||
else if (_reader.name() == QLatin1String("Country"))
|
||||
addr.setCountry(_reader.readElementText());
|
||||
else
|
||||
_reader.skipCurrentElement();
|
||||
}
|
||||
|
||||
waypoint.setAddress(addr);
|
||||
}
|
||||
|
||||
void GPXParser::wpExtension(Waypoint &waypoint)
|
||||
{
|
||||
while (_reader.readNextStartElement()) {
|
||||
if (_reader.name() == QLatin1String("Address"))
|
||||
address(waypoint);
|
||||
else
|
||||
_reader.skipCurrentElement();
|
||||
}
|
||||
}
|
||||
|
||||
void GPXParser::waypointExtensions(Waypoint &waypoint, SegmentData *autoRoute)
|
||||
{
|
||||
while (_reader.readNextStartElement()) {
|
||||
if (_reader.name() == QLatin1String("RoutePointExtension"))
|
||||
rpExtension(autoRoute);
|
||||
else if (_reader.name() == QLatin1String("WaypointExtension"))
|
||||
wpExtension(waypoint);
|
||||
else
|
||||
_reader.skipCurrentElement();
|
||||
}
|
||||
@ -156,6 +192,8 @@ void GPXParser::waypointData(Waypoint &waypoint, SegmentData *autoRoute)
|
||||
waypoint.setName(_reader.readElementText());
|
||||
else if (_reader.name() == QLatin1String("desc"))
|
||||
waypoint.setDescription(_reader.readElementText());
|
||||
else if (_reader.name() == QLatin1String("cmt"))
|
||||
waypoint.setComment(_reader.readElementText());
|
||||
else if (_reader.name() == QLatin1String("ele"))
|
||||
waypoint.setElevation(number());
|
||||
else if (_reader.name() == QLatin1String("geoidheight"))
|
||||
@ -170,8 +208,8 @@ void GPXParser::waypointData(Waypoint &waypoint, SegmentData *autoRoute)
|
||||
link10.setURL(_reader.readElementText());
|
||||
else if (_reader.name() == QLatin1String("urlname"))
|
||||
link10.setText(_reader.readElementText());
|
||||
else if (autoRoute && _reader.name() == QLatin1String("extensions"))
|
||||
rteptExtensions(autoRoute);
|
||||
else if (_reader.name() == QLatin1String("extensions"))
|
||||
waypointExtensions(waypoint, autoRoute);
|
||||
else
|
||||
_reader.skipCurrentElement();
|
||||
}
|
||||
@ -208,6 +246,8 @@ void GPXParser::routepoints(RouteData &route, QList<TrackData> &tracks)
|
||||
route.setName(_reader.readElementText());
|
||||
else if (_reader.name() == QLatin1String("desc"))
|
||||
route.setDescription(_reader.readElementText());
|
||||
else if (_reader.name() == QLatin1String("cmt"))
|
||||
route.setComment(_reader.readElementText());
|
||||
else if (_reader.name() == QLatin1String("link")) {
|
||||
Link l(link());
|
||||
if (!l.URL().isEmpty())
|
||||
@ -242,6 +282,8 @@ void GPXParser::track(TrackData &track)
|
||||
track.setName(_reader.readElementText());
|
||||
else if (_reader.name() == QLatin1String("desc"))
|
||||
track.setDescription(_reader.readElementText());
|
||||
else if (_reader.name() == QLatin1String("cmt"))
|
||||
track.setComment(_reader.readElementText());
|
||||
else if (_reader.name() == QLatin1String("link")) {
|
||||
Link l(link());
|
||||
if (!l.URL().isEmpty())
|
||||
|
@ -21,11 +21,13 @@ private:
|
||||
void rpExtension(SegmentData *autoRoute);
|
||||
void tpExtension(Trackpoint &trackpoint);
|
||||
void trkptExtensions(Trackpoint &trackpoint);
|
||||
void rteptExtensions(SegmentData *autoRoute);
|
||||
void wpExtension(Waypoint &waypoint);
|
||||
void waypointExtensions(Waypoint &waypoint, SegmentData *autoRoute);
|
||||
void area(Area &area);
|
||||
void gpxExtensions(QList<Area> &areas);
|
||||
void trackpointData(Trackpoint &trackpoint);
|
||||
void waypointData(Waypoint &waypoint, SegmentData *autoRoute = 0);
|
||||
void address(Waypoint &waypoint);
|
||||
qreal number();
|
||||
QDateTime time();
|
||||
Coordinates coordinates();
|
||||
|
@ -67,4 +67,17 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
class GraphPair
|
||||
{
|
||||
public:
|
||||
GraphPair(const Graph &primary, const Graph &secondary)
|
||||
: _primary(primary), _secondary(secondary) {}
|
||||
|
||||
const Graph &primary() const {return _primary;}
|
||||
const Graph &secondary() const {return _secondary;}
|
||||
|
||||
private:
|
||||
Graph _primary, _secondary;
|
||||
};
|
||||
|
||||
#endif // GRAPH_H
|
||||
|
@ -87,16 +87,18 @@ static bool readTimestamp(const char *data, QTime &time)
|
||||
|
||||
static bool readARecord(const char *line, qint64 len)
|
||||
{
|
||||
if (len < 7 || line[0] != 'A')
|
||||
/* The minimal A record length should be 7 according to the specification,
|
||||
but records with length of 6 exist in the wild */
|
||||
if (len < 6 || line[0] != 'A')
|
||||
return false;
|
||||
|
||||
for (int i = 1; i < 7; i++)
|
||||
for (int i = 1; i < 6; i++)
|
||||
if (!::isprint(line[i]))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IGCParser::readHRecord(const char *line, int len)
|
||||
bool IGCParser::readHRecord(CTX &ctx, const char *line, int len)
|
||||
{
|
||||
if (len < 11 || ::strncmp(line, "HFDTE", 5))
|
||||
return true;
|
||||
@ -112,9 +114,9 @@ bool IGCParser::readHRecord(const char *line, int len)
|
||||
return false;
|
||||
}
|
||||
|
||||
_date = QDate(y + 2000 <= QDate::currentDate().year() ? 2000 + y : 1900 + y,
|
||||
m, d);
|
||||
if (!_date.isValid()) {
|
||||
ctx.date = QDate(y + 2000 <= QDate::currentDate().year()
|
||||
? 2000 + y : 1900 + y, m, d);
|
||||
if (!ctx.date.isValid()) {
|
||||
_errorString = "Invalid date";
|
||||
return false;
|
||||
}
|
||||
@ -122,8 +124,8 @@ bool IGCParser::readHRecord(const char *line, int len)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IGCParser::readBRecord(SegmentData &segment, const char *line,
|
||||
int len)
|
||||
bool IGCParser::readBRecord(CTX &ctx, const char *line, int len,
|
||||
SegmentData &segment)
|
||||
{
|
||||
qreal lat, lon, ele;
|
||||
QTime time;
|
||||
@ -152,20 +154,20 @@ bool IGCParser::readBRecord(SegmentData &segment, const char *line,
|
||||
return false;
|
||||
}
|
||||
|
||||
if (time < _time && !segment.isEmpty()
|
||||
&& _date == segment.last().timestamp().date())
|
||||
_date = _date.addDays(1);
|
||||
_time = time;
|
||||
if (time < ctx.time && !segment.isEmpty()
|
||||
&& ctx.date == segment.last().timestamp().date())
|
||||
ctx.date = ctx.date.addDays(1);
|
||||
ctx.time = time;
|
||||
|
||||
Trackpoint t(Coordinates(lon, lat));
|
||||
t.setTimestamp(QDateTime(_date, _time, Qt::UTC));
|
||||
t.setTimestamp(QDateTime(ctx.date, ctx.time, Qt::UTC));
|
||||
t.setElevation(ele);
|
||||
segment.append(t);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IGCParser::readCRecord(RouteData &route, const char *line, int len)
|
||||
bool IGCParser::readCRecord(const char *line, int len, RouteData &route)
|
||||
{
|
||||
qreal lat, lon;
|
||||
|
||||
@ -202,6 +204,7 @@ bool IGCParser::parse(QFile *file, QList<TrackData> &tracks,
|
||||
qint64 len;
|
||||
char line[76 + 2 + 1 + 1];
|
||||
bool route = false, track = false;
|
||||
CTX ctx;
|
||||
|
||||
|
||||
_errorLine = 1;
|
||||
@ -225,28 +228,28 @@ bool IGCParser::parse(QFile *file, QList<TrackData> &tracks,
|
||||
}
|
||||
} else {
|
||||
if (line[0] == 'H') {
|
||||
if (!readHRecord(line, len))
|
||||
if (!readHRecord(ctx, line, len))
|
||||
return false;
|
||||
} else if (line[0] == 'C') {
|
||||
if (route) {
|
||||
if (!readCRecord(routes.last() ,line, len))
|
||||
if (!readCRecord(line, len, routes.last()))
|
||||
return false;
|
||||
} else {
|
||||
route = true;
|
||||
routes.append(RouteData());
|
||||
}
|
||||
} else if (line[0] == 'B') {
|
||||
if (_date.isNull()) {
|
||||
if (ctx.date.isNull()) {
|
||||
_errorString = "Missing date header";
|
||||
return false;
|
||||
}
|
||||
if (!track) {
|
||||
tracks.append(TrackData());
|
||||
tracks.last().append(SegmentData());
|
||||
_time = QTime(0, 0);
|
||||
ctx.time = QTime(0, 0);
|
||||
track = true;
|
||||
}
|
||||
if (!readBRecord(tracks.last().last(), line, len))
|
||||
if (!readBRecord(ctx, line, len, tracks.last().last()))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -17,15 +17,17 @@ public:
|
||||
int errorLine() const {return _errorLine;}
|
||||
|
||||
private:
|
||||
bool readHRecord(const char *line, int len);
|
||||
bool readBRecord(SegmentData &segment, const char *line, int len);
|
||||
bool readCRecord(RouteData &route, const char *line, int len);
|
||||
struct CTX {
|
||||
QDate date;
|
||||
QTime time;
|
||||
};
|
||||
|
||||
bool readHRecord(CTX &ctx, const char *line, int len);
|
||||
bool readBRecord(CTX &ctx, const char *line, int len, SegmentData &segment);
|
||||
bool readCRecord(const char *line, int len, RouteData &route);
|
||||
|
||||
int _errorLine;
|
||||
QString _errorString;
|
||||
|
||||
QDate _date;
|
||||
QTime _time;
|
||||
};
|
||||
|
||||
#endif // IGCPARSER_H
|
||||
|
@ -585,7 +585,9 @@ void KMLParser::document(QList<TrackData> &tracks, QList<Area> &areas,
|
||||
QVector<Waypoint> &waypoints)
|
||||
{
|
||||
while (_reader.readNextStartElement()) {
|
||||
if (_reader.name() == QLatin1String("Placemark"))
|
||||
if (_reader.name() == QLatin1String("Document"))
|
||||
document(tracks, areas, waypoints);
|
||||
else if (_reader.name() == QLatin1String("Placemark"))
|
||||
placemark(tracks, areas, waypoints);
|
||||
else if (_reader.name() == QLatin1String("Folder"))
|
||||
folder(tracks, areas, waypoints);
|
||||
|
@ -7,15 +7,15 @@ class Link {
|
||||
public:
|
||||
Link() {}
|
||||
Link(const QString &URL, const QString &text = QString())
|
||||
: _URL(URL), _text(text) {}
|
||||
: _url(URL), _text(text) {}
|
||||
|
||||
void setURL(const QString &URL) {_URL = URL;}
|
||||
void setURL(const QString &URL) {_url = URL;}
|
||||
void setText(const QString &text) {_text = text;}
|
||||
const QString &URL() const {return _URL;}
|
||||
const QString &URL() const {return _url;}
|
||||
const QString &text() const {return _text;}
|
||||
|
||||
private:
|
||||
QString _URL;
|
||||
QString _url;
|
||||
QString _text;
|
||||
};
|
||||
|
||||
|
@ -227,7 +227,8 @@ bool NMEAParser::readEW(const char *data, int len, qreal &lon)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NMEAParser::readRMC(SegmentData &segment, const char *line, int len)
|
||||
bool NMEAParser::readRMC(CTX &ctx, const char *line, int len,
|
||||
SegmentData &segment)
|
||||
{
|
||||
int col = 1;
|
||||
const char *vp = line;
|
||||
@ -280,23 +281,24 @@ bool NMEAParser::readRMC(SegmentData &segment, const char *line, int len)
|
||||
}
|
||||
|
||||
if (!date.isNull()) {
|
||||
if (_date.isNull() && !_time.isNull() && !segment.isEmpty())
|
||||
segment.last().setTimestamp(QDateTime(date, _time, Qt::UTC));
|
||||
_date = date;
|
||||
if (ctx.date.isNull() && !ctx.time.isNull() && !segment.isEmpty())
|
||||
segment.last().setTimestamp(QDateTime(date, ctx.time, Qt::UTC));
|
||||
ctx.date = date;
|
||||
}
|
||||
|
||||
Coordinates c(lon, lat);
|
||||
if (valid && !_GGA && c.isValid()) {
|
||||
if (valid && !ctx.GGA && c.isValid()) {
|
||||
Trackpoint t(c);
|
||||
if (!_date.isNull() && !time.isNull())
|
||||
t.setTimestamp(QDateTime(_date, time, Qt::UTC));
|
||||
if (!ctx.date.isNull() && !time.isNull())
|
||||
t.setTimestamp(QDateTime(ctx.date, time, Qt::UTC));
|
||||
segment.append(t);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NMEAParser::readGGA(SegmentData &segment, const char *line, int len)
|
||||
bool NMEAParser::readGGA(CTX &ctx, const char *line, int len,
|
||||
SegmentData &segment)
|
||||
{
|
||||
int col = 1;
|
||||
const char *vp = line;
|
||||
@ -306,7 +308,7 @@ bool NMEAParser::readGGA(SegmentData &segment, const char *line, int len)
|
||||
if (*lp == ',' || *lp == '*') {
|
||||
switch (col) {
|
||||
case 1:
|
||||
if (!readTime(vp, lp - vp, _time))
|
||||
if (!readTime(vp, lp - vp, ctx.time))
|
||||
return false;
|
||||
break;
|
||||
case 2:
|
||||
@ -360,19 +362,19 @@ bool NMEAParser::readGGA(SegmentData &segment, const char *line, int len)
|
||||
Coordinates c(lon, lat);
|
||||
if (c.isValid()) {
|
||||
Trackpoint t(c);
|
||||
if (!(_time.isNull() || _date.isNull()))
|
||||
t.setTimestamp(QDateTime(_date, _time, Qt::UTC));
|
||||
if (!(ctx.time.isNull() || ctx.date.isNull()))
|
||||
t.setTimestamp(QDateTime(ctx.date, ctx.time, Qt::UTC));
|
||||
if (!std::isnan(ele))
|
||||
t.setElevation(ele - gh);
|
||||
segment.append(t);
|
||||
|
||||
_GGA = true;
|
||||
ctx.GGA = true;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NMEAParser::readWPL(QVector<Waypoint> &waypoints, const char *line, int len)
|
||||
bool NMEAParser::readWPL(const char *line, int len, QVector<Waypoint> &waypoints)
|
||||
{
|
||||
int col = 1;
|
||||
const char *vp = line;
|
||||
@ -423,7 +425,7 @@ bool NMEAParser::readWPL(QVector<Waypoint> &waypoints, const char *line, int len
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NMEAParser::readZDA(const char *line, int len)
|
||||
bool NMEAParser::readZDA(CTX &ctx, const char *line, int len)
|
||||
{
|
||||
int col = 1;
|
||||
const char *vp = line;
|
||||
@ -468,8 +470,8 @@ bool NMEAParser::readZDA(const char *line, int len)
|
||||
return false;
|
||||
}
|
||||
|
||||
_date = QDate(y, m, d);
|
||||
if (!_date.isValid()) {
|
||||
ctx.date = QDate(y, m, d);
|
||||
if (!ctx.date.isValid()) {
|
||||
_errorString = "Invalid date";
|
||||
return false;
|
||||
}
|
||||
@ -486,13 +488,11 @@ bool NMEAParser::parse(QFile *file, QList<TrackData> &tracks,
|
||||
qint64 len;
|
||||
char line[80 + 2 + 1 + 1];
|
||||
SegmentData segment;
|
||||
CTX ctx;
|
||||
|
||||
|
||||
_errorLine = 1;
|
||||
_errorString.clear();
|
||||
_date = QDate();
|
||||
_time = QTime();
|
||||
_GGA = false;
|
||||
|
||||
while (!file->atEnd()) {
|
||||
len = file->readLine(line, sizeof(line));
|
||||
@ -507,16 +507,16 @@ bool NMEAParser::parse(QFile *file, QList<TrackData> &tracks,
|
||||
|
||||
if (validSentence(line, len)) {
|
||||
if (!memcmp(line + 3, "RMC,", 4)) {
|
||||
if (!readRMC(segment, line + 7, len - 7))
|
||||
if (!readRMC(ctx, line + 7, len - 7, segment))
|
||||
return false;
|
||||
} else if (!memcmp(line + 3, "GGA,", 4)) {
|
||||
if (!readGGA(segment, line + 7, len - 7))
|
||||
if (!readGGA(ctx, line + 7, len - 7, segment))
|
||||
return false;
|
||||
} else if (!memcmp(line + 3, "WPL,", 4)) {
|
||||
if (!readWPL(waypoints, line + 7, len - 7))
|
||||
if (!readWPL(line + 7, len - 7, waypoints))
|
||||
return false;
|
||||
} else if (!memcmp(line + 3, "ZDA,", 4)) {
|
||||
if (!readZDA(line + 7, len - 7))
|
||||
if (!readZDA(ctx, line + 7, len - 7))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user