mirror of
https://github.com/tumic0/GPXSee.git
synced 2025-07-14 10:54:24 +02:00
Compare commits
86 Commits
Author | SHA1 | Date | |
---|---|---|---|
0c434106af | |||
b938e24d65 | |||
1d65e32335 | |||
6be33a1fc1 | |||
660fdde8c2 | |||
d50ab8607e | |||
3709a3feb5 | |||
a073c93e0d | |||
f934df59e4 | |||
394fcf6d4d | |||
0e1584ea24 | |||
c592be7cfd | |||
c84d7871fb | |||
34669b68f5 | |||
849eaa57cc | |||
7f6ac2e4c3 | |||
5407fe35e6 | |||
133aac3bd4 | |||
a5cd05233c | |||
22b691252f | |||
988ea7d952 | |||
c253669017 | |||
37d8aadfed | |||
ae204e9ddf | |||
07410ad7d5 | |||
98b56485bd | |||
302fe4d8e1 | |||
045dab6cdd | |||
da522cd2ba | |||
38322f09a6 | |||
7803340c0e | |||
2232b011a1 | |||
94a0158243 | |||
018d0ba085 | |||
d5a472ddc0 | |||
09a6d8655e | |||
1d2b93466f | |||
9979a8b233 | |||
ef6f3a0516 | |||
4f81e120b7 | |||
ed68cbd891 | |||
a4c7449772 | |||
60d82c9b7b | |||
fe288a4fea | |||
9f95ded407 | |||
1241b71475 | |||
48a7ecb83e | |||
62a60723be | |||
b7ee1ac660 | |||
9f6ced0342 | |||
814eceb82c | |||
445598cd52 | |||
eab43332ee | |||
94571ccfc6 | |||
accea5d9da | |||
8d8a31eef9 | |||
221d1b3fdb | |||
ab062cc3ff | |||
78e8b03d66 | |||
82d2ac0871 | |||
0b3e35db72 | |||
0c4e5b0017 | |||
933f2c3837 | |||
6e4cc406ab | |||
21ce65146a | |||
c99adfd6d2 | |||
c537f1ba6c | |||
4e36d8633c | |||
8beeeb7526 | |||
69cc6ccb75 | |||
f042f11eed | |||
f72835f05e | |||
c8779b4592 | |||
4b30e665cc | |||
ac45ccaab6 | |||
6d2182eb46 | |||
50aea76bf7 | |||
7676a21fc3 | |||
dc6a57338e | |||
fa3fac5314 | |||
a53fedf838 | |||
4d284ad0e5 | |||
3f3ccb6856 | |||
2ea16eaaab | |||
effb0bb654 | |||
8bd08b31a3 |
@ -1,4 +1,4 @@
|
||||
version: 9.3.{build}
|
||||
version: 9.6.{build}
|
||||
|
||||
configuration:
|
||||
- Release
|
||||
@ -30,43 +30,29 @@ environment:
|
||||
NSISDEF: /DQT6
|
||||
|
||||
install:
|
||||
- cmd: >-
|
||||
- cmd: |-
|
||||
set PATH=%QTDIR%\bin;%NSISDIR%;%PATH%
|
||||
|
||||
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\"%VCVARS%
|
||||
|
||||
build_script:
|
||||
- cmd: >-
|
||||
- cmd: |-
|
||||
lrelease gpxsee.pro
|
||||
|
||||
qmake gpxsee.pro
|
||||
|
||||
nmake release
|
||||
|
||||
|
||||
md installer
|
||||
|
||||
copy release\GPXSee.exe installer
|
||||
|
||||
windeployqt --release installer\GPXSee.exe
|
||||
|
||||
copy pkg\%NSI% installer
|
||||
|
||||
copy pkg\macros.nsh installer
|
||||
|
||||
xcopy pkg\csv installer\csv /i
|
||||
|
||||
xcopy pkg\maps installer\maps /i
|
||||
|
||||
xcopy lang\*.qm installer\translations\ /sy
|
||||
|
||||
copy licence.txt installer
|
||||
|
||||
copy %OPENSSLDIR%\%LIBCRYPTO% installer
|
||||
|
||||
copy %OPENSSLDIR%\%LIBSSL% installer
|
||||
|
||||
|
||||
makensis.exe %NSISDEF% installer\%NSI%
|
||||
|
||||
artifacts:
|
||||
- path: installer\GPXSee-*.exe
|
||||
|
24
.travis.yml
24
.travis.yml
@ -5,15 +5,25 @@ os:
|
||||
- osx
|
||||
|
||||
dist: focal
|
||||
osx_image: xcode12
|
||||
osx_image: xcode12.5
|
||||
|
||||
before_install:
|
||||
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo apt-get -qq update; fi
|
||||
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update; fi
|
||||
cache:
|
||||
directories:
|
||||
- $HOME/Library/Caches/Homebrew
|
||||
|
||||
install:
|
||||
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install qt; fi
|
||||
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo apt-get install qtbase5-dev qtbase5-private-dev libqt5opengl5-dev qttools5-dev-tools; fi
|
||||
before_cache:
|
||||
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew cleanup; fi
|
||||
|
||||
addons:
|
||||
homebrew:
|
||||
packages:
|
||||
- qt
|
||||
apt:
|
||||
packages:
|
||||
- qtbase5-dev
|
||||
- qtbase5-private-dev
|
||||
- libqt5opengl5-dev
|
||||
- qttools5-dev-tools
|
||||
|
||||
script:
|
||||
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then PATH=/usr/local/opt/qt/bin/:${PATH}; fi
|
||||
|
@ -2,7 +2,7 @@
|
||||
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, SIGMA SLF, Suunto SML, LOC, GeoJSON, OziExplorer (PLT, RTE, WPT), Garmin GPI&CSV, TomTom OV2&ITN 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, TomTom OV2&ITN, ONmove OMD/GHP 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/GMAP & JNX maps, TwoNav RMaps, GeoTIFF images, BSB charts, KMZ maps, AlpineQuest maps, Locus/OsmAnd/RMaps SQLite maps, Mapsforge vector maps, ESRI World-File georeferenced images).
|
||||
* Elevation, speed, heart rate, cadence, power, temperature and gear ratio/shifts graphs.
|
||||
|
27
gpxsee.pro
27
gpxsee.pro
@ -3,7 +3,7 @@ unix:!macx {
|
||||
} else {
|
||||
TARGET = GPXSee
|
||||
}
|
||||
VERSION = 9.3
|
||||
VERSION = 9.6
|
||||
|
||||
QT += core \
|
||||
gui \
|
||||
@ -18,9 +18,12 @@ greaterThan(QT_MAJOR_VERSION, 5) {QT += openglwidgets}
|
||||
CONFIG += object_parallel_to_source
|
||||
INCLUDEPATH += ./src
|
||||
HEADERS += src/common/config.h \
|
||||
src/GUI/authenticationwidget.h \
|
||||
src/GUI/axislabelitem.h \
|
||||
src/GUI/dirselectwidget.h \
|
||||
src/GUI/flowlayout.h \
|
||||
src/GUI/graphicsscene.h \
|
||||
src/GUI/infolabel.h \
|
||||
src/GUI/mapaction.h \
|
||||
src/GUI/mapitem.h \
|
||||
src/GUI/marginswidget.h \
|
||||
@ -28,6 +31,7 @@ HEADERS += src/common/config.h \
|
||||
src/GUI/planeitem.h \
|
||||
src/GUI/poiaction.h \
|
||||
src/GUI/popup.h \
|
||||
src/GUI/thumbnail.h \
|
||||
src/common/garmin.h \
|
||||
src/common/coordinates.h \
|
||||
src/common/range.h \
|
||||
@ -41,6 +45,7 @@ HEADERS += src/common/config.h \
|
||||
src/common/greatcircle.h \
|
||||
src/common/programpaths.h \
|
||||
src/common/tifffile.h \
|
||||
src/common/downloader.h \
|
||||
src/GUI/app.h \
|
||||
src/GUI/icons.h \
|
||||
src/GUI/gui.h \
|
||||
@ -93,6 +98,7 @@ HEADERS += src/common/config.h \
|
||||
src/GUI/areaitem.h \
|
||||
src/data/itnparser.h \
|
||||
src/data/link.h \
|
||||
src/data/onmoveparsers.h \
|
||||
src/data/ov2parser.h \
|
||||
src/map/IMG/bitmapline.h \
|
||||
src/map/IMG/bitstream.h \
|
||||
@ -132,7 +138,6 @@ HEADERS += src/common/config.h \
|
||||
src/map/map.h \
|
||||
src/map/maplist.h \
|
||||
src/map/onlinemap.h \
|
||||
src/map/downloader.h \
|
||||
src/map/tile.h \
|
||||
src/map/emptymap.h \
|
||||
src/map/ozimap.h \
|
||||
@ -191,6 +196,7 @@ HEADERS += src/common/config.h \
|
||||
src/data/locparser.h \
|
||||
src/data/slfparser.h \
|
||||
src/data/dem.h \
|
||||
src/data/demloader.h \
|
||||
src/common/polygon.h \
|
||||
src/data/area.h \
|
||||
src/map/obliquestereographic.h \
|
||||
@ -228,12 +234,16 @@ HEADERS += src/common/config.h \
|
||||
src/map/worldfilemap.h
|
||||
|
||||
SOURCES += src/main.cpp \
|
||||
src/GUI/authenticationwidget.cpp \
|
||||
src/GUI/axislabelitem.cpp \
|
||||
src/GUI/dirselectwidget.cpp \
|
||||
src/GUI/flowlayout.cpp \
|
||||
src/GUI/infolabel.cpp \
|
||||
src/GUI/mapitem.cpp \
|
||||
src/GUI/marginswidget.cpp \
|
||||
src/GUI/markerinfoitem.cpp \
|
||||
src/GUI/popup.cpp \
|
||||
src/GUI/thumbnail.cpp \
|
||||
src/common/coordinates.cpp \
|
||||
src/common/rectc.cpp \
|
||||
src/common/range.cpp \
|
||||
@ -242,6 +252,7 @@ SOURCES += src/main.cpp \
|
||||
src/common/greatcircle.cpp \
|
||||
src/common/programpaths.cpp \
|
||||
src/common/tifffile.cpp \
|
||||
src/common/downloader.cpp \
|
||||
src/GUI/app.cpp \
|
||||
src/GUI/gui.cpp \
|
||||
src/GUI/axisitem.cpp \
|
||||
@ -261,7 +272,6 @@ SOURCES += src/main.cpp \
|
||||
src/GUI/fileselectwidget.cpp \
|
||||
src/GUI/temperaturegraph.cpp \
|
||||
src/GUI/trackitem.cpp \
|
||||
src/GUI/tooltip.cpp \
|
||||
src/GUI/routeitem.cpp \
|
||||
src/GUI/graphitem.cpp \
|
||||
src/GUI/pathitem.cpp \
|
||||
@ -286,6 +296,7 @@ SOURCES += src/main.cpp \
|
||||
src/GUI/areaitem.cpp \
|
||||
src/data/address.cpp \
|
||||
src/data/itnparser.cpp \
|
||||
src/data/onmoveparsers.cpp \
|
||||
src/data/ov2parser.cpp \
|
||||
src/data/waypoint.cpp \
|
||||
src/map/IMG/bitmapline.cpp \
|
||||
@ -310,7 +321,6 @@ SOURCES += src/main.cpp \
|
||||
src/map/kmzmap.cpp \
|
||||
src/map/maplist.cpp \
|
||||
src/map/onlinemap.cpp \
|
||||
src/map/downloader.cpp \
|
||||
src/map/emptymap.cpp \
|
||||
src/map/ozimap.cpp \
|
||||
src/map/polyconic.cpp \
|
||||
@ -372,6 +382,7 @@ SOURCES += src/main.cpp \
|
||||
src/data/locparser.cpp \
|
||||
src/data/slfparser.cpp \
|
||||
src/data/dem.cpp \
|
||||
src/data/demloader.cpp \
|
||||
src/map/obliquestereographic.cpp \
|
||||
src/GUI/coordinatesitem.cpp \
|
||||
src/map/rmap.cpp \
|
||||
@ -473,7 +484,9 @@ macx {
|
||||
icons/formats/sqlt.icns \
|
||||
icons/formats/ov2.icns \
|
||||
icons/formats/itn.icns \
|
||||
icons/formats/wld.icns
|
||||
icons/formats/wld.icns \
|
||||
icons/formats/omd.icns \
|
||||
icons/formats/ghp.icns
|
||||
QMAKE_BUNDLE_DATA += locale maps icons csv
|
||||
}
|
||||
|
||||
@ -505,7 +518,9 @@ win32 {
|
||||
icons/formats/sqlt.ico \
|
||||
icons/formats/ov2.ico \
|
||||
icons/formats/itn.ico \
|
||||
icons/formats/wld.ico
|
||||
icons/formats/wld.ico \
|
||||
icons/formats/omd.ico \
|
||||
icons/formats/ghp.ico
|
||||
DEFINES += _USE_MATH_DEFINES \
|
||||
NOGDI
|
||||
}
|
||||
|
@ -43,6 +43,8 @@
|
||||
<file alias="view-filter@2x.png">icons/GUI/view-filter@2x.png</file>
|
||||
<file alias="applications-internet_32.png">icons/GUI/applications-internet_32.png</file>
|
||||
<file alias="applications-internet_32@2x.png">icons/GUI/applications-internet_32@2x.png</file>
|
||||
<file alias="view-grid.png">icons/GUI/view-grid.png</file>
|
||||
<file alias="view-grid@2x.png">icons/GUI/view-grid@2x.png</file>
|
||||
</qresource>
|
||||
|
||||
<!-- POI icons for default IMG map style -->
|
||||
|
BIN
icons/GUI/view-grid.png
Normal file
BIN
icons/GUI/view-grid.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.4 KiB |
BIN
icons/GUI/view-grid@2x.png
Normal file
BIN
icons/GUI/view-grid@2x.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.1 KiB |
BIN
icons/formats/ghp.icns
Normal file
BIN
icons/formats/ghp.icns
Normal file
Binary file not shown.
BIN
icons/formats/ghp.ico
Normal file
BIN
icons/formats/ghp.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 304 KiB |
BIN
icons/formats/omd.icns
Normal file
BIN
icons/formats/omd.icns
Normal file
Binary file not shown.
BIN
icons/formats/omd.ico
Normal file
BIN
icons/formats/omd.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 305 KiB |
@ -25,3 +25,5 @@ sqlt:#303030
|
||||
ov2:#a8c920
|
||||
itn:#b8540d
|
||||
wld:#c74c8f
|
||||
omd:#ed09cb
|
||||
ghp:#ed09cb
|
||||
|
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
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
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -546,6 +546,38 @@
|
||||
<key>CFBundleTypeRole</key>
|
||||
<string>Viewer</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>CFBundleTypeExtensions</key>
|
||||
<array>
|
||||
<string>omd</string>
|
||||
</array>
|
||||
<key>CFBundleTypeMIMETypes</key>
|
||||
<array>
|
||||
<string>application/vnd.onmove.omd</string>
|
||||
</array>
|
||||
<key>CFBundleTypeIconFile</key>
|
||||
<string>icons/omd.icns</string>
|
||||
<key>CFBundleTypeName</key>
|
||||
<string>ONmove Log File</string>
|
||||
<key>CFBundleTypeRole</key>
|
||||
<string>Viewer</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>CFBundleTypeExtensions</key>
|
||||
<array>
|
||||
<string>ghp</string>
|
||||
</array>
|
||||
<key>CFBundleTypeMIMETypes</key>
|
||||
<array>
|
||||
<string>application/vnd.onmove.ghp</string>
|
||||
</array>
|
||||
<key>CFBundleTypeIconFile</key>
|
||||
<string>icons/ghp.icns</string>
|
||||
<key>CFBundleTypeName</key>
|
||||
<string>ONmove Log File</string>
|
||||
<key>CFBundleTypeRole</key>
|
||||
<string>Viewer</string>
|
||||
</dict>
|
||||
</array>
|
||||
|
||||
<key>UTImportedTypeDeclarations</key>
|
||||
@ -1232,6 +1264,48 @@
|
||||
<string>application/vnd.esri.wld</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>UTTypeIdentifier</key>
|
||||
<string>com.geonaute.omd</string>
|
||||
<key>UTTypeReferenceURL</key>
|
||||
<string>https://github.com/ColinPitrat/kalenji-gps-watch-reader</string>
|
||||
<key>UTTypeDescription</key>
|
||||
<string>ONmove Log File</string>
|
||||
<key>UTTypeConformsTo</key>
|
||||
<array>
|
||||
<string>public.data</string>
|
||||
</array>
|
||||
<key>UTTypeTagSpecification</key>
|
||||
<dict>
|
||||
<key>public.filename-extension</key>
|
||||
<array>
|
||||
<string>omd</string>
|
||||
</array>
|
||||
<key>public.mime-type</key>
|
||||
<string>application/vnd.onmove.omd</string>
|
||||
</dict>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>UTTypeIdentifier</key>
|
||||
<string>com.geonaute.ghp</string>
|
||||
<key>UTTypeReferenceURL</key>
|
||||
<string>https://github.com/ColinPitrat/kalenji-gps-watch-reader</string>
|
||||
<key>UTTypeDescription</key>
|
||||
<string>ONmove Log File</string>
|
||||
<key>UTTypeConformsTo</key>
|
||||
<array>
|
||||
<string>public.data</string>
|
||||
</array>
|
||||
<key>UTTypeTagSpecification</key>
|
||||
<dict>
|
||||
<key>public.filename-extension</key>
|
||||
<array>
|
||||
<string>ghp</string>
|
||||
</array>
|
||||
<key>public.mime-type</key>
|
||||
<string>application/vnd.onmove.ghp</string>
|
||||
</dict>
|
||||
</dict>
|
||||
</array>
|
||||
|
||||
<key>UTExportedTypeDeclarations</key>
|
||||
|
@ -14,8 +14,8 @@
|
||||
<ul>
|
||||
<li>Opens GPX, TCX, FIT, KML, IGC, NMEA, SIGMA SLF, Suunto SML, LOC,
|
||||
OziExplorer (PLT, WPT, RTE), GeoJSON, SeeYou CUP,
|
||||
Garmin GPI & CSV, TomTom OV2 & ITN and geotagged JPEG
|
||||
files.</li>
|
||||
Garmin GPI & CSV, TomTom OV2 & ITN, ONmove OMD/GHP
|
||||
and geotagged JPEG files.</li>
|
||||
<li>User-definable online maps (OpenStreetMap/Google tiles, WMTS,
|
||||
WMS, TMS, QuadTiles).</li>
|
||||
<li>Offline maps (MBTiles, OziExplorer maps, TrekBuddy maps/atlases,
|
||||
@ -95,5 +95,7 @@
|
||||
<mimetype>application/vnd.tomtom.ov2</mimetype>
|
||||
<mimetype>application/vnd.tomtom.itn</mimetype>
|
||||
<mimetype>application/vnd.esri.wld</mimetype>
|
||||
<mimetype>application/vnd.onmove.omd</mimetype>
|
||||
<mimetype>application/vnd.onmove.ghp</mimetype>
|
||||
</mimetypes>
|
||||
</component>
|
||||
|
@ -9,7 +9,7 @@ Unicode true
|
||||
; The name of the installer
|
||||
Name "GPXSee"
|
||||
; Program version
|
||||
!define VERSION "9.3"
|
||||
!define VERSION "9.6"
|
||||
|
||||
; The file to write
|
||||
OutFile "GPXSee-${VERSION}.exe"
|
||||
@ -138,14 +138,16 @@ Section "GPXSee" SEC_APP
|
||||
!insertmacro FILE_ASSOCIATION_ADD "gfw" "ESRI World File" 20
|
||||
!insertmacro FILE_ASSOCIATION_ADD "pgw" "ESRI World File" 20
|
||||
!insertmacro FILE_ASSOCIATION_ADD "tfw" "ESRI World File" 20
|
||||
!insertmacro FILE_ASSOCIATION_ADD "tcx" "Training Center XML" 21
|
||||
!insertmacro FILE_ASSOCIATION_ADD "kml" "Keyhole Markup Language" 22
|
||||
!insertmacro FILE_ASSOCIATION_ADD "kmz" "KML geographic compressed data" 22
|
||||
!insertmacro FILE_ASSOCIATION_ADD "fit" "Flexible and Interoperable Data Transfer" 23
|
||||
!insertmacro FILE_ASSOCIATION_ADD "igc" "Flight Recorder Data Format" 24
|
||||
!insertmacro FILE_ASSOCIATION_ADD "nmea" "NMEA 0183 Data" 25
|
||||
!insertmacro FILE_ASSOCIATION_ADD "plt" "OziExplorer Track File" 26
|
||||
!insertmacro FILE_ASSOCIATION_ADD "rte" "OziExplorer Route File" 27
|
||||
!insertmacro FILE_ASSOCIATION_ADD "omd" "ONmove Log File" 21
|
||||
!insertmacro FILE_ASSOCIATION_ADD "tcx" "Training Center XML" 22
|
||||
!insertmacro FILE_ASSOCIATION_ADD "ghp" "ONmove Log File" 23
|
||||
!insertmacro FILE_ASSOCIATION_ADD "kml" "Keyhole Markup Language" 24
|
||||
!insertmacro FILE_ASSOCIATION_ADD "kmz" "KML geographic compressed data" 24
|
||||
!insertmacro FILE_ASSOCIATION_ADD "fit" "Flexible and Interoperable Data Transfer" 25
|
||||
!insertmacro FILE_ASSOCIATION_ADD "igc" "Flight Recorder Data Format" 26
|
||||
!insertmacro FILE_ASSOCIATION_ADD "nmea" "NMEA 0183 Data" 27
|
||||
!insertmacro FILE_ASSOCIATION_ADD "plt" "OziExplorer Track File" 28
|
||||
!insertmacro FILE_ASSOCIATION_ADD "rte" "OziExplorer Route File" 29
|
||||
|
||||
WriteRegStr HKCR "Applications\GPXSee.exe\shell\open\command" "" "$\"$INSTDIR\GPXSee.exe$\" $\"%1$\""
|
||||
WriteRegStr HKCR ".gpx\OpenWithList" "GPXSee.exe" ""
|
||||
@ -189,6 +191,8 @@ Section "GPXSee" SEC_APP
|
||||
WriteRegStr HKCR ".gfw\OpenWithList" "GPXSee.exe" ""
|
||||
WriteRegStr HKCR ".pgw\OpenWithList" "GPXSee.exe" ""
|
||||
WriteRegStr HKCR ".tfw\OpenWithList" "GPXSee.exe" ""
|
||||
WriteRegStr HKCR ".omd\OpenWithList" "GPXSee.exe" ""
|
||||
WriteRegStr HKCR ".ghp\OpenWithList" "GPXSee.exe" ""
|
||||
|
||||
System::Call 'shell32.dll::SHChangeNotify(i, i, i, i) v (0x08000000, 0, 0, 0)'
|
||||
|
||||
@ -313,6 +317,8 @@ Section "Uninstall"
|
||||
!insertmacro FILE_ASSOCIATION_REMOVE "gfw"
|
||||
!insertmacro FILE_ASSOCIATION_REMOVE "pgw"
|
||||
!insertmacro FILE_ASSOCIATION_REMOVE "tfw"
|
||||
!insertmacro FILE_ASSOCIATION_REMOVE "omd"
|
||||
!insertmacro FILE_ASSOCIATION_REMOVE "ghp"
|
||||
|
||||
DeleteRegValue HKCR ".gpx\OpenWithList" "GPXSee.exe"
|
||||
DeleteRegValue HKCR ".tcx\OpenWithList" "GPXSee.exe"
|
||||
@ -355,6 +361,8 @@ Section "Uninstall"
|
||||
DeleteRegValue HKCR ".gfw\OpenWithList" "GPXSee.exe"
|
||||
DeleteRegValue HKCR ".pgw\OpenWithList" "GPXSee.exe"
|
||||
DeleteRegValue HKCR ".tfw\OpenWithList" "GPXSee.exe"
|
||||
DeleteRegValue HKCR ".omd\OpenWithList" "GPXSee.exe"
|
||||
DeleteRegValue HKCR ".ghp\OpenWithList" "GPXSee.exe"
|
||||
DeleteRegKey HKCR "Applications\GPXSee.exe"
|
||||
|
||||
System::Call 'shell32.dll::SHChangeNotify(i, i, i, i) v (0x08000000, 0, 0, 0)'
|
||||
|
@ -142,6 +142,20 @@
|
||||
<glob pattern="*.itn"/>
|
||||
</mime-type>
|
||||
|
||||
<mime-type type="application/vnd.onmove.omd">
|
||||
<comment>ONmove Log File</comment>
|
||||
<sub-class-of type="application/octet-stream"/>
|
||||
<generic-icon name="application/octet-stream"/>
|
||||
<glob pattern="*.omd"/>
|
||||
</mime-type>
|
||||
|
||||
<mime-type type="application/vnd.onmove.ghp">
|
||||
<comment>ONmove Log File</comment>
|
||||
<sub-class-of type="application/octet-stream"/>
|
||||
<generic-icon name="application/octet-stream"/>
|
||||
<glob pattern="*.ghp"/>
|
||||
</mime-type>
|
||||
|
||||
<!-- Maps -->
|
||||
|
||||
<mime-type type="application/vnd.garmin.img">
|
||||
|
@ -9,7 +9,7 @@ Unicode true
|
||||
; The name of the installer
|
||||
Name "GPXSee"
|
||||
; Program version
|
||||
!define VERSION "9.3"
|
||||
!define VERSION "9.6"
|
||||
|
||||
; The file to write
|
||||
OutFile "GPXSee-${VERSION}_x64.exe"
|
||||
@ -145,14 +145,16 @@ Section "GPXSee" SEC_APP
|
||||
!insertmacro FILE_ASSOCIATION_ADD "gfw" "ESRI World File" 20
|
||||
!insertmacro FILE_ASSOCIATION_ADD "pgw" "ESRI World File" 20
|
||||
!insertmacro FILE_ASSOCIATION_ADD "tfw" "ESRI World File" 20
|
||||
!insertmacro FILE_ASSOCIATION_ADD "tcx" "Training Center XML" 21
|
||||
!insertmacro FILE_ASSOCIATION_ADD "kml" "Keyhole Markup Language" 22
|
||||
!insertmacro FILE_ASSOCIATION_ADD "kmz" "KML geographic compressed data" 22
|
||||
!insertmacro FILE_ASSOCIATION_ADD "fit" "Flexible and Interoperable Data Transfer" 23
|
||||
!insertmacro FILE_ASSOCIATION_ADD "igc" "Flight Recorder Data Format" 24
|
||||
!insertmacro FILE_ASSOCIATION_ADD "nmea" "NMEA 0183 Data" 25
|
||||
!insertmacro FILE_ASSOCIATION_ADD "plt" "OziExplorer Track File" 26
|
||||
!insertmacro FILE_ASSOCIATION_ADD "rte" "OziExplorer Route File" 27
|
||||
!insertmacro FILE_ASSOCIATION_ADD "omd" "ONmove Log File" 21
|
||||
!insertmacro FILE_ASSOCIATION_ADD "tcx" "Training Center XML" 22
|
||||
!insertmacro FILE_ASSOCIATION_ADD "ghp" "ONmove Log File" 23
|
||||
!insertmacro FILE_ASSOCIATION_ADD "kml" "Keyhole Markup Language" 24
|
||||
!insertmacro FILE_ASSOCIATION_ADD "kmz" "KML geographic compressed data" 24
|
||||
!insertmacro FILE_ASSOCIATION_ADD "fit" "Flexible and Interoperable Data Transfer" 25
|
||||
!insertmacro FILE_ASSOCIATION_ADD "igc" "Flight Recorder Data Format" 26
|
||||
!insertmacro FILE_ASSOCIATION_ADD "nmea" "NMEA 0183 Data" 27
|
||||
!insertmacro FILE_ASSOCIATION_ADD "plt" "OziExplorer Track File" 28
|
||||
!insertmacro FILE_ASSOCIATION_ADD "rte" "OziExplorer Route File" 29
|
||||
|
||||
WriteRegStr HKCR "Applications\GPXSee.exe\shell\open\command" "" "$\"$INSTDIR\GPXSee.exe$\" $\"%1$\""
|
||||
WriteRegStr HKCR ".gpx\OpenWithList" "GPXSee.exe" ""
|
||||
@ -196,6 +198,8 @@ Section "GPXSee" SEC_APP
|
||||
WriteRegStr HKCR ".gfw\OpenWithList" "GPXSee.exe" ""
|
||||
WriteRegStr HKCR ".pgw\OpenWithList" "GPXSee.exe" ""
|
||||
WriteRegStr HKCR ".tfw\OpenWithList" "GPXSee.exe" ""
|
||||
WriteRegStr HKCR ".omd\OpenWithList" "GPXSee.exe" ""
|
||||
WriteRegStr HKCR ".ghp\OpenWithList" "GPXSee.exe" ""
|
||||
|
||||
System::Call 'shell32.dll::SHChangeNotify(i, i, i, i) v (0x08000000, 0, 0, 0)'
|
||||
|
||||
@ -336,6 +340,8 @@ Section "Uninstall"
|
||||
!insertmacro FILE_ASSOCIATION_REMOVE "gfw"
|
||||
!insertmacro FILE_ASSOCIATION_REMOVE "pgw"
|
||||
!insertmacro FILE_ASSOCIATION_REMOVE "tfw"
|
||||
!insertmacro FILE_ASSOCIATION_REMOVE "omd"
|
||||
!insertmacro FILE_ASSOCIATION_REMOVE "ghp"
|
||||
|
||||
DeleteRegValue HKCR ".gpx\OpenWithList" "GPXSee.exe"
|
||||
DeleteRegValue HKCR ".tcx\OpenWithList" "GPXSee.exe"
|
||||
@ -378,6 +384,8 @@ Section "Uninstall"
|
||||
DeleteRegValue HKCR ".gfw\OpenWithList" "GPXSee.exe"
|
||||
DeleteRegValue HKCR ".pgw\OpenWithList" "GPXSee.exe"
|
||||
DeleteRegValue HKCR ".tfw\OpenWithList" "GPXSee.exe"
|
||||
DeleteRegValue HKCR ".omd\OpenWithList" "GPXSee.exe"
|
||||
DeleteRegValue HKCR ".ghp\OpenWithList" "GPXSee.exe"
|
||||
DeleteRegKey HKCR "Applications\GPXSee.exe"
|
||||
|
||||
System::Call 'shell32.dll::SHChangeNotify(i, i, i, i) v (0x08000000, 0, 0, 0)'
|
||||
|
@ -9,7 +9,7 @@
|
||||
#include <QSurfaceFormat>
|
||||
#include "common/programpaths.h"
|
||||
#include "common/config.h"
|
||||
#include "map/downloader.h"
|
||||
#include "common/downloader.h"
|
||||
#include "map/ellipsoid.h"
|
||||
#include "map/gcs.h"
|
||||
#include "map/pcs.h"
|
||||
|
@ -9,7 +9,7 @@
|
||||
#include "areaitem.h"
|
||||
|
||||
|
||||
QString AreaItem::info() const
|
||||
ToolTip AreaItem::info() const
|
||||
{
|
||||
ToolTip tt;
|
||||
|
||||
@ -19,7 +19,7 @@ QString AreaItem::info() const
|
||||
tt.insert(qApp->translate("PolygonItem", "Description"),
|
||||
_area.description());
|
||||
|
||||
return tt.toString();
|
||||
return tt;
|
||||
}
|
||||
|
||||
AreaItem::AreaItem(const Area &area, Map *map, GraphicsItem *parent)
|
||||
|
@ -25,7 +25,7 @@ public:
|
||||
void setStyle(Qt::PenStyle style);
|
||||
void setDigitalZoom(int zoom);
|
||||
|
||||
QString info() const;
|
||||
ToolTip info() const;
|
||||
|
||||
protected:
|
||||
void hoverEnterEvent(QGraphicsSceneHoverEvent *event);
|
||||
|
15
src/GUI/authenticationwidget.cpp
Normal file
15
src/GUI/authenticationwidget.cpp
Normal file
@ -0,0 +1,15 @@
|
||||
#include <QFormLayout>
|
||||
#include "authenticationwidget.h"
|
||||
|
||||
AuthenticationWidget::AuthenticationWidget(QWidget *parent) : QWidget(parent)
|
||||
{
|
||||
_username = new QLineEdit();
|
||||
_password = new QLineEdit();
|
||||
|
||||
QFormLayout *layout = new QFormLayout();
|
||||
layout->addRow(tr("Username:"), _username);
|
||||
layout->addRow(tr("Password:"), _password);
|
||||
layout->setContentsMargins(0, 0, 0, 0);
|
||||
|
||||
setLayout(layout);
|
||||
}
|
24
src/GUI/authenticationwidget.h
Normal file
24
src/GUI/authenticationwidget.h
Normal file
@ -0,0 +1,24 @@
|
||||
#ifndef AUTHENTICATIONWIDGET_H
|
||||
#define AUTHENTICATIONWIDGET_H
|
||||
|
||||
#include <QWidget>
|
||||
#include <QLineEdit>
|
||||
|
||||
class AuthenticationWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
AuthenticationWidget(QWidget *parent = 0);
|
||||
|
||||
QString username() const {return _username->text();}
|
||||
QString password() const {return _password->text();}
|
||||
|
||||
void setUsername(const QString &username) {_username->setText(username);}
|
||||
void setPassword(const QString &password) {_password->setText(password);}
|
||||
|
||||
private:
|
||||
QLineEdit *_username, *_password;
|
||||
};
|
||||
|
||||
#endif // AUTHENTICATIONWIDGET_H
|
@ -9,7 +9,7 @@ CadenceGraphItem::CadenceGraphItem(const Graph &graph, GraphType type,
|
||||
{
|
||||
}
|
||||
|
||||
QString CadenceGraphItem::info() const
|
||||
ToolTip CadenceGraphItem::info() const
|
||||
{
|
||||
ToolTip tt;
|
||||
QLocale l(QLocale::system());
|
||||
@ -19,5 +19,5 @@ QString CadenceGraphItem::info() const
|
||||
tt.insert(tr("Average"), l.toString(avg(), 'f', 1)
|
||||
+ UNIT_SPACE + tr("rpm"));
|
||||
|
||||
return tt.toString();
|
||||
return tt;
|
||||
}
|
||||
|
@ -11,7 +11,7 @@ public:
|
||||
CadenceGraphItem(const Graph &graph, GraphType type, int width,
|
||||
const QColor &color, QGraphicsItem *parent = 0);
|
||||
|
||||
QString info() const;
|
||||
ToolTip info() const;
|
||||
};
|
||||
|
||||
#endif // CADENCEGRAPHITEM_H
|
||||
|
@ -26,7 +26,7 @@ ElevationGraphItem::ElevationGraphItem(const Graph &graph, GraphType type,
|
||||
}
|
||||
}
|
||||
|
||||
QString ElevationGraphItem::info() const
|
||||
ToolTip ElevationGraphItem::info() const
|
||||
{
|
||||
ToolTip tt;
|
||||
qreal scale = (_units == Metric) ? 1.0 : M2FT;
|
||||
@ -42,6 +42,5 @@ QString ElevationGraphItem::info() const
|
||||
tt.insert(tr("Minimum"), l.toString(min() * scale, 'f', 0)
|
||||
+ UNIT_SPACE + su);
|
||||
|
||||
|
||||
return tt.toString();
|
||||
return tt;
|
||||
}
|
||||
|
@ -18,7 +18,7 @@ public:
|
||||
qreal max() const {return _max;}
|
||||
qreal min() const {return _min;}
|
||||
|
||||
QString info() const;
|
||||
ToolTip info() const;
|
||||
|
||||
private:
|
||||
qreal _ascent, _descent, _min, _max;
|
||||
|
181
src/GUI/flowlayout.cpp
Normal file
181
src/GUI/flowlayout.cpp
Normal file
@ -0,0 +1,181 @@
|
||||
#include <QtWidgets>
|
||||
#include "flowlayout.h"
|
||||
|
||||
struct FlowLayoutItem
|
||||
{
|
||||
FlowLayoutItem() : item(0) {}
|
||||
FlowLayoutItem(QLayoutItem *item, int x, int y) : item(item), pos(x, y) {}
|
||||
|
||||
QLayoutItem *item;
|
||||
QPoint pos;
|
||||
};
|
||||
|
||||
FlowLayout::FlowLayout(QWidget *parent, int margin, int hSpacing, int vSpacing)
|
||||
: QLayout(parent), _hSpace(hSpacing), _vSpace(vSpacing)
|
||||
{
|
||||
setContentsMargins(margin, margin, margin, margin);
|
||||
}
|
||||
|
||||
FlowLayout::FlowLayout(int margin, int hSpacing, int vSpacing)
|
||||
: _hSpace(hSpacing), _vSpace(vSpacing)
|
||||
{
|
||||
setContentsMargins(margin, margin, margin, margin);
|
||||
}
|
||||
|
||||
FlowLayout::~FlowLayout()
|
||||
{
|
||||
qDeleteAll(_items);
|
||||
}
|
||||
|
||||
void FlowLayout::addItem(QLayoutItem *item)
|
||||
{
|
||||
_items.append(item);
|
||||
}
|
||||
|
||||
int FlowLayout::horizontalSpacing() const
|
||||
{
|
||||
return (_hSpace >= 0)
|
||||
? _hSpace
|
||||
: smartSpacing(QStyle::PM_LayoutHorizontalSpacing);
|
||||
}
|
||||
|
||||
int FlowLayout::verticalSpacing() const
|
||||
{
|
||||
return (_vSpace >= 0)
|
||||
? _vSpace
|
||||
: smartSpacing(QStyle::PM_LayoutVerticalSpacing);
|
||||
}
|
||||
|
||||
int FlowLayout::count() const
|
||||
{
|
||||
return _items.size();
|
||||
}
|
||||
|
||||
QLayoutItem *FlowLayout::itemAt(int index) const
|
||||
{
|
||||
return _items.value(index);
|
||||
}
|
||||
|
||||
QLayoutItem *FlowLayout::takeAt(int index)
|
||||
{
|
||||
if (index >= 0 && index < _items.size())
|
||||
return _items.takeAt(index);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Qt::Orientations FlowLayout::expandingDirections() const
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
bool FlowLayout::hasHeightForWidth() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
int FlowLayout::heightForWidth(int width) const
|
||||
{
|
||||
int height = doLayout(QRect(0, 0, width, 0), true);
|
||||
return height;
|
||||
}
|
||||
|
||||
void FlowLayout::setGeometry(const QRect &rect)
|
||||
{
|
||||
QLayout::setGeometry(rect);
|
||||
doLayout(rect, false);
|
||||
}
|
||||
|
||||
QSize FlowLayout::sizeHint() const
|
||||
{
|
||||
return minimumSize();
|
||||
}
|
||||
|
||||
QSize FlowLayout::minimumSize() const
|
||||
{
|
||||
QSize size;
|
||||
|
||||
for (int i = 0; i < _items.size(); i++)
|
||||
size = size.expandedTo(_items.at(i)->minimumSize());
|
||||
|
||||
const QMargins margins = contentsMargins();
|
||||
size += QSize(margins.left() + margins.right(), margins.top()
|
||||
+ margins.bottom());
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
int FlowLayout::doLayout(const QRect &rect, bool testOnly) const
|
||||
{
|
||||
int left, top, right, bottom;
|
||||
getContentsMargins(&left, &top, &right, &bottom);
|
||||
QRect effectiveRect = rect.adjusted(+left, +top, -right, -bottom);
|
||||
int x = effectiveRect.x();
|
||||
int y = effectiveRect.y();
|
||||
int lineHeight = 0;
|
||||
QVector<QVector<FlowLayoutItem>> rows;
|
||||
|
||||
for (int i = 0; i < _items.size(); i++) {
|
||||
QLayoutItem *item = _items.at(i);
|
||||
const QWidget *wid = item->widget();
|
||||
int spaceX = horizontalSpacing();
|
||||
if (spaceX == -1)
|
||||
spaceX = wid->style()->layoutSpacing(QSizePolicy::PushButton,
|
||||
QSizePolicy::PushButton, Qt::Horizontal);
|
||||
int spaceY = verticalSpacing();
|
||||
if (spaceY == -1)
|
||||
spaceY = wid->style()->layoutSpacing(QSizePolicy::PushButton,
|
||||
QSizePolicy::PushButton, Qt::Vertical);
|
||||
|
||||
int nextX = x + item->sizeHint().width() + spaceX;
|
||||
if (nextX - spaceX > effectiveRect.right() && lineHeight > 0) {
|
||||
x = effectiveRect.x();
|
||||
y = y + lineHeight + spaceY;
|
||||
nextX = x + item->sizeHint().width() + spaceX;
|
||||
lineHeight = 0;
|
||||
rows.append(QVector<FlowLayoutItem>());
|
||||
}
|
||||
|
||||
if (rows.isEmpty())
|
||||
rows.append(QVector<FlowLayoutItem>());
|
||||
rows.last().append(FlowLayoutItem(item, x, y));
|
||||
|
||||
x = nextX;
|
||||
lineHeight = qMax(lineHeight, item->sizeHint().height());
|
||||
}
|
||||
|
||||
if (!testOnly) {
|
||||
for (int i = 0; i < rows.size(); i++) {
|
||||
const FlowLayoutItem &li = rows.at(i).last();
|
||||
int width = li.item->sizeHint().width() + li.pos.x()
|
||||
- effectiveRect.x();
|
||||
int offset = (effectiveRect.width() - width) / 2;
|
||||
|
||||
int height = 0;
|
||||
for (int j = 0; j < rows.at(i).size(); j++)
|
||||
height = qMax(rows.at(i).at(j).item->sizeHint().height(), height);
|
||||
|
||||
for (int j = 0; j < rows.at(i).size(); j++) {
|
||||
QLayoutItem *item = rows.at(i).at(j).item;
|
||||
const QPoint &p = rows.at(i).at(j).pos;
|
||||
QSize sh(item->sizeHint());
|
||||
item->setGeometry(QRect(QPoint(p.x() + offset, p.y() + height
|
||||
- sh.height()), sh));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return y + lineHeight - rect.y() + bottom;
|
||||
}
|
||||
|
||||
int FlowLayout::smartSpacing(QStyle::PixelMetric pm) const
|
||||
{
|
||||
QObject *parent = this->parent();
|
||||
if (!parent)
|
||||
return -1;
|
||||
else if (parent->isWidgetType()) {
|
||||
QWidget *pw = static_cast<QWidget *>(parent);
|
||||
return pw->style()->pixelMetric(pm, 0, pw);
|
||||
} else
|
||||
return static_cast<QLayout *>(parent)->spacing();
|
||||
}
|
38
src/GUI/flowlayout.h
Normal file
38
src/GUI/flowlayout.h
Normal file
@ -0,0 +1,38 @@
|
||||
#ifndef FLOWLAYOUT_H
|
||||
#define FLOWLAYOUT_H
|
||||
|
||||
#include <QLayout>
|
||||
#include <QRect>
|
||||
#include <QStyle>
|
||||
|
||||
class FlowLayout : public QLayout
|
||||
{
|
||||
public:
|
||||
FlowLayout(QWidget *parent, int margin = -1, int hSpacing = -1,
|
||||
int vSpacing = -1);
|
||||
FlowLayout(int margin = -1, int hSpacing = -1, int vSpacing = -1);
|
||||
~FlowLayout();
|
||||
|
||||
void addItem(QLayoutItem *item);
|
||||
int horizontalSpacing() const;
|
||||
int verticalSpacing() const;
|
||||
Qt::Orientations expandingDirections() const;
|
||||
bool hasHeightForWidth() const;
|
||||
int heightForWidth(int) const;
|
||||
int count() const;
|
||||
QLayoutItem *itemAt(int index) const;
|
||||
QSize minimumSize() const;
|
||||
void setGeometry(const QRect &rect);
|
||||
QSize sizeHint() const;
|
||||
QLayoutItem *takeAt(int index);
|
||||
|
||||
private:
|
||||
int doLayout(const QRect &rect, bool testOnly) const;
|
||||
int smartSpacing(QStyle::PixelMetric pm) const;
|
||||
|
||||
QList<QLayoutItem *> _items;
|
||||
int _hSpace;
|
||||
int _vSpace;
|
||||
};
|
||||
|
||||
#endif // FLOWLAYOUT_H
|
@ -27,7 +27,7 @@ GearRatioGraphItem::GearRatioGraphItem(const Graph &graph, GraphType type,
|
||||
_top = key;
|
||||
}
|
||||
|
||||
QString GearRatioGraphItem::info() const
|
||||
ToolTip GearRatioGraphItem::info() const
|
||||
{
|
||||
ToolTip tt;
|
||||
QLocale l(QLocale::system());
|
||||
@ -36,5 +36,5 @@ QString GearRatioGraphItem::info() const
|
||||
tt.insert(tr("Maximum"), l.toString(max(), 'f', 2));
|
||||
tt.insert(tr("Most used"), l.toString(top(), 'f', 2));
|
||||
|
||||
return tt.toString();
|
||||
return tt;
|
||||
}
|
||||
|
@ -15,7 +15,7 @@ public:
|
||||
qreal top() const {return _top;}
|
||||
const QMap<qreal, qreal> &map() const {return _map;}
|
||||
|
||||
QString info() const;
|
||||
ToolTip info() const;
|
||||
|
||||
private:
|
||||
QMap<qreal, qreal> _map;
|
||||
|
@ -3,13 +3,14 @@
|
||||
|
||||
#include <QGraphicsScene>
|
||||
#include <QGraphicsItem>
|
||||
#include "tooltip.h"
|
||||
|
||||
class GraphicsItem : public QGraphicsItem
|
||||
{
|
||||
public:
|
||||
GraphicsItem(QGraphicsItem *parent = 0) : QGraphicsItem(parent) {}
|
||||
|
||||
virtual QString info() const = 0;
|
||||
virtual ToolTip info() const = 0;
|
||||
int type() const {return QGraphicsItem::UserType + 1;}
|
||||
};
|
||||
|
||||
|
@ -16,7 +16,7 @@ public:
|
||||
const QColor &color, Qt::PenStyle style, QGraphicsItem *parent = 0);
|
||||
virtual ~GraphItem() {}
|
||||
|
||||
virtual QString info() const = 0;
|
||||
virtual ToolTip info() const = 0;
|
||||
|
||||
QPainterPath shape() const {return _shape;}
|
||||
QRectF boundingRect() const {return _shape.boundingRect();}
|
||||
|
130
src/GUI/gui.cpp
130
src/GUI/gui.cpp
@ -26,11 +26,12 @@
|
||||
#include <QStyle>
|
||||
#include <QTabBar>
|
||||
#include "common/programpaths.h"
|
||||
#include "common/downloader.h"
|
||||
#include "data/data.h"
|
||||
#include "data/poi.h"
|
||||
#include "data/demloader.h"
|
||||
#include "map/maplist.h"
|
||||
#include "map/emptymap.h"
|
||||
#include "map/downloader.h"
|
||||
#include "map/crs.h"
|
||||
#include "icons.h"
|
||||
#include "keys.h"
|
||||
@ -62,6 +63,8 @@ GUI::GUI()
|
||||
TreeNode<POIAction*> poiActions;
|
||||
|
||||
_poi = new POI(this);
|
||||
_dem = new DEMLoader(ProgramPaths::demDir(true), this);
|
||||
connect(_dem, &DEMLoader::finished, this, &GUI::demLoaded);
|
||||
|
||||
createMapView();
|
||||
createGraphTabs();
|
||||
@ -352,6 +355,7 @@ void GUI::createActions(TreeNode<MapAction*> &mapActions,
|
||||
_showTracksAction = new QAction(tr("Show tracks"), this);
|
||||
_showTracksAction->setMenuRole(QAction::NoRole);
|
||||
_showTracksAction->setCheckable(true);
|
||||
_showTracksAction->setShortcut(SHOW_TRACKS_SHORTCUT);
|
||||
connect(_showTracksAction, &QAction::triggered, this, &GUI::showTracks);
|
||||
_showRoutesAction = new QAction(tr("Show routes"), this);
|
||||
_showRoutesAction->setMenuRole(QAction::NoRole);
|
||||
@ -360,13 +364,12 @@ void GUI::createActions(TreeNode<MapAction*> &mapActions,
|
||||
_showWaypointsAction = new QAction(tr("Show waypoints"), this);
|
||||
_showWaypointsAction->setMenuRole(QAction::NoRole);
|
||||
_showWaypointsAction->setCheckable(true);
|
||||
connect(_showWaypointsAction, &QAction::triggered, _mapView,
|
||||
&MapView::showWaypoints);
|
||||
connect(_showWaypointsAction, &QAction::triggered, this,
|
||||
&GUI::showWaypoints);
|
||||
_showAreasAction = new QAction(tr("Show areas"), this);
|
||||
_showAreasAction->setMenuRole(QAction::NoRole);
|
||||
_showAreasAction->setCheckable(true);
|
||||
connect(_showAreasAction, &QAction::triggered, _mapView,
|
||||
&MapView::showAreas);
|
||||
connect(_showAreasAction, &QAction::triggered, this, &GUI::showAreas);
|
||||
_showWaypointLabelsAction = new QAction(tr("Waypoint labels"), this);
|
||||
_showWaypointLabelsAction->setMenuRole(QAction::NoRole);
|
||||
_showWaypointLabelsAction->setCheckable(true);
|
||||
@ -402,6 +405,13 @@ void GUI::createActions(TreeNode<MapAction*> &mapActions,
|
||||
_showMarkerCoordinatesAction->setCheckable(true);
|
||||
_showMarkerCoordinatesAction->setActionGroup(markerInfoGroup);
|
||||
|
||||
// DEM actions
|
||||
_downloadDEMAction = new QAction(tr("Download DEM data"), this);
|
||||
_downloadDEMAction->setMenuRole(QAction::NoRole);
|
||||
_downloadDEMAction->setEnabled(false);
|
||||
_downloadDEMAction->setShortcut(DOWNLOAD_DEM_SHORTCUT);
|
||||
connect(_downloadDEMAction, &QAction::triggered, this, &GUI::downloadDEM);
|
||||
|
||||
// Graph actions
|
||||
_showGraphsAction = new QAction(QIcon(SHOW_GRAPHS_ICON), tr("Show graphs"),
|
||||
this);
|
||||
@ -585,18 +595,6 @@ void GUI::createMenus(const TreeNode<MapAction*> &mapActions,
|
||||
graphMenu->addSeparator();
|
||||
graphMenu->addAction(_showGraphsAction);
|
||||
|
||||
_poiMenu = menuBar()->addMenu(tr("&POI"));
|
||||
createPOINodeMenu(poiActions, _poiMenu);
|
||||
_poisEnd = _poiMenu->addSeparator();
|
||||
_poiMenu->addAction(_openPOIAction);
|
||||
_poiMenu->addAction(_selectAllPOIAction);
|
||||
_poiMenu->addAction(_unselectAllPOIAction);
|
||||
_poiMenu->addSeparator();
|
||||
_poiMenu->addAction(_showPOILabelsAction);
|
||||
_poiMenu->addAction(_overlapPOIAction);
|
||||
_poiMenu->addSeparator();
|
||||
_poiMenu->addAction(_showPOIAction);
|
||||
|
||||
QMenu *dataMenu = menuBar()->addMenu(tr("&Data"));
|
||||
dataMenu->addAction(_showWaypointLabelsAction);
|
||||
dataMenu->addAction(_showRouteWaypointsAction);
|
||||
@ -612,6 +610,22 @@ void GUI::createMenus(const TreeNode<MapAction*> &mapActions,
|
||||
dataMenu->addAction(_showAreasAction);
|
||||
dataMenu->addAction(_showWaypointsAction);
|
||||
|
||||
_poiMenu = menuBar()->addMenu(tr("&POI"));
|
||||
createPOINodeMenu(poiActions, _poiMenu);
|
||||
_poisEnd = _poiMenu->addSeparator();
|
||||
_poiMenu->addAction(_openPOIAction);
|
||||
_poiMenu->addAction(_selectAllPOIAction);
|
||||
_poiMenu->addAction(_unselectAllPOIAction);
|
||||
_poiMenu->addSeparator();
|
||||
_poiMenu->addAction(_showPOILabelsAction);
|
||||
_poiMenu->addAction(_overlapPOIAction);
|
||||
_poiMenu->addSeparator();
|
||||
_poiMenu->addAction(_showPOIAction);
|
||||
|
||||
QMenu *demMenu = menuBar()->addMenu(tr("DEM"));
|
||||
demMenu->addSeparator();
|
||||
demMenu->addAction(_downloadDEMAction);
|
||||
|
||||
QMenu *settingsMenu = menuBar()->addMenu(tr("&Settings"));
|
||||
QMenu *timeMenu = settingsMenu->addMenu(tr("Time"));
|
||||
timeMenu->addAction(_totalTimeAction);
|
||||
@ -652,7 +666,9 @@ void GUI::createToolBars()
|
||||
_fileToolBar->addAction(_openFileAction);
|
||||
_fileToolBar->addAction(_reloadFileAction);
|
||||
_fileToolBar->addAction(_closeFileAction);
|
||||
#ifndef Q_OS_MAC
|
||||
_fileToolBar->addAction(_printFileAction);
|
||||
#endif // Q_OS_MAC
|
||||
|
||||
_showToolBar = addToolBar(tr("Show"));
|
||||
_showToolBar->setObjectName("Show");
|
||||
@ -854,6 +870,7 @@ bool GUI::loadFile(const QString &fileName, bool silent)
|
||||
updateStatusBarInfo();
|
||||
updateWindowTitle();
|
||||
updateGraphTabs();
|
||||
updateDEMDownloadAction();
|
||||
|
||||
QString error = tr("Error loading data file:") + "\n\n"
|
||||
+ fileName + "\n\n" + data.errorString();
|
||||
@ -919,6 +936,8 @@ void GUI::loadData(const Data &data)
|
||||
pi->setMarkerPosition(gt->sliderPosition());
|
||||
}
|
||||
}
|
||||
|
||||
updateDEMDownloadAction();
|
||||
}
|
||||
|
||||
void GUI::openPOIFile()
|
||||
@ -1052,6 +1071,15 @@ void GUI::openOptions()
|
||||
if (options.poiRadius != _options.poiRadius)
|
||||
_poi->setRadius(options.poiRadius);
|
||||
|
||||
if (options.demURL != _options.demURL)
|
||||
_dem->setUrl(options.demURL);
|
||||
if (options.demAuthorization != _options.demAuthorization
|
||||
|| options.demUsername != _options.demUsername
|
||||
|| options.demPassword != _options.demPassword)
|
||||
_dem->setAuthorization(options.demAuthorization
|
||||
? Authorization(options.demUsername, options.demPassword)
|
||||
: Authorization());
|
||||
|
||||
if (options.pixmapCache != _options.pixmapCache)
|
||||
QPixmapCache::setCacheLimit(options.pixmapCache * 1024);
|
||||
|
||||
@ -1071,6 +1099,8 @@ void GUI::openOptions()
|
||||
reloadFiles();
|
||||
|
||||
_options = options;
|
||||
|
||||
updateDEMDownloadAction();
|
||||
}
|
||||
|
||||
void GUI::printFile()
|
||||
@ -1364,6 +1394,7 @@ void GUI::reloadFiles()
|
||||
_fileActionGroup->setEnabled(false);
|
||||
else
|
||||
_browser->setCurrent(_files.last());
|
||||
updateDEMDownloadAction();
|
||||
}
|
||||
|
||||
void GUI::closeFiles()
|
||||
@ -1396,6 +1427,7 @@ void GUI::closeAll()
|
||||
updateStatusBarInfo();
|
||||
updateWindowTitle();
|
||||
updateGraphTabs();
|
||||
updateDEMDownloadAction();
|
||||
}
|
||||
|
||||
void GUI::showGraphs(bool show)
|
||||
@ -1455,6 +1487,7 @@ void GUI::showTracks(bool show)
|
||||
|
||||
updateStatusBarInfo();
|
||||
updateGraphTabs();
|
||||
updateDEMDownloadAction();
|
||||
}
|
||||
|
||||
void GUI::showRoutes(bool show)
|
||||
@ -1466,6 +1499,19 @@ void GUI::showRoutes(bool show)
|
||||
|
||||
updateStatusBarInfo();
|
||||
updateGraphTabs();
|
||||
updateDEMDownloadAction();
|
||||
}
|
||||
|
||||
void GUI::showWaypoints(bool show)
|
||||
{
|
||||
_mapView->showWaypoints(show);
|
||||
updateDEMDownloadAction();
|
||||
}
|
||||
|
||||
void GUI::showAreas(bool show)
|
||||
{
|
||||
_mapView->showAreas(show);
|
||||
updateDEMDownloadAction();
|
||||
}
|
||||
|
||||
void GUI::showGraphGrids(bool show)
|
||||
@ -1688,6 +1734,30 @@ void GUI::clearMapCache()
|
||||
_mapView->clearMapCache();
|
||||
}
|
||||
|
||||
void GUI::downloadDEM()
|
||||
{
|
||||
RectC br(_mapView->boundingRect());
|
||||
_demRects.append(br);
|
||||
|
||||
if (!_dem->loadTiles(br) && _demRects.size() == 1)
|
||||
demLoaded();
|
||||
}
|
||||
|
||||
void GUI::demLoaded()
|
||||
{
|
||||
for (int i = 0; i < _demRects.size(); i++) {
|
||||
if (!_dem->checkTiles(_demRects.at(i))) {
|
||||
QMessageBox::warning(this, APP_NAME,
|
||||
tr("Could not download all required DEM files."));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
DEM::clearCache();
|
||||
_demRects.clear();
|
||||
reloadFiles();
|
||||
}
|
||||
|
||||
void GUI::updateStatusBarInfo()
|
||||
{
|
||||
if (_files.count() == 0)
|
||||
@ -1843,6 +1913,12 @@ bool GUI::updateGraphTabs()
|
||||
return (hidden != _graphTabWidget->isHidden());
|
||||
}
|
||||
|
||||
void GUI::updateDEMDownloadAction()
|
||||
{
|
||||
_downloadDEMAction->setEnabled(!_dem->url().isEmpty()
|
||||
&& !_dem->checkTiles(_mapView->boundingRect()));
|
||||
}
|
||||
|
||||
void GUI::setTimeType(TimeType type)
|
||||
{
|
||||
for (int i = 0; i <_tabs.count(); i++)
|
||||
@ -2236,6 +2312,14 @@ void GUI::writeSettings()
|
||||
settings.setValue(USE_SEGMENTS_SETTING, _options.useSegments);
|
||||
if (_options.poiRadius != POI_RADIUS_DEFAULT)
|
||||
settings.setValue(POI_RADIUS_SETTING, _options.poiRadius);
|
||||
if (_options.demURL != DEM_URL_DEFAULT)
|
||||
settings.setValue(DEM_URL_SETTING, _options.demURL);
|
||||
if (_options.demAuthorization != DEM_AUTH_DEFAULT)
|
||||
settings.setValue(DEM_AUTH_SETTING, _options.demAuthorization);
|
||||
if (_options.demUsername != DEM_USERNAME_DEFAULT)
|
||||
settings.setValue(DEM_USERNAME_SETTING, _options.demUsername);
|
||||
if (_options.demPassword != DEM_PASSWORD_DEFAULT)
|
||||
settings.setValue(DEM_PASSWORD_SETTING, _options.demPassword);
|
||||
if (_options.useOpenGL != USE_OPENGL_DEFAULT)
|
||||
settings.setValue(USE_OPENGL_SETTING, _options.useOpenGL);
|
||||
if (_options.enableHTTP2 != ENABLE_HTTP2_DEFAULT)
|
||||
@ -2547,6 +2631,13 @@ void GUI::readSettings()
|
||||
PAUSE_INTERVAL_DEFAULT).toInt();
|
||||
_options.poiRadius = settings.value(POI_RADIUS_SETTING, POI_RADIUS_DEFAULT)
|
||||
.toInt();
|
||||
_options.demURL = settings.value(DEM_URL_SETTING, DEM_URL_DEFAULT).toString();
|
||||
_options.demAuthorization = settings.value(DEM_AUTH_SETTING,
|
||||
DEM_AUTH_DEFAULT).toBool();
|
||||
_options.demUsername = settings.value(DEM_USERNAME_SETTING,
|
||||
DEM_USERNAME_DEFAULT).toString();
|
||||
_options.demPassword = settings.value(DEM_PASSWORD_SETTING,
|
||||
DEM_PASSWORD_DEFAULT).toString();
|
||||
_options.useOpenGL = settings.value(USE_OPENGL_SETTING, USE_OPENGL_DEFAULT)
|
||||
.toBool();
|
||||
_options.enableHTTP2 = settings.value(ENABLE_HTTP2_SETTING,
|
||||
@ -2641,6 +2732,11 @@ void GUI::readSettings()
|
||||
|
||||
_poi->setRadius(_options.poiRadius);
|
||||
|
||||
_dem->setUrl(_options.demURL);
|
||||
if (_options.demAuthorization)
|
||||
_dem->setAuthorization(Authorization(_options.demUsername,
|
||||
_options.demPassword));
|
||||
|
||||
QPixmapCache::setCacheLimit(_options.pixmapCache * 1024);
|
||||
|
||||
settings.endGroup();
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include <QDate>
|
||||
#include <QPrinter>
|
||||
#include "common/treenode.h"
|
||||
#include "common/rectc.h"
|
||||
#include "data/graph.h"
|
||||
#include "units.h"
|
||||
#include "timetype.h"
|
||||
@ -32,6 +33,7 @@ class QScreen;
|
||||
class MapAction;
|
||||
class POIAction;
|
||||
class Data;
|
||||
class DEMLoader;
|
||||
|
||||
class GUI : public QMainWindow
|
||||
{
|
||||
@ -65,12 +67,15 @@ private slots:
|
||||
void showFullscreen(bool show);
|
||||
void showTracks(bool show);
|
||||
void showRoutes(bool show);
|
||||
void showAreas(bool show);
|
||||
void showWaypoints(bool show);
|
||||
void loadMap();
|
||||
void loadMapDir();
|
||||
void nextMap();
|
||||
void prevMap();
|
||||
void openOptions();
|
||||
void clearMapCache();
|
||||
void downloadDEM();
|
||||
|
||||
void mapChanged(QAction *action);
|
||||
void graphChanged(int);
|
||||
@ -102,6 +107,8 @@ private slots:
|
||||
void mapLoadedDir();
|
||||
void mapInitialized();
|
||||
|
||||
void demLoaded();
|
||||
|
||||
private:
|
||||
typedef QPair<QDateTime, QDateTime> DateTimeRange;
|
||||
|
||||
@ -138,6 +145,7 @@ private:
|
||||
void updateStatusBarInfo();
|
||||
void updateWindowTitle();
|
||||
bool updateGraphTabs();
|
||||
void updateDEMDownloadAction();
|
||||
|
||||
TimeType timeType() const;
|
||||
Units units() const;
|
||||
@ -224,6 +232,7 @@ private:
|
||||
QAction *_showTicksAction;
|
||||
QAction *_showCoordinatesAction;
|
||||
QAction *_openOptionsAction;
|
||||
QAction *_downloadDEMAction;
|
||||
QAction *_mapsEnd;
|
||||
QAction *_poisEnd;
|
||||
|
||||
@ -239,6 +248,7 @@ private:
|
||||
|
||||
POI *_poi;
|
||||
Map *_map;
|
||||
DEMLoader *_dem;
|
||||
|
||||
FileBrowser *_browser;
|
||||
QList<QString> _files;
|
||||
@ -260,6 +270,8 @@ private:
|
||||
QString _dataDir, _mapDir, _poiDir;
|
||||
|
||||
Units _units;
|
||||
|
||||
QList<RectC> _demRects;
|
||||
};
|
||||
|
||||
#endif // GUI_H
|
||||
|
@ -9,7 +9,7 @@ HeartRateGraphItem::HeartRateGraphItem(const Graph &graph, GraphType type,
|
||||
{
|
||||
}
|
||||
|
||||
QString HeartRateGraphItem::info() const
|
||||
ToolTip HeartRateGraphItem::info() const
|
||||
{
|
||||
ToolTip tt;
|
||||
QLocale l(QLocale::system());
|
||||
@ -19,5 +19,5 @@ QString HeartRateGraphItem::info() const
|
||||
tt.insert(tr("Average"), l.toString(avg(), 'f', 0)
|
||||
+ UNIT_SPACE + tr("bpm"));
|
||||
|
||||
return tt.toString();
|
||||
return tt;
|
||||
}
|
||||
|
@ -11,7 +11,7 @@ public:
|
||||
HeartRateGraphItem(const Graph &graph, GraphType type, int width,
|
||||
const QColor &color, QGraphicsItem *parent = 0);
|
||||
|
||||
QString info() const;
|
||||
ToolTip info() const;
|
||||
};
|
||||
|
||||
#endif // HEARTRATEGRAPHITEM_H
|
||||
|
@ -26,5 +26,6 @@
|
||||
#define PRINT_EXPORT_ICON ":/document-print_32.png"
|
||||
#define DATA_ICON ":/view-filter.png"
|
||||
#define MAPS_ICON ":/applications-internet_32.png"
|
||||
#define DEM_ICON ":/view-grid.png"
|
||||
|
||||
#endif /* ICONS_H */
|
||||
|
@ -56,17 +56,25 @@ void InfoItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
|
||||
//painter->drawRect(boundingRect());
|
||||
}
|
||||
|
||||
int InfoItem::indexOf(const QString &key) const
|
||||
{
|
||||
for (int i = 0; i < _list.size(); i++)
|
||||
if (_list.at(i).key() == key)
|
||||
return i;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void InfoItem::insert(const QString &key, const QString &value)
|
||||
{
|
||||
KV<QString, QString> kv(key, value);
|
||||
int i;
|
||||
|
||||
prepareGeometryChange();
|
||||
|
||||
if ((i = _list.indexOf(kv)) < 0)
|
||||
_list.append(kv);
|
||||
if ((i = indexOf(key)) < 0)
|
||||
_list.append(KV<QString, QString>(key, value));
|
||||
else
|
||||
_list[i] = kv;
|
||||
_list[i] = KV<QString, QString>(key, value);
|
||||
|
||||
updateBoundingRect();
|
||||
update();
|
||||
|
@ -22,6 +22,7 @@ public:
|
||||
|
||||
private:
|
||||
void updateBoundingRect();
|
||||
int indexOf(const QString &key) const;
|
||||
|
||||
QList<KV<QString, QString> > _list;
|
||||
QRectF _boundingRect;
|
||||
|
15
src/GUI/infolabel.cpp
Normal file
15
src/GUI/infolabel.cpp
Normal file
@ -0,0 +1,15 @@
|
||||
#include <QtGlobal>
|
||||
#include "infolabel.h"
|
||||
|
||||
InfoLabel::InfoLabel(const QString &text, QWidget *parent)
|
||||
: QLabel(text, parent)
|
||||
{
|
||||
QFont f(font());
|
||||
#ifdef Q_OS_MAC
|
||||
f.setPointSize(qMax(10, f.pointSize() - 2));
|
||||
#else // Q_OS_MAC
|
||||
f.setPointSize(f.pointSize() - 1);
|
||||
#endif // Q_OS_MAC
|
||||
setWordWrap(true);
|
||||
setFont(f);
|
||||
}
|
12
src/GUI/infolabel.h
Normal file
12
src/GUI/infolabel.h
Normal file
@ -0,0 +1,12 @@
|
||||
#ifndef INFOLABEL_H
|
||||
#define INFOLABEL_H
|
||||
|
||||
#include <QLabel>
|
||||
|
||||
class InfoLabel : public QLabel
|
||||
{
|
||||
public:
|
||||
InfoLabel(const QString &text, QWidget *parent = 0);
|
||||
};
|
||||
|
||||
#endif // INFOLABEL_H
|
@ -28,6 +28,8 @@
|
||||
#define PREV_MAP_SHORTCUT QKeySequence(QKeySequence::Back)
|
||||
#define SHOW_GRAPHS_SHORTCUT QKeySequence(Qt::CTRL + Qt::Key_G)
|
||||
#define STATISTICS_SHORTCUT QKeySequence(Qt::CTRL + Qt::Key_S)
|
||||
#define DOWNLOAD_DEM_SHORTCUT QKeySequence(Qt::CTRL + Qt::Key_D)
|
||||
#define SHOW_TRACKS_SHORTCUT QKeySequence(Qt::CTRL + Qt::Key_T)
|
||||
#define FULLSCREEN_SHORTCUT (QKeySequence(QKeySequence::FullScreen).isEmpty() \
|
||||
? QKeySequence(Qt::Key_F11) \
|
||||
: QKeySequence(QKeySequence::FullScreen))
|
||||
|
@ -69,7 +69,7 @@ static QRectF bbox(const RectC &rect, Map *map, int samples = 100)
|
||||
return prect;
|
||||
}
|
||||
|
||||
QString MapItem::info() const
|
||||
ToolTip MapItem::info() const
|
||||
{
|
||||
ToolTip tt;
|
||||
|
||||
@ -78,7 +78,7 @@ QString MapItem::info() const
|
||||
if (!_fileName.isEmpty())
|
||||
tt.insert(tr("File"), _fileName);
|
||||
|
||||
return tt.toString();
|
||||
return tt;
|
||||
}
|
||||
|
||||
MapItem::MapItem(MapAction *action, Map *map, GraphicsItem *parent)
|
||||
|
@ -26,7 +26,7 @@ public:
|
||||
void setStyle(Qt::PenStyle style);
|
||||
void setDigitalZoom(int zoom);
|
||||
|
||||
QString info() const;
|
||||
ToolTip info() const;
|
||||
|
||||
signals:
|
||||
void triggered();
|
||||
|
@ -1147,3 +1147,19 @@ void MapView::fitContentToSize()
|
||||
|
||||
centerOn(contentCenter());
|
||||
}
|
||||
|
||||
RectC MapView::boundingRect() const
|
||||
{
|
||||
RectC rect;
|
||||
|
||||
if (_showTracks)
|
||||
rect |= _tr;
|
||||
if (_showRoutes)
|
||||
rect |= _rr;
|
||||
if (_showWaypoints)
|
||||
rect |= _wr;
|
||||
if (_showAreas)
|
||||
rect |= _ar;
|
||||
|
||||
return rect;
|
||||
}
|
||||
|
@ -88,6 +88,8 @@ public:
|
||||
void clearMapCache();
|
||||
void fitContentToSize();
|
||||
|
||||
RectC boundingRect() const;
|
||||
|
||||
public slots:
|
||||
void showMap(bool show);
|
||||
void showPOI(bool show);
|
||||
|
@ -14,12 +14,14 @@
|
||||
#include <QSysInfo>
|
||||
#include <QButtonGroup>
|
||||
#include "icons.h"
|
||||
#include "infolabel.h"
|
||||
#include "colorbox.h"
|
||||
#include "stylecombobox.h"
|
||||
#include "oddspinbox.h"
|
||||
#include "percentslider.h"
|
||||
#include "projectioncombobox.h"
|
||||
#include "dirselectwidget.h"
|
||||
#include "authenticationwidget.h"
|
||||
#include "optionsdialog.h"
|
||||
|
||||
|
||||
@ -53,17 +55,11 @@ QWidget *OptionsDialog::createMapPage()
|
||||
_inputProjection->setCurrentIndex(_inputProjection->findData(
|
||||
_options.inputProjection));
|
||||
|
||||
QLabel *inInfo = new QLabel(tr("Select the proper projection of maps"
|
||||
InfoLabel *inInfo = new InfoLabel(tr("Select the proper projection of maps"
|
||||
" without a projection definition (JNX, KMZ and world file maps)."));
|
||||
QLabel *outInfo = new QLabel(tr("Select the desired projection of vector"
|
||||
" maps (IMG and Mapsforge maps). The projection must be valid for"
|
||||
InfoLabel *outInfo = new InfoLabel(tr("Select the desired projection of"
|
||||
" vector maps (IMG and Mapsforge maps). The projection must be valid for"
|
||||
" the whole map area."));
|
||||
QFont f = inInfo->font();
|
||||
f.setPointSize(f.pointSize() - 1);
|
||||
inInfo->setWordWrap(true);
|
||||
outInfo->setWordWrap(true);
|
||||
inInfo->setFont(f);
|
||||
outInfo->setFont(f);
|
||||
|
||||
_hidpi = new QRadioButton(tr("High-resolution"));
|
||||
_lodpi = new QRadioButton(tr("Standard"));
|
||||
@ -71,14 +67,10 @@ QWidget *OptionsDialog::createMapPage()
|
||||
_hidpi->setChecked(true);
|
||||
else
|
||||
_lodpi->setChecked(true);
|
||||
QLabel *lhi = new QLabel(tr("Non-HiDPI maps are loaded as HiDPI maps. "
|
||||
InfoLabel *lhi = new InfoLabel(tr("Non-HiDPI maps are loaded as HiDPI maps. "
|
||||
"The map is sharp but map objects are small/hard to read."));
|
||||
QLabel *llo = new QLabel(tr("Non-HiDPI maps are loaded such as they are. "
|
||||
InfoLabel *llo = new InfoLabel(tr("Non-HiDPI maps are loaded such as they are. "
|
||||
"Map objects have the expected size but the map is blurry."));
|
||||
lhi->setWordWrap(true);
|
||||
llo->setWordWrap(true);
|
||||
lhi->setFont(f);
|
||||
llo->setFont(f);
|
||||
|
||||
QVBoxLayout *inLayout = new QVBoxLayout();
|
||||
inLayout->addWidget(_inputProjection);
|
||||
@ -134,34 +126,12 @@ QWidget *OptionsDialog::createAppearancePage()
|
||||
_trackWidth->setMinimum(1);
|
||||
_trackStyle = new StyleComboBox();
|
||||
_trackStyle->setValue(_options.trackStyle);
|
||||
QFormLayout *trackLayout = new QFormLayout();
|
||||
#ifdef Q_OS_MAC
|
||||
trackLayout->addRow(tr("Track width:"), _trackWidth);
|
||||
trackLayout->addRow(tr("Track style:"), _trackStyle);
|
||||
#else // Q_OS_MAC
|
||||
trackLayout->addRow(tr("Width:"), _trackWidth);
|
||||
trackLayout->addRow(tr("Style:"), _trackStyle);
|
||||
QGroupBox *trackBox = new QGroupBox(tr("Tracks"));
|
||||
trackBox->setLayout(trackLayout);
|
||||
#endif // Q_OS_MAC
|
||||
|
||||
// Routes
|
||||
_routeWidth = new QSpinBox();
|
||||
_routeWidth->setValue(_options.routeWidth);
|
||||
_routeWidth->setMinimum(1);
|
||||
_routeStyle = new StyleComboBox();
|
||||
_routeStyle->setValue(_options.routeStyle);
|
||||
QFormLayout *routeLayout = new QFormLayout();
|
||||
#ifdef Q_OS_MAC
|
||||
routeLayout->addRow(tr("Route width:"), _routeWidth);
|
||||
routeLayout->addRow(tr("Route style:"), _routeStyle);
|
||||
#else // Q_OS_MAC
|
||||
routeLayout->addRow(tr("Width:"), _routeWidth);
|
||||
routeLayout->addRow(tr("Style:"), _routeStyle);
|
||||
QGroupBox *routeBox = new QGroupBox(tr("Routes"));
|
||||
routeBox->setLayout(routeLayout);
|
||||
#endif // Q_OS_MAC
|
||||
|
||||
// Areas
|
||||
_areaWidth = new QSpinBox();
|
||||
_areaWidth->setValue(_options.areaWidth);
|
||||
@ -169,52 +139,64 @@ QWidget *OptionsDialog::createAppearancePage()
|
||||
_areaStyle->setValue(_options.areaStyle);
|
||||
_areaOpacity = new PercentSlider();
|
||||
_areaOpacity->setValue(_options.areaOpacity);
|
||||
QFormLayout *areaLayout = new QFormLayout();
|
||||
#ifdef Q_OS_MAC
|
||||
areaLayout->addRow(tr("Area border width:"), _areaWidth);
|
||||
areaLayout->addRow(tr("Area border style:"), _areaStyle);
|
||||
areaLayout->addRow(tr("Area fill opacity:"), _areaOpacity);
|
||||
#else // Q_OS_MAC
|
||||
areaLayout->addRow(tr("Width:"), _areaWidth);
|
||||
areaLayout->addRow(tr("Style:"), _areaStyle);
|
||||
areaLayout->addRow(tr("Fill opacity:"), _areaOpacity);
|
||||
QGroupBox *areaBox = new QGroupBox(tr("Areas"));
|
||||
areaBox->setLayout(areaLayout);
|
||||
#endif // Q_OS_MAC
|
||||
|
||||
// Palette & antialiasing
|
||||
_baseColor = new ColorBox();
|
||||
_baseColor->setColor(_options.palette.color());
|
||||
_colorOffset = new PercentSlider();
|
||||
_colorOffset->setValue(_options.palette.shift() * 100);
|
||||
_pathAA = new QCheckBox(tr("Use anti-aliasing"));
|
||||
_pathAA->setChecked(_options.pathAntiAliasing);
|
||||
|
||||
#ifdef Q_OS_MAC
|
||||
QWidget *pathTab = new QWidget();
|
||||
QFormLayout *pathTabLayout = new QFormLayout();
|
||||
pathTabLayout->addRow(tr("Track width:"), _trackWidth);
|
||||
pathTabLayout->addRow(tr("Track style:"), _trackStyle);
|
||||
pathTabLayout->addRow(line());
|
||||
pathTabLayout->addRow(tr("Route width:"), _routeWidth);
|
||||
pathTabLayout->addRow(tr("Route style:"), _routeStyle);
|
||||
pathTabLayout->addRow(line());
|
||||
pathTabLayout->addRow(tr("Area border width:"), _areaWidth);
|
||||
pathTabLayout->addRow(tr("Area border style:"), _areaStyle);
|
||||
pathTabLayout->addRow(tr("Area fill opacity:"), _areaOpacity);
|
||||
pathTabLayout->addRow(line());
|
||||
pathTabLayout->addRow(tr("Base color:"), _baseColor);
|
||||
pathTabLayout->addRow(tr("Palette shift:"), _colorOffset);
|
||||
pathTabLayout->addRow(line());
|
||||
pathTabLayout->addWidget(_pathAA);
|
||||
pathTab->setLayout(pathTabLayout);
|
||||
#else // Q_OS_MAC
|
||||
QFormLayout *trackLayout = new QFormLayout();
|
||||
trackLayout->addRow(tr("Width:"), _trackWidth);
|
||||
trackLayout->addRow(tr("Style:"), _trackStyle);
|
||||
QGroupBox *trackBox = new QGroupBox(tr("Tracks"));
|
||||
trackBox->setLayout(trackLayout);
|
||||
QFormLayout *routeLayout = new QFormLayout();
|
||||
routeLayout->addRow(tr("Width:"), _routeWidth);
|
||||
routeLayout->addRow(tr("Style:"), _routeStyle);
|
||||
QGroupBox *routeBox = new QGroupBox(tr("Routes"));
|
||||
routeBox->setLayout(routeLayout);
|
||||
QFormLayout *areaLayout = new QFormLayout();
|
||||
areaLayout->addRow(tr("Width:"), _areaWidth);
|
||||
areaLayout->addRow(tr("Style:"), _areaStyle);
|
||||
areaLayout->addRow(tr("Fill opacity:"), _areaOpacity);
|
||||
QGroupBox *areaBox = new QGroupBox(tr("Areas"));
|
||||
areaBox->setLayout(areaLayout);
|
||||
QFormLayout *paletteLayout = new QFormLayout();
|
||||
paletteLayout->addRow(tr("Base color:"), _baseColor);
|
||||
paletteLayout->addRow(tr("Palette shift:"), _colorOffset);
|
||||
|
||||
_pathAA = new QCheckBox(tr("Use anti-aliasing"));
|
||||
_pathAA->setChecked(_options.pathAntiAliasing);
|
||||
QFormLayout *pathAALayout = new QFormLayout();
|
||||
pathAALayout->addWidget(_pathAA);
|
||||
|
||||
QWidget *pathTab = new QWidget();
|
||||
QVBoxLayout *pathTabLayout = new QVBoxLayout();
|
||||
#ifdef Q_OS_MAC
|
||||
pathTabLayout->addLayout(trackLayout);
|
||||
pathTabLayout->addWidget(line());
|
||||
pathTabLayout->addLayout(routeLayout);
|
||||
pathTabLayout->addWidget(line());
|
||||
pathTabLayout->addLayout(areaLayout);
|
||||
pathTabLayout->addWidget(line());
|
||||
#else // Q_OS_MAC
|
||||
pathTabLayout->addWidget(trackBox);
|
||||
pathTabLayout->addWidget(routeBox);
|
||||
pathTabLayout->addWidget(areaBox);
|
||||
#endif // Q_OS_MAC
|
||||
pathTabLayout->addLayout(paletteLayout);
|
||||
pathTabLayout->addLayout(pathAALayout);
|
||||
pathTabLayout->addStretch();
|
||||
pathTab->setLayout(pathTabLayout);
|
||||
|
||||
#endif // Q_OS_MAC
|
||||
|
||||
// Waypoints
|
||||
_waypointSize = new QSpinBox();
|
||||
@ -222,46 +204,40 @@ QWidget *OptionsDialog::createAppearancePage()
|
||||
_waypointSize->setValue(_options.waypointSize);
|
||||
_waypointColor = new ColorBox();
|
||||
_waypointColor->setColor(_options.waypointColor);
|
||||
QFormLayout *waypointLayout = new QFormLayout();
|
||||
#ifdef Q_OS_MAC
|
||||
waypointLayout->addRow(tr("Waypoint color:"), _waypointColor);
|
||||
waypointLayout->addRow(tr("Waypoint size:"), _waypointSize);
|
||||
#else // Q_OS_MAC
|
||||
waypointLayout->addRow(tr("Color:"), _waypointColor);
|
||||
waypointLayout->addRow(tr("Size:"), _waypointSize);
|
||||
QGroupBox *waypointBox = new QGroupBox(tr("Waypoints"));
|
||||
waypointBox->setLayout(waypointLayout);
|
||||
#endif // Q_OS_MAC
|
||||
|
||||
// POI
|
||||
_poiSize = new QSpinBox();
|
||||
_poiSize->setMinimum(1);
|
||||
_poiSize->setValue(_options.poiSize);
|
||||
_poiColor = new ColorBox();
|
||||
_poiColor->setColor(_options.poiColor);
|
||||
QFormLayout *poiLayout = new QFormLayout();
|
||||
|
||||
#ifdef Q_OS_MAC
|
||||
poiLayout->addRow(tr("POI color:"), _poiColor);
|
||||
poiLayout->addRow(tr("POI size:"), _poiSize);
|
||||
QWidget *pointTab = new QWidget();
|
||||
QFormLayout *pointTabLayout = new QFormLayout();
|
||||
pointTabLayout->addRow(tr("Waypoint color:"), _waypointColor);
|
||||
pointTabLayout->addRow(tr("Waypoint size:"), _waypointSize);
|
||||
pointTabLayout->addRow(line());
|
||||
pointTabLayout->addRow(tr("POI color:"), _poiColor);
|
||||
pointTabLayout->addRow(tr("POI size:"), _poiSize);
|
||||
pointTab->setLayout(pointTabLayout);
|
||||
#else // Q_OS_MAC
|
||||
QFormLayout *waypointLayout = new QFormLayout();
|
||||
waypointLayout->addRow(tr("Color:"), _waypointColor);
|
||||
waypointLayout->addRow(tr("Size:"), _waypointSize);
|
||||
QGroupBox *waypointBox = new QGroupBox(tr("Waypoints"));
|
||||
waypointBox->setLayout(waypointLayout);
|
||||
QFormLayout *poiLayout = new QFormLayout();
|
||||
poiLayout->addRow(tr("Color:"), _poiColor);
|
||||
poiLayout->addRow(tr("Size:"), _poiSize);
|
||||
QGroupBox *poiBox = new QGroupBox(tr("POIs"));
|
||||
poiBox->setLayout(poiLayout);
|
||||
#endif // Q_OS_MAC
|
||||
|
||||
QWidget *pointTab = new QWidget();
|
||||
QVBoxLayout *pointTabLayout = new QVBoxLayout();
|
||||
#ifdef Q_OS_MAC
|
||||
pointTabLayout->addLayout(waypointLayout);
|
||||
pointTabLayout->addWidget(line());
|
||||
pointTabLayout->addLayout(poiLayout);
|
||||
#else // Q_OS_MAC
|
||||
pointTabLayout->addWidget(waypointBox);
|
||||
pointTabLayout->addWidget(poiBox);
|
||||
#endif // Q_OS_MAC
|
||||
pointTabLayout->addStretch();
|
||||
pointTab->setLayout(pointTabLayout);
|
||||
|
||||
#endif // Q_OS_MAC
|
||||
|
||||
// Graphs
|
||||
_sliderColor = new ColorBox();
|
||||
@ -269,23 +245,29 @@ QWidget *OptionsDialog::createAppearancePage()
|
||||
_graphWidth = new QSpinBox();
|
||||
_graphWidth->setValue(_options.graphWidth);
|
||||
_graphWidth->setMinimum(1);
|
||||
_graphAA = new QCheckBox(tr("Use anti-aliasing"));
|
||||
_graphAA->setChecked(_options.graphAntiAliasing);
|
||||
|
||||
#ifdef Q_OS_MAC
|
||||
QWidget *graphTab = new QWidget();
|
||||
QFormLayout *graphTabLayout = new QFormLayout();
|
||||
graphTabLayout->addRow(tr("Line width:"), _graphWidth);
|
||||
graphTabLayout->addRow(tr("Slider color:"), _sliderColor);
|
||||
graphTabLayout->addWidget(_graphAA);
|
||||
graphTab->setLayout(graphTabLayout);
|
||||
#else // Q_OS_MAC
|
||||
QFormLayout *graphLayout = new QFormLayout();
|
||||
graphLayout->addRow(tr("Line width:"), _graphWidth);
|
||||
graphLayout->addRow(tr("Slider color:"), _sliderColor);
|
||||
|
||||
_graphAA = new QCheckBox(tr("Use anti-aliasing"));
|
||||
_graphAA->setChecked(_options.graphAntiAliasing);
|
||||
QFormLayout *graphAALayout = new QFormLayout();
|
||||
graphAALayout->addWidget(_graphAA);
|
||||
|
||||
QWidget *graphTab = new QWidget();
|
||||
QVBoxLayout *graphTabLayout = new QVBoxLayout();
|
||||
graphTabLayout->addLayout(graphLayout);
|
||||
graphTabLayout->addLayout(graphAALayout);
|
||||
graphTabLayout->addStretch();
|
||||
graphTab->setLayout(graphTabLayout);
|
||||
|
||||
#endif // Q_OS_MAC
|
||||
|
||||
// Map
|
||||
_mapOpacity = new PercentSlider();
|
||||
@ -297,14 +279,12 @@ QWidget *OptionsDialog::createAppearancePage()
|
||||
QFormLayout *mapLayout = new QFormLayout();
|
||||
mapLayout->addRow(tr("Background color:"), _backgroundColor);
|
||||
mapLayout->addRow(tr("Map opacity:"), _mapOpacity);
|
||||
|
||||
QWidget *mapTab = new QWidget();
|
||||
QVBoxLayout *mapTabLayout = new QVBoxLayout();
|
||||
mapTabLayout->addLayout(mapLayout);
|
||||
mapTabLayout->addStretch();
|
||||
mapTab->setLayout(mapTabLayout);
|
||||
|
||||
|
||||
QTabWidget *appearancePage = new QTabWidget();
|
||||
appearancePage->addTab(pathTab, tr("Paths"));
|
||||
appearancePage->addTab(pointTab, tr("Points"));
|
||||
@ -334,36 +314,39 @@ QWidget *OptionsDialog::createDataPage()
|
||||
_powerFilter->setValue(_options.powerFilter);
|
||||
_powerFilter->setToolTip(filterToolTip);
|
||||
|
||||
_outlierEliminate = new QCheckBox(tr("Eliminate GPS outliers"));
|
||||
_outlierEliminate->setChecked(_options.outlierEliminate);
|
||||
|
||||
#ifdef Q_OS_MAC
|
||||
QWidget *filterTab = new QWidget();
|
||||
QFormLayout *filterTabLayout = new QFormLayout();
|
||||
filterTabLayout->addWidget(new QLabel(tr("Smoothing")));
|
||||
filterTabLayout->addRow(tr("Elevation:"), _elevationFilter);
|
||||
filterTabLayout->addRow(tr("Speed:"), _speedFilter);
|
||||
filterTabLayout->addRow(tr("Heart rate:"), _heartRateFilter);
|
||||
filterTabLayout->addRow(tr("Cadence:"), _cadenceFilter);
|
||||
filterTabLayout->addRow(tr("Power:"), _powerFilter);
|
||||
filterTabLayout->addWidget(new QWidget());
|
||||
filterTabLayout->addWidget(_outlierEliminate);
|
||||
filterTab->setLayout(filterTabLayout);
|
||||
#else // Q_OS_MAC
|
||||
QFormLayout *smoothLayout = new QFormLayout();
|
||||
smoothLayout->addRow(tr("Elevation:"), _elevationFilter);
|
||||
smoothLayout->addRow(tr("Speed:"), _speedFilter);
|
||||
smoothLayout->addRow(tr("Heart rate:"), _heartRateFilter);
|
||||
smoothLayout->addRow(tr("Cadence:"), _cadenceFilter);
|
||||
smoothLayout->addRow(tr("Power:"), _powerFilter);
|
||||
#ifndef Q_OS_MAC
|
||||
QGroupBox *smoothBox = new QGroupBox(tr("Smoothing"));
|
||||
smoothBox->setLayout(smoothLayout);
|
||||
#endif // Q_OS_MAC
|
||||
|
||||
_outlierEliminate = new QCheckBox(tr("Eliminate GPS outliers"));
|
||||
_outlierEliminate->setChecked(_options.outlierEliminate);
|
||||
|
||||
QFormLayout *outlierLayout = new QFormLayout();
|
||||
outlierLayout->addWidget(_outlierEliminate);
|
||||
|
||||
QWidget *filterTab = new QWidget();
|
||||
QVBoxLayout *filterTabLayout = new QVBoxLayout();
|
||||
#ifdef Q_OS_MAC
|
||||
filterTabLayout->addWidget(new QLabel(tr("Smoothing:")));
|
||||
filterTabLayout->addLayout(smoothLayout);
|
||||
filterTabLayout->addWidget(line());
|
||||
#else // Q_OS_MAC
|
||||
QGroupBox *smoothBox = new QGroupBox(tr("Smoothing"));
|
||||
smoothBox->setLayout(smoothLayout);
|
||||
QFormLayout *outlierLayout = new QFormLayout();
|
||||
outlierLayout->addWidget(_outlierEliminate);
|
||||
filterTabLayout->addWidget(smoothBox);
|
||||
#endif // Q_OS_MAC
|
||||
filterTabLayout->addLayout(outlierLayout);
|
||||
filterTabLayout->addStretch();
|
||||
filterTab->setLayout(filterTabLayout);
|
||||
|
||||
#endif // Q_OS_MAC
|
||||
|
||||
_automaticPause = new QRadioButton(tr("Automatic"));
|
||||
_manualPause = new QRadioButton(tr("Custom"));
|
||||
@ -396,26 +379,6 @@ QWidget *OptionsDialog::createDataPage()
|
||||
connect(_automaticPause, &QRadioButton::toggled, this,
|
||||
&OptionsDialog::automaticPauseDetectionSet);
|
||||
|
||||
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);
|
||||
|
||||
|
||||
_computedSpeed = new QRadioButton(tr("Computed from distance/time"));
|
||||
_reportedSpeed = new QRadioButton(tr("Recorded by device"));
|
||||
if (_options.useReportedSpeed)
|
||||
@ -458,10 +421,9 @@ QWidget *OptionsDialog::createDataPage()
|
||||
_useSegments = new QCheckBox(tr("Use segments"));
|
||||
_useSegments->setChecked(_options.useSegments);
|
||||
|
||||
QWidget *sourceTab = new QWidget();
|
||||
QVBoxLayout *sourceTabLayout = new QVBoxLayout();
|
||||
|
||||
#ifdef Q_OS_MAC
|
||||
QWidget *sourceTab = new QWidget();
|
||||
QFormLayout *sourceTabLayout = new QFormLayout();
|
||||
QButtonGroup *speedGroup = new QButtonGroup(this);
|
||||
speedGroup->addButton(_computedSpeed);
|
||||
speedGroup->addButton(_reportedSpeed);
|
||||
@ -469,7 +431,6 @@ QWidget *OptionsDialog::createDataPage()
|
||||
speedOptions->addWidget(_computedSpeed);
|
||||
speedOptions->addWidget(_reportedSpeed);
|
||||
speedOptions->addWidget(_showSecondarySpeed);
|
||||
|
||||
QButtonGroup *elevationGroup = new QButtonGroup(this);
|
||||
elevationGroup->addButton(_dataGPSElevation);
|
||||
elevationGroup->addButton(_dataDEMElevation);
|
||||
@ -477,7 +438,6 @@ QWidget *OptionsDialog::createDataPage()
|
||||
elevationOptions->addWidget(_dataGPSElevation);
|
||||
elevationOptions->addWidget(_dataDEMElevation);
|
||||
elevationOptions->addWidget(_showSecondaryElevation);
|
||||
|
||||
QButtonGroup *timeZoneGroup = new QButtonGroup(this);
|
||||
timeZoneGroup->addButton(_utcZone);
|
||||
timeZoneGroup->addButton(_systemZone);
|
||||
@ -487,62 +447,68 @@ QWidget *OptionsDialog::createDataPage()
|
||||
zoneOptions->addWidget(_systemZone);
|
||||
zoneOptions->addWidget(_customZone);
|
||||
zoneOptions->addItem(customZoneLayout);
|
||||
|
||||
QFormLayout *formLayout = new QFormLayout();
|
||||
formLayout->addRow(tr("Speed:"), speedOptions);
|
||||
formLayout->addRow(tr("Elevation:"), elevationOptions);
|
||||
|
||||
formLayout->addRow(tr("Time zone:"), zoneOptions);
|
||||
|
||||
QFormLayout *segmentsLayout = new QFormLayout();
|
||||
segmentsLayout->addWidget(_useSegments);
|
||||
|
||||
sourceTabLayout->addLayout(formLayout);
|
||||
sourceTabLayout->addWidget(line());
|
||||
sourceTabLayout->addLayout(segmentsLayout);
|
||||
|
||||
sourceTabLayout->addRow(tr("Speed:"), speedOptions);
|
||||
sourceTabLayout->addRow(tr("Elevation:"), elevationOptions);
|
||||
sourceTabLayout->addRow(tr("Time zone:"), zoneOptions);
|
||||
sourceTabLayout->addRow(line());
|
||||
sourceTabLayout->addWidget(_useSegments);
|
||||
sourceTab->setLayout(sourceTabLayout);
|
||||
#else // Q_OS_MAC
|
||||
QWidget *sourceTab = new QWidget();
|
||||
QVBoxLayout *sourceTabLayout = new QVBoxLayout();
|
||||
QFormLayout *speedLayout = new QFormLayout();
|
||||
QFormLayout *elevationLayout = new QFormLayout();
|
||||
QFormLayout *timeZoneLayout = new QFormLayout();
|
||||
QFormLayout *segmentsLayout = new QFormLayout();
|
||||
|
||||
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);
|
||||
|
||||
timeZoneLayout->addWidget(_utcZone);
|
||||
timeZoneLayout->addWidget(_systemZone);
|
||||
timeZoneLayout->addWidget(_customZone);
|
||||
timeZoneLayout->addItem(customZoneLayout);
|
||||
|
||||
QGroupBox *timeZoneBox = new QGroupBox(tr("Time zone"));
|
||||
timeZoneBox->setLayout(timeZoneLayout);
|
||||
|
||||
segmentsLayout->addWidget(_useSegments);
|
||||
|
||||
sourceTabLayout->addWidget(speedBox);
|
||||
sourceTabLayout->addWidget(elevationBox);
|
||||
sourceTabLayout->addWidget(timeZoneBox);
|
||||
sourceTabLayout->addLayout(segmentsLayout);
|
||||
#endif // Q_OS_MAC
|
||||
sourceTabLayout->addStretch();
|
||||
sourceTab->setLayout(sourceTabLayout);
|
||||
#endif // Q_OS_MAC
|
||||
|
||||
|
||||
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);
|
||||
|
||||
|
||||
QTabWidget *dataPage = new QTabWidget();
|
||||
dataPage->addTab(filterTab, tr("Filtering"));
|
||||
dataPage->addTab(sourceTab, tr("Sources"));
|
||||
dataPage->addTab(filterTab, tr("Filtering"));
|
||||
dataPage->addTab(pauseTab, tr("Pause detection"));
|
||||
|
||||
return dataPage;
|
||||
@ -576,6 +542,57 @@ QWidget *OptionsDialog::createPOIPage()
|
||||
return poiPage;
|
||||
}
|
||||
|
||||
QWidget *OptionsDialog::createDEMPage()
|
||||
{
|
||||
_demURL = new QLineEdit();
|
||||
_demURL->setMinimumWidth(300);
|
||||
_demURL->setText(_options.demURL);
|
||||
_demAuth = new AuthenticationWidget();
|
||||
_demAuth->setUsername(_options.demUsername);
|
||||
_demAuth->setPassword(_options.demPassword);
|
||||
_demAuth->setEnabled(_options.demAuthorization);
|
||||
|
||||
QCheckBox *useAuth = new QCheckBox(tr("Use HTTP authentication"));
|
||||
useAuth->setChecked(_demAuth->isEnabled());
|
||||
connect(useAuth, &QRadioButton::toggled, _demAuth,
|
||||
&AuthenticationWidget::setEnabled);
|
||||
|
||||
InfoLabel *info = new InfoLabel(
|
||||
tr("Use $lat and $lon for NYY/SYY and EXXX/WXXX in the URL."));
|
||||
info->setMinimumWidth(_demURL->minimumWidth());
|
||||
|
||||
#ifdef Q_OS_MAC
|
||||
QFormLayout *sourceLayout = new QFormLayout();
|
||||
sourceLayout->addRow(tr("URL:"), _demURL);
|
||||
sourceLayout->addWidget(info);
|
||||
sourceLayout->addWidget(new QWidget());
|
||||
sourceLayout->addWidget(useAuth);
|
||||
sourceLayout->addWidget(_demAuth);
|
||||
sourceLayout->setAlignment(_demAuth, Qt::AlignLeft);
|
||||
QWidget *sourceTab = new QWidget();
|
||||
sourceTab->setLayout(sourceLayout);
|
||||
#else // Q_OS_MAC
|
||||
QVBoxLayout *urlValueLayout = new QVBoxLayout();
|
||||
urlValueLayout->addWidget(_demURL);
|
||||
urlValueLayout->addWidget(info);
|
||||
QFormLayout *urlLayout = new QFormLayout();
|
||||
urlLayout->addRow(tr("URL:"), urlValueLayout);
|
||||
QVBoxLayout *sourceLayout = new QVBoxLayout();
|
||||
sourceLayout->addLayout(urlLayout);
|
||||
sourceLayout->addSpacing(10);
|
||||
sourceLayout->addWidget(useAuth);
|
||||
sourceLayout->addWidget(_demAuth);
|
||||
sourceLayout->addStretch();
|
||||
QWidget *sourceTab = new QWidget();
|
||||
sourceTab->setLayout(sourceLayout);
|
||||
#endif // Q_OS_MAC
|
||||
|
||||
QTabWidget *demPage = new QTabWidget();
|
||||
demPage->addTab(sourceTab, tr("Source"));
|
||||
|
||||
return demPage;
|
||||
}
|
||||
|
||||
QWidget *OptionsDialog::createExportPage()
|
||||
{
|
||||
_wysiwyg = new QRadioButton(tr("WYSIWYG"));
|
||||
@ -584,17 +601,11 @@ QWidget *OptionsDialog::createExportPage()
|
||||
_hires->setChecked(true);
|
||||
else
|
||||
_wysiwyg->setChecked(true);
|
||||
QLabel *lw = new QLabel(tr("The printed area is approximately the display"
|
||||
" area. The map zoom level does not change."));
|
||||
QLabel *lh = new QLabel(tr("The zoom level will be changed so that"
|
||||
InfoLabel *lw = new InfoLabel(tr("The printed area is approximately the "
|
||||
"display area. The map zoom level does not change."));
|
||||
InfoLabel *lh = new InfoLabel(tr("The zoom level will be changed so that"
|
||||
" the whole content (tracks/waypoints) fits to the printed area and"
|
||||
" the map resolution is as close as possible to the print resolution."));
|
||||
QFont f = lw->font();
|
||||
f.setPointSize(f.pointSize() - 1);
|
||||
lw->setWordWrap(true);
|
||||
lh->setWordWrap(true);
|
||||
lw->setFont(f);
|
||||
lh->setFont(f);
|
||||
|
||||
QVBoxLayout *modeTabLayout = new QVBoxLayout();
|
||||
modeTabLayout->addWidget(_wysiwyg);
|
||||
@ -669,20 +680,28 @@ QWidget *OptionsDialog::createSystemPage()
|
||||
_connectionTimeout->setSuffix(UNIT_SPACE + tr("s"));
|
||||
_connectionTimeout->setValue(_options.connectionTimeout);
|
||||
|
||||
#ifdef Q_OS_MAC
|
||||
QWidget *systemTab = new QWidget();
|
||||
QFormLayout *systemTabLayout = new QFormLayout();
|
||||
systemTabLayout->addRow(tr("Image cache size:"), _pixmapCache);
|
||||
systemTabLayout->addRow(tr("Connection timeout:"), _connectionTimeout);
|
||||
systemTabLayout->addWidget(_enableHTTP2);
|
||||
systemTabLayout->addWidget(_useOpenGL);
|
||||
systemTab->setLayout(systemTabLayout);
|
||||
#else // Q_OS_MAC
|
||||
QFormLayout *formLayout = new QFormLayout();
|
||||
formLayout->addRow(tr("Image cache size:"), _pixmapCache);
|
||||
formLayout->addRow(tr("Connection timeout:"), _connectionTimeout);
|
||||
|
||||
QFormLayout *checkboxLayout = new QFormLayout();
|
||||
checkboxLayout->addWidget(_enableHTTP2);
|
||||
checkboxLayout->addWidget(_useOpenGL);
|
||||
|
||||
QWidget *systemTab = new QWidget();
|
||||
QVBoxLayout *systemTabLayout = new QVBoxLayout();
|
||||
systemTabLayout->addLayout(formLayout);
|
||||
systemTabLayout->addLayout(checkboxLayout);
|
||||
systemTabLayout->addStretch();
|
||||
systemTab->setLayout(systemTabLayout);
|
||||
#endif // Q_OS_MAC
|
||||
|
||||
_dataPath = new DirSelectWidget();
|
||||
_dataPath->setDir(_options.dataPath);
|
||||
@ -691,12 +710,8 @@ QWidget *OptionsDialog::createSystemPage()
|
||||
_poiPath = new DirSelectWidget();
|
||||
_poiPath->setDir(_options.poiPath);
|
||||
|
||||
QLabel *info = new QLabel(tr("Select the initial paths of the file open"
|
||||
" dialogues. Leave the field empty for the system default."));
|
||||
QFont f = info->font();
|
||||
f.setPointSize(f.pointSize() - 1);
|
||||
info->setFont(f);
|
||||
info->setWordWrap(true);
|
||||
InfoLabel *info = new InfoLabel(tr("Select the initial paths of the file"
|
||||
" open dialogues. Leave the field empty for the system default."));
|
||||
|
||||
QFormLayout *pathsFormLayout = new QFormLayout();
|
||||
pathsFormLayout->addRow(tr("Data:"), _dataPath);
|
||||
@ -705,8 +720,8 @@ QWidget *OptionsDialog::createSystemPage()
|
||||
|
||||
QWidget *pathsTab = new QWidget();
|
||||
QVBoxLayout *pathsTabLayout = new QVBoxLayout();
|
||||
pathsTabLayout->addWidget(info);
|
||||
pathsTabLayout->addLayout(pathsFormLayout);
|
||||
pathsTabLayout->addWidget(info);
|
||||
pathsTabLayout->addStretch();
|
||||
pathsTab->setLayout(pathsTabLayout);
|
||||
|
||||
@ -725,6 +740,7 @@ OptionsDialog::OptionsDialog(Options &options, Units units, QWidget *parent)
|
||||
pages->addWidget(createMapPage());
|
||||
pages->addWidget(createDataPage());
|
||||
pages->addWidget(createPOIPage());
|
||||
pages->addWidget(createDEMPage());
|
||||
pages->addWidget(createExportPage());
|
||||
pages->addWidget(createSystemPage());
|
||||
|
||||
@ -735,6 +751,7 @@ OptionsDialog::OptionsDialog(Options &options, Units units, QWidget *parent)
|
||||
new QListWidgetItem(QIcon(MAPS_ICON), tr("Maps"), menu);
|
||||
new QListWidgetItem(QIcon(DATA_ICON), tr("Data"), menu);
|
||||
new QListWidgetItem(QIcon(POI_ICON), tr("POI"), menu);
|
||||
new QListWidgetItem(QIcon(DEM_ICON), tr("DEM"), menu);
|
||||
new QListWidgetItem(QIcon(PRINT_EXPORT_ICON), tr("Print & Export"),
|
||||
menu);
|
||||
new QListWidgetItem(QIcon(SYSTEM_ICON), tr("System"), menu);
|
||||
@ -764,6 +781,9 @@ OptionsDialog::OptionsDialog(Options &options, Units units, QWidget *parent)
|
||||
QVBoxLayout *layout = new QVBoxLayout;
|
||||
layout->addLayout(contentLayout);
|
||||
layout->addWidget(buttonBox);
|
||||
#ifdef Q_OS_MAC
|
||||
layout->setSizeConstraint(QLayout::SetFixedSize);
|
||||
#endif // Q_OS_MAC
|
||||
setLayout(layout);
|
||||
|
||||
setWindowTitle(tr("Options"));
|
||||
@ -831,6 +851,11 @@ void OptionsDialog::accept()
|
||||
if (qAbs(poiRadius - _options.poiRadius) > 0.01)
|
||||
_options.poiRadius = poiRadius;
|
||||
|
||||
_options.demURL = _demURL->text();
|
||||
_options.demAuthorization = _demAuth->isEnabled();
|
||||
_options.demUsername = _demAuth->username();
|
||||
_options.demPassword = _demAuth->password();
|
||||
|
||||
_options.useOpenGL = _useOpenGL->isChecked();
|
||||
_options.enableHTTP2 = _enableHTTP2->isChecked();
|
||||
_options.pixmapCache = _pixmapCache->value();
|
||||
|
@ -6,18 +6,19 @@
|
||||
#include "units.h"
|
||||
#include "timezoneinfo.h"
|
||||
|
||||
class ColorBox;
|
||||
class StyleComboBox;
|
||||
class OddSpinBox;
|
||||
class QSpinBox;
|
||||
class QDoubleSpinBox;
|
||||
class QComboBox;
|
||||
class QCheckBox;
|
||||
class QRadioButton;
|
||||
class QLineEdit;
|
||||
class ColorBox;
|
||||
class StyleComboBox;
|
||||
class OddSpinBox;
|
||||
class PercentSlider;
|
||||
class ProjectionComboBox;
|
||||
class DirSelectWidget;
|
||||
|
||||
class AuthenticationWidget;
|
||||
|
||||
struct Options {
|
||||
// Appearance
|
||||
@ -61,6 +62,11 @@ struct Options {
|
||||
bool useSegments;
|
||||
// POI
|
||||
int poiRadius;
|
||||
// DEM
|
||||
QString demURL;
|
||||
QString demUsername;
|
||||
QString demPassword;
|
||||
bool demAuthorization;
|
||||
// System
|
||||
bool useOpenGL;
|
||||
bool enableHTTP2;
|
||||
@ -100,6 +106,7 @@ private:
|
||||
QWidget *createPOIPage();
|
||||
QWidget *createSystemPage();
|
||||
QWidget *createExportPage();
|
||||
QWidget *createDEMPage();
|
||||
|
||||
Options &_options;
|
||||
|
||||
@ -153,6 +160,9 @@ private:
|
||||
QCheckBox *_useSegments;
|
||||
// POI
|
||||
QDoubleSpinBox *_poiRadius;
|
||||
// DEM
|
||||
QLineEdit *_demURL;
|
||||
AuthenticationWidget *_demAuth;
|
||||
// System
|
||||
QSpinBox *_pixmapCache;
|
||||
QSpinBox *_connectionTimeout;
|
||||
|
@ -19,7 +19,10 @@ public:
|
||||
void setDigitalZoom(int zoom) {setScale(pow(2, -zoom));}
|
||||
|
||||
int type() const {return parentItem()->type();}
|
||||
QString info() const {return static_cast<GraphicsItem*>(parentItem())->info();}
|
||||
ToolTip info() const
|
||||
{
|
||||
return static_cast<GraphicsItem*>(parentItem())->info();
|
||||
}
|
||||
|
||||
static QRect tickRect(int value);
|
||||
|
||||
|
@ -6,25 +6,31 @@
|
||||
#include <QMouseEvent>
|
||||
#include <QBasicTimer>
|
||||
#include <QScreen>
|
||||
#include <QVBoxLayout>
|
||||
#include <QApplication>
|
||||
#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
|
||||
#include <QDesktopWidget>
|
||||
#endif // QT 5.15
|
||||
#include "tooltip.h"
|
||||
#include "thumbnail.h"
|
||||
#include "flowlayout.h"
|
||||
#include "popup.h"
|
||||
|
||||
|
||||
class PopupLabel : public QLabel
|
||||
class PopupFrame : public QFrame
|
||||
{
|
||||
public:
|
||||
PopupLabel(const QString &text, QWidget *parent = 0);
|
||||
~PopupLabel();
|
||||
PopupFrame(const ToolTip &toolTip, QWidget *parent = 0);
|
||||
~PopupFrame();
|
||||
|
||||
const ToolTip &toolTip() const {return _toolTip;}
|
||||
|
||||
bool eventFilter(QObject *o, QEvent *ev);
|
||||
void place(const QPoint &pos, QWidget *w);
|
||||
void deleteAfterTimer();
|
||||
void stopTimer() {_timer.stop();}
|
||||
|
||||
static PopupLabel *_instance;
|
||||
static PopupFrame *_instance;
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *event);
|
||||
@ -32,14 +38,17 @@ protected:
|
||||
void contextMenuEvent(QContextMenuEvent *) {}
|
||||
|
||||
private:
|
||||
void createLayout(const ToolTip &content);
|
||||
|
||||
QBasicTimer _timer;
|
||||
ToolTip _toolTip;
|
||||
};
|
||||
|
||||
PopupLabel *PopupLabel::_instance = 0;
|
||||
PopupFrame *PopupFrame::_instance = 0;
|
||||
|
||||
PopupLabel::PopupLabel(const QString &text, QWidget *parent)
|
||||
: QLabel(text, parent, Qt::ToolTip | Qt::BypassGraphicsProxyWidget
|
||||
| Qt::WindowDoesNotAcceptFocus)
|
||||
PopupFrame::PopupFrame(const ToolTip &toolTip, QWidget *parent)
|
||||
: QFrame(parent, Qt::ToolTip | Qt::BypassGraphicsProxyWidget
|
||||
| Qt::WindowDoesNotAcceptFocus), _toolTip(toolTip)
|
||||
{
|
||||
delete _instance;
|
||||
_instance = this;
|
||||
@ -48,39 +57,73 @@ PopupLabel::PopupLabel(const QString &text, QWidget *parent)
|
||||
setBackgroundRole(QPalette::ToolTipBase);
|
||||
setPalette(QToolTip::palette());
|
||||
ensurePolished();
|
||||
setMargin(1 + style()->pixelMetric(QStyle::PM_ToolTipLabelFrameWidth, 0,
|
||||
this));
|
||||
|
||||
setFrameStyle(QFrame::NoFrame);
|
||||
setAlignment(Qt::AlignLeft);
|
||||
setIndent(1);
|
||||
setWindowOpacity(style()->styleHint(QStyle::SH_ToolTipLabel_Opacity, 0,
|
||||
this) / 255.0);
|
||||
|
||||
setTextInteractionFlags(Qt::TextBrowserInteraction);
|
||||
setOpenExternalLinks(true);
|
||||
setWordWrap(true);
|
||||
createLayout(toolTip);
|
||||
|
||||
setMouseTracking(true);
|
||||
|
||||
qApp->installEventFilter(this);
|
||||
}
|
||||
|
||||
PopupLabel::~PopupLabel()
|
||||
PopupFrame::~PopupFrame()
|
||||
{
|
||||
_instance = 0;
|
||||
}
|
||||
|
||||
void PopupLabel::paintEvent(QPaintEvent *event)
|
||||
void PopupFrame::createLayout(const ToolTip &content)
|
||||
{
|
||||
QVBoxLayout *layout = new QVBoxLayout();
|
||||
int margin = 1 + style()->pixelMetric(QStyle::PM_ToolTipLabelFrameWidth, 0,
|
||||
this);
|
||||
layout->setContentsMargins(margin, margin, margin, margin);
|
||||
layout->setSpacing(0);
|
||||
|
||||
if (!content.images().isEmpty()) {
|
||||
FlowLayout *imagesLayout = new FlowLayout(0, 2, 2);
|
||||
int size = qMin(960/content.images().size(), 240);
|
||||
|
||||
for (int i = 0; i < content.images().size(); i++)
|
||||
imagesLayout->addWidget(new Thumbnail(content.images().at(i), size));
|
||||
|
||||
layout->addLayout(imagesLayout);
|
||||
}
|
||||
|
||||
if (!content.list().isEmpty()) {
|
||||
QString html = "<table>";
|
||||
for (int i = 0; i < content.list().count(); i++)
|
||||
html += "<tr><td align=\"right\"><b>" + content.list().at(i).key()
|
||||
+ ": </b></td><td>" + content.list().at(i).value()
|
||||
+ "</td></tr>";
|
||||
html += "</table>";
|
||||
|
||||
QLabel *label = new QLabel(html);
|
||||
label->setAlignment(Qt::AlignLeft);
|
||||
label->setIndent(1);
|
||||
label->setTextInteractionFlags(Qt::TextBrowserInteraction);
|
||||
label->setOpenExternalLinks(true);
|
||||
label->setWordWrap(true);
|
||||
|
||||
layout->addWidget(label);
|
||||
}
|
||||
|
||||
setLayout(layout);
|
||||
}
|
||||
|
||||
void PopupFrame::paintEvent(QPaintEvent *event)
|
||||
{
|
||||
QStylePainter p(this);
|
||||
QStyleOptionFrame opt;
|
||||
opt.initFrom(this);
|
||||
p.drawPrimitive(QStyle::PE_PanelTipLabel, opt);
|
||||
p.end();
|
||||
QLabel::paintEvent(event);
|
||||
QFrame::paintEvent(event);
|
||||
}
|
||||
|
||||
void PopupLabel::timerEvent(QTimerEvent *event)
|
||||
void PopupFrame::timerEvent(QTimerEvent *event)
|
||||
{
|
||||
if (event->timerId() == _timer.timerId()) {
|
||||
_timer.stop();
|
||||
@ -88,7 +131,7 @@ void PopupLabel::timerEvent(QTimerEvent *event)
|
||||
}
|
||||
}
|
||||
|
||||
bool PopupLabel::eventFilter(QObject *o, QEvent *ev)
|
||||
bool PopupFrame::eventFilter(QObject *o, QEvent *ev)
|
||||
{
|
||||
Q_UNUSED(o);
|
||||
|
||||
@ -123,7 +166,7 @@ bool PopupLabel::eventFilter(QObject *o, QEvent *ev)
|
||||
return false;
|
||||
}
|
||||
|
||||
void PopupLabel::place(const QPoint &pos, QWidget *w)
|
||||
void PopupFrame::place(const QPoint &pos, QWidget *w)
|
||||
{
|
||||
#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
|
||||
QRect screen = QApplication::desktop()->screenGeometry(w);
|
||||
@ -148,31 +191,34 @@ void PopupLabel::place(const QPoint &pos, QWidget *w)
|
||||
this->move(p);
|
||||
}
|
||||
|
||||
void PopupLabel::deleteAfterTimer()
|
||||
void PopupFrame::deleteAfterTimer()
|
||||
{
|
||||
if (!_timer.isActive())
|
||||
_timer.start(300, this);
|
||||
}
|
||||
|
||||
|
||||
void Popup::show(const QPoint &pos, const QString &text, QWidget *w)
|
||||
void Popup::show(const QPoint &pos, const ToolTip &toolTip, QWidget *w)
|
||||
{
|
||||
if (text.isEmpty())
|
||||
if (toolTip.isEmpty())
|
||||
return;
|
||||
|
||||
if (PopupLabel::_instance) {
|
||||
PopupLabel::_instance->stopTimer();
|
||||
PopupLabel::_instance->setText(text);
|
||||
if (PopupFrame::_instance) {
|
||||
if (toolTip == PopupFrame::_instance->toolTip())
|
||||
PopupFrame::_instance->stopTimer();
|
||||
else {
|
||||
delete PopupFrame::_instance;
|
||||
PopupFrame::_instance = new PopupFrame(toolTip);
|
||||
}
|
||||
} else
|
||||
PopupLabel::_instance = new PopupLabel(text);
|
||||
PopupFrame::_instance = new PopupFrame(toolTip);
|
||||
|
||||
PopupLabel::_instance->resize(PopupLabel::_instance->sizeHint());
|
||||
PopupLabel::_instance->place(pos, w);
|
||||
PopupLabel::_instance->showNormal();
|
||||
PopupFrame::_instance->resize(PopupFrame::_instance->sizeHint());
|
||||
PopupFrame::_instance->place(pos, w);
|
||||
PopupFrame::_instance->showNormal();
|
||||
}
|
||||
|
||||
void Popup::clear()
|
||||
{
|
||||
if (PopupLabel::_instance)
|
||||
delete PopupLabel::_instance;
|
||||
if (PopupFrame::_instance)
|
||||
delete PopupFrame::_instance;
|
||||
}
|
||||
|
@ -2,13 +2,13 @@
|
||||
#define POPUP_H
|
||||
|
||||
class QPoint;
|
||||
class QString;
|
||||
class QWidget;
|
||||
class ToolTip;
|
||||
|
||||
class Popup
|
||||
{
|
||||
public:
|
||||
static void show(const QPoint &pos, const QString &text, QWidget *w);
|
||||
static void show(const QPoint &pos, const ToolTip &toolTip, QWidget *w);
|
||||
static void clear();
|
||||
};
|
||||
|
||||
|
@ -9,7 +9,7 @@ PowerGraphItem::PowerGraphItem(const Graph &graph, GraphType type, int width,
|
||||
{
|
||||
}
|
||||
|
||||
QString PowerGraphItem::info() const
|
||||
ToolTip PowerGraphItem::info() const
|
||||
{
|
||||
ToolTip tt;
|
||||
QLocale l(QLocale::system());
|
||||
@ -19,5 +19,5 @@ QString PowerGraphItem::info() const
|
||||
tt.insert(tr("Average"), l.toString(avg(), 'f', 1)
|
||||
+ UNIT_SPACE + tr("W"));
|
||||
|
||||
return tt.toString();
|
||||
return tt;
|
||||
}
|
||||
|
@ -11,7 +11,7 @@ public:
|
||||
PowerGraphItem(const Graph &graph, GraphType type, int width,
|
||||
const QColor &color, QGraphicsItem *parent = 0);
|
||||
|
||||
QString info() const;
|
||||
ToolTip info() const;
|
||||
};
|
||||
|
||||
#endif // POWERGRAPHITEM_H
|
||||
|
@ -8,7 +8,7 @@
|
||||
#include "routeitem.h"
|
||||
|
||||
|
||||
QString RouteItem::info() const
|
||||
ToolTip RouteItem::info() const
|
||||
{
|
||||
ToolTip tt;
|
||||
|
||||
@ -32,7 +32,7 @@ QString RouteItem::info() const
|
||||
tt.insert(tr("Links"), links);
|
||||
}
|
||||
|
||||
return tt.toString();
|
||||
return tt;
|
||||
}
|
||||
|
||||
RouteItem::RouteItem(const Route &route, Map *map, QGraphicsItem *parent)
|
||||
|
@ -21,7 +21,7 @@ public:
|
||||
void showWaypoints(bool show);
|
||||
void showWaypointLabels(bool show);
|
||||
|
||||
QString info() const;
|
||||
ToolTip info() const;
|
||||
QDateTime date() const {return QDateTime();}
|
||||
|
||||
private:
|
||||
|
@ -173,6 +173,14 @@
|
||||
#define USE_SEGMENTS_DEFAULT true
|
||||
#define POI_RADIUS_SETTING "poiRadius"
|
||||
#define POI_RADIUS_DEFAULT (int)(IMPERIAL_UNITS() ? MIINM : KMINM)
|
||||
#define DEM_URL_SETTING "demURL"
|
||||
#define DEM_URL_DEFAULT ""
|
||||
#define DEM_AUTH_SETTING "demAuthentication"
|
||||
#define DEM_AUTH_DEFAULT false
|
||||
#define DEM_USERNAME_SETTING "demUsername"
|
||||
#define DEM_USERNAME_DEFAULT ""
|
||||
#define DEM_PASSWORD_SETTING "demPassword"
|
||||
#define DEM_PASSWORD_DEFAULT ""
|
||||
#define USE_OPENGL_SETTING "useOpenGL"
|
||||
#define USE_OPENGL_DEFAULT false
|
||||
#define ENABLE_HTTP2_SETTING "enableHTTP2"
|
||||
|
@ -15,7 +15,7 @@ SpeedGraphItem::SpeedGraphItem(const Graph &graph, GraphType type, int width,
|
||||
_mavg = graph.last().last().s() / movingTime;
|
||||
}
|
||||
|
||||
QString SpeedGraphItem::info() const
|
||||
ToolTip SpeedGraphItem::info() const
|
||||
{
|
||||
ToolTip tt;
|
||||
qreal scale = (_units == Imperial) ? MS2MIH : (_units == Nautical)
|
||||
@ -34,7 +34,7 @@ QString SpeedGraphItem::info() const
|
||||
? avg() * scale : mavg() * scale, 'f', 1) + UNIT_SPACE + su);
|
||||
tt.insert(tr("Pace"), pace + UNIT_SPACE + pu);
|
||||
|
||||
return tt.toString();
|
||||
return tt;
|
||||
}
|
||||
|
||||
void SpeedGraphItem::setTimeType(TimeType type)
|
||||
|
@ -17,7 +17,7 @@ public:
|
||||
qreal mavg() const {return _mavg;}
|
||||
qreal max() const {return _max;}
|
||||
|
||||
QString info() const;
|
||||
ToolTip info() const;
|
||||
|
||||
void setTimeType(TimeType type);
|
||||
|
||||
|
@ -12,7 +12,7 @@ TemperatureGraphItem::TemperatureGraphItem(const Graph &graph, GraphType type,
|
||||
_avg = GraphItem::avg();
|
||||
}
|
||||
|
||||
QString TemperatureGraphItem::info() const
|
||||
ToolTip TemperatureGraphItem::info() const
|
||||
{
|
||||
ToolTip tt;
|
||||
qreal scale = (_units == Metric) ? 1.0 : C2FS;
|
||||
@ -28,5 +28,5 @@ QString TemperatureGraphItem::info() const
|
||||
tt.insert(tr("Minimum"), l.toString(min() * scale + offset, 'f', 1)
|
||||
+ UNIT_SPACE + su);
|
||||
|
||||
return tt.toString();
|
||||
return tt;
|
||||
}
|
||||
|
@ -15,7 +15,7 @@ public:
|
||||
qreal min() const {return _min;}
|
||||
qreal avg() const {return _avg;}
|
||||
|
||||
QString info() const;
|
||||
ToolTip info() const;
|
||||
|
||||
private:
|
||||
qreal _min, _max, _avg;
|
||||
|
43
src/GUI/thumbnail.cpp
Normal file
43
src/GUI/thumbnail.cpp
Normal file
@ -0,0 +1,43 @@
|
||||
#include <QImageReader>
|
||||
#include <QDesktopServices>
|
||||
#include <QFileInfo>
|
||||
#include <QMouseEvent>
|
||||
#include "data/imageinfo.h"
|
||||
#include "thumbnail.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);
|
||||
}
|
||||
|
||||
return QSize(width, height);
|
||||
}
|
||||
|
||||
Thumbnail::Thumbnail(const ImageInfo &img, int size, QWidget *parent)
|
||||
: QLabel(parent)
|
||||
{
|
||||
QImageReader reader(img.path());
|
||||
reader.setAutoTransform(true);
|
||||
reader.setScaledSize(thumbnailSize(img, size));
|
||||
setPixmap(QPixmap::fromImage(reader.read()));
|
||||
|
||||
setCursor(Qt::PointingHandCursor);
|
||||
|
||||
setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
|
||||
|
||||
_path = QFileInfo(img.path()).absoluteFilePath();
|
||||
}
|
||||
|
||||
void Thumbnail::mousePressEvent(QMouseEvent *event)
|
||||
{
|
||||
if (event->button() == Qt::LeftButton)
|
||||
QDesktopServices::openUrl(QUrl::fromLocalFile(_path));
|
||||
}
|
20
src/GUI/thumbnail.h
Normal file
20
src/GUI/thumbnail.h
Normal file
@ -0,0 +1,20 @@
|
||||
#ifndef THUMBNAIL_H
|
||||
#define THUMBNAIL_H
|
||||
|
||||
#include <QLabel>
|
||||
|
||||
class ImageInfo;
|
||||
|
||||
class Thumbnail : public QLabel
|
||||
{
|
||||
public:
|
||||
Thumbnail(const ImageInfo &img, int size, QWidget *parent = 0);
|
||||
|
||||
protected:
|
||||
void mousePressEvent(QMouseEvent *event);
|
||||
|
||||
private:
|
||||
QString _path;
|
||||
};
|
||||
|
||||
#endif // THUMBNAIL_H
|
@ -1,52 +0,0 @@
|
||||
#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);
|
||||
}
|
||||
|
||||
return QSize(width, height);
|
||||
}
|
||||
|
||||
void ToolTip::insert(const QString &key, const QString &value)
|
||||
{
|
||||
_list.append(KV<QString, QString>(key, value));
|
||||
}
|
||||
|
||||
QString ToolTip::toString() const
|
||||
{
|
||||
QString html;
|
||||
|
||||
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 += 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>";
|
||||
}
|
||||
|
||||
if (!_list.isEmpty()) {
|
||||
html += "<table>";
|
||||
for (int i = 0; i < _list.count(); i++)
|
||||
html += "<tr><td align=\"right\"><b>" + _list.at(i).key()
|
||||
+ ": </b></td><td>" + _list.at(i).value() + "</td></tr>";
|
||||
html += "</table>";
|
||||
}
|
||||
|
||||
return html;
|
||||
}
|
@ -10,9 +10,31 @@
|
||||
class ToolTip
|
||||
{
|
||||
public:
|
||||
void insert(const QString &key, const QString &value);
|
||||
void setImages(const QVector<ImageInfo> &images) {_images = images;}
|
||||
QString toString() const;
|
||||
const QList<KV<QString, QString> > &list() const {return _list;}
|
||||
const QVector<ImageInfo> &images() const {return _images;}
|
||||
|
||||
bool isEmpty() const
|
||||
{
|
||||
return _list.isEmpty() && _images.isEmpty();
|
||||
}
|
||||
|
||||
bool operator==(const ToolTip &other) const
|
||||
{
|
||||
return (_list == other._list && _images == other._images);
|
||||
}
|
||||
bool operator!=(const ToolTip &other) const
|
||||
{
|
||||
return (_list != other._list || _images != other._images);
|
||||
}
|
||||
|
||||
void insert(const QString &key, const QString &value)
|
||||
{
|
||||
_list.append(KV<QString, QString>(key, value));
|
||||
}
|
||||
void setImages(const QVector<ImageInfo> &images)
|
||||
{
|
||||
_images = images;
|
||||
}
|
||||
|
||||
private:
|
||||
QList<KV<QString, QString> > _list;
|
||||
|
@ -6,7 +6,7 @@
|
||||
#include "trackitem.h"
|
||||
|
||||
|
||||
QString TrackItem::info() const
|
||||
ToolTip TrackItem::info() const
|
||||
{
|
||||
ToolTip tt;
|
||||
QLocale l;
|
||||
@ -37,7 +37,7 @@ QString TrackItem::info() const
|
||||
tt.insert(tr("Links"), links);
|
||||
}
|
||||
|
||||
return tt.toString();
|
||||
return tt;
|
||||
}
|
||||
|
||||
TrackItem::TrackItem(const Track &track, Map *map, QGraphicsItem *parent)
|
||||
|
@ -15,7 +15,7 @@ class TrackItem : public PathItem
|
||||
public:
|
||||
TrackItem(const Track &track, Map *map, QGraphicsItem *parent = 0);
|
||||
|
||||
QString info() const;
|
||||
ToolTip info() const;
|
||||
QDateTime date() const {return _date;}
|
||||
|
||||
private:
|
||||
|
@ -3,7 +3,6 @@
|
||||
#include <QGraphicsSceneMouseEvent>
|
||||
#include <QLabel>
|
||||
#include "font.h"
|
||||
#include "tooltip.h"
|
||||
#include "popup.h"
|
||||
#include "waypointitem.h"
|
||||
|
||||
@ -18,7 +17,7 @@ Units WaypointItem::_units = Metric;
|
||||
CoordinatesFormat WaypointItem::_format = DecimalDegrees;
|
||||
QTimeZone WaypointItem::_timeZone = QTimeZone::utc();
|
||||
|
||||
QString WaypointItem::info() const
|
||||
ToolTip WaypointItem::info() const
|
||||
{
|
||||
ToolTip tt;
|
||||
QLocale l;
|
||||
@ -66,7 +65,7 @@ QString WaypointItem::info() const
|
||||
}
|
||||
tt.setImages(_waypoint.images());
|
||||
|
||||
return tt.toString();
|
||||
return tt;
|
||||
}
|
||||
|
||||
WaypointItem::WaypointItem(const Waypoint &waypoint, Map *map,
|
||||
|
@ -30,7 +30,7 @@ public:
|
||||
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
|
||||
QWidget *widget);
|
||||
|
||||
QString info() const;
|
||||
ToolTip info() const;
|
||||
|
||||
static void setUnits(Units units) {_units = units;}
|
||||
static void setCoordinatesFormat(CoordinatesFormat format)
|
||||
|
204
src/common/downloader.cpp
Normal file
204
src/common/downloader.cpp
Normal file
@ -0,0 +1,204 @@
|
||||
#include <QFile>
|
||||
#include <QFileInfo>
|
||||
#include <QNetworkRequest>
|
||||
#include <QDir>
|
||||
#include <QTimerEvent>
|
||||
#include "common/config.h"
|
||||
#include "downloader.h"
|
||||
|
||||
|
||||
#if defined(Q_OS_LINUX)
|
||||
#define PLATFORM_STR "Linux"
|
||||
#elif defined(Q_OS_WIN32)
|
||||
#define PLATFORM_STR "Windows"
|
||||
#elif defined(Q_OS_MAC)
|
||||
#define PLATFORM_STR "OS X"
|
||||
#else
|
||||
#define PLATFORM_STR "Unknown"
|
||||
#endif
|
||||
|
||||
#define USER_AGENT \
|
||||
APP_NAME "/" APP_VERSION " (" PLATFORM_STR "; Qt " QT_VERSION_STR ")"
|
||||
|
||||
#define MAX_REDIRECT_LEVEL 5
|
||||
#define RETRIES 3
|
||||
|
||||
#define ATTR_REDIRECT_POLICY QNetworkRequest::RedirectPolicyAttribute
|
||||
#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
|
||||
#define ATTR_HTTP2_ALLOWED QNetworkRequest::HTTP2AllowedAttribute
|
||||
#else // QT 5.15
|
||||
#define ATTR_HTTP2_ALLOWED QNetworkRequest::Http2AllowedAttribute
|
||||
#endif // QT 5.15
|
||||
|
||||
#define TMP_SUFFIX ".download"
|
||||
|
||||
|
||||
static QString tmpName(const QString &origName)
|
||||
{
|
||||
return origName + TMP_SUFFIX;
|
||||
}
|
||||
|
||||
static QString origName(const QString &tmpName)
|
||||
{
|
||||
return tmpName.left(tmpName.size() - (sizeof(TMP_SUFFIX) - 1));
|
||||
}
|
||||
|
||||
Authorization::Authorization(const QString &username, const QString &password)
|
||||
{
|
||||
QString concatenated = username + ":" + password;
|
||||
QByteArray data = concatenated.toLocal8Bit().toBase64();
|
||||
_header = "Basic " + data;
|
||||
}
|
||||
|
||||
NetworkTimeout::NetworkTimeout(int timeout, QNetworkReply *reply)
|
||||
: QObject(reply), _timeout(timeout)
|
||||
{
|
||||
connect(reply, &QIODevice::readyRead, this, &NetworkTimeout::reset);
|
||||
_timer.start(timeout * 1000, this);
|
||||
}
|
||||
|
||||
void NetworkTimeout::reset()
|
||||
{
|
||||
_timer.start(_timeout * 1000, this);
|
||||
}
|
||||
|
||||
void NetworkTimeout::timerEvent(QTimerEvent *ev)
|
||||
{
|
||||
if (!_timer.isActive() || ev->timerId() != _timer.timerId())
|
||||
return;
|
||||
QNetworkReply *reply = static_cast<QNetworkReply*>(parent());
|
||||
if (reply->isRunning())
|
||||
reply->close();
|
||||
_timer.stop();
|
||||
}
|
||||
|
||||
|
||||
QNetworkAccessManager *Downloader::_manager = 0;
|
||||
int Downloader::_timeout = 30;
|
||||
bool Downloader::_http2 = true;
|
||||
|
||||
bool Downloader::doDownload(const Download &dl, const Authorization &auth)
|
||||
{
|
||||
const QUrl &url = dl.url();
|
||||
|
||||
if (!url.isValid() || !(url.scheme() == QLatin1String("http")
|
||||
|| url.scheme() == QLatin1String("https"))) {
|
||||
qWarning("%s: Invalid URL", qPrintable(url.toString()));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_errorDownloads.value(url) >= RETRIES)
|
||||
return false;
|
||||
if (_currentDownloads.contains(url))
|
||||
return false;
|
||||
|
||||
QNetworkRequest request(url);
|
||||
request.setMaximumRedirectsAllowed(MAX_REDIRECT_LEVEL);
|
||||
request.setAttribute(ATTR_REDIRECT_POLICY,
|
||||
QNetworkRequest::NoLessSafeRedirectPolicy);
|
||||
request.setAttribute(ATTR_HTTP2_ALLOWED, QVariant(_http2));
|
||||
request.setRawHeader("User-Agent", USER_AGENT);
|
||||
if (!auth.isNull())
|
||||
request.setRawHeader("Authorization", auth.header());
|
||||
|
||||
QFile *file = new QFile(tmpName(dl.file()));
|
||||
if (!file->open(QIODevice::WriteOnly)) {
|
||||
qWarning("%s: %s", qPrintable(file->fileName()),
|
||||
qPrintable(file->errorString()));
|
||||
_errorDownloads.insert(url, RETRIES);
|
||||
return false;
|
||||
}
|
||||
|
||||
Q_ASSERT(_manager);
|
||||
QNetworkReply *reply = _manager->get(request);
|
||||
file->setParent(reply);
|
||||
_currentDownloads.insert(url, file);
|
||||
|
||||
if (reply->isRunning()) {
|
||||
/* Starting with Qt 5.15 this can be replaced by
|
||||
QNetworkRequest::setTransferTimeout() */
|
||||
new NetworkTimeout(_timeout, reply);
|
||||
connect(reply, &QIODevice::readyRead, this, &Downloader::emitReadReady);
|
||||
connect(reply, &QNetworkReply::finished, this, &Downloader::emitFinished);
|
||||
} else {
|
||||
readData(reply);
|
||||
downloadFinished(reply);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Downloader::emitFinished()
|
||||
{
|
||||
downloadFinished(static_cast<QNetworkReply*>(sender()));
|
||||
}
|
||||
|
||||
void Downloader::emitReadReady()
|
||||
{
|
||||
readData(static_cast<QNetworkReply*>(sender()));
|
||||
}
|
||||
|
||||
void Downloader::insertError(const QUrl &url, QNetworkReply::NetworkError error)
|
||||
{
|
||||
if (error == QNetworkReply::OperationCanceledError)
|
||||
_errorDownloads.insert(url, _errorDownloads.value(url) + 1);
|
||||
else
|
||||
_errorDownloads.insert(url, RETRIES);
|
||||
}
|
||||
|
||||
void Downloader::readData(QNetworkReply *reply)
|
||||
{
|
||||
QFile *file = _currentDownloads.value(reply->request().url());
|
||||
Q_ASSERT(file);
|
||||
file->write(reply->readAll());
|
||||
}
|
||||
|
||||
void Downloader::downloadFinished(QNetworkReply *reply)
|
||||
{
|
||||
QUrl url(reply->request().url());
|
||||
QNetworkReply::NetworkError error = reply->error();
|
||||
|
||||
QFile *file = _currentDownloads.value(reply->request().url());
|
||||
if (error) {
|
||||
insertError(url, error);
|
||||
qWarning("%s: %s", url.toEncoded().constData(),
|
||||
qPrintable(reply->errorString()));
|
||||
file->remove();
|
||||
} else {
|
||||
file->close();
|
||||
file->rename(origName(file->fileName()));
|
||||
}
|
||||
|
||||
_currentDownloads.remove(url);
|
||||
reply->deleteLater();
|
||||
|
||||
if (_currentDownloads.isEmpty())
|
||||
emit finished();
|
||||
}
|
||||
|
||||
bool Downloader::get(const QList<Download> &list,
|
||||
const Authorization &authorization)
|
||||
{
|
||||
bool finishEmitted = false;
|
||||
|
||||
for (int i = 0; i < list.count(); i++)
|
||||
finishEmitted |= doDownload(list.at(i), authorization);
|
||||
|
||||
return finishEmitted;
|
||||
}
|
||||
|
||||
void Downloader::enableHTTP2(bool enable)
|
||||
{
|
||||
Q_ASSERT(_manager);
|
||||
_http2 = enable;
|
||||
_manager->clearConnectionCache();
|
||||
}
|
||||
|
||||
#ifndef QT_NO_DEBUG
|
||||
QDebug operator<<(QDebug dbg, const Download &download)
|
||||
{
|
||||
dbg.nospace() << "Download(" << download.url() << "," << download.file()
|
||||
<< ")";
|
||||
return dbg.space();
|
||||
}
|
||||
#endif // QT_NO_DEBUG
|
@ -3,11 +3,12 @@
|
||||
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QNetworkReply>
|
||||
#include <QBasicTimer>
|
||||
#include <QUrl>
|
||||
#include <QList>
|
||||
#include <QSet>
|
||||
#include <QHash>
|
||||
|
||||
class QFile;
|
||||
|
||||
class Download
|
||||
{
|
||||
@ -28,12 +29,30 @@ public:
|
||||
Authorization() {}
|
||||
Authorization(const QString &username, const QString &password);
|
||||
|
||||
bool isNull() const {return _header.isNull();}
|
||||
const QByteArray &header() const {return _header;}
|
||||
|
||||
private:
|
||||
QByteArray _header;
|
||||
};
|
||||
|
||||
class NetworkTimeout : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
NetworkTimeout(int timeout, QNetworkReply *reply);
|
||||
|
||||
private slots:
|
||||
void reset();
|
||||
|
||||
private:
|
||||
void timerEvent(QTimerEvent *ev);
|
||||
|
||||
QBasicTimer _timer;
|
||||
int _timeout;
|
||||
};
|
||||
|
||||
class Downloader : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
@ -55,18 +74,17 @@ signals:
|
||||
|
||||
private slots:
|
||||
void emitFinished();
|
||||
void downloadFinished(QNetworkReply *reply);
|
||||
void emitReadReady();
|
||||
|
||||
private:
|
||||
class Redirect;
|
||||
class ReplyTimeout;
|
||||
|
||||
void insertError(const QUrl &url, QNetworkReply::NetworkError error);
|
||||
bool doDownload(const Download &dl, const QByteArray &authorization,
|
||||
const Redirect *redirect = 0);
|
||||
bool saveToDisk(const QString &filename, QIODevice *data);
|
||||
bool doDownload(const Download &dl, const Authorization &auth);
|
||||
void downloadFinished(QNetworkReply *reply);
|
||||
void readData(QNetworkReply *reply);
|
||||
|
||||
QSet<QUrl> _currentDownloads;
|
||||
QHash<QUrl, QFile*> _currentDownloads;
|
||||
QHash<QUrl, int> _errorDownloads;
|
||||
|
||||
static QNetworkAccessManager *_manager;
|
||||
@ -74,4 +92,8 @@ private:
|
||||
static bool _http2;
|
||||
};
|
||||
|
||||
#ifndef QT_NO_DEBUG
|
||||
QDebug operator<<(QDebug dbg, const Download &download);
|
||||
#endif // QT_NO_DEBUG
|
||||
|
||||
#endif // DOWNLOADER_H
|
@ -9,8 +9,19 @@ public:
|
||||
const KEY &key() const {return _key;}
|
||||
const VALUE &value() const {return _value;}
|
||||
|
||||
bool operator==(const KV &other) const {return _key == other._key;}
|
||||
bool operator<(const KV &other) const {return _key < other._key;}
|
||||
bool operator==(const KV &other) const
|
||||
{
|
||||
return (_key == other._key && _value == other._value);
|
||||
}
|
||||
bool operator<(const KV &other) const
|
||||
{
|
||||
if (_key < other._key)
|
||||
return true;
|
||||
else if (_key > other._key)
|
||||
return false;
|
||||
else
|
||||
return _value < other._value;
|
||||
}
|
||||
|
||||
private:
|
||||
KEY _key;
|
||||
|
@ -19,6 +19,7 @@
|
||||
#include "smlparser.h"
|
||||
#include "ov2parser.h"
|
||||
#include "itnparser.h"
|
||||
#include "onmoveparsers.h"
|
||||
#include "data.h"
|
||||
|
||||
|
||||
@ -41,6 +42,8 @@ static GPIParser gpi;
|
||||
static SMLParser sml;
|
||||
static OV2Parser ov2;
|
||||
static ITNParser itn;
|
||||
static OMDParser omd;
|
||||
static GHPParser ghp;
|
||||
|
||||
static QMap<QString, Parser*> parsers()
|
||||
{
|
||||
@ -67,6 +70,8 @@ static QMap<QString, Parser*> parsers()
|
||||
map.insert("sml", &sml);
|
||||
map.insert("ov2", &ov2);
|
||||
map.insert("itn", &itn);
|
||||
map.insert("omd", &omd);
|
||||
map.insert("ghp", &ghp);
|
||||
|
||||
return map;
|
||||
}
|
||||
@ -144,6 +149,7 @@ QString Data::formats()
|
||||
+ qApp->translate("Data", "KML files") + " (*.kml);;"
|
||||
+ qApp->translate("Data", "LOC files") + " (*.loc);;"
|
||||
+ qApp->translate("Data", "NMEA files") + " (*.nmea);;"
|
||||
+ qApp->translate("Data", "ONmove files") + " (*.omd *.ghp);;"
|
||||
+ qApp->translate("Data", "OV2 files") + " (*.ov2);;"
|
||||
+ qApp->translate("Data", "OziExplorer files") + " (*.plt *.rte *.wpt);;"
|
||||
+ qApp->translate("Data", "SLF files") + " (*.slf);;"
|
||||
|
@ -16,7 +16,7 @@
|
||||
#include <QDir>
|
||||
#include <QFile>
|
||||
#include <private/qzipreader_p.h>
|
||||
#include "common/coordinates.h"
|
||||
#include "common/rectc.h"
|
||||
#include "dem.h"
|
||||
|
||||
|
||||
@ -66,19 +66,26 @@ static qreal height(const Coordinates &c, const QByteArray *data)
|
||||
}
|
||||
|
||||
|
||||
QString DEM::_dir;
|
||||
QCache<DEM::Key, QByteArray> DEM::_data;
|
||||
|
||||
QString DEM::baseName(const Key &key)
|
||||
QString DEM::Tile::latStr() const
|
||||
{
|
||||
const char ns = (key.lat() >= 0) ? 'N' : 'S';
|
||||
const char ew = (key.lon() >= 0) ? 'E' : 'W';
|
||||
|
||||
return QString("%1%2%3%4.hgt").arg(ns)
|
||||
.arg(qAbs(key.lat()), 2, 10, QChar('0')).arg(ew)
|
||||
.arg(qAbs(key.lon()), 3, 10, QChar('0'));
|
||||
const char ns = (_lat >= 0) ? 'N' : 'S';
|
||||
return QString("%1%2").arg(ns).arg(qAbs(_lat), 2, 10, QChar('0'));
|
||||
}
|
||||
|
||||
QString DEM::Tile::lonStr() const
|
||||
{
|
||||
const char ew = (_lon >= 0) ? 'E' : 'W';
|
||||
return QString("%1%2").arg(ew).arg(qAbs(_lon), 3, 10, QChar('0'));
|
||||
}
|
||||
|
||||
QString DEM::Tile::baseName() const
|
||||
{
|
||||
return QString("%1%2.hgt").arg(latStr(), lonStr());
|
||||
}
|
||||
|
||||
QString DEM::_dir;
|
||||
QCache<DEM::Tile, QByteArray> DEM::_data;
|
||||
|
||||
QString DEM::fileName(const QString &baseName)
|
||||
{
|
||||
return QDir(_dir).absoluteFilePath(baseName);
|
||||
@ -89,16 +96,21 @@ void DEM::setDir(const QString &path)
|
||||
_dir = path;
|
||||
}
|
||||
|
||||
void DEM::clearCache()
|
||||
{
|
||||
_data.clear();
|
||||
}
|
||||
|
||||
qreal DEM::elevation(const Coordinates &c)
|
||||
{
|
||||
if (_dir.isEmpty())
|
||||
return NAN;
|
||||
|
||||
Key k(qFloor(c.lon()), qFloor(c.lat()));
|
||||
Tile tile(qFloor(c.lon()), qFloor(c.lat()));
|
||||
|
||||
QByteArray *ba = _data[k];
|
||||
QByteArray *ba = _data[tile];
|
||||
if (!ba) {
|
||||
QString bn(baseName(k));
|
||||
QString bn(tile.baseName());
|
||||
QString fn(fileName(bn));
|
||||
QString zn(fn + ".zip");
|
||||
|
||||
@ -106,22 +118,30 @@ qreal DEM::elevation(const Coordinates &c)
|
||||
QZipReader zip(zn, QIODevice::ReadOnly);
|
||||
ba = new QByteArray(zip.fileData(bn));
|
||||
qreal ele = height(c, ba);
|
||||
_data.insert(k, ba);
|
||||
_data.insert(tile, ba);
|
||||
return ele;
|
||||
} else {
|
||||
QFile file(fn);
|
||||
if (!file.open(QIODevice::ReadOnly)) {
|
||||
qWarning("%s: %s", qPrintable(file.fileName()),
|
||||
qPrintable(file.errorString()));
|
||||
_data.insert(k, new QByteArray());
|
||||
_data.insert(tile, new QByteArray());
|
||||
return NAN;
|
||||
} else {
|
||||
ba = new QByteArray(file.readAll());
|
||||
qreal ele = height(c, ba);
|
||||
_data.insert(k, ba);
|
||||
_data.insert(tile, ba);
|
||||
return ele;
|
||||
}
|
||||
}
|
||||
} else
|
||||
return height(c, ba);
|
||||
}
|
||||
|
||||
#ifndef QT_NO_DEBUG
|
||||
QDebug operator<<(QDebug dbg, const DEM::Tile &tile)
|
||||
{
|
||||
dbg.nospace() << "Tile(" << tile.baseName() << ")";
|
||||
return dbg.space();
|
||||
}
|
||||
#endif // QT_NO_DEBUG
|
||||
|
@ -8,18 +8,23 @@
|
||||
|
||||
class QString;
|
||||
class Coordinates;
|
||||
class RectC;
|
||||
|
||||
class DEM
|
||||
{
|
||||
private:
|
||||
class Key {
|
||||
public:
|
||||
class Tile {
|
||||
public:
|
||||
Key(int lon, int lat) : _lon(lon), _lat(lat) {}
|
||||
Tile(int lon, int lat) : _lon(lon), _lat(lat) {}
|
||||
|
||||
int lon() const {return _lon;}
|
||||
int lat() const {return _lat;}
|
||||
|
||||
bool operator==(const Key &other) const
|
||||
QString lonStr() const;
|
||||
QString latStr() const;
|
||||
QString baseName() const;
|
||||
|
||||
bool operator==(const Tile &other) const
|
||||
{
|
||||
return (_lon == other._lon && _lat == other._lat);
|
||||
}
|
||||
@ -28,22 +33,24 @@ private:
|
||||
int _lon, _lat;
|
||||
};
|
||||
|
||||
static QString baseName(const Key &key);
|
||||
static void setDir(const QString &path);
|
||||
static void clearCache();
|
||||
static qreal elevation(const Coordinates &c);
|
||||
|
||||
private:
|
||||
static QString fileName(const QString &baseName);
|
||||
|
||||
static QString _dir;
|
||||
static QCache<Key, QByteArray> _data;
|
||||
|
||||
public:
|
||||
static void setDir(const QString &path);
|
||||
static qreal elevation(const Coordinates &c);
|
||||
|
||||
friend HASH_T qHash(const Key &key);
|
||||
static QCache<Tile, QByteArray> _data;
|
||||
};
|
||||
|
||||
inline HASH_T qHash(const DEM::Key &key)
|
||||
inline HASH_T qHash(const DEM::Tile &tile)
|
||||
{
|
||||
return (qHash(key.lon()) ^ qHash(key.lat()));
|
||||
return (qHash(tile.lon()) ^ qHash(tile.lat()));
|
||||
}
|
||||
|
||||
#ifndef QT_NO_DEBUG
|
||||
QDebug operator<<(QDebug dbg, const DEM::Tile &tile);
|
||||
#endif // QT_NO_DEBUG
|
||||
|
||||
#endif // DEM_H
|
||||
|
99
src/data/demloader.cpp
Normal file
99
src/data/demloader.cpp
Normal file
@ -0,0 +1,99 @@
|
||||
#include <QtMath>
|
||||
#include <QFileInfo>
|
||||
#include "common/rectc.h"
|
||||
#include "demloader.h"
|
||||
|
||||
|
||||
#define DOWNLOAD_LIMIT 16
|
||||
|
||||
static QList<DEM::Tile> tiles(const RectC &rect)
|
||||
{
|
||||
QList<DEM::Tile> list;
|
||||
|
||||
if (!rect.isValid())
|
||||
return list;
|
||||
|
||||
for (int i = qFloor(rect.top()); i >= qFloor(rect.bottom()); i--)
|
||||
for (int j = qFloor(rect.left()); j <= qFloor(rect.right()); j++)
|
||||
list.append(DEM::Tile(j, i));
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
static bool isZip(const QUrl &url)
|
||||
{
|
||||
QFileInfo fi(url.fileName());
|
||||
return (fi.suffix().toLower() == "zip");
|
||||
}
|
||||
|
||||
|
||||
DEMLoader::DEMLoader(const QString &dir, QObject *parent)
|
||||
: QObject(parent), _dir(dir)
|
||||
{
|
||||
_downloader = new Downloader(this);
|
||||
connect(_downloader, &Downloader::finished, this, &DEMLoader::finished);
|
||||
}
|
||||
|
||||
bool DEMLoader::loadTiles(const RectC &rect)
|
||||
{
|
||||
QList<DEM::Tile> tl(tiles(rect));
|
||||
QList<Download> dl;
|
||||
|
||||
/* Create the user DEM dir only when a download is requested as it will
|
||||
override the global DEM dir. */
|
||||
if (!_dir.mkpath(_dir.absolutePath())) {
|
||||
qWarning("%s: %s", qPrintable(_dir.canonicalPath()),
|
||||
"Error creating DEM directory");
|
||||
return false;
|
||||
}
|
||||
DEM::setDir(_dir.path());
|
||||
|
||||
for (int i = 0; i < tl.size(); i++) {
|
||||
const DEM::Tile &t = tl.at(i);
|
||||
QString fn(tileFile(t));
|
||||
QString zn(fn + ".zip");
|
||||
|
||||
if (!(QFileInfo::exists(zn) || QFileInfo::exists(fn))) {
|
||||
QUrl url(tileUrl(t));
|
||||
dl.append(Download(url, isZip(url) ? zn : fn));
|
||||
}
|
||||
|
||||
if (dl.size() > DOWNLOAD_LIMIT) {
|
||||
qWarning("DEM download limit exceeded.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return _downloader->get(dl, _authorization);
|
||||
}
|
||||
|
||||
bool DEMLoader::checkTiles(const RectC &rect) const
|
||||
{
|
||||
QList<DEM::Tile> tl(tiles(rect));
|
||||
|
||||
for (int i = 0; i < tl.size(); i++) {
|
||||
const DEM::Tile &t = tl.at(i);
|
||||
QString fn(tileFile(t));
|
||||
QString zn(fn + ".zip");
|
||||
|
||||
if (!(QFileInfo::exists(zn) || QFileInfo::exists(fn)))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
QUrl DEMLoader::tileUrl(const DEM::Tile &tile) const
|
||||
{
|
||||
QString url(_url);
|
||||
|
||||
url.replace("$lon", tile.lonStr());
|
||||
url.replace("$lat", tile.latStr());
|
||||
|
||||
return QUrl(url);
|
||||
}
|
||||
|
||||
QString DEMLoader::tileFile(const DEM::Tile &tile) const
|
||||
{
|
||||
return _dir.absoluteFilePath(tile.baseName());
|
||||
}
|
40
src/data/demloader.h
Normal file
40
src/data/demloader.h
Normal file
@ -0,0 +1,40 @@
|
||||
#ifndef DEMLOADER_H
|
||||
#define DEMLOADER_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QDir>
|
||||
#include "common/downloader.h"
|
||||
#include "dem.h"
|
||||
|
||||
class RectC;
|
||||
|
||||
class DEMLoader : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
DEMLoader(const QString &dir, QObject *parent = 0);
|
||||
|
||||
void setUrl(const QString &url) {_url = url;}
|
||||
void setAuthorization(const Authorization &authorization)
|
||||
{_authorization = authorization;}
|
||||
|
||||
bool loadTiles(const RectC &rect);
|
||||
bool checkTiles(const RectC &rect) const;
|
||||
|
||||
const QString &url() const {return _url;}
|
||||
|
||||
signals:
|
||||
void finished();
|
||||
|
||||
private:
|
||||
QUrl tileUrl(const DEM::Tile &tile) const;
|
||||
QString tileFile(const DEM::Tile &tile) const;
|
||||
|
||||
Downloader *_downloader;
|
||||
QString _url;
|
||||
QDir _dir;
|
||||
Authorization _authorization;
|
||||
};
|
||||
|
||||
#endif // DEMLOADER_H
|
@ -16,6 +16,11 @@ public:
|
||||
|
||||
bool isValid() const {return _size.isValid() && !_path.isEmpty();}
|
||||
|
||||
bool operator==(const ImageInfo &other) const
|
||||
{
|
||||
return (_path == other._path);
|
||||
}
|
||||
|
||||
private:
|
||||
QString _path;
|
||||
QSize _size;
|
||||
|
278
src/data/onmoveparsers.cpp
Normal file
278
src/data/onmoveparsers.cpp
Normal file
@ -0,0 +1,278 @@
|
||||
#include <QFileInfo>
|
||||
#include <QDir>
|
||||
#include <QtEndian>
|
||||
#include "onmoveparsers.h"
|
||||
|
||||
|
||||
static inline quint16 u16(const char *buffer)
|
||||
{
|
||||
return qFromLittleEndian<quint16>(buffer);
|
||||
}
|
||||
|
||||
static inline qint16 s16(const char *buffer)
|
||||
{
|
||||
return qFromLittleEndian<qint16>(buffer);
|
||||
}
|
||||
|
||||
static inline qint32 s32(const char *buffer)
|
||||
{
|
||||
return qFromLittleEndian<qint32>(buffer);
|
||||
}
|
||||
|
||||
|
||||
bool OMDParser::readHeaderFile(const QString &omdPath, Header &hdr)
|
||||
{
|
||||
QFileInfo fi(omdPath);
|
||||
QString path = fi.absoluteDir().filePath(fi.baseName() + ".OMH");
|
||||
QFile file(path);
|
||||
char buffer[60];
|
||||
|
||||
if (!file.open(QIODevice::ReadOnly)) {
|
||||
qWarning("%s: %s", qPrintable(path), qPrintable(file.errorString()));
|
||||
return false;
|
||||
}
|
||||
if (file.read(buffer, sizeof(buffer)) != sizeof(buffer)) {
|
||||
qWarning("%s: invalid OMH file", qPrintable(path));
|
||||
return false;
|
||||
}
|
||||
|
||||
quint8 Y = buffer[14];
|
||||
quint8 M = buffer[15];
|
||||
quint8 D = buffer[16];
|
||||
quint8 h = buffer[17];
|
||||
quint8 m = buffer[18];
|
||||
quint16 ascent = u16(buffer + 22);
|
||||
quint16 descent = u16(buffer + 24);
|
||||
quint8 avgHr = buffer[12];
|
||||
quint8 maxHr = buffer[13];
|
||||
|
||||
QDateTime date(QDate(Y + 2000, M, D), QTime(h, m), Qt::UTC);
|
||||
if (!date.isValid()) {
|
||||
qWarning("%s: invalid date", qPrintable(path));
|
||||
return false;
|
||||
}
|
||||
|
||||
hdr.date = date;
|
||||
hdr.hr = avgHr || maxHr;
|
||||
hdr.elevation = ascent || descent;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OMDParser::readF1(const char *chunk, const Header &hdr, Sequence &seq,
|
||||
SegmentData &segment)
|
||||
{
|
||||
if (seq.cnt > 1) {
|
||||
_errorString = "invalid chunk sequence";
|
||||
return false;
|
||||
}
|
||||
|
||||
qint32 lat = s32(chunk);
|
||||
qint32 lon = s32(chunk + 4);
|
||||
quint16 sec = u16(chunk + 12);
|
||||
quint8 fia = chunk[14];
|
||||
qint16 alt = s16(chunk + 15);
|
||||
|
||||
if (fia == 3) {
|
||||
Trackpoint t(Coordinates(lon / 1000000.0, lat / 1000000.0));
|
||||
if (!t.coordinates().isValid()) {
|
||||
_errorString = "invalid coordinates";
|
||||
return false;
|
||||
}
|
||||
t.setTimestamp(QDateTime(hdr.date.date(),
|
||||
hdr.date.time().addSecs(sec), Qt::UTC));
|
||||
if (hdr.elevation)
|
||||
t.setElevation(alt);
|
||||
|
||||
seq.idx[seq.cnt] = segment.size();
|
||||
segment.append(t);
|
||||
} else
|
||||
seq.idx[seq.cnt] = -1;
|
||||
|
||||
seq.cnt++;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OMDParser::readF2(const char *chunk, const Header &hdr, Sequence &seq,
|
||||
SegmentData &segment)
|
||||
{
|
||||
if (!seq.cnt) {
|
||||
_errorString = "invalid chunk sequence";
|
||||
return false;
|
||||
}
|
||||
|
||||
quint16 speed1 = u16(chunk + 2);
|
||||
quint8 hr1 = chunk[6];
|
||||
quint16 speed2 = u16(chunk + 12);
|
||||
quint8 hr2 = chunk[16];
|
||||
|
||||
if (seq.idx[0] >= 0) {
|
||||
Trackpoint &p0 = segment[seq.idx[0]];
|
||||
if (hdr.hr)
|
||||
p0.setHeartRate(hr1);
|
||||
p0.setSpeed(speed1 / 360.0);
|
||||
}
|
||||
if (seq.idx[1] >= 0) {
|
||||
Trackpoint &p1 = segment[seq.idx[1]];
|
||||
if (hdr.hr)
|
||||
p1.setHeartRate(hr2);
|
||||
p1.setSpeed(speed2 / 360.0);
|
||||
}
|
||||
|
||||
seq.idx[0] = -1;
|
||||
seq.idx[1] = -1;
|
||||
seq.cnt = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OMDParser::parse(QFile *file, QList<TrackData> &tracks,
|
||||
QList<RouteData> &routes, QList<Area> &polygons, QVector<Waypoint> &waypoints)
|
||||
{
|
||||
Q_UNUSED(routes);
|
||||
Q_UNUSED(waypoints);
|
||||
Q_UNUSED(polygons);
|
||||
SegmentData segment;
|
||||
Header hdr;
|
||||
Sequence seq;
|
||||
char chunk[20];
|
||||
qint64 size;
|
||||
|
||||
// If no header file is found or it is invalid, continue with the default
|
||||
// header values. The track will have a fictional date and possibly some
|
||||
// zero-graphs, but it will be still usable.
|
||||
readHeaderFile(file->fileName(), hdr);
|
||||
|
||||
while ((size = file->read(chunk, sizeof(chunk))) == sizeof(chunk)) {
|
||||
switch ((quint8)chunk[19]) {
|
||||
case 0xF1:
|
||||
if (!readF1(chunk, hdr, seq, segment))
|
||||
return false;
|
||||
break;
|
||||
case 0xF2:
|
||||
if (!readF2(chunk, hdr, seq, segment))
|
||||
return false;
|
||||
break;
|
||||
default:
|
||||
_errorString = "invalid chunk type";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (size < 0) {
|
||||
_errorString = "I/O error";
|
||||
return false;
|
||||
} else if (size) {
|
||||
_errorString = "unexpected end of file";
|
||||
return false;
|
||||
}
|
||||
|
||||
tracks.append(TrackData());
|
||||
tracks.last().append(segment);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool GHPParser::readHeaderFile(const QString &ghpPath, Header &hdr)
|
||||
{
|
||||
QFileInfo fi(ghpPath);
|
||||
QString path = fi.absoluteDir().filePath(fi.baseName() + ".GHT");
|
||||
QFile file(path);
|
||||
char buffer[96];
|
||||
|
||||
if (!file.open(QIODevice::ReadOnly)) {
|
||||
qWarning("%s: %s", qPrintable(path), qPrintable(file.errorString()));
|
||||
return false;
|
||||
}
|
||||
if (file.read(buffer, sizeof(buffer)) != sizeof(buffer)) {
|
||||
qWarning("%s: invalid GHT file", qPrintable(path));
|
||||
return false;
|
||||
}
|
||||
|
||||
quint8 Y = buffer[0];
|
||||
quint8 M = buffer[1];
|
||||
quint8 D = buffer[2];
|
||||
quint8 h = buffer[3];
|
||||
quint8 m = buffer[4];
|
||||
quint8 s = buffer[5];
|
||||
quint8 avgHr = buffer[61];
|
||||
quint8 maxHr = buffer[60];
|
||||
|
||||
QDateTime date(QDate(Y + 2000, M, D), QTime(h, m, s), Qt::UTC);
|
||||
if (!date.isValid()) {
|
||||
qWarning("%s: invalid date", qPrintable(path));
|
||||
return false;
|
||||
}
|
||||
|
||||
hdr.date = date;
|
||||
hdr.hr = avgHr || maxHr;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GHPParser::readF0(const char *chunk, const Header &hdr, int &time,
|
||||
SegmentData &segment)
|
||||
{
|
||||
qint32 lat = s32(chunk);
|
||||
qint32 lon = s32(chunk + 4);
|
||||
qint16 alt = s16(chunk + 8);
|
||||
quint16 speed = u16(chunk + 10);
|
||||
quint8 hr = chunk[12];
|
||||
quint8 fia = chunk[13];
|
||||
quint8 ms = chunk[16];
|
||||
|
||||
if (fia == 3) {
|
||||
Trackpoint t(Coordinates(lon / 1000000.0, lat / 1000000.0));
|
||||
if (!t.coordinates().isValid()) {
|
||||
_errorString = "invalid coordinates";
|
||||
return false;
|
||||
}
|
||||
t.setTimestamp(QDateTime(hdr.date.date(),
|
||||
hdr.date.time().addMSecs(time * 100), Qt::UTC));
|
||||
t.setSpeed(speed / 360.0);
|
||||
t.setElevation(alt);
|
||||
if (hdr.hr)
|
||||
t.setHeartRate(hr);
|
||||
|
||||
segment.append(t);
|
||||
}
|
||||
|
||||
time += ms;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GHPParser::parse(QFile *file, QList<TrackData> &tracks,
|
||||
QList<RouteData> &routes, QList<Area> &polygons, QVector<Waypoint> &waypoints)
|
||||
{
|
||||
Q_UNUSED(routes);
|
||||
Q_UNUSED(waypoints);
|
||||
Q_UNUSED(polygons);
|
||||
SegmentData segment;
|
||||
Header hdr;
|
||||
int time = 0;
|
||||
char chunk[20];
|
||||
qint64 size;
|
||||
|
||||
// see OMD
|
||||
readHeaderFile(file->fileName(), hdr);
|
||||
|
||||
while ((size = file->read(chunk, sizeof(chunk))) == sizeof(chunk))
|
||||
if (!readF0(chunk, hdr, time, segment))
|
||||
return false;
|
||||
|
||||
if (size < 0) {
|
||||
_errorString = "I/O error";
|
||||
return false;
|
||||
} else if (size) {
|
||||
_errorString = "unexpected end of file";
|
||||
return false;
|
||||
}
|
||||
|
||||
tracks.append(TrackData());
|
||||
tracks.last().append(segment);
|
||||
|
||||
return true;
|
||||
}
|
67
src/data/onmoveparsers.h
Normal file
67
src/data/onmoveparsers.h
Normal file
@ -0,0 +1,67 @@
|
||||
#ifndef ONMOVEPARSERS_H
|
||||
#define ONMOVEPARSERS_H
|
||||
|
||||
#include "parser.h"
|
||||
|
||||
class OMDParser : public Parser
|
||||
{
|
||||
public:
|
||||
bool parse(QFile *file, QList<TrackData> &tracks, QList<RouteData> &routes,
|
||||
QList<Area> &polygons, QVector<Waypoint> &waypoints);
|
||||
QString errorString() const {return _errorString;}
|
||||
int errorLine() const {return 0;}
|
||||
|
||||
private:
|
||||
struct Header
|
||||
{
|
||||
Header() : date(QDateTime(QDate(1970, 1, 1), QTime(0, 0), Qt::UTC)),
|
||||
elevation(true), hr(true) {}
|
||||
|
||||
QDateTime date;
|
||||
bool elevation;
|
||||
bool hr;
|
||||
};
|
||||
|
||||
struct Sequence
|
||||
{
|
||||
Sequence() : cnt(0), idx{-1, -1} {}
|
||||
|
||||
unsigned cnt;
|
||||
int idx[2];
|
||||
};
|
||||
|
||||
bool readHeaderFile(const QString &omdPath, Header &hdr);
|
||||
bool readF1(const char *chunk, const Header &hdr, Sequence &seq,
|
||||
SegmentData &segment);
|
||||
bool readF2(const char *chunk, const Header &hdr, Sequence &seq,
|
||||
SegmentData &segment);
|
||||
|
||||
QString _errorString;
|
||||
};
|
||||
|
||||
class GHPParser : public Parser
|
||||
{
|
||||
public:
|
||||
bool parse(QFile *file, QList<TrackData> &tracks, QList<RouteData> &routes,
|
||||
QList<Area> &polygons, QVector<Waypoint> &waypoints);
|
||||
QString errorString() const {return _errorString;}
|
||||
int errorLine() const {return 0;}
|
||||
|
||||
private:
|
||||
struct Header
|
||||
{
|
||||
Header() : date(QDateTime(QDate(1970, 1, 1), QTime(0, 0), Qt::UTC)),
|
||||
hr(true) {}
|
||||
|
||||
QDateTime date;
|
||||
bool hr;
|
||||
};
|
||||
|
||||
bool readHeaderFile(const QString &ghpPath, Header &hdr);
|
||||
bool readF0(const char *chunk, const Header &hdr, int &time,
|
||||
SegmentData &segment);
|
||||
|
||||
QString _errorString;
|
||||
};
|
||||
|
||||
#endif // ONMOVEPARSERS_H
|
@ -6,8 +6,6 @@
|
||||
|
||||
using namespace IMG;
|
||||
|
||||
typedef QMap<QByteArray, VectorTile*> TileMap;
|
||||
|
||||
static SubFile::Type tileType(const char str[3])
|
||||
{
|
||||
if (!memcmp(str, "TRE", 3))
|
||||
@ -26,25 +24,25 @@ static SubFile::Type tileType(const char str[3])
|
||||
return SubFile::Unknown;
|
||||
}
|
||||
|
||||
IMGData::IMGData(const QString &fileName) : _fileName(fileName)
|
||||
bool IMGData::readSubFileBlocks(QFile &file, quint64 offset, SubFile *subFile)
|
||||
{
|
||||
#define CHECK(condition) \
|
||||
if (!(condition)) { \
|
||||
_errorString = "Unsupported or invalid IMG file"; \
|
||||
qDeleteAll(tileMap); \
|
||||
return; \
|
||||
quint16 block;
|
||||
|
||||
if (!file.seek(offset + 0x20))
|
||||
return false;
|
||||
for (int i = 0; i < 240; i++) {
|
||||
if (!readValue(file, block))
|
||||
return false;
|
||||
if (block == 0xFFFF)
|
||||
break;
|
||||
subFile->addBlock(block);
|
||||
}
|
||||
|
||||
QFile file(fileName);
|
||||
TileMap tileMap;
|
||||
QByteArray typFile;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!file.open(QFile::ReadOnly)) {
|
||||
_errorString = file.errorString();
|
||||
return;
|
||||
}
|
||||
|
||||
// Read IMG header
|
||||
bool IMGData::readIMGHeader(QFile &file)
|
||||
{
|
||||
char signature[7], identifier[7];
|
||||
file.read((char*)&_key, 1) && file.seek(0x10)
|
||||
&& read(file, signature, sizeof(signature)) && file.seek(0x41)
|
||||
@ -52,24 +50,35 @@ IMGData::IMGData(const QString &fileName) : _fileName(fileName)
|
||||
if (memcmp(signature, "DSKIMG", sizeof(signature))
|
||||
|| memcmp(identifier, "GARMIN", sizeof(identifier))) {
|
||||
_errorString = "Not a Garmin IMG file";
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
char d1[20], d2[31];
|
||||
quint8 e1, e2;
|
||||
CHECK(file.seek(0x49) && read(file, d1, sizeof(d1)) && file.seek(0x61)
|
||||
if (!(file.seek(0x49) && read(file, d1, sizeof(d1)) && file.seek(0x61)
|
||||
&& readValue(file, e1) && readValue(file, e2) && file.seek(0x65)
|
||||
&& read(file, d2, sizeof(d2)));
|
||||
&& read(file, d2, sizeof(d2)))) {
|
||||
_errorString = "Error reading IMG header";
|
||||
return false;
|
||||
}
|
||||
|
||||
QByteArray nba(QByteArray(d1, sizeof(d1)) + QByteArray(d2, sizeof(d2)));
|
||||
_name = QString::fromLatin1(nba.constData(), nba.size()-1).trimmed();
|
||||
_blockBits = e1 + e2;
|
||||
|
||||
// Read the FAT table
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IMGData::readFAT(QFile &file, TileMap &tileMap)
|
||||
{
|
||||
QByteArray typFile;
|
||||
quint8 flag;
|
||||
quint64 offset = 0x200;
|
||||
|
||||
// Skip unused FAT blocks if any
|
||||
while (true) {
|
||||
CHECK(file.seek(offset) && readValue(file, flag));
|
||||
if (!(file.seek(offset) && readValue(file, flag)))
|
||||
return false;
|
||||
if (flag)
|
||||
break;
|
||||
offset += 512;
|
||||
@ -79,17 +88,18 @@ IMGData::IMGData(const QString &fileName) : _fileName(fileName)
|
||||
char name[8], type[3];
|
||||
quint32 size;
|
||||
quint16 part;
|
||||
CHECK(file.seek(offset + 12) && readValue(file, size));
|
||||
if (!(file.seek(offset + 12) && readValue(file, size)))
|
||||
return false;
|
||||
offset += 512;
|
||||
int cnt = (size - offset) / 512;
|
||||
|
||||
// Read FAT blocks describing the IMG sub-files
|
||||
for (int i = 0; i < cnt; i++) {
|
||||
quint16 block;
|
||||
CHECK(file.seek(offset) && readValue(file, flag)
|
||||
if (!(file.seek(offset) && readValue(file, flag)
|
||||
&& read(file, name, sizeof(name))
|
||||
&& read(file, type, sizeof(type)) && readValue(file, size)
|
||||
&& readValue(file, part));
|
||||
&& readValue(file, part)))
|
||||
return false;
|
||||
SubFile::Type tt = tileType(type);
|
||||
|
||||
QByteArray fn(name, sizeof(name));
|
||||
@ -104,15 +114,8 @@ IMGData::IMGData(const QString &fileName) : _fileName(fileName)
|
||||
|
||||
SubFile *subFile = part ? tile->file(tt)
|
||||
: tile->addFile(this, tt);
|
||||
CHECK(subFile);
|
||||
|
||||
CHECK(file.seek(offset + 0x20));
|
||||
for (int i = 0; i < 240; i++) {
|
||||
CHECK(readValue(file, block));
|
||||
if (block == 0xFFFF)
|
||||
break;
|
||||
subFile->addBlock(block);
|
||||
}
|
||||
if (!(subFile && readSubFileBlocks(file, offset, subFile)))
|
||||
return false;
|
||||
} else if (tt == SubFile::TYP) {
|
||||
SubFile *typ = 0;
|
||||
if (typFile.isNull()) {
|
||||
@ -122,28 +125,26 @@ IMGData::IMGData(const QString &fileName) : _fileName(fileName)
|
||||
} else if (fn == typFile)
|
||||
typ = _typ;
|
||||
|
||||
if (typ) {
|
||||
CHECK(file.seek(offset + 0x20));
|
||||
for (int i = 0; i < 240; i++) {
|
||||
CHECK(readValue(file, block));
|
||||
if (block == 0xFFFF)
|
||||
break;
|
||||
typ->addBlock(block);
|
||||
}
|
||||
}
|
||||
if (typ && !readSubFileBlocks(file, offset, typ))
|
||||
return false;
|
||||
}
|
||||
|
||||
offset += 512;
|
||||
}
|
||||
|
||||
// Create tile tree
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IMGData::createTileTree(const TileMap &tileMap)
|
||||
{
|
||||
int minMapZoom = 24;
|
||||
|
||||
for (TileMap::const_iterator it = tileMap.constBegin();
|
||||
it != tileMap.constEnd(); ++it) {
|
||||
VectorTile *tile = it.value();
|
||||
|
||||
if (!tile->init()) {
|
||||
qWarning("%s: %s: Invalid map tile", qPrintable(file.fileName()),
|
||||
qWarning("%s: %s: Invalid map tile", qPrintable(_fileName),
|
||||
qPrintable(it.key()));
|
||||
delete tile;
|
||||
continue;
|
||||
@ -177,9 +178,31 @@ IMGData::IMGData(const QString &fileName) : _fileName(fileName)
|
||||
if (!_baseMap)
|
||||
_zooms.setMin(_zooms.min() - 2);
|
||||
|
||||
if (!_tileTree.Count())
|
||||
return (_tileTree.Count() > 0);
|
||||
}
|
||||
|
||||
IMGData::IMGData(const QString &fileName) : _fileName(fileName)
|
||||
{
|
||||
QFile file(fileName);
|
||||
TileMap tileMap;
|
||||
|
||||
if (!file.open(QFile::ReadOnly)) {
|
||||
_errorString = file.errorString();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!readIMGHeader(file))
|
||||
return;
|
||||
if (!readFAT(file, tileMap)) {
|
||||
_errorString = "Error reading FAT data";
|
||||
qDeleteAll(tileMap);
|
||||
return;
|
||||
}
|
||||
if (!createTileTree(tileMap)) {
|
||||
_errorString = "No usable map tile found";
|
||||
else
|
||||
return;
|
||||
}
|
||||
|
||||
_valid = true;
|
||||
}
|
||||
|
||||
|
@ -18,8 +18,14 @@ public:
|
||||
bool readBlock(QFile &file, int blockNum, char *data) const;
|
||||
|
||||
private:
|
||||
typedef QMap<QByteArray, VectorTile*> TileMap;
|
||||
|
||||
qint64 read(QFile &file, char *data, qint64 maxSize) const;
|
||||
template<class T> bool readValue(QFile &file, T &val) const;
|
||||
bool readSubFileBlocks(QFile &file, quint64 offset, SubFile *subFile);
|
||||
bool readFAT(QFile &file, TileMap &tileMap);
|
||||
bool readIMGHeader(QFile &file);
|
||||
bool createTileTree(const TileMap &tileMap);
|
||||
|
||||
QString _fileName;
|
||||
quint8 _key;
|
||||
|
@ -57,6 +57,12 @@ static QString capitalized(const QString &str)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static QByteArray ft2m(const QByteArray &str)
|
||||
{
|
||||
bool ok;
|
||||
int number = str.toInt(&ok);
|
||||
return ok ? QByteArray::number(qRound(number * 0.3048)) : str;
|
||||
}
|
||||
|
||||
LBLFile::~LBLFile()
|
||||
{
|
||||
@ -130,13 +136,15 @@ void LBLFile::clear()
|
||||
_rasters = 0;
|
||||
}
|
||||
|
||||
Label LBLFile::label6b(Handle &hdl, quint32 offset, bool capitalize) const
|
||||
Label LBLFile::label6b(Handle &hdl, quint32 offset, bool capitalize,
|
||||
bool convert) const
|
||||
{
|
||||
Shield::Type shieldType = Shield::None;
|
||||
QByteArray label, shieldLabel;
|
||||
QByteArray *bap = &label;
|
||||
Charset curCharSet = Normal;
|
||||
quint8 b1, b2, b3;
|
||||
int split = -1;
|
||||
|
||||
if (!seek(hdl, offset))
|
||||
return Label();
|
||||
@ -149,6 +157,10 @@ Label LBLFile::label6b(Handle &hdl, quint32 offset, bool capitalize) const
|
||||
|
||||
for (int cpt = 0; cpt < 4; cpt++) {
|
||||
if (c[cpt] > 0x2f || (curCharSet == Normal && c[cpt] == 0x1d)) {
|
||||
if (split >= 0)
|
||||
label = label.left(split) + ft2m(label.mid(split));
|
||||
else if (convert)
|
||||
label = ft2m(label);
|
||||
QString text(QString::fromLatin1(label));
|
||||
return Label(capitalize && isAllUpperCase(text)
|
||||
? capitalized(text) : text, Shield(shieldType, shieldLabel));
|
||||
@ -159,7 +171,16 @@ Label LBLFile::label6b(Handle &hdl, quint32 offset, bool capitalize) const
|
||||
curCharSet = Symbol;
|
||||
else if (c[cpt] == 0x1b)
|
||||
curCharSet = Special;
|
||||
else if (c[cpt] >= 0x2a && c[cpt] <= 0x2f) {
|
||||
else if (c[cpt] >= 0x1e && c[cpt] <= 0x1f) {
|
||||
if (bap == &shieldLabel)
|
||||
bap = &label;
|
||||
else {
|
||||
if (!bap->isEmpty())
|
||||
bap->append('\n');
|
||||
if (c[cpt] == 0x1f && split < 0)
|
||||
split = bap->size();
|
||||
}
|
||||
} else if (c[cpt] >= 0x2a && c[cpt] <= 0x2f) {
|
||||
shieldType = static_cast<Shield::Type>(c[cpt] - 0x29);
|
||||
bap = &shieldLabel;
|
||||
} else if (bap == &shieldLabel
|
||||
@ -181,11 +202,13 @@ Label LBLFile::label6b(Handle &hdl, quint32 offset, bool capitalize) const
|
||||
}
|
||||
}
|
||||
|
||||
Label LBLFile::str2label(const QVector<quint8> &str, bool capitalize) const
|
||||
Label LBLFile::str2label(const QVector<quint8> &str, bool capitalize,
|
||||
bool convert) const
|
||||
{
|
||||
Shield::Type shieldType = Shield::None;
|
||||
QByteArray label, shieldLabel;
|
||||
QByteArray *bap = &label;
|
||||
int split = -1;
|
||||
|
||||
for (int i = 0; i < str.size(); i++) {
|
||||
const quint8 &c = str.at(i);
|
||||
@ -198,8 +221,12 @@ Label LBLFile::str2label(const QVector<quint8> &str, bool capitalize) const
|
||||
else if ((c >= 0x1e && c <= 0x1f)) {
|
||||
if (bap == &shieldLabel)
|
||||
bap = &label;
|
||||
else
|
||||
bap->append(' ');
|
||||
else {
|
||||
if (!bap->isEmpty())
|
||||
bap->append('\n');
|
||||
if (c == 0x1f && split < 0)
|
||||
split = bap->size();
|
||||
}
|
||||
} else if (c < 0x07) {
|
||||
shieldType = static_cast<Shield::Type>(c);
|
||||
bap = &shieldLabel;
|
||||
@ -209,13 +236,17 @@ Label LBLFile::str2label(const QVector<quint8> &str, bool capitalize) const
|
||||
bap->append(c);
|
||||
}
|
||||
|
||||
if (split >= 0)
|
||||
label = label.left(split) + ft2m(label.mid(split));
|
||||
else if (convert)
|
||||
label = ft2m(label);
|
||||
QString text(_codec.toString(label));
|
||||
|
||||
return Label(capitalize && isAllUpperCase(text) ? capitalized(text) : text,
|
||||
Shield(shieldType, _codec.toString(shieldLabel)));
|
||||
}
|
||||
|
||||
Label LBLFile::label8b(Handle &hdl, quint32 offset, bool capitalize) const
|
||||
Label LBLFile::label8b(Handle &hdl, quint32 offset, bool capitalize,
|
||||
bool convert) const
|
||||
{
|
||||
QVector<quint8> str;
|
||||
quint8 c;
|
||||
@ -229,10 +260,11 @@ Label LBLFile::label8b(Handle &hdl, quint32 offset, bool capitalize) const
|
||||
str.append(c);
|
||||
} while (c);
|
||||
|
||||
return str2label(str, capitalize);
|
||||
return str2label(str, capitalize, convert);
|
||||
}
|
||||
|
||||
Label LBLFile::labelHuffman(Handle &hdl, quint32 offset, bool capitalize) const
|
||||
Label LBLFile::labelHuffman(Handle &hdl, quint32 offset, bool capitalize,
|
||||
bool convert) const
|
||||
{
|
||||
QVector<quint8> str;
|
||||
|
||||
@ -241,7 +273,7 @@ Label LBLFile::labelHuffman(Handle &hdl, quint32 offset, bool capitalize) const
|
||||
if (!_huffmanText->decode(this, hdl, str))
|
||||
return Label();
|
||||
if (!_table)
|
||||
return str2label(str, capitalize);
|
||||
return str2label(str, capitalize, convert);
|
||||
|
||||
|
||||
QVector<quint8> str2;
|
||||
@ -268,10 +300,11 @@ Label LBLFile::labelHuffman(Handle &hdl, quint32 offset, bool capitalize) const
|
||||
}
|
||||
}
|
||||
|
||||
return str2label(str2, capitalize);
|
||||
return str2label(str2, capitalize, convert);
|
||||
}
|
||||
|
||||
Label LBLFile::label(Handle &hdl, quint32 offset, bool poi, bool capitalize) const
|
||||
Label LBLFile::label(Handle &hdl, quint32 offset, bool poi, bool capitalize,
|
||||
bool convert) const
|
||||
{
|
||||
quint32 labelOffset;
|
||||
if (poi) {
|
||||
@ -289,12 +322,12 @@ Label LBLFile::label(Handle &hdl, quint32 offset, bool poi, bool capitalize) con
|
||||
|
||||
switch (_encoding) {
|
||||
case 6:
|
||||
return label6b(hdl, labelOffset, capitalize);
|
||||
return label6b(hdl, labelOffset, capitalize, convert);
|
||||
case 9:
|
||||
case 10:
|
||||
return label8b(hdl, labelOffset, capitalize);
|
||||
return label8b(hdl, labelOffset, capitalize, convert);
|
||||
case 11:
|
||||
return labelHuffman(hdl, labelOffset, capitalize);
|
||||
return labelHuffman(hdl, labelOffset, capitalize, convert);
|
||||
default:
|
||||
return Label();
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ public:
|
||||
void clear();
|
||||
|
||||
Label label(Handle &hdl, quint32 offset, bool poi = false,
|
||||
bool capitalize = true) const;
|
||||
bool capitalize = true, bool convert = false) const;
|
||||
|
||||
quint8 imageIdSize() const {return _imgOffsetIdSize;}
|
||||
QPixmap image(Handle &hdl, quint32 id) const;
|
||||
@ -43,10 +43,14 @@ private:
|
||||
quint32 size;
|
||||
};
|
||||
|
||||
Label str2label(const QVector<quint8> &str, bool capitalize) const;
|
||||
Label label6b(Handle &hdl, quint32 offset, bool capitalize) const;
|
||||
Label label8b(Handle &hdl, quint32 offset, bool capitalize) const;
|
||||
Label labelHuffman(Handle &hdl, quint32 offset, bool capitalize) const;
|
||||
Label str2label(const QVector<quint8> &str, bool capitalize,
|
||||
bool convert) const;
|
||||
Label label6b(Handle &hdl, quint32 offset, bool capitalize,
|
||||
bool convert) const;
|
||||
Label label8b(Handle &hdl, quint32 offset, bool capitalize,
|
||||
bool convert) const;
|
||||
Label labelHuffman(Handle &hdl, quint32 offset, bool capitalize,
|
||||
bool convert) const;
|
||||
bool loadRasterTable(Handle &hdl, quint32 offset, quint32 size,
|
||||
quint32 recordSize);
|
||||
|
||||
|
@ -180,9 +180,9 @@ static bool readShape(const NODFile *nod, SubFile::Handle &nodHdl,
|
||||
return false;
|
||||
flags |= (v2 << 8);
|
||||
|
||||
bool hasCoordinatesAdjustBit = flags & (1 << (v2b + 7));
|
||||
bool useEosBit = flags & (1 << (v2b + 5));
|
||||
bool hasAdjustBit = flags & (1 << (v2b + 7));
|
||||
bool startWithStream = flags & (1 << (v2b + 6));
|
||||
bool useEosBit = flags & (1 << (v2b + 5));
|
||||
|
||||
quint32 extraBits;
|
||||
int lonSign, latSign;
|
||||
@ -257,7 +257,7 @@ static bool readShape(const NODFile *nod, SubFile::Handle &nodHdl,
|
||||
if (!stream.readNext(lonDelta, latDelta))
|
||||
break;
|
||||
|
||||
if (hasCoordinatesAdjustBit && !stream.read(1, adjustBit))
|
||||
if (hasAdjustBit && !stream.read(1, adjustBit))
|
||||
return false;
|
||||
|
||||
stepsCnt++;
|
||||
@ -411,9 +411,9 @@ void NETFile::clear()
|
||||
}
|
||||
|
||||
bool NETFile::link(const SubDiv *subdiv, quint32 shift, Handle &hdl,
|
||||
const NODFile *nod, Handle &nodHdl, const LBLFile *lbl, Handle &lblHdl,
|
||||
const NODFile::BlockInfo &blockInfo, quint8 linkId, quint8 lineId,
|
||||
QList<MapData::Poly> *lines) const
|
||||
const NODFile *nod, Handle &nodHdl2, Handle &nodHdl, const LBLFile *lbl,
|
||||
Handle &lblHdl, const NODFile::BlockInfo &blockInfo, quint8 linkId,
|
||||
quint8 lineId, QList<MapData::Poly> *lines) const
|
||||
{
|
||||
MapData::Poly poly;
|
||||
if (!nod->linkType(nodHdl, blockInfo, linkId, poly.type))
|
||||
@ -433,24 +433,24 @@ bool NETFile::link(const SubDiv *subdiv, quint32 shift, Handle &hdl,
|
||||
quint16 mask = 0;
|
||||
quint32 size;
|
||||
|
||||
quint8 s68 = (linkInfo.flags >> 0x12) & 1;
|
||||
quint8 s69 = (linkInfo.flags >> 0x11) & 1;
|
||||
quint8 s6a = (linkInfo.flags >> 0x13) & 1;
|
||||
bool firstIsShape = (linkInfo.flags >> 10) & 1;
|
||||
bool singleTopology = (linkInfo.flags >> 9) & 1;
|
||||
bool hasLevels = (linkInfo.flags >> 11) & 1;
|
||||
|
||||
if (s69 == 0 || s6a == 1) {
|
||||
if (!singleTopology || hasLevels) {
|
||||
if (!bs.readVUInt32(size))
|
||||
return false;
|
||||
}
|
||||
if (s69 == 0) {
|
||||
if (!singleTopology) {
|
||||
if (!readAdjCounts(bs, ca, mask))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!subdiv->level()) {
|
||||
NODFile::AdjacencyInfo adj(nod, blockInfo, linkId, linkInfo);
|
||||
NODFile::AdjacencyInfo adj(nodHdl2, blockInfo, linkId, linkInfo);
|
||||
|
||||
if (s69 == 1) {
|
||||
if (s68 == 1) {
|
||||
if (singleTopology) {
|
||||
if (firstIsShape) {
|
||||
if (!readShape(nod, nodHdl, adj, bs, _tp, subdiv, shift, poly))
|
||||
return false;
|
||||
} else {
|
||||
@ -461,7 +461,7 @@ bool NETFile::link(const SubDiv *subdiv, quint32 shift, Handle &hdl,
|
||||
quint16 mask2 = mask + 0xffff;
|
||||
for (int i = 0; i <= ca.size(); i++) {
|
||||
quint16 step = (i < ca.size()) ? ca.at(i) & mask2 : 0xFFFF;
|
||||
bool shape = (i > 0) ? ca.at(i-1) & mask : (s68 == 1);
|
||||
bool shape = (i > 0) ? ca.at(i-1) & mask : firstIsShape;
|
||||
if (i == lineId) {
|
||||
if (shape) {
|
||||
bool check = (i < ca.size()) ? (ca.at(i) & mask) : false;
|
||||
@ -482,7 +482,9 @@ bool NETFile::link(const SubDiv *subdiv, quint32 shift, Handle &hdl,
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!skipAdjShapes(bs, ca, mask, s68 == 1))
|
||||
Q_ASSERT(hasLevels);
|
||||
|
||||
if (!skipAdjShapes(bs, ca, mask, firstIsShape))
|
||||
return false;
|
||||
|
||||
if (!seekToLevel(bs, subdiv->level()))
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user